What is the relationship between scales and frequency in a Morlet wavelet transform? I'm using PyWavelets, with a complex Morlet wavelet. Its complex wavelet transform function requires scales as one of its parameters, rather than frequencies. However, I don't understand the relationship between the two. I'm generating my scales like this:

base_scale = CENTER_FREQ * quality / 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)


That is, if I expect my signal to be at about 20 kHz, I want to set the scales to be such that the frequencies returned are between 10 kHz and 40 kHz. In this case, the num_octaves variable might be 2, base_freq would be 10000, and voices_per_octave might be 50. Then scales would be an array of length 101, ranging logarithmically from the scale corresponding to 10 kHz up to the scale corresponding to 40 kHz.

However, this only works if CENTER_FREQ (the wavelet's central frequency) is a small number. If I increase it beyond 31, the frequencies returned by:

coeffs, freqs = pywt.cwt(data, scales, wavelet, 1/quality)


(where quality is the sampling rate of the data) are dead wrong. Is there any easier way to determine the needed scales that correspond to the frequencies I want?
I found some details, for those who might come after me.

Scale and frequency should be inversely proportional, which is as one might figure. However, there seems to be an issue (possibly a bug) in PyWavelets that makes this not always the case.

There is an internal function in the PyWavelets library called scale2frequency() that takes 2 arguments plus an optional 3rd: wavelet, scale, and then precision. By its name, I assume that it's made to take a scale and return the associated frequency. However it's an involutory function: $f(f(x)) = x$. So it can also be used to calculate scale from frequency. (This might be undocumented behavior, and I have no idea if it'll still work this way in future versions.)

The problem I was running into involved the optional precision argument. It would appear that as the wavelet's central frequency increases, the required precision became very high. I was able to mitigate the problem somewhat by increasing precision beyond the default value of 8. But as it gets higher and higher, the amount of memory and processing power increases drastically, to the point where I burned through all my system's virtual memory long before it was high enough to return valid answers.

My final workaround involved altering my data's sampling rate by a factor of 1000 or so. In essence, I just told it that my data was in the Hz range rather than the kHz range. This made it so that the code wasn't returning any obvious errors. It's not ideal, but it seems to work well enough.