I wanted to make wavelet transform and represent the frequencies as function of time instead of the scale of the wavelet as function of time. This example that uses ssqueezepy does it however I would like to understand precisely first what are the frequencies that it calculates (is it the frequency of the signal?) and then how have they been calculated ?

Moreover, what are the range of colours used ? Is red corresponding to high overlapping and blue no overlapping for instance ?

import numpy as np
from ssqueezepy import cwt, Wavelet
from ssqueezepy.experimental import scale_to_freq
from ssqueezepy.visuals import imshow

t = np.linspace(-1, 1, 200, endpoint=False)
sig = (np.cos(2 * np.pi * 7 * t) +

wavelet = Wavelet(('gmw', {'beta': 4}))
Wx, scales = cwt(sig, wavelet, padtype='zero')

freqs = scale_to_freq(scales, wavelet, N=len(sig), fs=1/(t[1] - t[0]))
imshow(Wx, abs=1, yticks=freqs,  xticks=t,
       xlabel="time [sec]", ylabel="frequency [Hz]")

The time domain is the following:

enter image description here

The resulting CWT transform is instead:

enter image description here

Example from the SE post here. As observed in the answer to the linked question, the red band is around frequency equal to 7 matching np.cos(2 * np.pi * 7 * t).

Thanks in advance.


1 Answer 1



Currently, scale_to_freq computes the peak center frequencies of wavelets, via np.argmax(np.abs(wavelet_in_freq)), which returns the peak's index, and can convert to physical via * fs. Relevant reading: Wavelet "center frequency" explanation? Relation to CWT scales?, and on units, see bottom of this.


It's turbo, left is minimum right is maximum value. Moreover, by default ssqueezepy.visuals.imshow with abs=1 forces the lower limit to be 0, which is a good idea for visualizing non-negatives.

enter image description here


Is red corresponding to high overlapping and blue no overlapping for instance ?

Greater value = stronger correlation (similarity / inner product), of wavelet with input. out[5, 20] = sum(x * np.roll(psi_5, 20)), where psi_5 is in time. See animation under "Continuous Wavelet Transform" here.

The amount of overlap never affects the values of CWT/STFT, only the total number of values: for frequency overlap, Sx.shape[0], for time overlap, Sx.shape[1]. For ssqueezepy's CWT, the time overlap is always maximum, hop_size=1, and frequency overlap is controlled by nv, CWT's equivalent of STFT's n_fft (except nv is density, so ~proportional to total number of wavelets).

The time-domain perspective is explained in more detail here under "Convolution <=> Windowed Fourier equivalence"; it's for STFT, but as far as any individual filter is concerned, they're exactly the same thing.

Strength of correlation, in short

First, if unfamiliar with how Fourier transform works, I highly recommend this clip. I've also skimmed this one on CWT - seems visually rich but I've no clue what's in it, maybe a better spending of time.

But in short, in physics the dot product measures the alignment of vectors - the greater the value, the stronger the alignment. It's exactly the same here in time, and similar in frequency: per convolution theorem, "convolution in time <=> multiplication in frequency", and we're multiplying by the wavelets' frequency responses in frequency, for every row of CWT, which measures the alignment of input signal's frequency with the wavelet's - and each wavelet is narrowly confined in frequency. And at the same time, each output point of convolution is the result of a dot product in time, and wavelets are also narrowly localized in time - hence, "time-frequency", localized in both!

enter image description here

CWT output for that wavelet is ifft of the plot on right (minus the absolute value which is for visual convenience), which is one row, e.g. Wx[5]. For your example that peaks at f=7:

enter image description here

from ssqueezepy.visuals import plot
from numpy.fft import ifftshift, ifft

max_row_idx = np.where(np.abs(Wx) == np.abs(Wx).max())[0][0]
max_row_wavelet_fr = wavelet._Psih[max_row_idx]
# unpad by 156 to match `len(sig)`
max_row_wavelet_tm = ifftshift(ifft(max_row_wavelet_fr))[156:-156]

a = max_row_wavelet_tm.real
b = sig
a = a / np.abs(a).max()
b = b / np.abs(b).max()
plot(b, w=1.1, h=.7)
plot(a, title='signal; wavelet of "reddest" CWT row, real part')

Visualize the filters

You can tell everything about the transform from its filters. Below adds to your code:

from ssqueezepy.visuals import plot
from numpy.fft import ifft, ifftshift

# should take `cwt` at least once
psihs = wavelet._Psih
# show in freq domain
plot(psihs.T, color='tab:blue', show=1, title="CWT filterbank")
plot(psihs[:, :30].T, color='tab:blue', show=1, title="zoomed")
# show one in time domain
# for FFT-convolution, it's centered at index 0, `ifftshift` centers visually
pt = ifftshift(ifft(psihs[-50]))
plot(pt, complex=1, title="time-domain example")
plot(pt, abs=1, color='k', linestyle='--', show=1)
  • $\begingroup$ Thank you very much for your detailed answer. However I can not grasp everything: so in simple words when I have red spots it means stronger correlation (similarity / inner product), of wavelet with input from the point of view of frequecy ? $\endgroup$
    – User
    Commented Mar 4, 2023 at 9:10
  • $\begingroup$ @User I've added some information. $\endgroup$ Commented Mar 4, 2023 at 12:36
  • $\begingroup$ Thanks again for the addition but I am familiar with Fourier Transform. So it is as I thought: red color (in the colormap that you have chosen) means high overlapping between the wavelet and the signal ? $\endgroup$
    – User
    Commented Mar 4, 2023 at 13:12
  • $\begingroup$ @User Depends what you have in mind with "overlapping", but it's not the right terminology here. Yes, they "match" more - if you plot the wavelet that generates the "reddest" point, you'll see its "wiggles" exactly match the signal's. $\endgroup$ Commented Mar 4, 2023 at 13:15
  • $\begingroup$ P.S. I have already watched the video about CWT that you linked and yes it was really helpfull ! Because I knew about Fourier Transform but I am new to CWT. $\endgroup$
    – User
    Commented Mar 4, 2023 at 13:17

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.