291 lines
9.3 KiB
Matlab
291 lines
9.3 KiB
Matlab
function workflow = buildReducedImddWorkflow(scenario)
|
|
%BUILDREDUCEDIMDDWORKFLOW Build a reduced deterministic IM/DD workflow.
|
|
%
|
|
% The helper keeps the stage order aligned with the project workflow while
|
|
% allowing tests to switch between representative scenarios:
|
|
% - "minimal": reduced regression baseline
|
|
% - "no-impairment": near-ideal baseline with impairment knobs neutralized
|
|
% - "baseline": reference point for monotonicity checks
|
|
% - "impaired": intentionally degraded variant for monotonicity checks
|
|
|
|
arguments
|
|
scenario (1, 1) string = "minimal"
|
|
end
|
|
|
|
params = scenarioParameters(scenario);
|
|
workflow = runReducedWorkflow(params, scenario);
|
|
end
|
|
|
|
function workflow = runReducedWorkflow(params, scenario)
|
|
% -------------------- TX --------------------
|
|
txPulse = Pulseformer( ...
|
|
"fsym", params.fsym, ...
|
|
"fdac", params.fdac, ...
|
|
"pulse", "rrc", ...
|
|
"pulselength", params.pulseLength, ...
|
|
"alpha", params.rcalpha);
|
|
|
|
[digiSig, symbols, txBits] = PAMsource( ...
|
|
"fsym", params.fsym, ...
|
|
"M", params.M, ...
|
|
"order", params.sourceOrder, ...
|
|
"useprbs", false, ...
|
|
"fs_out", params.fdac, ...
|
|
"applyclipping", false, ...
|
|
"applypulseform", true, ...
|
|
"pulseformer", txPulse, ...
|
|
"randkey", params.randomKey, ...
|
|
"duobinary_mode", db_mode.no_db, ...
|
|
"mrds_code", 0).process();
|
|
|
|
elSig = AWG( ...
|
|
"fdac", params.fdac, ...
|
|
"f_cutoff", params.fsym, ...
|
|
"lpf_active", params.awgLpfActive, ...
|
|
"kover", params.kover, ...
|
|
"bit_resolution", params.awgBitResolution, ...
|
|
"upsampling_method", params.awgUpsamplingMethod, ...
|
|
"precomp_sinc_rolloff", params.awgPrecompSincRolloff, ...
|
|
"normalize2dac", params.awgNormalize2dac).process(digiSig);
|
|
|
|
elSig = elSig.normalize("mode", "oneone");
|
|
elSig = elSig .* params.driverScaling;
|
|
|
|
% -------------------- Optical Channel --------------------
|
|
optSigTx = EML( ...
|
|
"mode", eml_mode.im_cosinus, ...
|
|
"power", params.opticalPowerDbm, ...
|
|
"fsimu", elSig.fs, ...
|
|
"lambda", params.laserWavelengthNm, ...
|
|
"bias", params.vbias, ...
|
|
"u_pi", params.uPi, ...
|
|
"linewidth", 0, ...
|
|
"randomkey", params.randomKey + 1, ...
|
|
"alpha", 0).process(elSig);
|
|
|
|
optSig = Fiber( ...
|
|
"fsimu", optSigTx.fs, ...
|
|
"fiber_length", params.linkLengthKm, ...
|
|
"alpha", params.fiberAlphaDbPerKm, ...
|
|
"D", 0, ...
|
|
"lambda0", 1310, ...
|
|
"gamma", 0, ...
|
|
"Dslope", 0.07).process(optSigTx);
|
|
|
|
rxOptSig = Amplifier( ...
|
|
"amp_mode", "ideal_no_noise", ...
|
|
"gain_mode", "output_power", ...
|
|
"amplification_db", params.ropDbm).process(optSig);
|
|
|
|
rxSigAfterPd = Photodiode( ...
|
|
"fsimu", params.fdac * params.kover, ...
|
|
"dark_current", 0, ...
|
|
"responsivity", 1, ...
|
|
"temperature", 20, ...
|
|
"nep", 0, ...
|
|
"randomkey", params.randomKey + 2).process(rxOptSig);
|
|
|
|
rxSigFiltered = Filter( ...
|
|
"active", params.rxFilterActive, ...
|
|
"filterType", filtertypes.butterworth, ...
|
|
"f_cutoff", params.rxElectricalBandwidthHz, ...
|
|
"fs", params.fdac * params.kover, ...
|
|
"signal_length", 0, ...
|
|
"filtdegree", 4, ...
|
|
"lowpass", 1).process(rxSigAfterPd);
|
|
|
|
scopeLpf = Filter( ...
|
|
"active", params.scopeLpfActive, ...
|
|
"filterType", filtertypes.butterworth, ...
|
|
"f_cutoff", params.scopeBandwidthHz, ...
|
|
"fs", params.fadc, ...
|
|
"signal_length", 0, ...
|
|
"filtdegree", 4, ...
|
|
"lowpass", 1);
|
|
|
|
scpeSigPreMf = Scope( ...
|
|
"fsimu", params.fdac * params.kover, ...
|
|
"fadc", params.fadc, ...
|
|
"adcresolution", params.scopeAdcResolution, ...
|
|
"quantbuffer", params.scopeQuantBuffer, ...
|
|
"delay", 0, ...
|
|
"fixed_delay", 0, ...
|
|
"filtertype", filtertypes.butterworth, ...
|
|
"samplingdelay", 0, ...
|
|
"rand_samplingdelay", 0, ...
|
|
"freq_offset", 0, ...
|
|
"samp_jitter", 0, ...
|
|
"block_dc", 1, ...
|
|
"lpf_active", params.scopeLpfActive, ...
|
|
"H_lpf", scopeLpf).process(rxSigFiltered);
|
|
|
|
rxMatchedFilter = Pulseformer( ...
|
|
"fsym", params.fsym, ...
|
|
"fdac", 2 * params.fsym, ...
|
|
"pulse", "rrc", ...
|
|
"pulselength", params.pulseLength, ...
|
|
"alpha", params.rcalpha, ...
|
|
"matched", 1);
|
|
scpeSig = rxMatchedFilter.process(scpeSigPreMf);
|
|
|
|
[syncedSig, ~] = scpeSig.tsynch( ...
|
|
"reference", symbols, ...
|
|
"fs_ref", params.fsym, ...
|
|
"debug_plots", 0);
|
|
syncedCenteredSig = syncedSig - mean(syncedSig.signal);
|
|
syncedSig = syncedCenteredSig;
|
|
syncedSig.signal = syncedSig.signal(1 : 2 * length(symbols));
|
|
|
|
% -------------------- DSP --------------------
|
|
ffeEq = FFE( ...
|
|
"epochs_tr", 2, ...
|
|
"epochs_dd", 1, ...
|
|
"len_tr", params.lenTr, ...
|
|
"mu_dd", 1e-4, ...
|
|
"mu_tr", 1e-2, ...
|
|
"order", 21, ...
|
|
"sps", 2, ...
|
|
"decide", 0, ...
|
|
"adaption_technique", adaption_method.nlms, ...
|
|
"dd_mode", 1);
|
|
|
|
ffeResults = ffe( ...
|
|
ffeEq, ...
|
|
params.M, ...
|
|
syncedSig, ...
|
|
symbols, ...
|
|
txBits, ...
|
|
"precode_mode", db_mode.no_db, ...
|
|
"showAnalysis", 0, ...
|
|
"postFFE", [], ...
|
|
"eth_style_symbol_mapping", 0);
|
|
|
|
mlseEq = FFE( ...
|
|
"epochs_tr", 2, ...
|
|
"epochs_dd", 1, ...
|
|
"len_tr", params.lenTr, ...
|
|
"mu_dd", 1e-4, ...
|
|
"mu_tr", 1e-2, ...
|
|
"order", 21, ...
|
|
"sps", 2, ...
|
|
"decide", 0, ...
|
|
"adaption_technique", adaption_method.nlms, ...
|
|
"dd_mode", 1);
|
|
postfilter = Postfilter("ncoeff", 1, "useBurg", 1);
|
|
mlse = MLSE( ...
|
|
"duobinary_output", 0, ...
|
|
"M", params.M, ...
|
|
"trellis_states", PAMmapper(params.M, 0).levels);
|
|
|
|
[vnleResults, mlseResults] = vnle_postfilter_mlse( ...
|
|
mlseEq, ...
|
|
postfilter, ...
|
|
mlse, ...
|
|
params.M, ...
|
|
syncedSig, ...
|
|
symbols, ...
|
|
txBits, ...
|
|
"precode_mode", db_mode.no_db, ...
|
|
"showAnalysis", 0, ...
|
|
"postFFE", [], ...
|
|
"eth_style_symbol_mapping", 0);
|
|
|
|
workflow = struct();
|
|
workflow.scenario = scenario;
|
|
workflow.params = params;
|
|
workflow.Digi_sig = digiSig;
|
|
workflow.Symbols = symbols;
|
|
workflow.Tx_bits = txBits;
|
|
workflow.El_sig = elSig;
|
|
workflow.Opt_sig_tx = optSigTx;
|
|
workflow.Opt_sig = optSig;
|
|
workflow.Rx_sig_after_pd = rxSigAfterPd;
|
|
workflow.Rx_sig_filtered = rxSigFiltered;
|
|
workflow.Scpe_sig_pre_mf = scpeSigPreMf;
|
|
workflow.Scpe_sig = scpeSig;
|
|
workflow.Synced_sig_centered = syncedCenteredSig;
|
|
workflow.Synced_sig = syncedSig;
|
|
workflow.ffe_results = ffeResults;
|
|
workflow.vnle_results = vnleResults;
|
|
workflow.mlse_results = mlseResults;
|
|
end
|
|
|
|
function params = scenarioParameters(scenario)
|
|
params = commonParameters();
|
|
|
|
switch lower(string(scenario))
|
|
case "minimal"
|
|
params.ropDbm = 0;
|
|
params.rxElectricalBandwidthHz = 40e9;
|
|
params.scopeBandwidthHz = 25e9;
|
|
|
|
case "no-impairment"
|
|
params.randomKey = 11;
|
|
params.linkLengthKm = 0;
|
|
params.fiberAlphaDbPerKm = 0;
|
|
params.ropDbm = 3;
|
|
params.rxElectricalBandwidthHz = 200e9;
|
|
params.scopeBandwidthHz = 200e9;
|
|
params.rxFilterActive = false;
|
|
params.scopeLpfActive = false;
|
|
params.scopeAdcResolution = 24;
|
|
params.scopeQuantBuffer = 0.05;
|
|
params.awgLpfActive = false;
|
|
params.awgBitResolution = 12;
|
|
params.awgUpsamplingMethod = upsampling_mode.resample;
|
|
params.awgNormalize2dac = true;
|
|
|
|
case "baseline"
|
|
params.ropDbm = 0;
|
|
params.rxElectricalBandwidthHz = 40e9;
|
|
params.scopeBandwidthHz = 25e9;
|
|
|
|
case "impaired"
|
|
params.ropDbm = -15;
|
|
params.rxElectricalBandwidthHz = 12e9;
|
|
params.scopeBandwidthHz = 12e9;
|
|
|
|
otherwise
|
|
error("buildReducedImddWorkflow:UnknownScenario", ...
|
|
"Unknown reduced IM/DD scenario '%s'.", scenario);
|
|
end
|
|
end
|
|
|
|
function params = commonParameters()
|
|
params = struct();
|
|
|
|
params.M = 4;
|
|
params.fsym = 16e9;
|
|
params.fdac = 64e9;
|
|
params.fadc = 64e9;
|
|
params.kover = 2;
|
|
params.randomKey = 1;
|
|
params.sourceOrder = 12;
|
|
params.rcalpha = 0.05;
|
|
params.pulseLength = 12;
|
|
params.lenTr = 256;
|
|
|
|
params.uPi = 3;
|
|
params.vbiasRel = 0.5;
|
|
params.vbias = -params.vbiasRel * params.uPi;
|
|
params.driverScaling = 0.6 * (params.uPi / 2 - abs(params.vbias - params.uPi / 2));
|
|
|
|
params.laserWavelengthNm = 1293;
|
|
params.opticalPowerDbm = 3;
|
|
params.linkLengthKm = 1;
|
|
params.fiberAlphaDbPerKm = 0.3;
|
|
|
|
params.ropDbm = 0;
|
|
params.rxElectricalBandwidthHz = 40e9;
|
|
params.scopeBandwidthHz = 25e9;
|
|
params.rxFilterActive = true;
|
|
params.scopeLpfActive = true;
|
|
params.scopeAdcResolution = 8;
|
|
params.scopeQuantBuffer = 0.1;
|
|
params.awgLpfActive = false;
|
|
params.awgBitResolution = 8;
|
|
params.awgUpsamplingMethod = upsampling_mode.samplehold;
|
|
params.awgPrecompSincRolloff = 1;
|
|
params.awgNormalize2dac = false;
|
|
end
|