classdef MLSE_test < IMDDTestCase methods (Test, TestTags = {'unit', 'fast', 'dsp', 'mlse'}) function constructorStoresConfiguration(testCase) mlse = MLSE( ... "M", 4, ... "DIR", [1 0.35], ... "trellis_states", [-3 -1 1 3], ... "duobinary_output", false, ... "trellis_state_mode", 2, ... "trellis_exclusion", 0, ... "scale_mode", 0, ... "debug", 0); testCase.verifyEqual(mlse.M, 4); testCase.verifyEqual(mlse.DIR, [1 0.35]); testCase.verifyEqual(mlse.trellis_states, [-3 -1 1 3]); testCase.verifyFalse(mlse.duobinary_output); testCase.verifyEqual(mlse.trellis_state_mode, 2); testCase.verifyEqual(mlse.trellis_exclusion, 0); testCase.verifyEqual(mlse.scale_mode, 0); testCase.verifyEqual(mlse.debug, 0); end function processRecoversKnownPAM4Sequence(testCase) [txBits, txSymbols, rxSymbols, mlse] = makePam4Fixture(); txSignal = Informationsignal(txSymbols, "fs", 1); rxSignal = Signal(rxSymbols, "fs", 1); hdSignal = mlse.process(rxSignal, txSignal); rxBits = PAMmapper(4, 0).demap(hdSignal); testCase.verifyClass(hdSignal, "Signal"); testCase.verifyEqual(hdSignal.fs, rxSignal.fs); testCase.verifyEqual(rxBits.signal, txBits, ... "MLSE should recover the transmitted PAM-4 bits on the deterministic fixture."); end function processReturnsExpectedShapesAndFiniteMetric(testCase) [txBits, txSymbols, rxSymbols, mlse] = makePam4Fixture(); [viterbiSymbols, llr, gmi] = mlse.process_(rxSymbols, txSymbols); rxBits = PAMmapper(4, 0).demap(viterbiSymbols(:)); expectedSymbols = txSymbols(:) ./ rms(txSymbols(:)); testCase.verifyEqual(numel(viterbiSymbols), numel(rxSymbols)); testCase.verifyEqual(size(llr), [numel(rxSymbols), 2]); testCase.verifyTrue(isfinite(gmi)); testCase.verifyEqual(viterbiSymbols(:), expectedSymbols, "AbsTol", 1e-12); testCase.verifyEqual(rxBits, txBits, ... "Lower-level MLSE output should decode the same deterministic fixture."); end end end function [txBits, txSymbols, rxSymbols, mlse] = makePam4Fixture() txBits = [ ... 0 0; ... 0 1; ... 1 1; ... 1 0; ... 0 1; ... 1 0; ... 0 0; ... 1 1]; mapper = PAMmapper(4, 0); txSignal = Informationsignal(txBits); txSymbols = mapper.map(txSignal).signal; channel = [1 0.35]; rxSymbols = filter(channel, 1, txSymbols); rxSymbols = rxSymbols + 0.01 * [0; 1; -1; 2; -2; 1; -1; 0]; mlse = MLSE( ... "M", 4, ... "DIR", channel, ... "trellis_states", mapper.levels, ... "duobinary_output", false, ... "trellis_state_mode", 2, ... "trellis_exclusion", 0, ... "scale_mode", 0, ... "debug", 0); end