classdef Signal_test < IMDDTestCase methods (Test, TestTags = {'unit', 'fast', 'signals'}) function constructorStoresSignalAndSamplingRate(testCase) sig = Signal([1; 2; 3], "fs", 64e9); testCase.verifyEqual(sig.signal, [1; 2; 3]); testCase.verifyEqual(sig.fs, 64e9); testCase.verifyEmpty(sig.logbook); end function arithmeticOperatorsSupportSignalOperands(testCase) x = Signal([1; 2; 3]); y = Signal([4; 5; 6]); sumSig = x + y; diffSig = y - x; prodSig = x .* y; testCase.verifyEqual(sumSig.signal, [5; 7; 9]); testCase.verifyEqual(diffSig.signal, [3; 3; 3]); testCase.verifyEqual(prodSig.signal, [4; 10; 18]); end function arithmeticOperatorsSupportNumericOperands(testCase) x = Signal([1; 2; 3]); sumSig = x + 2; diffSig = x - 1; prodSig = x .* 3; testCase.verifyEqual(sumSig.signal, [3; 4; 5]); testCase.verifyEqual(diffSig.signal, [0; 1; 2]); testCase.verifyEqual(prodSig.signal, [3; 6; 9]); end function lengthReturnsSignalLength(testCase) sig = Signal(zeros(11, 1)); testCase.verifyEqual(sig.length(), 11); end function normalizeRmsScalesSignalToUnitPower(testCase) sig = Signal([1; -1; 1; -1]); sig = sig.normalize("mode", normalization_mode.rms); testCase.verifyEqual(mean(abs(sig.signal).^2), 1, "AbsTol", 1e-12); end function normalizeOneOneMapsSignalToMinusOneToOne(testCase) sig = Signal([2; 4; 6]); sig = sig.normalize("mode", normalization_mode.oneone); testCase.verifyEqual(sig.signal, [-1; 0; 1], "AbsTol", 1e-12); end function logbookEntryAppendsRowAndDescription(testCase) sig = Signal([1; 0; -1], "fs", 1); sig = sig.logbookentry("unit-test entry", sig); testCase.verifyEqual(height(sig.logbook), 1); testCase.verifyEqual(string(sig.logbook.SignalType(1)), "Signal"); testCase.verifyEqual(string(sig.logbook.Description(1)), "unit-test entry"); testCase.verifyEqual(string(sig.logbook.ModifierName(1)), "Signal"); end function resampleWithIdenticalRatesKeepsSignalAndFs(testCase) original = [1; 2; 3; 4]; sig = Signal(original, "fs", 8); sig = sig.resample("fs_in", 8, "fs_out", 8); testCase.verifyEqual(sig.signal, original); testCase.verifyEqual(sig.fs, 8); testCase.verifyEqual(height(sig.logbook), 1); end function resampleToNewRateUpdatesSamplingRate(testCase) sig = Signal((1:8).', "fs", 8); sig = sig.resample("fs_in", 8, "fs_out", 16); testCase.verifyEqual(sig.fs, 16); testCase.verifyNotEmpty(sig.signal); testCase.verifyEqual(height(sig.logbook), 1); end function spectrumCanUseSamplingRateNormalizedFrequencyAxis(testCase) fig = figure("Visible", "off"); cleanup = onCleanup(@() close(fig)); fignum = fig.Number; sig = Signal(randn(4096, 1), "fs", 8e9); sig.spectrum( ... "fignum", fignum, ... "normalizeToSamplingRate", 1, ... "normalizeTo0dB", 1, ... "fft_length", 512); ax = findobj(fig, "Type", "Axes"); lineObj = findobj(ax, "Type", "Line"); testCase.verifyEqual(ax.XLim, [-0.5 0.5], "AbsTol", 1e-12); testCase.verifyEqual(string(ax.XLabel.String), "Normalized Frequency f/fs"); testCase.verifyGreaterThanOrEqual(min(lineObj.XData), -0.5); testCase.verifyLessThanOrEqual(max(lineObj.XData), 0.5); testCase.verifyLessThanOrEqual(abs(min(lineObj.XData) + 0.5), 1/512); testCase.verifyLessThanOrEqual(abs(max(lineObj.XData) - 0.5), 1/512); end function spectrumCanShowOneSidedSamplingRateNormalizedAxis(testCase) fig = figure("Visible", "off"); cleanup = onCleanup(@() close(fig)); fignum = fig.Number; sig = Signal(randn(4096, 1), "fs", 8e9); sig.spectrum( ... "fignum", fignum, ... "normalizeToSamplingRate", 1, ... "show_onesided", true, ... "normalizeTo0dB", 1, ... "fft_length", 512); ax = findobj(fig, "Type", "Axes"); lineObj = findobj(ax, "Type", "Line"); testCase.verifyEqual(ax.XLim, [0 0.5], "AbsTol", 1e-12); testCase.verifyGreaterThanOrEqual(min(lineObj.XData), 0); testCase.verifyLessThanOrEqual(max(lineObj.XData), 0.5); testCase.verifyLessThanOrEqual(abs(max(lineObj.XData) - 0.5), 1/512); end function castingRoundTripPreservesSignalThroughAllDomains(testCase) infoIn = Informationsignal([0; 1; 1; 0]); elecFromInfo = infoIn.Electricalsignal("fs", 64e9, "logbook", infoIn.logbook); optFromElec = elecFromInfo.Opticalsignal( ... "fs", elecFromInfo.fs, ... "logbook", elecFromInfo.logbook, ... "lambda", 1310e-9, ... "nase", 0, ... "polrot", 0); elecFromOpt = optFromElec.Electricalsignal("fs", optFromElec.fs, "logbook", optFromElec.logbook); infoOut = elecFromOpt.Informationsignal("fs", elecFromOpt.fs, "logbook", elecFromOpt.logbook); testCase.verifyClass(elecFromInfo, 'Electricalsignal'); testCase.verifyClass(optFromElec, 'Opticalsignal'); testCase.verifyClass(elecFromOpt, 'Electricalsignal'); testCase.verifyClass(infoOut, 'Informationsignal'); testCase.verifyEqual(infoOut.signal, infoIn.signal); testCase.verifyEqual(elecFromInfo.fs, 64e9); testCase.verifyEqual(optFromElec.fs, 64e9); testCase.verifyEqual(elecFromOpt.fs, 64e9); testCase.verifyEqual(infoOut.fs, 64e9); testCase.verifyEqual(optFromElec.lambda, 1310e-9); testCase.verifyEqual(optFromElec.nase, 0); end end end