Build out MATLAB test framework and core integration coverage

This commit is contained in:
Silas Oettinghaus
2026-03-24 17:23:02 +01:00
parent 9446dfb888
commit a592ebefda
154 changed files with 2281 additions and 1305 deletions

View File

@@ -1,11 +1,120 @@
classdef Pulseformer_test < matlab.unittest.TestCase
% Test class for Pulseformer
classdef Pulseformer_test < IMDDTestCase
methods (Test, TestTags = {'unit', 'fast', 'transmit', 'pulseformer'})
function constructorStoresConfiguredProperties(testCase)
pf = Pulseformer( ...
"fdac", 64e9, ...
"fsym", 16e9, ...
"pulse", pulseform.rrc, ...
"pulselength", 12, ...
"alpha", 0.2, ...
"matched", 1);
methods (Test)
function testExample(testCase)
% Example test case for Pulseformer
% Add your test code here
testCase.verifyTrue(true);
testCase.verifyEqual(pf.fdac, 64e9);
testCase.verifyEqual(pf.fsym, 16e9);
testCase.verifyEqual(pf.pulse, pulseform.rrc);
testCase.verifyEqual(pf.pulselength, 12);
testCase.verifyEqual(pf.alpha, 0.2);
testCase.verifyEqual(pf.matched, 1);
end
function processUsesSymbolRateFallbackAndUpdatesSignalMetadata(testCase)
fsym = 16e9;
fdac = 64e9;
tx = makeInformationsignal([1; 0; -1; 1; 1; 0], []);
pf = Pulseformer( ...
"fdac", fdac, ...
"fsym", fsym, ...
"pulse", pulseform.rc, ...
"pulselength", 8, ...
"alpha", 0.35, ...
"matched", 0);
rx = pf.process(tx);
expected = expectedPulseformerOutput(pf, tx);
testCase.verifyClass(rx, 'Informationsignal');
testCase.verifyEqual(rx.signal, expected, "AbsTol", 1e-12);
testCase.verifyEqual(rx.fs, fdac);
testCase.verifyEqual(height(rx.logbook), height(tx.logbook) + 1);
testCase.verifyEqual(string(rx.logbook.Description(end)), "Applied Pulseshaping");
end
function matchedAndUnmatchedProcessingPreserveTheSameRealWaveform(testCase)
tx = makeInformationsignal([1; 0; 0; -1; 1; -1; 0; 1], 16e9);
unmatched = Pulseformer( ...
"fdac", 32e9, ...
"fsym", 16e9, ...
"pulse", pulseform.rrc, ...
"pulselength", 10, ...
"alpha", 0.15, ...
"matched", 0);
matched = Pulseformer( ...
"fdac", 32e9, ...
"fsym", 16e9, ...
"pulse", pulseform.rrc, ...
"pulselength", 10, ...
"alpha", 0.15, ...
"matched", 1);
rxUnmatched = unmatched.process(tx);
rxMatched = matched.process(tx);
testCase.verifyEqual(length(rxUnmatched.signal), length(rxMatched.signal));
testCase.verifyEqual(rxUnmatched.signal, rxMatched.signal, "AbsTol", 1e-12);
testCase.verifyEqual(rxUnmatched.signal, expectedPulseformerOutput(unmatched, tx), "AbsTol", 1e-12);
testCase.verifyEqual(rxMatched.signal, expectedPulseformerOutput(matched, tx), "AbsTol", 1e-12);
end
function processPreservesLengthForIntegerRateConversion(testCase)
tx = makeInformationsignal((1:5).', []);
pf = Pulseformer( ...
"fdac", 20e9, ...
"fsym", 5e9, ...
"pulse", pulseform.rc, ...
"pulselength", 6, ...
"alpha", 0.25, ...
"matched", 0);
rx = pf.process(tx);
testCase.verifyEqual(length(rx.signal), 20);
testCase.verifyEqual(rx.fs, 20e9);
end
end
end
function sig = makeInformationsignal(values, fs)
base = Signal(values);
sig = Informationsignal(values, "fs", fs, "logbook", base.logbook);
end
function expected = expectedPulseformerOutput(pf, signalclass_in)
if isprop(signalclass_in, 'fs') && ~isempty(signalclass_in.fs)
f_in = signalclass_in.fs;
else
f_in = pf.fsym;
end
[p, q] = rat(pf.fdac / f_in);
fs_intermediate = f_in * p;
sps_filter = fs_intermediate / pf.fsym;
if pf.pulse == pulseform.rc
filtertype = 'normal';
else
filtertype = 'sqrt';
end
h = rcosdesign(pf.alpha, pf.pulselength, sps_filter, filtertype);
if pf.matched
h = conj(fliplr(h));
end
data_out_ = upfirdn(signalclass_in.signal, h, p, q);
delay_samples_intermediate = (length(h) - 1) / 2;
delay_samples_out = delay_samples_intermediate / q;
st = floor(delay_samples_out) + 1;
len_out = ceil(length(signalclass_in.signal) * p / q);
expected = data_out_(st : st + len_out - 1);
end