I have some artifacts in a PyWavelets transform that are really confusing me. I'm using version 0.5.2. Can someone explain what is happening here?
I start by creating a 1-kHz signal, and then I attempt to analyze this signal with a complex Morlet continuous wavelet transform. I'm doing so with 3 octaves: 0.5 kHz to 1 kHz, 1 kHz to 2 kHz, and 2 kHz to 4 kHz, each one with 40 log-scaled scales. My intuition says that there should be a single peak at y=40 (being equivalent to 1 kHz), and that any difference in time should be minimal. Instead, I'm getting a peak at around y=35 to 37 (0.92 to 0.95 kHz), and there's some kind of periodic effect. (Strangely, this effect seems to occur only in the real component of the transform--the imaginary component looks closer to how I imagined it should look, though it's still not centered correctly. I believe that the real component and the imaginary component should look like time-shifted versions of each other, when looking at a pure sine wave.)
Am I misusing PyWavelets? Is there possibly a bug here? Any help would be welcome.
import numpy
import pywt
import matplotlib.pyplot as plt
# makes a 1-kHz signal
def make_data(length, quality):
tau = 2*numpy.pi
x = numpy.arange(length)
y = numpy.sin(tau * x/(quality/1000)) # the 1000 is for 1 kHz
return y
# does the continuous wavelet transform, outputting pic
def do_transform(data, base_freq, num_octaves, voices_per_octave, quality):
# calculate the scales, based on the desired frequencies
base_scale = quality / (2*base_freq)
far_scale = base_scale / 2**num_octaves
scales = numpy.geomspace(base_scale, far_scale, num=num_octaves*voices_per_octave+1, endpoint=True)
# actual calculation
coeffs, freqs = pywt.cwt(data, scales, "cmor", 1/quality)
print("freqs: " +str(freqs))
# output
truncated = coeffs[:, 100:200]
plt.imshow(abs(truncated), origin='lower', interpolation='none')
#plt.imshow(truncated.real, origin='lower', interpolation='none')
#plt.imshow(truncated.imag, origin='lower', interpolation='none')
plt.subplots_adjust(left=0.01, right=0.99, top=0.99, bottom=0.05)
plt.show()
data = make_data(1000, 44100)
do_transform(data, 500, 3, 40, 44100)
It turns out that this is a known issue. (It's still not clear if this is a bug or just unexpected behavior, but the discussion is here: https://github.com/PyWavelets/pywt/issues/307 .)
Thanks to everyone who looked at it and considered it.