121 lines
4.3 KiB
Matlab
121 lines
4.3 KiB
Matlab
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);
|
|
|
|
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
|