Unify scope preprocessing and simulation DSP handoff
This commit is contained in:
@@ -38,6 +38,7 @@ try
|
||||
"parameters", options.parameters);
|
||||
|
||||
output.ffe_package{r} = scopeOutput.ffe_package;
|
||||
output.dfe_package{r} = scopeOutput.dfe_package;
|
||||
output.mlse_package{r} = scopeOutput.mlse_package;
|
||||
output.vnle_package{r} = scopeOutput.vnle_package;
|
||||
output.dbtgt_package{r} = scopeOutput.dbtgt_package;
|
||||
@@ -58,6 +59,7 @@ end
|
||||
|
||||
function output = initializeOutput()
|
||||
output.ffe_package = {};
|
||||
output.dfe_package = {};
|
||||
output.mlse_package = {};
|
||||
output.vnle_package = {};
|
||||
output.dbtgt_package = {};
|
||||
|
||||
@@ -9,9 +9,13 @@ function output = dsp_scope_signal(Scpe_sig_raw, Symbols, Tx_bits, options)
|
||||
options.M
|
||||
options.duob_mode
|
||||
options.parameters struct = struct()
|
||||
options.preprocess_mode string = "auto"
|
||||
options.tx_pulseformer = []
|
||||
options.debug_plots (1,1) logical = false
|
||||
end
|
||||
|
||||
output.ffe_package = [];
|
||||
output.dfe_package = [];
|
||||
output.mlse_package = [];
|
||||
output.vnle_package = [];
|
||||
output.dbtgt_package = [];
|
||||
@@ -24,8 +28,13 @@ function output = dsp_scope_signal(Scpe_sig_raw, Symbols, Tx_bits, options)
|
||||
|
||||
len_tr = 4096*2;
|
||||
|
||||
ffe_order = [50, 5, 5];
|
||||
dfe_order = [0, 0, 0];
|
||||
ffe_order_ffe = [50, 0, 0];
|
||||
ffe_order_dfe = [50, 5, 5];
|
||||
ffe_order_vnle = [50, 5, 5];
|
||||
ffe_order_dbtgt = [50, 5, 5];
|
||||
dfe_order_vnle = [0, 0, 0];
|
||||
dfe_order_dbtgt = [0, 0, 0];
|
||||
dfe_feedback_order = [2, 0, 0];
|
||||
pf_ncoeffs = 1;
|
||||
mu_ffe = [0.0001, 0.0008, 0.001];
|
||||
mu_dfe = 0.0004;
|
||||
@@ -43,6 +52,8 @@ function output = dsp_scope_signal(Scpe_sig_raw, Symbols, Tx_bits, options)
|
||||
use_dbtgt = 0;
|
||||
use_dbenc = 0;
|
||||
use_ml_mlse = 0;
|
||||
showAnalysis = 0;
|
||||
decoding_mode = [];
|
||||
|
||||
addProcessingResultToDatabase = 0; %#ok<NASGU>
|
||||
|
||||
@@ -63,11 +74,14 @@ function output = dsp_scope_signal(Scpe_sig_raw, Symbols, Tx_bits, options)
|
||||
eq_post = FFE("epochs_tr",5,"epochs_dd",2,"len_tr",2^13,"mu_dd",mu_dd,"mu_tr",mu_tr,"order",25,"sps",2,"decide",0, "adaption",adaption_method(adaption),"dd_mode",use_dd_mode); %#ok<NASGU>
|
||||
|
||||
mlse_db_enc = MLSE("DIR", [1,1], "duobinary_output", 0, "M", M, "trellis_states", PAMmapper(M,0).levels); %#ok<NASGU>
|
||||
eq_db_enc = EQ("Ne", ffe_order, "Nb", dfe_order, "training_length", len_tr, ...
|
||||
eq_db_enc = EQ("Ne", ffe_order_dbtgt, "Nb", dfe_order_dbtgt, "training_length", len_tr, ...
|
||||
"training_loops", 5, "dd_loops", 5, "K", 2, "DCmu", mu_dc, ...
|
||||
"DDmu", [mu_ffe mu_dfe], "DFEmu", 0.005, "FFEmu", 0, "plotfinal", 0, "ideal_dfe", 1);
|
||||
|
||||
Scpe_sig = preprocessSignal(Scpe_sig_raw, Symbols, fsym);
|
||||
Scpe_sig = preprocessSignal(Scpe_sig_raw, Symbols, fsym, ...
|
||||
"mode", options.preprocess_mode, ...
|
||||
"tx_pulseformer", options.tx_pulseformer, ...
|
||||
"debug_plots", options.debug_plots);
|
||||
Scpe_sig.spectrum("fignum",200,"normalizeTo0dB",1,"displayname",'Rx','addDCoffset',-6);
|
||||
Scpe_sig.spectrum("fignum",201,"normalizeTo0dB",0,"displayname",'Rx');
|
||||
|
||||
@@ -79,39 +93,35 @@ function output = dsp_scope_signal(Scpe_sig_raw, Symbols, Tx_bits, options)
|
||||
|
||||
if duob_mode ~= db_mode.db_encoded
|
||||
if use_ffe
|
||||
ffe_order = [50, 0, 0];
|
||||
eq_dfe = EQ("Ne",ffe_order,"Nb",[0,0,0],"training_length",len_tr,"training_loops",5,"dd_loops",5,"K",2,"DCmu",mu_dc,"DDmu",[mu_ffe mu_dfe],"DFEmu",0.005,"FFEmu",0,"plotfinal",0,"ideal_dfe",0);
|
||||
eq_dfe = EQ("Ne",ffe_order_ffe,"Nb",[0,0,0],"training_length",len_tr,"training_loops",5,"dd_loops",5,"K",2,"DCmu",mu_dc,"DDmu",[mu_ffe mu_dfe],"DFEmu",0.005,"FFEmu",0,"plotfinal",0,"ideal_dfe",0);
|
||||
|
||||
ffe_results = ffe(eq_dfe, M, Scpe_sig, Symbols, Tx_bits, ...
|
||||
"precode_mode", duob_mode, ...
|
||||
'showAnalysis', 0, ...
|
||||
'showAnalysis', showAnalysis, ...
|
||||
"postFFE", [], ...
|
||||
"eth_style_symbol_mapping", 0);
|
||||
|
||||
output.ffe_package = ffe_results;
|
||||
ffe_results.metrics.print;
|
||||
ffe_results.config.equalizer_structure = "ffe";
|
||||
ffe_results.metrics.print;
|
||||
output.ffe_package = ffe_results;
|
||||
end
|
||||
|
||||
if use_dfe
|
||||
ffe_order = [50, 5, 5];
|
||||
eq_dfe = EQ("Ne",ffe_order,"Nb",[2,0,0],"training_length",len_tr,"training_loops",5,"dd_loops",5,"K",2,"DCmu",mu_dc,"DDmu",[mu_ffe mu_dfe],"DFEmu",0.005,"FFEmu",0,"plotfinal",0,"ideal_dfe",0);
|
||||
eq_dfe = EQ("Ne",ffe_order_dfe,"Nb",dfe_feedback_order,"training_length",len_tr,"training_loops",5,"dd_loops",5,"K",2,"DCmu",mu_dc,"DDmu",[mu_ffe mu_dfe],"DFEmu",0.005,"FFEmu",0,"plotfinal",0,"ideal_dfe",0);
|
||||
|
||||
dfe_results = ffe(eq_dfe, M, Scpe_sig, Symbols, Tx_bits, ...
|
||||
"precode_mode", duob_mode, ...
|
||||
'showAnalysis', 0, ...
|
||||
'showAnalysis', showAnalysis, ...
|
||||
"postFFE", [], ...
|
||||
"eth_style_symbol_mapping", 0);
|
||||
|
||||
output.ffe_package = dfe_results;
|
||||
dfe_results.config.equalizer_structure = "dfe";
|
||||
dfe_results.metrics.print;
|
||||
output.dfe_package = dfe_results;
|
||||
end
|
||||
|
||||
if use_vnle_mlse
|
||||
pf_ncoeffs = 1;
|
||||
ffe_order = [50, 5, 5];
|
||||
eq_ = EQ("Ne",ffe_order,"Nb",dfe_order,"training_length",len_tr,"training_loops",5,"dd_loops",5,"K",2,"DCmu",mu_dc,"DDmu",[mu_ffe mu_dfe],"DFEmu",0.005,"FFEmu",0,"plotfinal",0,"ideal_dfe",0);
|
||||
eq_ = EQ("Ne",ffe_order_vnle,"Nb",dfe_order_vnle,"training_length",len_tr,"training_loops",5,"dd_loops",5,"K",2,"DCmu",mu_dc,"DDmu",[mu_ffe mu_dfe],"DFEmu",0.005,"FFEmu",0,"plotfinal",0,"ideal_dfe",0);
|
||||
pf_ = Postfilter("ncoeff",pf_ncoeffs,"useBurg",1);
|
||||
|
||||
useviterbi = 0;
|
||||
@@ -129,12 +139,12 @@ function output = dsp_scope_signal(Scpe_sig_raw, Symbols, Tx_bits, options)
|
||||
|
||||
[ffe_results, mlse_results] = vnle_postfilter_mlse(eq_, pf_, mlse_, M, Scpe_sig, Symbols, Tx_bits, ...
|
||||
"precode_mode", duob_mode, ...
|
||||
'showAnalysis', 0, ...
|
||||
'showAnalysis', showAnalysis, ...
|
||||
"postFFE", [], ...
|
||||
"eth_style_symbol_mapping", 0);
|
||||
|
||||
ffe_results.metrics.print;
|
||||
ffe_results.config.equalizer_structure = "vnle";
|
||||
ffe_results.metrics.print;
|
||||
mlse_results.metrics.print;
|
||||
|
||||
output.mlse_package = mlse_results;
|
||||
@@ -165,13 +175,20 @@ function output = dsp_scope_signal(Scpe_sig_raw, Symbols, Tx_bits, options)
|
||||
mlse_db_ = MLSE("DIR",[1,1],"duobinary_output",0,"M",M,"trellis_states",PAMmapper(M,0).levels,'scale_mode',2,'trellis_exclusion',trellexlusion,'trellis_state_mode',3);
|
||||
end
|
||||
|
||||
ffe_order = [50, 5, 5];
|
||||
eq_ = EQ("Ne",ffe_order,"Nb",dfe_order,"training_length",len_tr,"training_loops",5,"dd_loops",5,"K",2,"DCmu",mu_dc,"DDmu",[mu_ffe mu_dfe],"DFEmu",0.005,"FFEmu",0,"plotfinal",0,"ideal_dfe",1);
|
||||
eq_ = EQ("Ne",ffe_order_dbtgt,"Nb",dfe_order_dbtgt,"training_length",len_tr,"training_loops",5,"dd_loops",5,"K",2,"DCmu",mu_dc,"DDmu",[mu_ffe mu_dfe],"DFEmu",0.005,"FFEmu",0,"plotfinal",0,"ideal_dfe",1);
|
||||
|
||||
dbt_results = duobinary_target(eq_, mlse_db_, M, Scpe_sig, Symbols, Tx_bits, ...
|
||||
"precode_mode", duob_mode, ...
|
||||
'showAnalysis', 0, ...
|
||||
"postFFE", []);
|
||||
if isempty(decoding_mode)
|
||||
dbt_results = duobinary_target(eq_, mlse_db_, M, Scpe_sig, Symbols, Tx_bits, ...
|
||||
"precode_mode", duob_mode, ...
|
||||
'showAnalysis', showAnalysis, ...
|
||||
"postFFE", []);
|
||||
else
|
||||
dbt_results = duobinary_target(eq_, mlse_db_, M, Scpe_sig, Symbols, Tx_bits, ...
|
||||
"precode_mode", duob_mode, ...
|
||||
'showAnalysis', showAnalysis, ...
|
||||
"postFFE", [], ...
|
||||
"decoding_mode", decoding_mode);
|
||||
end
|
||||
|
||||
dbt_results.metrics.print;
|
||||
output.dbtgt_package = dbt_results;
|
||||
@@ -182,7 +199,7 @@ function output = dsp_scope_signal(Scpe_sig_raw, Symbols, Tx_bits, options)
|
||||
mlse_db_enc = MLSE_viterbi("duobinary_output",0,'M',M,'trellis_states',PAMmapper(M,0).levels); %#ok<NASGU>
|
||||
mlse_db_enc = MLSE("DIR", [1,1], "duobinary_output", 0, "M", M, "trellis_states", PAMmapper(M,0).levels);
|
||||
|
||||
db_results = duobinary_signaling(eq_db_enc, mlse_db_enc, M, Scpe_sig, Symbols, Tx_bits, "precode_mode",duob_mode, "showAnalysis",0,"postFFE",[]);
|
||||
db_results = duobinary_signaling(eq_db_enc, mlse_db_enc, M, Scpe_sig, Symbols, Tx_bits, "precode_mode",duob_mode, "showAnalysis",showAnalysis,"postFFE",[]);
|
||||
output.dbenc_package = db_results;
|
||||
end
|
||||
end
|
||||
|
||||
@@ -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
|
||||
|
||||
86
Functions/Job_Processing/findSignalPulseformer.m
Normal file
86
Functions/Job_Processing/findSignalPulseformer.m
Normal file
@@ -0,0 +1,86 @@
|
||||
function pulseformer = findSignalPulseformer(signalLike)
|
||||
%FINDSIGNALPULSEFORMER Try to recover TX pulseformer metadata from a signal logbook.
|
||||
|
||||
pulseformer = [];
|
||||
|
||||
if isempty(signalLike) || ~isprop(signalLike, 'logbook') || isempty(signalLike.logbook)
|
||||
return
|
||||
end
|
||||
|
||||
if ~ismember('ModifierCopy', signalLike.logbook.Properties.VariableNames)
|
||||
return
|
||||
end
|
||||
|
||||
modifierCopies = signalLike.logbook.ModifierCopy;
|
||||
for idx = numel(modifierCopies):-1:1
|
||||
pulseformer = extractPulseformerCandidate(modifierCopies{idx});
|
||||
if ~isempty(pulseformer)
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function pulseformer = extractPulseformerCandidate(candidate)
|
||||
pulseformer = [];
|
||||
|
||||
if isempty(candidate)
|
||||
return
|
||||
end
|
||||
|
||||
if isa(candidate, 'Pulseformer')
|
||||
pulseformer = candidate;
|
||||
return
|
||||
end
|
||||
|
||||
if iscell(candidate)
|
||||
for cellIdx = 1:numel(candidate)
|
||||
pulseformer = extractPulseformerCandidate(candidate{cellIdx});
|
||||
if ~isempty(pulseformer)
|
||||
return
|
||||
end
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
if isstruct(candidate)
|
||||
if isfield(candidate, 'pulseformer')
|
||||
pulseformer = extractPulseformerCandidate(candidate.pulseformer);
|
||||
if ~isempty(pulseformer)
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
if hasPulseformerFields(candidate)
|
||||
pulseformer = candidate;
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
try
|
||||
if isprop(candidate, 'pulseformer')
|
||||
pulseformer = extractPulseformerCandidate(candidate.pulseformer);
|
||||
if ~isempty(pulseformer)
|
||||
return
|
||||
end
|
||||
end
|
||||
catch
|
||||
end
|
||||
|
||||
try
|
||||
if hasPulseformerFields(candidate)
|
||||
pulseformer = candidate;
|
||||
end
|
||||
catch
|
||||
end
|
||||
end
|
||||
|
||||
function tf = hasPulseformerFields(candidate)
|
||||
tf = false;
|
||||
|
||||
if isstruct(candidate)
|
||||
tf = isfield(candidate, 'pulse') && isfield(candidate, 'pulselength');
|
||||
return
|
||||
end
|
||||
|
||||
tf = isobject(candidate) && isprop(candidate, 'pulse') && isprop(candidate, 'pulselength');
|
||||
end
|
||||
Reference in New Issue
Block a user