Signal Processing - Maple Help

Home : Support : Online Help : System : Information : Updates : Maple 2022 : Signal Processing

Signal Processing

The SignalProcessing package has been expanded with new and updated commands.

 > restart;

SignalProcessing

 > with( SignalProcessing ):

GenerateSignal

The new GenerateSignal command is useful for creating signals, filters, and windows from algebraic expressions. For example:

 > X := GenerateSignal( 3 * sin(t) + cos(2*t), t = 0 .. 4 * Pi, 100 );

The command also packages many related features and data for the signal:

 > sample_rate, Times, Signal := GenerateSignal( t * exp(-t), t = 0 .. 5, 10^3, 'output' = ['samplerate','times','signal'] );
 > R := GenerateSignal( t / (1+t^2), t = 0 .. 4, 2^10, 'noisetype' = 'additive', 'noisedeviation' = 0.01, 'output' = 'record' ):
 > R['signalplot'];
 > R['periodogram'];

DynamicTimeWarping

The DynamicTimeWarping command, which has many applications including speech recognition and genetic sequencing, determines the best match between two signals by varying the sampling rates dynamically. For example:

 > X := GenerateSignal( 5 + sqrt(1-(t-1)^4), t = 0 .. 2, 200, 'mirror' = 'antisymmetric', 'copies' = 4 ):
 > Y := GenerateSignal( 6 - abs(t-1), t = 0 .. 2, 200, 'mirror' = 'antisymmetric', 'copies' = 4 ):
 > R := DynamicTimeWarping( X, Y, 'compiled', 'output' = 'record' ):
 > R['unwarpedplot'];
 > R['warpedplot'];

The match is computed by inserting zero or more copies of each sample for both signals in such a way that the cost with respect to the metric (taxicab, by default) is minimal. For this example:

 > R['cost'];
 ${28.7505811441736654}$ (1.2.1)

In terms of the root mean square error:

 > R['rmse'];
 ${0.0220493272388582497}$ (1.2.2)

DifferentiateData

The new DifferentiateData command offers the standard methods, namely Backward, Central, and Forward Difference, and also features spectral differentiation. For example:

 > f := piecewise( t < Pi  or t > 3 * Pi, sin(4*t) + 5, 1/10 * sin(40*t) + 5 ); a, b := 0, 4 * Pi; n := 2^14;
 ${f}{≔}\left\{\begin{array}{cc}{\mathrm{sin}}{}\left({4}{}{t}\right){+}{5}& {t}{<}{\mathrm{\pi }}\phantom{\rule[-0.0ex]{0.3em}{0.0ex}}{\mathbf{or}}\phantom{\rule[-0.0ex]{0.3em}{0.0ex}}{3}{}{\mathrm{\pi }}{<}{t}\\ \frac{{\mathrm{sin}}{}\left({40}{}{t}\right)}{{10}}{+}{5}& {\mathrm{otherwise}}\end{array}\right\$
 ${a}{,}{b}{≔}{0}{,}{4}{}{\mathrm{\pi }}$
 ${n}{≔}{16384}$ (1.3.1)
 > ( dt, T, X ) := GenerateSignal( f, t = a .. b, n, 'includefinishtime' = 'false', 'output' = ['timestep','times','signal'] ):
 > DX := DifferentiateData( X, 1, 'step' = dt, 'method' = 'spectral', 'extrapolation' = 'periodic' ):
 > dataplot( T, [X,DX], 'style' = 'line', 'color' = ['red','blue'], 'legend' = ["Signal","First derivative"], 'size' = [500,250] );

IntegrateData and IntegrateData2D

The IntegrateData2D command provides a fast and accurate way of finding the volume under a two-dimensional dataset. For example:

 > f := (x,y) -> sqrt( 1 + sin( Pi * ( x^2 + 3 * y^2 ) ) ); a, b, c, d := 0.0, 1.0, -0.5, 1.5;
 ${f}{≔}\left({x}{,}{y}\right){↦}\sqrt{{1}{+}{\mathrm{sin}}{}\left({\mathrm{\pi }}{\cdot }\left({{x}}^{{2}}{+}{3}{\cdot }{{y}}^{{2}}\right)\right)}$
 ${a}{,}{b}{,}{c}{,}{d}{≔}{0.}{,}{1.0}{,}{-0.5}{,}{1.5}$ (1.4.1)
 > plot3d( f, a .. b, c .. d );
 > m, n := 100, 100; dx, dy := evalhf( (b-a) / (m-1) ), evalhf( (d-c) / (n-1) );
 ${m}{,}{n}{≔}{100}{,}{100}$
 ${\mathrm{dx}}{,}{\mathrm{dy}}{≔}{0.0101010101010101019}{,}{0.0202020202020202037}$ (1.4.2)
 > X := Vector( m, i -> evalhf( a + (i-1) * dx ), 'datatype' = 'float[8]' ): Y := Vector( n, j -> evalhf( c + (j-1) * dy ), 'datatype' = 'float[8]' ): Z := Matrix( m, n, (i,j) -> evalhf( f( X[i], Y[i] ) ), 'datatype' = 'float[8]' );
 > IntegrateData2D( X, Y, Z, 'uniform', 'compiled', 'method' = 'simpson' );
 ${2.09312887784632640}$ (1.4.3)

This command supports both uniform (regular) and non-uniform (irregular) data. The option uniform tells the algorithm to skip the check for uniformity and use the uniform version of Simpson's Rule, which is quicker. The existing (added in Maple 2021) one-dimensional version of the command, IntegrateData, has been updated to include the compiled and uniform options.

RealPart and ImaginaryPart

The new RealPart and ImaginaryPart commands complement the existing ComplexToReal command. They, respectively, take a complex[8] container and quickly create a float[8] container for the real part and imaginary part. For example:

 > X := LinearAlgebra:-RandomVector( 5, 'generator' = -1.0 - 1.0 * I .. 1.0 + 1.0 * I, 'datatype' = 'complex[8]' );
 $\left[\begin{array}{c}-0.17095492221378317-0.07032011674972538{}I\\ 0.9989832401954093-0.4243013103697255{}I\\ 0.0799641980758583+0.4138348386455255{}I\\ -0.7636896031065787+0.9768358575699612{}I\\ -0.3383420095933909+0.7969722756685991{}I\end{array}\right]$ (1.5.1)
 > Y := RealPart( X );
 $\left[\begin{array}{c}-0.17095492221378317\\ 0.9989832401954093\\ 0.0799641980758583\\ -0.7636896031065787\\ -0.3383420095933909\end{array}\right]$ (1.5.2)
 > Z := ImaginaryPart( X );
 $\left[\begin{array}{c}-0.07032011674972538\\ -0.4243013103697255\\ 0.4138348386455255\\ 0.9768358575699612\\ 0.7969722756685991\end{array}\right]$ (1.5.3)

Of course, if you need both the real and imaginary parts, it is best to use the ComplexToReal command:

 > ComplexToReal( X );
 $\left[\begin{array}{c}{-0.170954922213783}\\ {0.998983240195409}\\ {0.0799641980758583}\\ {-0.763689603106579}\\ {-0.338342009593391}\end{array}\right]{,}\left[\begin{array}{c}{-0.0703201167497254}\\ {-0.424301310369726}\\ {0.413834838645526}\\ {0.976835857569961}\\ {0.796972275668599}\end{array}\right]$ (1.5.4)

Insert

The new Insert command can take one signal, and insert it into another at any point. For example:

 > n := 2^10;
 ${n}{≔}{1024}$ (1.6.1)
 > X := GenerateSignal( sin(4*t) + 5, t = 0 .. 2 * Pi, n, 'includefinishtime' = 'false' ):
 > SignalPlot( X, 'view' = ['DEFAULT',0..10], 'color' = 'blue' );
 > Y := GenerateSignal( 1/10 * sin(40*t) + 5, t = 0 .. 2 * Pi, n, 'includefinishtime' = 'false' ):
 > SignalPlot( Y, 'view' = ['DEFAULT',0..10], 'color' = 'blue' );
 > Insert( X, floor(n/2) + 1, Y, 'inplace' ):
 > SignalPlot( X, 'view' = ['DEFAULT',0..10], 'color' = 'blue' );

FindPeakPoints

The FindPeakPoints command now has output options for the indices of the peaks and valleys. For example:

 > X := < -5, 12, 6, 7, 3, 15, -10 >;
 $\left[\begin{array}{r}-5\\ 12\\ 6\\ 7\\ 3\\ 15\\ -10\end{array}\right]$ (1.7.1)
 > FindPeakPoints( X, 'output' = 'plot', 'plotincludepoints' = ['peaks','regular','valleys'], 'gridlines' );
 > FindPeakPoints( X, 'output' = ['peakindices','valleyindices'] );
 $\left[\begin{array}{c}{2}\\ {4}\\ {6}\end{array}\right]{,}\left[\begin{array}{c}{1}\\ {3}\\ {5}\\ {7}\end{array}\right]$ (1.7.2)

RootMeanSquareError and RelativeRootMeanSquareError

The RootMeanSquareError and RelativeRootMeanSquareError commands have been sped up for large data containers. For example:

 > n := 10^5; r := 1.0 + 1.0 * I; dt := 'complex[8]'; X := LinearAlgebra:-RandomVector( n, 'generator' = -r .. r, 'datatype' = dt ): Y := LinearAlgebra:-RandomVector( n, 'generator' = -r .. r, 'datatype' = dt ):
 ${n}{≔}{100000}$
 ${r}{≔}{1.0}{+}{I}$
 ${\mathrm{dt}}{≔}{{\mathrm{complex}}}_{{8}}$ (1.8.1)
 > tests := 25; CodeTools:-Usage( RootMeanSquareError( X, Y ), 'iterations' = tests ); CodeTools:-Usage( RelativeRootMeanSquareError( X, Y ), 'iterations' = tests );
 ${\mathrm{tests}}{≔}{25}$
 memory used=16.36KiB, alloc change=0 bytes, cpu time=3.12ms, real time=3.56ms, gc time=0ns
 ${1.15349306481481761}$
 memory used=44.40KiB, alloc change=0 bytes, cpu time=7.48ms, real time=7.20ms, gc time=0ns
 ${1.41397255876189520}$ (1.8.2)