Unify scope preprocessing and simulation DSP handoff

This commit is contained in:
Silas Oettinghaus
2026-03-25 14:52:43 +01:00
parent 8c55b25112
commit d3235a5c9c
6 changed files with 317 additions and 116 deletions

View File

@@ -1,4 +1,4 @@
function Scpe_sig = preprocessSignal(Scpe_sig, Symbols, fsym)
function Scpe_sig = preprocessSignal(Scpe_sig, Symbols, fsym, options)
% PREPROCESSSIGNAL Performs standard preprocessing on a signal
%
% Inputs:
@@ -9,19 +9,35 @@ function Scpe_sig = preprocessSignal(Scpe_sig, Symbols, fsym)
% Outputs:
% Scpe_sig - Preprocessed signal
% Resample to 2x symbol rate
Scpe_sig = Scpe_sig.resample("fs_out", 2*fsym);
arguments
Scpe_sig
Symbols
fsym
options.mode string = "auto"
options.tx_pulseformer = []
options.debug_plots (1,1) logical = false
options.apply_gaussian_filter (1,1) logical = true
options.gaussian_cutoff_factor (1,1) double = 0.52
end
% Synchronize with reference
[Scpe_sig, ~] = Scpe_sig.tsynch("reference", Symbols, "fs_ref", fsym, "debug_plots", 0);
preprocessMode = resolvePreprocessMode(options.mode, options.tx_pulseformer, Symbols);
targetFs = 2 * fsym;
switch preprocessMode
case "matched_filter"
matchedPulseformer = buildMatchedPulseformer(options.tx_pulseformer, Symbols, fsym, targetFs);
Scpe_sig = matchedPulseformer.process(Scpe_sig);
case "resample"
Scpe_sig = Scpe_sig.resample("fs_out", targetFs);
otherwise
error('preprocessSignal:InvalidMode', 'Unsupported preprocessing mode "%s".', preprocessMode);
end
[Scpe_sig, ~] = Scpe_sig.tsynch("reference", Symbols, "fs_ref", fsym, "debug_plots", options.debug_plots);
% Apply Gaussian filter
if 1
Scpe_sig = Filter('filtdegree', 8, "f_cutoff", Symbols.fs.*0.52, ...
"fs", Scpe_sig.fs, "filterType", filtertypes.gaussian, ...
"active", true).process(Scpe_sig);
else
Scpe_sig = Filter('filtdegree', 4, "f_cutoff", Symbols.fs.*0.6, ...
if options.apply_gaussian_filter
Scpe_sig = Filter('filtdegree', 8, "f_cutoff", Symbols.fs.*options.gaussian_cutoff_factor, ...
"fs", Scpe_sig.fs, "filterType", filtertypes.gaussian, ...
"active", true).process(Scpe_sig);
end
@@ -29,4 +45,101 @@ end
%Remove DC offset
Scpe_sig = Scpe_sig - mean(Scpe_sig.signal);
end
end
function preprocessMode = resolvePreprocessMode(requestedMode, txPulseformer, Symbols)
requestedMode = string(requestedMode);
if requestedMode ~= "auto"
preprocessMode = requestedMode;
return
end
pulseformer = txPulseformer;
if isempty(pulseformer)
pulseformer = findSignalPulseformer(Symbols);
end
if isRootRaisedCosinePulseformer(pulseformer)
preprocessMode = "matched_filter";
else
preprocessMode = "resample";
end
end
function tf = isRootRaisedCosinePulseformer(pulseformer)
tf = false;
if isempty(pulseformer)
return
end
pulseValue = readPulseformerField(pulseformer, 'pulse', []);
if isempty(pulseValue)
return
end
pulseValue = normalizePulseValue(pulseValue);
tf = pulseValue == pulseform.rrc;
end
function matchedPulseformer = buildMatchedPulseformer(txPulseformer, Symbols, fsym, targetFs)
pulseformerMeta = txPulseformer;
if isempty(pulseformerMeta)
pulseformerMeta = findSignalPulseformer(Symbols);
end
pulseValue = normalizePulseValue(readPulseformerField(pulseformerMeta, 'pulse', pulseform.rrc));
alphaValue = readPulseformerField(pulseformerMeta, 'alpha', 0.05);
pulseLengthValue = readPulseformerField(pulseformerMeta, 'pulselength', 16);
if isempty(alphaValue)
alphaValue = 0.05;
end
matchedPulseformer = Pulseformer( ...
"fsym", fsym, ...
"fdac", targetFs, ...
"pulse", pulseValue, ...
"pulselength", pulseLengthValue, ...
"alpha", alphaValue, ...
"matched", 1);
end
function value = readPulseformerField(pulseformerMeta, fieldName, defaultValue)
value = defaultValue;
if isempty(pulseformerMeta)
return
end
if isstruct(pulseformerMeta) && isfield(pulseformerMeta, fieldName)
candidate = pulseformerMeta.(fieldName);
if ~isempty(candidate)
value = candidate;
end
return
end
if isobject(pulseformerMeta) && isprop(pulseformerMeta, fieldName)
candidate = pulseformerMeta.(fieldName);
if ~isempty(candidate)
value = candidate;
end
end
end
function pulseValue = normalizePulseValue(rawValue)
if isa(rawValue, 'pulseform')
pulseValue = rawValue;
return
end
if iscell(rawValue)
rawValue = rawValue{1};
end
if isstring(rawValue) || ischar(rawValue)
pulseValue = pulseform.(char(string(rawValue)));
return
end
pulseValue = pulseform(rawValue);
end