Improve test dashboard and update WDM test planning

This commit is contained in:
Silas Oettinghaus
2026-03-25 09:33:33 +01:00
parent 76be57515d
commit e16806b520
4 changed files with 1020 additions and 95 deletions

View File

@@ -58,9 +58,8 @@ classdef WDM_mux_demux_optical_chain_integration_test < IMDDTestCase
wf = testCase.workflow;
numChannels = wf.params.numChannels;
projectionPower = zeros(numChannels);
branchPower = zeros(numChannels, 1);
branchLambdaIdx = zeros(numChannels, 1);
branchPower = zeros(numChannels, 1);
for outCh = 1:numChannels
branchSignal = wf.demuxOut{outCh}.signal;
@@ -68,31 +67,26 @@ classdef WDM_mux_demux_optical_chain_integration_test < IMDDTestCase
branchLambdaIdx(outCh) = nearestWavelengthIndex( ...
wf.demuxOut{outCh}.lambda, ...
wf.channelPlanM);
for refCh = 1:numChannels
projectionPower(outCh, refCh) = projectedPower( ...
branchSignal, ...
wf.channelRefs{refCh}.signal);
end
end
referencePower = zeros(numChannels, 1);
for refCh = 1:numChannels
referencePower(refCh) = mean(abs(wf.channelRefs{refCh}.signal).^2, 'all');
end
referenceFraction = referencePower / sum(referencePower);
recoveredFraction = branchPower / sum(branchPower);
for ch = 1:numChannels
matchedRef = branchLambdaIdx(ch);
otherIdx = setdiff(1:numChannels, matchedRef);
bestProjection = projectionPower(ch, matchedRef);
offProjection = max(projectionPower(ch, otherIdx));
matchedError = abs(recoveredFraction(ch) - referenceFraction(matchedRef));
offErrors = abs(recoveredFraction(ch) - referenceFraction(otherIdx));
% The recovered branch should keep non-trivial optical power
% after demux, even when compared against the leaked branches.
testCase.verifyGreaterThan(branchPower(ch), 0);
testCase.verifyGreaterThan(branchPower(ch), 0.7 * mean(branchPower));
% The intended branch should dominate its row of the
% projection matrix even if the demux ordering changes.
testCase.verifyGreaterThan(bestProjection, offProjection * 1.0001);
testCase.verifyGreaterThan( ...
bestProjection / sum(projectionPower(ch, :)), ...
0.5 / numChannels);
testCase.verifyLessThanOrEqual(matchedError, min(offErrors) + 1e-3);
testCase.verifyLessThan(matchedError, 0.2);
% Correlation is kept as a secondary diagnostic metric.
testCase.verifyTrue(isfinite(normalizedCorrelation( ...
@@ -108,8 +102,8 @@ function workflow = buildWdmWorkflow()
channelPlanNm = calcWavelengthPlan(params.numChannels, params.channelSpacingHz, params.lambdaCenterNm);
channelPlanM = channelPlanNm * 1e-9;
% Build the two WDM channels separately so the test can later compare
% the recovered branch against the original reference branch.
% Build the WDM channels separately so the test can later compare the
% recovered branch against the original reference branch.
channelRefs = cell(1, params.numChannels);
for ch = 1:params.numChannels
drive = makeElectricalSignal(params.driveSignals{ch}, params.fsBase);
@@ -118,7 +112,7 @@ function workflow = buildWdmWorkflow()
"mode", eml_mode.im_cosinus, ...
"fsimu", params.fsBase, ...
"lambda", channelPlanNm(ch), ...
"power", params.laserPowerDbm, ...
"power", params.laserPowerDbm(ch), ...
"linewidth", 0, ...
"alpha", 0, ...
"ampl_imbal", 0, ...
@@ -131,7 +125,7 @@ function workflow = buildWdmWorkflow()
% scripts where the mux receives DP optical signals.
channelRefs{ch} = Polarization_Controller( ...
"mode", "rot_power", ...
"desired_power", 50).process(optical);
"desired_power", 100).process(optical);
end
mux = Optical_Multiplex( ...
@@ -142,7 +136,7 @@ function workflow = buildWdmWorkflow()
"random_key", 0, ...
"attenuation", 0, ...
"filtype", 1, ...
"B", 200e9);
"B", 120e9);
muxOut = mux.process(channelRefs);
% A very small deterministic propagation hop keeps the fixture closer
@@ -201,12 +195,12 @@ function params = wdmIntegrationParameters()
% Keep the fixture small, deterministic, and close to the WDM scripts.
params.numChannels = 4;
params.channelSpacingHz = 200e9;
params.channelSpacingHz = 400e9;
params.lambdaCenterNm = 1310;
params.fsBase = 64e9;
params.fsMux = 4 * params.fsBase;
params.laserPowerDbm = 3;
params.launchPowerDbm = params.laserPowerDbm + 10*log10(params.numChannels);
params.laserPowerDbm = [-3, 0, 3, 6];
params.launchPowerDbm = 3 + 10*log10(params.numChannels);
params.uPi = 4.6;
params.vbias = -0.5 * params.uPi;
params.randomKey = 11;
@@ -245,19 +239,6 @@ function idx = nearestWavelengthIndex(value, plan)
[~, idx] = min(abs(plan(:) - value));
end
function pwr = projectedPower(refSignal, candidateSignal)
ref = refSignal(:);
cand = candidateSignal(:);
denom = sum(abs(ref).^2);
if denom == 0
pwr = 0;
return
end
pwr = abs(sum(conj(ref) .* cand)).^2 / denom;
end
function centeredEnvelope = centredPowerEnvelope(signal)
powerEnvelope = abs(signal(:)).^2;
centeredEnvelope = powerEnvelope - mean(powerEnvelope);