Skip to main content

signal processing - Extracting information from the result of ContinuousWaveletTransform


I'm trying to analysis a signal and identify some time-frequency information of it. For example, around which time the specific frequency arrives. It appears that Mathematica has very powerful wavelet analysis functions builtin suitable for my job. I've being reading the documentation of them, but still can't get it. In particular I don't really understand what the functions ContinuousWaveletTransform and WaveletScalogram do.


For example, for this example in the document,


data = Table[
Piecewise[{{Sin[2 π 10 t], 0 <= t < 1/4}, {Sin[2 π 25 t],
1/4 <= t < 1/2}, {Sin[2 π 50 t],
1/2 <= t < 3/4}, {Sin[2 π 100 t], 3/4 <= t <= 1}}], {t, 0,
1, 1/1023}];
ListLinePlot[data, AspectRatio -> 0.2]


enter image description here


cwd = ContinuousWaveletTransform[data, 
DGaussianWavelet[5], {Automatic, 12}];
WaveletScalogram[cwd, ColorFunction -> "RustTones"]

enter image description here


The above example shows the maps of a 1D time signal into a 2D time-frequency representation.


So my questions are:



  1. In the documentation, it says WaveletScalogram "plots wavelet vector coefficients", what that really mean? What is the x and y axis represent? In my understanding the time-frequency 2d plot is kind of like a musical score where the time axis is horizontal and the frequencies (notes) are plotted on a vertical axis. It this understanding correct?


  2. Is there a way to see the identify frequencies in the signal from the 2D plot? For example, we can see four difference frequencies from the 2d plot, can we read off their frequencies from the corresponding y value?



Answer



Yes, you are right. WaveletScalogram produces a plot that is very similar in behaviour to that used in music. Here, the octave axis is also logarithmic: -Log[2,b], meaning that the frequency at the next octave is doubled. We can illustrate this by a simple example - Consider a signal with a freq = 440Hz and a signal with double that freq = 880Hz. Now, knowing that higher frequencies are resolved at lower octaves and lower frequencies at higher octaves we can do the following calculation:


N[Log[440]/Log[2]]


 8.78136

N[Log[880]/Log[2]]



 9.78136

What this shows us is that two signals with frequencies respectively ω and 2ω are resolved at octaves next to each other.


And yes, you can identify a certain frequency from the WaveletScalogram. You have the following relation between the scales used in the wavelet transform,ContinuousWaveletTransform or DiscreteWaveletTransform, and the specific frequency: $$F_{a}=\frac{F_{c}}{a \Delta }$$



  • a is a scale

  • Δ is the SampleRate

  • Fc is the center frequency of a wavelet in Hz


  • Fa is the frequency corresponding to the scale a, in Hz


For ease of use we will give Fc = 1. For a better localisation search the Internet for the exact centre frequency corresponding to the wavelet family you are using. Now, all we need is the SampleRate which by default is equal to 8000Hz and the scales used in the wavelet transform you gave as an example.


freq = (#1[[1]] -> 8000/#1[[2]] &) /@ cwd["Scales"]


  {{1, 1} -> 20230.3, {1, 2} -> 19094.9, {1, 3} -> 18023.2, {1, 4} -> 17011.6,
{1, 5} -> 16056.8, {1, 6} -> 15155.6, {1, 7} -> 14305., {1, 8} -> 13502.1,
{1, 9} -> 12744.3, {1, 10} -> 12029., {1, 11} -> 11353.9, {1, 12} -> 10716.6,
{2, 1} -> 10115.2, {2, 2} -> 9547.44, {2, 3} -> 9011.58, {2, 4} -> 8505.8,

{2, 5} -> 8028.41, {2, 6} -> 7577.81, {2, 7} -> 7152.5, {2, 8} -> 6751.06,
{2, 9} -> 6372.15, {2, 10} -> 6014.51, {2, 11} -> 5676.94, {2, 12} -> 5358.32, ... }

We need to filter the frequency we are interested in and we will be able to say where we can find it in the scalogram. Say we are interested in the ω = 50Hz


Cases[freq, u_ /; 49 <= Last[u] <= 51]


{{9, 9} -> 49.7824}

Look back at the scalogram and locate octave 9 and voice 9 - and there it is !



At first I thought that the logical step to perform was to scale the data before passing it to the WaveletScalogram. And since we are using -Log scale you need to scale by a factor 2. I am still trying to figure out how to do this in WaveletScalogram. If that isn't something you need really fast you can use the following approach:


ListPlot[Abs@Reverse[Last /@ cwd[All]], PlotRange -> All]


Linear scale scalogram



Or optionally in 3D:


ListPlot3D[Abs@Reverse[Last /@ cwd[All]], PlotRange -> All, 
Mesh -> None, Boxed -> False, ColorFunction -> "DeepSeaColors",
AxesLabel -> {"time", "octaves", "magnitude"}]



Wavelet Scalogram in 3D





Edit by xslittlegrass


Sometimes we need to plot the wavelet transform scalogram in unit of frequencies rather than scales. The following shows how to do that (Thanks @Rojo and @MichaelE2 for discussion).


sampleRate=1023;
data = Table[
Piecewise[{{Sin[2 π 10 t], 0 <= t < 1/4}, {Sin[2 π 25 t],

1/4 <= t < 1/2}, {Sin[2 π 50 t],
1/2 <= t < 3/4}, {Sin[2 π 100 t], 3/4 <= t <= 1}}], {t, 0, 1,
1/sampleRate}];
cwd = ContinuousWaveletTransform[data,
DGaussianWavelet[5], {Automatic, 12}, SampleRate -> sampleRate]

Note that the frequencies in wavelet plot is characterized by pairs of numbers {octave, voice}. A octave means the frequency is doubled, and voices are further divisions of a octave. For example, if f1==2*f2, then f1 is one octave above f2. These wavelet scales can be converted into frequencies easily in a very clean way thanks to the "Scales" and "FourierFactor" properties of the wavelet transform data.


This calculates the frequency (in Hz) of each octave (corresponding to {1,1}, {2,1}, ... in the {octave,voice} notation.)


freq = (cwd["SampleRate"]/(#*cwd["Wavelet"]["FourierFactor"])) & /@
(Thread[{Range[cwd["Octaves"]], 1}] /. cwd["Scales"]);


this gives expression for ticks at each octave


ticks = Transpose[{Range[Length[freq]], freq}];

this display the wavelet scalogram in the frequency.


WaveletScalogram[cwd, Frame -> True, FrameTicks -> {{ticks, Automatic}, Automatic}, 
FrameLabel -> {"Time", "Frequency(Hz)"},
ColorFunction -> "RustTones"]

enter image description here



From above plots, one can see that there are frequencies at around 10Hz, 25Hz, 50Hz and 100Hz as we have in the signal.


Comments

Popular posts from this blog

plotting - How to draw lines between specified dots on ListPlot?

I would like to create a plot where I have unconnected dots and some connected. So far, I have figured out how to draw the dots. My code is the following: ListPlot[{{1, 1}, {2, 2}, {3, 3}, {4, 4}, {1, 4}, {2, 5}, {3, 6}, {4, 7}, {1, 7}, {2, 8}, {3, 9}, {4, 10}, {1, 10}, {2, 11}, {3, 12}, {4,13}, {2.5, 7}}, Ticks -> {{1, 2, 3, 4}, None}, AxesStyle -> Thin, TicksStyle -> Directive[Black, Bold, 12], Mesh -> Full] I have thought using ListLinePlot command, but I don't know how to specify to the command to draw only selected lines between the dots. Do have any suggestions/hints on how to do that? Thank you. Answer One possibility would be to use Epilog with Line : ListPlot[ {{1, 1}, {2, 2}, {3, 3}, {4, 4}, {1, 4}, {2, 5}, {3, 6}, {4, 7}, {1, 7}, {2, 8}, {3, 9}, {4, 10}, {1, 10}, {2, 11}, {3, 12}, {4, 13}, {2.5, 7}}, Ticks -> {{1, 2, 3, 4}, None}, AxesStyle -> Thin, TicksStyle -> Directive[Black, Bold, 12], Mesh -> Full, Epilog -> { Line[ ...

equation solving - Invert and fit implicitly defined curve

I need to fit an implicitly defined curve. I thought I could get some data out of Solve , and then using FindFit . Therefore, I would like to find the relation the parametric curve defined by $F(x,y)=0$: Solve[-(1/2) + 1/2 (0.41202 BesselK[0, 0.1 Sqrt[x^2 + y^2]] + (0.101483 x BesselK[1, 0.1 Sqrt[x^2 + y^2]])/Sqrt[x^2 + y^2]) == 0, y] But I can't get an output: Solve was unable to solve the system with inexact coefficients or the system obtained by direct rationalization of inexact numbers present in the system. Since many of the methods used by Solve require exact input, providing Solve with an exact version of the system may help. >> Edit: In particular, I would like to fit the data coming from the curve with the expression of another curve, and not with a function $f(x)$. In particular, since this clearly looks like a cardioid , I would like it to fit to something like it. What other strategies could I try?

dynamic - How can I make a clickable ArrayPlot that returns input?

I would like to create a dynamic ArrayPlot so that the rectangles, when clicked, provide the input. Can I use ArrayPlot for this? Or is there something else I should have to use? Answer ArrayPlot is much more than just a simple array like Grid : it represents a ranged 2D dataset, and its visualization can be finetuned by options like DataReversed and DataRange . These features make it quite complicated to reproduce the same layout and order with Grid . Here I offer AnnotatedArrayPlot which comes in handy when your dataset is more than just a flat 2D array. The dynamic interface allows highlighting individual cells and possibly interacting with them. AnnotatedArrayPlot works the same way as ArrayPlot and accepts the same options plus Enabled , HighlightCoordinates , HighlightStyle and HighlightElementFunction . data = {{Missing["HasSomeMoreData"], GrayLevel[ 1], {RGBColor[0, 1, 1], RGBColor[0, 0, 1], GrayLevel[1]}, RGBColor[0, 1, 0]}, {GrayLevel[0], GrayLevel...