restructure and organize
This commit is contained in:
196
Functions/Job_Processing/loadAndSyncRunSignals.m
Normal file
196
Functions/Job_Processing/loadAndSyncRunSignals.m
Normal file
@@ -0,0 +1,196 @@
|
||||
function [Bits, Symbols, Scpe_cell, found_sync] = loadAndSyncRunSignals(dataTable, options)
|
||||
%LOADANDSYNCRUNSIGNALS Load and synchronize signal files for one run.
|
||||
%
|
||||
% Inputs:
|
||||
% dataTable - one-row table with run metadata and signal file paths
|
||||
% options - struct with storage_path, start_occurence and max_occurences
|
||||
%
|
||||
% Outputs:
|
||||
% Bits - transmitted bit reference
|
||||
% Symbols - transmitted symbol reference
|
||||
% Scpe_cell - synchronized received signal occurrences
|
||||
% found_sync - true when a valid synchronization was found
|
||||
|
||||
found_sync = 0;
|
||||
tempLocalStorage = 1;
|
||||
Scpe_cell = {};
|
||||
loaded_from_cache = false;
|
||||
|
||||
storage_dir = fullfile(prefdir, 'temp_sync_data');
|
||||
|
||||
if tempLocalStorage == 1
|
||||
local_filename = fullfile(storage_dir, sprintf('sync_data_run_%s.mat', num2str(dataTable.run_id)));
|
||||
if exist(local_filename, 'file')
|
||||
try
|
||||
cacheData = load(local_filename, 'Bits', 'Symbols', 'Scpe_cell');
|
||||
if isValidSyncCache(cacheData)
|
||||
Bits = cacheData.Bits;
|
||||
Symbols = cacheData.Symbols;
|
||||
Scpe_cell = cacheData.Scpe_cell;
|
||||
found_sync = 1;
|
||||
loaded_from_cache = true;
|
||||
else
|
||||
warning('loadAndSyncRunSignals:InvalidSyncCache', ...
|
||||
'Ignoring incomplete sync cache file "%s".', local_filename);
|
||||
safeDelete(local_filename);
|
||||
end
|
||||
catch
|
||||
safeDelete(local_filename);
|
||||
found_sync = 0;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if ~found_sync
|
||||
Bits = load(composeStoragePath(options.storage_path, dataTable.tx_bits_path));
|
||||
Bits = Bits.Bits;
|
||||
|
||||
M = double(dataTable.pam_level);
|
||||
fsym = dataTable.symbolrate;
|
||||
Symbols_mapped = PAMmapper(M,0).map(Bits);
|
||||
Symbols_mapped.fs = fsym;
|
||||
|
||||
Symbols = load(composeStoragePath(options.storage_path, dataTable.tx_symbols_path));
|
||||
Symbols = Symbols.Symbols;
|
||||
|
||||
found_sync = 0;
|
||||
try
|
||||
Scpe_load = load(composeStoragePath(options.storage_path, dataTable.rx_sync_path));
|
||||
Scpe_cell = Scpe_load.S;
|
||||
[~,~,~,found_sync] = Scpe_cell{1}.tsynch("reference", Symbols, ...
|
||||
"fs_ref", fsym, ...
|
||||
"debug_plots", 0);
|
||||
catch
|
||||
% Continue with raw data if pre-synchronized data is unavailable.
|
||||
end
|
||||
end
|
||||
|
||||
if ~found_sync
|
||||
try
|
||||
Scpe_sig_raw = load(composeStoragePath(options.storage_path, dataTable.rx_raw_path));
|
||||
Scpe_sig_raw = Scpe_sig_raw.Scpe_sig_raw;
|
||||
Scpe_sig_resampled = Scpe_sig_raw.resample("fs_in", Scpe_sig_raw.fs, "fs_out", 2*fsym);
|
||||
[~, Scpe_cell, ~, found_sync] = Scpe_sig_resampled.tsynch("reference", Symbols, ...
|
||||
"fs_ref", fsym, ...
|
||||
"debug_plots", 0);
|
||||
catch
|
||||
% Continue to mapped-symbol fallback if raw data sync fails.
|
||||
end
|
||||
end
|
||||
|
||||
if ~found_sync && exist('Scpe_sig_raw', 'var')
|
||||
if length(Symbols_mapped.signal) ~= sum(Symbols_mapped.signal == Symbols.signal)
|
||||
[~, Scpe_cell, ~, found_sync] = Scpe_sig_raw.tsynch("reference", Symbols_mapped, ...
|
||||
"fs_ref", fsym, ...
|
||||
"debug_plots", 0);
|
||||
end
|
||||
end
|
||||
|
||||
if tempLocalStorage == 1 && found_sync && ~loaded_from_cache
|
||||
if ~exist(storage_dir, 'dir')
|
||||
mkdir(storage_dir);
|
||||
end
|
||||
|
||||
max_local_files = 10;
|
||||
files = dir(fullfile(storage_dir, 'sync_data_run_*.mat'));
|
||||
if length(files) >= max_local_files
|
||||
[~, fileOrder] = sort([files.datenum]);
|
||||
delete(fullfile(storage_dir, files(fileOrder(1)).name));
|
||||
end
|
||||
|
||||
writeSyncCache(local_filename, Bits, Symbols, Scpe_cell);
|
||||
end
|
||||
|
||||
if found_sync
|
||||
Scpe_cell = selectSyncedOccurrences(Scpe_cell, options);
|
||||
else
|
||||
warning('Could not synchronize the received signal with the stored symbols!');
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function path = composeStoragePath(storagePath, relativePath)
|
||||
relativePath = firstValue(relativePath);
|
||||
path = char(string(storagePath) + string(relativePath));
|
||||
end
|
||||
|
||||
function value = firstValue(value)
|
||||
if iscell(value)
|
||||
value = value{1};
|
||||
elseif ~ischar(value) && ~isscalar(value)
|
||||
value = value(1);
|
||||
end
|
||||
end
|
||||
|
||||
function Scpe_cell = selectSyncedOccurrences(Scpe_cell, options)
|
||||
available_occurences = length(Scpe_cell);
|
||||
start_occurence = floor(getOption(options, 'start_occurence', 1));
|
||||
max_occurences = floor(getOption(options, 'max_occurences', available_occurences));
|
||||
|
||||
if available_occurences < 1
|
||||
warning('loadAndSyncRunSignals:NoSyncedOccurrences', ...
|
||||
'Synchronization reported success, but no synced occurrences are available.');
|
||||
return
|
||||
end
|
||||
|
||||
if start_occurence < 1
|
||||
error('loadAndSyncRunSignals:InvalidStartOccurrence', ...
|
||||
'start_occurence must be >= 1.');
|
||||
end
|
||||
|
||||
if max_occurences < 1
|
||||
Scpe_cell = Scpe_cell(1:0);
|
||||
return
|
||||
end
|
||||
|
||||
if start_occurence > available_occurences
|
||||
warning('loadAndSyncRunSignals:StartOccurrenceTooHigh', ...
|
||||
['Requested start_occurence %d, but only %d synced occurrences are available. ', ...
|
||||
'Processing the last occurrence only.'], ...
|
||||
start_occurence, available_occurences);
|
||||
Scpe_cell = Scpe_cell(available_occurences);
|
||||
return
|
||||
end
|
||||
|
||||
stop_occurence = min(available_occurences, start_occurence + max_occurences - 1);
|
||||
Scpe_cell = Scpe_cell(start_occurence:stop_occurence);
|
||||
end
|
||||
|
||||
function value = getOption(options, name, defaultValue)
|
||||
if isfield(options, name)
|
||||
value = options.(name);
|
||||
else
|
||||
value = defaultValue;
|
||||
end
|
||||
end
|
||||
|
||||
function valid = isValidSyncCache(cacheData)
|
||||
valid = isfield(cacheData, 'Bits') && ...
|
||||
isfield(cacheData, 'Symbols') && ...
|
||||
isfield(cacheData, 'Scpe_cell') && ...
|
||||
iscell(cacheData.Scpe_cell) && ...
|
||||
~isempty(cacheData.Scpe_cell);
|
||||
end
|
||||
|
||||
function writeSyncCache(local_filename, Bits, Symbols, Scpe_cell)
|
||||
cache_dir = fileparts(local_filename);
|
||||
temp_filename = [tempname(cache_dir), '.mat'];
|
||||
|
||||
try
|
||||
save(temp_filename, 'Bits', 'Symbols', 'Scpe_cell');
|
||||
movefile(temp_filename, local_filename, 'f');
|
||||
catch ME
|
||||
safeDelete(temp_filename);
|
||||
rethrow(ME);
|
||||
end
|
||||
end
|
||||
|
||||
function safeDelete(filename)
|
||||
if exist(filename, 'file')
|
||||
try
|
||||
delete(filename);
|
||||
catch
|
||||
% Another parallel worker may already have removed or replaced it.
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user