Strengthen WDM and IM/DD optical tests

This commit is contained in:
Silas Oettinghaus
2026-03-25 08:07:31 +01:00
parent 0e6be4a584
commit 76be57515d
26 changed files with 1606 additions and 566 deletions

View File

@@ -1,10 +1,78 @@
classdef DP_Fiber_test < IMDDTestCase
% Auto-generated placeholder for DP_Fiber.
% Target: C:/Users/Silas/Documents/MATLAB/imdd_simulation/Classes/02_optical/DP_Fiber.m
methods (Test, TestTags = {'unit', 'fast', 'optical', 'dp_fiber'})
function constructorStoresConfigurationAndStartsWithEmptyState(testCase)
fiber = makeIdentityFiber();
methods (Test, TestTags = {'placeholder', 'todo'})
function testNotImplemented(testCase)
testCase.assumeFail("Tests for DP_Fiber are not implemented yet.");
testCase.verifyEqual(fiber.L, 0);
testCase.verifyEqual(fiber.dz, 1);
testCase.verifyEqual(fiber.lambda, 1550);
testCase.verifyEqual(fiber.rng, 7);
testCase.verifyEqual(fiber.gamma, 0);
testCase.verifyEqual(fiber.fa, 64e9);
testCase.verifyEqual(fiber.X_alpha, 0);
testCase.verifyEqual(fiber.D, 0);
testCase.verifyEqual(fiber.Ds, 0);
testCase.verifyEqual(fiber.Dpmd, 0);
testCase.verifyEqual(fiber.n_waveplates, 1);
testCase.verifyEqual(fiber.useGPU, false);
testCase.verifyEqual(fiber.useSingle, false);
testCase.verifyTrue(isstruct(fiber.state));
testCase.verifyEmpty(fieldnames(fiber.state));
end
function processPreservesAZeroImpairmentDualPolarizationSignal(testCase)
fiber = makeIdentityFiber();
inputMatrix = [ ...
1 + 1i, 2 - 1i; ...
0.5, -0.25i; ...
-1 + 0.2i, 0.75 - 0.5i; ...
0, 0.25 + 0.75i];
sigIn = Signal(inputMatrix, "fs", fiber.fa);
sigOut = fiber.process(sigIn);
testCase.verifyClass(sigOut, "Signal");
testCase.verifyEqual(sigOut.fs, sigIn.fs);
testCase.verifyEqual(size(sigOut.signal), size(sigIn.signal));
testCase.verifyEqual(sigOut.signal, sigIn.signal, "AbsTol", 1e-12);
testCase.verifyEqual(height(sigOut.logbook), 1);
end
function process_ProducesIdentityOutputForRawMatrixInput(testCase)
fiber = makeIdentityFiber();
inputMatrix = [ ...
1 + 1i, 2 - 1i; ...
0.5, -0.25i; ...
-1 + 0.2i, 0.75 - 0.5i; ...
0, 0.25 + 0.75i];
sigOut = fiber.process_(inputMatrix, fiber.fa);
testCase.verifyEqual(size(sigOut), size(inputMatrix));
testCase.verifyEqual(sigOut, inputMatrix, "AbsTol", 1e-12);
end
end
end
function fiber = makeIdentityFiber()
fiber = DP_Fiber( ...
"L", 0, ...
"dz", 1, ...
"lambda", 1550, ...
"rng", 7, ...
"gamma", 0, ...
"fa", 64e9, ...
"X_alpha", 0, ...
"D", 0, ...
"Ds", 0, ...
"Dpmd", 0, ...
"beat_len", 1e9, ...
"corr_len", 1e9, ...
"manakov", 0, ...
"SS_dphimax", 5e-3, ...
"SS_dzmax", 1, ...
"SS_dzmin", 1, ...
"n_waveplates", 1, ...
"useGPU", false, ...
"useSingle", false);
end

View File

@@ -1,10 +1,100 @@
classdef EML_test < IMDDTestCase
% Auto-generated placeholder for EML.
% Target: C:/Users/Silas/Documents/MATLAB/imdd_simulation/Classes/02_optical/EML.m
methods (Test, TestTags = {'unit', 'fast', 'optical', 'eml'})
function constructorStoresDerivedScalarsForDeterministicIqMode(testCase)
eml = EML( ...
"mode", eml_mode.iq_linear, ...
"fsimu", 64e9, ...
"lambda", 1550, ...
"power", 0, ...
"linewidth", 0, ...
"alpha", 0, ...
"ampl_imbal", 0, ...
"pha_imbal", 0, ...
"bias", 0, ...
"u_pi", 1, ...
"randomkey", 7);
methods (Test, TestTags = {'placeholder', 'todo'})
function testNotImplemented(testCase)
testCase.assumeFail("Tests for EML are not implemented yet.");
testCase.verifyEqual(eml.mode, eml_mode.iq_linear);
testCase.verifyEqual(eml.fsimu, 64e9);
testCase.verifyEqual(eml.lambda, 1550);
testCase.verifyEqual(eml.power, 0);
testCase.verifyEqual(eml.linewidth, 0);
testCase.verifyEqual(eml.alpha, 0);
testCase.verifyEqual(eml.field, sqrt(1e-3), "AbsTol", 1e-12);
testCase.verifyEqual(eml.noisefactor, 0, "AbsTol", 1e-12);
testCase.verifyEqual(eml.phase, 0, "AbsTol", 1e-12);
end
function process_ProducesDeterministicIqLinearOutput(testCase)
eml = EML( ...
"mode", eml_mode.iq_linear, ...
"fsimu", 32e9, ...
"lambda", 1310, ...
"power", 3, ...
"linewidth", 0, ...
"alpha", 0, ...
"ampl_imbal", 0, ...
"pha_imbal", 0, ...
"bias", 0, ...
"u_pi", 2, ...
"randomkey", 11);
inputSig = makeElectricalsignal([1 + 1i; -2 + 0.5i; 0.25 - 0.75i], 32e9);
[optField, emlOut] = eml.process_(inputSig.signal);
expectedField = eml.field .* inputSig.signal ./ eml.u_pi;
testCase.verifyEqual(optField, expectedField, "AbsTol", 1e-12);
testCase.verifyEqual(emlOut.signal_len, length(inputSig));
testCase.verifyEqual(emlOut.phase, 0, "AbsTol", 1e-12);
end
function processReturnsOpticalsignalWithUpdatedMetadata(testCase)
eml = EML( ...
"mode", eml_mode.iq_linear, ...
"fsimu", 64e9, ...
"lambda", 1550, ...
"power", 0, ...
"linewidth", 0, ...
"alpha", 0, ...
"ampl_imbal", 0, ...
"pha_imbal", 0, ...
"bias", 0, ...
"u_pi", 1, ...
"randomkey", 19);
inputSig = makeElectricalsignal([1 + 1i; -1 - 1i], 64e9);
[outputSig, emlOut] = eml.process(inputSig);
expectedField = eml.field .* inputSig.signal ./ eml.u_pi;
testCase.verifyClass(outputSig, 'Opticalsignal');
testCase.verifyEqual(outputSig.signal, expectedField, "AbsTol", 1e-12);
testCase.verifyEqual(outputSig.fs, eml.fsimu);
testCase.verifyEqual(outputSig.lambda, eml.lambda * 1e-9, "AbsTol", 1e-15);
testCase.verifyEqual(height(outputSig.logbook), height(inputSig.logbook) + 1);
testCase.verifyTrue(contains(string(outputSig.logbook.Description(end)), "nm Laser"));
testCase.verifyEqual(emlOut.signal_len, length(inputSig));
end
end
end
function sig = makeElectricalsignal(values, fs)
sig = Electricalsignal(values, ...
"fs", fs, ...
"logbook", emptyLogbook());
end
function lb = emptyLogbook()
SignalType = [];
TimeStamp = [];
Length = [];
SignalPower = [];
Nase = [];
SignalCopy = [];
ModifierName = [];
ModifierCopy = {};
Description = [];
lb = table(SignalType, TimeStamp, Length, SignalPower, Nase, SignalCopy, ModifierName, ModifierCopy, Description);
end

View File

@@ -1,10 +1,96 @@
classdef Optical_Demultiplex_test < IMDDTestCase
% Auto-generated placeholder for Optical_Demultiplex.
% Target: C:/Users/Silas/Documents/MATLAB/imdd_simulation/Classes/02_optical/Optical_Demultiplex.m
methods (Test, TestTags = {'unit', 'fast', 'optical', 'demux'})
function processReturnsOneCellPerChannelAndPreservesMetadata(testCase)
fs = 32e9;
lambdaCenterNm = 1310;
lambdaA = 1309e-9;
lambdaB = 1311e-9;
methods (Test, TestTags = {'placeholder', 'todo'})
function testNotImplemented(testCase)
testCase.assumeFail("Tests for Optical_Demultiplex are not implemented yet.");
sigA = makeOpticalSignal( ...
[1 2; 1 2; 1 2; 1 2], ...
fs, ...
lambdaA, ...
0.10);
sigB = makeOpticalSignal( ...
[3 4; 3 4; 3 4; 3 4], ...
fs, ...
lambdaB, ...
0.90);
mux = Optical_Multiplex( ...
"fs_in", fs, ...
"fs_out", fs, ...
"lambda_center", lambdaCenterNm, ...
"delta_f", 0, ...
"random_key", 0, ...
"attenuation", 0, ...
"filtype", 3, ...
"B", 200e9);
muxOut = mux.process({sigA, sigB});
demux = Optical_Demultiplex( ...
"fs_in", muxOut.fs, ...
"fs_out", muxOut.fs, ...
"lambda_center", lambdaCenterNm, ...
"attenuation", 0, ...
"filtype", 3, ...
"B", 200e9);
out = demux.process(muxOut);
testCase.verifyClass(out, 'cell');
testCase.verifyNumElements(out, 2);
testCase.verifyClass(out{1}, 'Opticalsignal');
testCase.verifyClass(out{2}, 'Opticalsignal');
testCase.verifyEqual(size(out{1}.signal), size(muxOut.signal));
testCase.verifyEqual(size(out{2}.signal), size(muxOut.signal));
testCase.verifyEqual(out{1}.fs, fs);
testCase.verifyEqual(out{2}.fs, fs);
testCase.verifyEqual(out{1}.lambda, muxOut.lambda(1), 'AbsTol', 1e-12);
testCase.verifyEqual(out{2}.lambda, muxOut.lambda(2), 'AbsTol', 1e-12);
end
function roundTripThroughMuxAndDemuxPreservesChannelMagnitudes(testCase)
fs = 16e9;
lambdaCenterNm = 1310;
sigA = makeOpticalSignal(ones(8, 2), fs, 1309.5e-9, 0.0);
mux = Optical_Multiplex( ...
"fs_in", fs, ...
"fs_out", fs, ...
"lambda_center", lambdaCenterNm, ...
"delta_f", 0, ...
"random_key", 0, ...
"attenuation", 0, ...
"filtype", 3, ...
"B", 200e9);
muxOut = mux.process({sigA});
demux = Optical_Demultiplex( ...
"fs_in", muxOut.fs, ...
"fs_out", muxOut.fs, ...
"lambda_center", lambdaCenterNm, ...
"attenuation", 0, ...
"filtype", 3, ...
"B", 200e9);
out = demux.process(muxOut);
testCase.verifyNumElements(out, 1);
testCase.verifyEqual(size(out{1}.signal), size(sigA.signal));
testCase.verifyEqual(out{1}.fs, fs);
testCase.verifyEqual(out{1}.lambda, muxOut.lambda(1), 'AbsTol', 1e-12);
testCase.verifyEqual(mean(abs(out{1}.signal), 'all'), mean(abs(sigA.signal), 'all'), 'AbsTol', 1e-6);
end
end
end
function sig = makeOpticalSignal(signal, fs, lambda, polrot)
base = Signal(signal, "fs", fs);
sig = Opticalsignal( ...
signal, ...
"fs", fs, ...
"logbook", base.logbook, ...
"lambda", lambda, ...
"nase", 0, ...
"polrot", polrot);
end

View File

@@ -1,10 +1,101 @@
classdef Optical_Multiplex_test < IMDDTestCase
% Auto-generated placeholder for Optical_Multiplex.
% Target: C:/Users/Silas/Documents/MATLAB/imdd_simulation/Classes/02_optical/Optical_Multiplex.m
methods (Test, TestTags = {'unit', 'fast', 'optical', 'mux'})
function processCombinesChannelsAndPreservesMetadata(testCase)
fs = 32e9;
lambdaCenter = 1550;
lambdaA = 1550e-9;
lambdaB = 1550e-9;
methods (Test, TestTags = {'placeholder', 'todo'})
function testNotImplemented(testCase)
testCase.assumeFail("Tests for Optical_Multiplex are not implemented yet.");
sigA = makeOpticalSignal( ...
[1 2; 1 2; 1 2], ...
fs, ...
lambdaA, ...
0.10);
sigB = makeOpticalSignal( ...
[3 4; 3 4; 3 4], ...
fs, ...
lambdaB, ...
0.90);
mux = Optical_Multiplex( ...
"fs_in", fs, ...
"fs_out", fs, ...
"lambda_center", lambdaCenter, ...
"delta_f", 0, ...
"random_key", 0, ...
"attenuation", 0, ...
"filtype", 3);
out = mux.process({sigA, sigB});
expected = combineSingleChannelMuxOutputs({sigA, sigB}, mux);
testCase.verifyClass(out, 'Opticalsignal');
testCase.verifyEqual(size(out.signal), [3 2]);
testCase.verifyEqual(out.signal, expected, 'AbsTol', 1e-12);
testCase.verifyEqual(out.fs, fs);
testCase.verifyEqual(out.lambda, [lambdaA, lambdaB], 'AbsTol', 1e-9);
testCase.verifyEqual(out.polrot, [0.10, 0.90], 'AbsTol', 1e-12);
testCase.verifyEqual(height(out.logbook), 2);
testCase.verifyEqual(string(out.logbook.Description(end)), "Opt. Mux. ");
end
function processSupportsMoreThanOneInputChannel(testCase)
fs = 16e9;
lambdaCenter = 1310;
sig1 = makeOpticalSignal(ones(4, 2), fs, lambdaCenter * 1e-9, 0.0);
sig2 = makeOpticalSignal(2 * ones(4, 2), fs, lambdaCenter * 1e-9, 0.5);
sig3 = makeOpticalSignal(3 * ones(4, 2), fs, lambdaCenter * 1e-9, 1.0);
mux = Optical_Multiplex( ...
"fs_in", fs, ...
"fs_out", fs, ...
"lambda_center", lambdaCenter, ...
"delta_f", 0, ...
"random_key", 0, ...
"attenuation", 0, ...
"filtype", 3);
out = mux.process({sig1, sig2, sig3});
expected = combineSingleChannelMuxOutputs({sig1, sig2, sig3}, mux);
testCase.verifySize(out.signal, [4, 2]);
testCase.verifyEqual(out.signal, expected, 'AbsTol', 1e-12);
testCase.verifyEqual(numel(out.lambda), 3);
testCase.verifyEqual(numel(out.polrot), 3);
end
end
end
function sig = makeOpticalSignal(signal, fs, lambda, polrot)
base = Signal(signal, "fs", fs);
sig = Opticalsignal( ...
signal, ...
"fs", fs, ...
"logbook", base.logbook, ...
"lambda", lambda, ...
"nase", 0, ...
"polrot", polrot);
end
function expected = combineSingleChannelMuxOutputs(signals, muxPrototype)
expected = [];
for idx = 1:numel(signals)
mux = Optical_Multiplex( ...
"fs_in", muxPrototype.fs_in, ...
"fs_out", muxPrototype.fs_out, ...
"lambda_center", muxPrototype.lambda_center, ...
"delta_f", muxPrototype.delta_f, ...
"random_key", muxPrototype.random_key, ...
"attenuation", muxPrototype.attenuation, ...
"filtype", muxPrototype.filtype);
singleOut = mux.process({signals{idx}});
if isempty(expected)
expected = zeros(size(singleOut.signal));
end
expected = expected + singleOut.signal;
end
end