# What do computed CWT frequencies and color values correspond to?

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) +
np.real(np.exp(-7*(t-0.4)**2)*np.exp(1j*2*np.pi*2*(t-0.4))))

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

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


The time domain is the following: The resulting CWT transform is instead: 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).

### Frequencies

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.

### Colormap

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. ### Other

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, for time overlap, Sx.shape. 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! 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. For your example that peaks at f=7: from ssqueezepy.visuals import plot
from numpy.fft import ifftshift, ifft

max_row_idx = np.where(np.abs(Wx) == np.abs(Wx).max())
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

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

# should take cwt at least once
psihs = wavelet._Psih
print(psihs.shape)
# 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)

• 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 ?
– User
Mar 4 at 9:10
• @User I've added some information. Mar 4 at 12:36
• 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 ?
– User
Mar 4 at 13:12
• @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. Mar 4 at 13:15
• 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.
– User
Mar 4 at 13:17