202 lines
6.1 KiB
Matlab
202 lines
6.1 KiB
Matlab
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));
|
|
if ismac
|
|
path = strrep(path,'\','/');
|
|
else
|
|
path = strrep(path,'/','\');
|
|
end
|
|
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
|