<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://mscneuro.neuro.uni-bremen.de/index.php?action=history&amp;feed=atom&amp;title=PyWavelets%3A_Wavelet_Transforms_in_Python</id>
	<title>PyWavelets: Wavelet Transforms in Python - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://mscneuro.neuro.uni-bremen.de/index.php?action=history&amp;feed=atom&amp;title=PyWavelets%3A_Wavelet_Transforms_in_Python"/>
	<link rel="alternate" type="text/html" href="https://mscneuro.neuro.uni-bremen.de/index.php?title=PyWavelets:_Wavelet_Transforms_in_Python&amp;action=history"/>
	<updated>2026-06-02T21:52:06Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.43.5</generator>
	<entry>
		<id>https://mscneuro.neuro.uni-bremen.de/index.php?title=PyWavelets:_Wavelet_Transforms_in_Python&amp;diff=446&amp;oldid=prev</id>
		<title>Davrot: Created page with &quot;How do we do wavelet transforms under Python?  Questions to [mailto:davrot@uni-bremen.de David Rotermund]  You might want to read: [https://paos.colorado.edu/research/wavelets/ A Practical Guide to Wavelet Analysis] -&amp;#x3E; [https://paos.colorado.edu/research/wavelets/bams_79_01_0061.pdf PDF]&lt;syntaxhighlight lang=&quot;shell&quot;&gt;pip install PyWavelets&lt;/syntaxhighlight&gt;  == Which [https://pywavelets.readthedocs.io/en/latest/ref/cwt.html#continuous-wavelet-families continuous moth...&quot;</title>
		<link rel="alternate" type="text/html" href="https://mscneuro.neuro.uni-bremen.de/index.php?title=PyWavelets:_Wavelet_Transforms_in_Python&amp;diff=446&amp;oldid=prev"/>
		<updated>2025-10-21T09:10:04Z</updated>

		<summary type="html">&lt;p&gt;Created page with &amp;quot;How do we do wavelet transforms under Python?  Questions to [mailto:davrot@uni-bremen.de David Rotermund]  You might want to read: [https://paos.colorado.edu/research/wavelets/ A Practical Guide to Wavelet Analysis] -&amp;gt; [https://paos.colorado.edu/research/wavelets/bams_79_01_0061.pdf PDF]&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;pip install PyWavelets&amp;lt;/syntaxhighlight&amp;gt;  == Which [https://pywavelets.readthedocs.io/en/latest/ref/cwt.html#continuous-wavelet-families continuous moth...&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;How do we do wavelet transforms under Python?&lt;br /&gt;
&lt;br /&gt;
Questions to [mailto:davrot@uni-bremen.de David Rotermund]&lt;br /&gt;
&lt;br /&gt;
You might want to read: [https://paos.colorado.edu/research/wavelets/ A Practical Guide to Wavelet Analysis] -&amp;amp;#x3E; [https://paos.colorado.edu/research/wavelets/bams_79_01_0061.pdf PDF]&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;pip install PyWavelets&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Which [https://pywavelets.readthedocs.io/en/latest/ref/cwt.html#continuous-wavelet-families continuous mother wavelets] are available? ==&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;import pywt&lt;br /&gt;
&lt;br /&gt;
wavelet_list = pywt.wavelist(kind=&amp;quot;continuous&amp;quot;)&lt;br /&gt;
print(wavelet_list)&amp;lt;/syntaxhighlight&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;[&amp;#039;cgau1&amp;#039;, &amp;#039;cgau2&amp;#039;, &amp;#039;cgau3&amp;#039;, &amp;#039;cgau4&amp;#039;, &amp;#039;cgau5&amp;#039;, &amp;#039;cgau6&amp;#039;, &amp;#039;cgau7&amp;#039;, &amp;#039;cgau8&amp;#039;, &amp;#039;cmor&amp;#039;, &amp;#039;fbsp&amp;#039;, &amp;#039;gaus1&amp;#039;, &amp;#039;gaus2&amp;#039;, &amp;#039;gaus3&amp;#039;, &amp;#039;gaus4&amp;#039;, &amp;#039;gaus5&amp;#039;, &amp;#039;gaus6&amp;#039;, &amp;#039;gaus7&amp;#039;, &amp;#039;gaus8&amp;#039;, &amp;#039;mexh&amp;#039;, &amp;#039;morl&amp;#039;, &amp;#039;shan&amp;#039;]&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* The mexican hat wavelet “mexh”&lt;br /&gt;
* The Morlet wavelet “morl”&lt;br /&gt;
* The complex Morlet wavelet (“cmorB-C” with floating point values B, C)&lt;br /&gt;
* The Gaussian wavelets (“gausP” where P is an integer between 1 and and 8)&lt;br /&gt;
* The complex Gaussian wavelets (“cgauP” where P is an integer between 1 and 8)&lt;br /&gt;
* The Shannon wavelets (“shanB-C” with floating point values B and C)&lt;br /&gt;
* The frequency B-spline wavelets (“fpspM-B-C” with integer M and floating point B, C)&lt;br /&gt;
&lt;br /&gt;
see [https://pywavelets.readthedocs.io/en/latest/ref/cwt.html#choosing-the-scales-for-cwt Choosing the scales for cwt]&lt;br /&gt;
&lt;br /&gt;
== Visualizing wavelets ==&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;import numpy as np&lt;br /&gt;
import matplotlib.pyplot as plt&lt;br /&gt;
import pywt&lt;br /&gt;
&lt;br /&gt;
wavelet_name: str = &amp;quot;cmor1.5-1.0&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Invoking the complex morlet wavelet object&lt;br /&gt;
wav = pywt.ContinuousWavelet(wavelet_name)&lt;br /&gt;
&lt;br /&gt;
# Integrate psi wavelet function from -Inf to x&lt;br /&gt;
# using the rectangle integration method.&lt;br /&gt;
int_psi, x = pywt.integrate_wavelet(wav, precision=10)&lt;br /&gt;
int_psi /= np.abs(int_psi).max()&lt;br /&gt;
wav_filter: np.ndarray = int_psi[::-1]&lt;br /&gt;
&lt;br /&gt;
nt: int = len(wav_filter)&lt;br /&gt;
t: np.ndarray = np.linspace(-nt // 2, nt // 2, nt)&lt;br /&gt;
plt.plot(t, wav_filter.real, label=&amp;quot;real&amp;quot;)&lt;br /&gt;
plt.plot(t, wav_filter.imag, label=&amp;quot;imaginary&amp;quot;)&lt;br /&gt;
plt.ylim([-1, 1])&lt;br /&gt;
plt.legend(loc=&amp;quot;upper left&amp;quot;)&lt;br /&gt;
plt.xlabel(&amp;quot;time (samples)&amp;quot;)&lt;br /&gt;
plt.title(f&amp;quot;filter {wavelet_name}&amp;quot;)&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
[[File:16 1.png|center]]&lt;br /&gt;
&amp;lt;div class=&amp;quot;figure&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Building a frequency scale for the complex Morlet wavelet ==&lt;br /&gt;
We don’t want to waste computations power. Thus we want to put the frequency band for higher frequencies further away than for smaller frequencies. Thus we will use a &amp;lt;math display=&amp;quot;inline&amp;quot;&amp;gt;2^{N \cdot Scale}&amp;lt;/math&amp;gt; scale.&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;import numpy as np&lt;br /&gt;
import matplotlib.pyplot as plt&lt;br /&gt;
import pywt&lt;br /&gt;
&lt;br /&gt;
number_of_frequences: int = 20  # Number of frequency bands&lt;br /&gt;
frequency_range: tuple[float, float] = (2, 200)  # Hz&lt;br /&gt;
dt: float = 1 / 1000  # sec&lt;br /&gt;
&lt;br /&gt;
frequency_range_np: np.ndarray = np.array(frequency_range)&lt;br /&gt;
&lt;br /&gt;
s_spacing = (1.0 / (number_of_frequences - 1)) * np.log2(&lt;br /&gt;
    frequency_range_np.max() / frequency_range_np.min()&lt;br /&gt;
)&lt;br /&gt;
scale = np.power(2, np.arange(0, number_of_frequences) * s_spacing)&lt;br /&gt;
&lt;br /&gt;
frequency_axis_np = frequency_range_np.min() * np.flip(scale)&lt;br /&gt;
plt.plot(frequency_axis_np, &amp;quot;--*&amp;quot;, label=&amp;quot;Frequency we want&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
wave_scales = 1.0 / (frequency_axis_np * dt)&lt;br /&gt;
&lt;br /&gt;
frequency_axis = pywt.scale2frequency(&amp;quot;cmor1.5-1.0&amp;quot;, wave_scales) / dt&lt;br /&gt;
&lt;br /&gt;
plt.plot(frequency_axis, &amp;quot;.&amp;quot;, label=&amp;quot;Frequency we got&amp;quot;)&lt;br /&gt;
plt.legend()&lt;br /&gt;
plt.xlim([0, number_of_frequences - 1])&lt;br /&gt;
plt.xticks(np.arange(0, number_of_frequences))&lt;br /&gt;
plt.ylabel(&amp;quot;Frequency [Hz]&amp;quot;)&lt;br /&gt;
plt.xlabel(&amp;quot;Frequency band&amp;quot;)&lt;br /&gt;
plt.show()&amp;lt;/syntaxhighlight&amp;gt;[[File:16 2.png]]&amp;lt;div class=&amp;quot;figure&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Cone of influence for the complex Morlet wavelet ==&lt;br /&gt;
At the edges of the time series, the wavelet is dangling out of the allowed time axis. Thus these values are nonsense and need to be removed. The size of the wavelet is connected to its scale, hence for different scales the bad zone has different sizes. For the complex Morlet wavelet the number of samples are defined by the equation &amp;lt;math display=&amp;quot;inline&amp;quot;&amp;gt;\sqrt(2) \cdot scale&amp;lt;/math&amp;gt; ( [https://paos.colorado.edu/research/wavelets/ A Practical Guide to Wavelet Analysis] -&amp;amp;#x3E; [https://paos.colorado.edu/research/wavelets/bams_79_01_0061.pdf PDF] ). Which looks like this: &amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;cone_of_influence = np.ceil(np.sqrt(2) * wave_scales).astype(dtype=np.int64)&lt;br /&gt;
print(cone_of_influence)&lt;br /&gt;
plt.plot(frequency_axis, cone_of_influence, &amp;quot;*&amp;quot;)&lt;br /&gt;
plt.ylabel(&amp;quot;Number of invalid data samples&amp;quot;)&lt;br /&gt;
plt.xlabel(&amp;quot;Frequency [Hz]&amp;quot;)&lt;br /&gt;
plt.show()&amp;lt;/syntaxhighlight&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;[  8  10  12  15  19  24  31  39  50  63  80 102 130 166 211 269 342 436 555 708]&amp;lt;/syntaxhighlight&amp;gt;[[File:16 3.png]]&amp;lt;div class=&amp;quot;figure&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Analyzing a test signal ==&lt;br /&gt;
First we need a test signal. We will use a 50Hz sinus for that&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;import numpy as np&lt;br /&gt;
import matplotlib.pyplot as plt&lt;br /&gt;
&lt;br /&gt;
f_test: float = 50  # Hz&lt;br /&gt;
number_of_test_samples: int = 1000&lt;br /&gt;
dt: float = 1.0 / 1000  # sec&lt;br /&gt;
&lt;br /&gt;
t_test: np.ndarray = np.arange(0, number_of_test_samples) * dt&lt;br /&gt;
test_data: np.ndarray = np.sin(2 * np.pi * f_test * t_test)&lt;br /&gt;
&lt;br /&gt;
plt.plot(t_test, test_data)&lt;br /&gt;
plt.xlabel(&amp;quot;time [sec]&amp;quot;)&lt;br /&gt;
plt.ylabel(&amp;quot;time series&amp;quot;)&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
[[File:16 4.png|center]]&lt;br /&gt;
&amp;lt;div class=&amp;quot;figure&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;import numpy as np&lt;br /&gt;
import matplotlib.pyplot as plt&lt;br /&gt;
import pywt&lt;br /&gt;
&lt;br /&gt;
# Calculate the wavelet scales we requested&lt;br /&gt;
def calculate_wavelet_scale(&lt;br /&gt;
    number_of_frequences: int,&lt;br /&gt;
    frequency_range_min: float,&lt;br /&gt;
    frequency_range_max: float,&lt;br /&gt;
    dt: float,&lt;br /&gt;
) -&amp;gt; np.ndarray:&lt;br /&gt;
    s_spacing: np.ndarray = (1.0 / (number_of_frequences - 1)) * np.log2(&lt;br /&gt;
        frequency_range_max / frequency_range_min&lt;br /&gt;
    )&lt;br /&gt;
    scale: np.ndarray = np.power(2, np.arange(0, number_of_frequences) * s_spacing)&lt;br /&gt;
    frequency_axis_request: np.ndarray = frequency_range_min * np.flip(scale)&lt;br /&gt;
    return 1.0 / (frequency_axis_request * dt)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
f_test: float = 50  # Hz&lt;br /&gt;
number_of_test_samples: int = 1000&lt;br /&gt;
&lt;br /&gt;
# The wavelet we want to use&lt;br /&gt;
mother = pywt.ContinuousWavelet(&amp;quot;cmor1.5-1.0&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
# Parameters for the wavelet transform&lt;br /&gt;
number_of_frequences: int = 25  # frequency bands&lt;br /&gt;
frequency_range_min: float = 15  # Hz&lt;br /&gt;
frequency_range_max: float = 200  # Hz&lt;br /&gt;
dt: float = 1.0 / 1000  # sec&lt;br /&gt;
&lt;br /&gt;
t_test: np.ndarray = np.arange(0, number_of_test_samples) * dt&lt;br /&gt;
test_data: np.ndarray = np.sin(2 * np.pi * f_test * t_test)&lt;br /&gt;
&lt;br /&gt;
wave_scales = calculate_wavelet_scale(&lt;br /&gt;
    number_of_frequences=number_of_frequences,&lt;br /&gt;
    frequency_range_min=frequency_range_min,&lt;br /&gt;
    frequency_range_max=frequency_range_max,&lt;br /&gt;
    dt=dt,&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
complex_spectrum, frequency_axis = pywt.cwt(&lt;br /&gt;
    data=test_data, scales=wave_scales, wavelet=mother, sampling_period=dt&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
plt.imshow(abs(complex_spectrum) ** 2, cmap=&amp;quot;hot&amp;quot;, aspect=&amp;quot;auto&amp;quot;)&lt;br /&gt;
plt.colorbar()&lt;br /&gt;
&lt;br /&gt;
plt.yticks(np.arange(0, frequency_axis.shape[0]), frequency_axis)&lt;br /&gt;
plt.xticks(np.arange(0, t_test.shape[0]), t_test)&lt;br /&gt;
&lt;br /&gt;
plt.xlabel(&amp;quot;Time [sec]&amp;quot;)&lt;br /&gt;
plt.ylabel(&amp;quot;Frequency [Hz]&amp;quot;)&lt;br /&gt;
plt.show()&amp;lt;/syntaxhighlight&amp;gt;[[File:16 5.png]]&amp;lt;div class=&amp;quot;figure&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&amp;#039;&amp;#039;&amp;#039;Done&amp;#039;&amp;#039;&amp;#039; ?!?!&lt;br /&gt;
&lt;br /&gt;
=== Fixing the problems – the axis of the plot ===&lt;br /&gt;
The axis look horrible! Let us fix that.&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;import numpy as np&lt;br /&gt;
import matplotlib.pyplot as plt&lt;br /&gt;
import pywt&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# Calculate the wavelet scales we requested&lt;br /&gt;
def calculate_wavelet_scale(&lt;br /&gt;
    number_of_frequences: int,&lt;br /&gt;
    frequency_range_min: float,&lt;br /&gt;
    frequency_range_max: float,&lt;br /&gt;
    dt: float,&lt;br /&gt;
) -&amp;gt; np.ndarray:&lt;br /&gt;
    s_spacing: np.ndarray = (1.0 / (number_of_frequences - 1)) * np.log2(&lt;br /&gt;
        frequency_range_max / frequency_range_min&lt;br /&gt;
    )&lt;br /&gt;
    scale: np.ndarray = np.power(2, np.arange(0, number_of_frequences) * s_spacing)&lt;br /&gt;
    frequency_axis_request: np.ndarray = frequency_range_min * np.flip(scale)&lt;br /&gt;
    return 1.0 / (frequency_axis_request * dt)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def get_y_ticks(&lt;br /&gt;
    reduction_to_ticks: int, frequency_axis: np.ndarray, round: int&lt;br /&gt;
) -&amp;gt; tuple[np.ndarray, np.ndarray]:&lt;br /&gt;
    output_ticks = np.arange(&lt;br /&gt;
        0,&lt;br /&gt;
        frequency_axis.shape[0],&lt;br /&gt;
        int(np.floor(frequency_axis.shape[0] / reduction_to_ticks)),&lt;br /&gt;
    )&lt;br /&gt;
    if round &amp;lt; 0:&lt;br /&gt;
        output_freq = frequency_axis[output_ticks]&lt;br /&gt;
    else:&lt;br /&gt;
        output_freq = np.round(frequency_axis[output_ticks], round)&lt;br /&gt;
    return output_ticks, output_freq&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def get_x_ticks(&lt;br /&gt;
    reduction_to_ticks: int, dt: float, number_of_timesteps: int, round: int&lt;br /&gt;
) -&amp;gt; tuple[np.ndarray, np.ndarray]:&lt;br /&gt;
    time_axis = dt * np.arange(0, number_of_timesteps)&lt;br /&gt;
    output_ticks = np.arange(&lt;br /&gt;
        0, time_axis.shape[0], int(np.floor(time_axis.shape[0] / reduction_to_ticks))&lt;br /&gt;
    )&lt;br /&gt;
    if round &amp;lt; 0:&lt;br /&gt;
        output_time_axis = time_axis[output_ticks]&lt;br /&gt;
    else:&lt;br /&gt;
        output_time_axis = np.round(time_axis[output_ticks], round)&lt;br /&gt;
    return output_ticks, output_time_axis&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
f_test: float = 50  # Hz&lt;br /&gt;
number_of_test_samples: int = 1000&lt;br /&gt;
&lt;br /&gt;
# The wavelet we want to use&lt;br /&gt;
mother = pywt.ContinuousWavelet(&amp;quot;cmor1.5-1.0&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
# Parameters for the wavelet transform&lt;br /&gt;
number_of_frequences: int = 25  # frequency bands&lt;br /&gt;
frequency_range_min: float = 15  # Hz&lt;br /&gt;
frequency_range_max: float = 200  # Hz&lt;br /&gt;
dt: float = 1.0 / 1000  # sec&lt;br /&gt;
&lt;br /&gt;
t_test: np.ndarray = np.arange(0, number_of_test_samples) * dt&lt;br /&gt;
test_data: np.ndarray = np.sin(2 * np.pi * f_test * t_test)&lt;br /&gt;
&lt;br /&gt;
wave_scales = calculate_wavelet_scale(&lt;br /&gt;
    number_of_frequences=number_of_frequences,&lt;br /&gt;
    frequency_range_min=frequency_range_min,&lt;br /&gt;
    frequency_range_max=frequency_range_max,&lt;br /&gt;
    dt=dt,&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
complex_spectrum, frequency_axis = pywt.cwt(&lt;br /&gt;
    data=test_data, scales=wave_scales, wavelet=mother, sampling_period=dt&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
plt.imshow(abs(complex_spectrum) ** 2, cmap=&amp;quot;hot&amp;quot;, aspect=&amp;quot;auto&amp;quot;)&lt;br /&gt;
plt.colorbar()&lt;br /&gt;
&lt;br /&gt;
y_ticks, y_labels = get_y_ticks(&lt;br /&gt;
    reduction_to_ticks=10, frequency_axis=frequency_axis, round=1&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
x_ticks, x_labels = get_x_ticks(&lt;br /&gt;
    reduction_to_ticks=10, dt=dt, number_of_timesteps=complex_spectrum.shape[1], round=2&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
plt.yticks(y_ticks, y_labels)&lt;br /&gt;
plt.xticks(x_ticks, x_labels)&lt;br /&gt;
&lt;br /&gt;
plt.xlabel(&amp;quot;Time [sec]&amp;quot;)&lt;br /&gt;
plt.ylabel(&amp;quot;Frequency [Hz]&amp;quot;)&lt;br /&gt;
plt.show()&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
[[File:16 6.png|center]]&lt;br /&gt;
&amp;lt;div class=&amp;quot;figure&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;This looks already better…&lt;br /&gt;
&lt;br /&gt;
=== Fixing the problems – Cone of influence ===&lt;br /&gt;
If the look at the edges of the 2d plot, we see that the power tapers of. There regions are invalid results because part of the wavelet hangs outside of the time series. The larger the frequency, the larger the region.&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;import numpy as np&lt;br /&gt;
import matplotlib.pyplot as plt&lt;br /&gt;
import pywt&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# Calculate the wavelet scales we requested&lt;br /&gt;
def calculate_wavelet_scale(&lt;br /&gt;
    number_of_frequences: int,&lt;br /&gt;
    frequency_range_min: float,&lt;br /&gt;
    frequency_range_max: float,&lt;br /&gt;
    dt: float,&lt;br /&gt;
) -&amp;gt; np.ndarray:&lt;br /&gt;
    s_spacing: np.ndarray = (1.0 / (number_of_frequences - 1)) * np.log2(&lt;br /&gt;
        frequency_range_max / frequency_range_min&lt;br /&gt;
    )&lt;br /&gt;
    scale: np.ndarray = np.power(2, np.arange(0, number_of_frequences) * s_spacing)&lt;br /&gt;
    frequency_axis_request: np.ndarray = frequency_range_min * np.flip(scale)&lt;br /&gt;
&lt;br /&gt;
    return 1.0 / (frequency_axis_request * dt)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def calculate_cone_of_influence(dt: float, frequency_axis: np.ndarray):&lt;br /&gt;
    wave_scales = 1.0 / (frequency_axis * dt)&lt;br /&gt;
    cone_of_influence: np.ndarray = np.ceil(np.sqrt(2) * wave_scales).astype(np.int64)&lt;br /&gt;
    return cone_of_influence&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def get_y_ticks(&lt;br /&gt;
    reduction_to_ticks: int, frequency_axis: np.ndarray, round: int&lt;br /&gt;
) -&amp;gt; tuple[np.ndarray, np.ndarray]:&lt;br /&gt;
    output_ticks = np.arange(&lt;br /&gt;
        0,&lt;br /&gt;
        frequency_axis.shape[0],&lt;br /&gt;
        int(np.floor(frequency_axis.shape[0] / reduction_to_ticks)),&lt;br /&gt;
    )&lt;br /&gt;
    if round &amp;lt; 0:&lt;br /&gt;
        output_freq = frequency_axis[output_ticks]&lt;br /&gt;
    else:&lt;br /&gt;
        output_freq = np.round(frequency_axis[output_ticks], round)&lt;br /&gt;
    return output_ticks, output_freq&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def get_x_ticks(&lt;br /&gt;
    reduction_to_ticks: int, dt: float, number_of_timesteps: int, round: int&lt;br /&gt;
) -&amp;gt; tuple[np.ndarray, np.ndarray]:&lt;br /&gt;
    time_axis = dt * np.arange(0, number_of_timesteps)&lt;br /&gt;
    output_ticks = np.arange(&lt;br /&gt;
        0, time_axis.shape[0], int(np.floor(time_axis.shape[0] / reduction_to_ticks))&lt;br /&gt;
    )&lt;br /&gt;
    if round &amp;lt; 0:&lt;br /&gt;
        output_time_axis = time_axis[output_ticks]&lt;br /&gt;
    else:&lt;br /&gt;
        output_time_axis = np.round(time_axis[output_ticks], round)&lt;br /&gt;
    return output_ticks, output_time_axis&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
f_test: float = 50  # Hz&lt;br /&gt;
number_of_test_samples: int = 1000&lt;br /&gt;
&lt;br /&gt;
# The wavelet we want to use&lt;br /&gt;
mother = pywt.ContinuousWavelet(&amp;quot;cmor1.5-1.0&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
# Parameters for the wavelet transform&lt;br /&gt;
number_of_frequences: int = 25  # frequency bands&lt;br /&gt;
frequency_range_min: float = 15  # Hz&lt;br /&gt;
frequency_range_max: float = 200  # Hz&lt;br /&gt;
dt: float = 1.0 / 1000  # sec&lt;br /&gt;
&lt;br /&gt;
t_test: np.ndarray = np.arange(0, number_of_test_samples) * dt&lt;br /&gt;
test_data: np.ndarray = np.sin(2 * np.pi * f_test * t_test)&lt;br /&gt;
&lt;br /&gt;
wave_scales = calculate_wavelet_scale(&lt;br /&gt;
    number_of_frequences=number_of_frequences,&lt;br /&gt;
    frequency_range_min=frequency_range_min,&lt;br /&gt;
    frequency_range_max=frequency_range_max,&lt;br /&gt;
    dt=dt,&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
complex_spectrum, frequency_axis = pywt.cwt(&lt;br /&gt;
    data=test_data, scales=wave_scales, wavelet=mother, sampling_period=dt&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
cone_of_influence = calculate_cone_of_influence(dt, frequency_axis)&lt;br /&gt;
&lt;br /&gt;
plt.imshow(abs(complex_spectrum) ** 2, cmap=&amp;quot;hot&amp;quot;, aspect=&amp;quot;auto&amp;quot;)&lt;br /&gt;
plt.plot(cone_of_influence, np.arange(0, cone_of_influence.shape[0]), &amp;quot;g&amp;quot;)&lt;br /&gt;
plt.plot(&lt;br /&gt;
    complex_spectrum.shape[1] - 1 - cone_of_influence,&lt;br /&gt;
    np.arange(0, cone_of_influence.shape[0]),&lt;br /&gt;
    &amp;quot;g&amp;quot;,&lt;br /&gt;
)&lt;br /&gt;
plt.colorbar()&lt;br /&gt;
&lt;br /&gt;
y_ticks, y_labels = get_y_ticks(&lt;br /&gt;
    reduction_to_ticks=10, frequency_axis=frequency_axis, round=1&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
x_ticks, x_labels = get_x_ticks(&lt;br /&gt;
    reduction_to_ticks=10, dt=dt, number_of_timesteps=complex_spectrum.shape[1], round=2&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
plt.yticks(y_ticks, y_labels)&lt;br /&gt;
plt.xticks(x_ticks, x_labels)&lt;br /&gt;
&lt;br /&gt;
plt.xlabel(&amp;quot;Time [sec]&amp;quot;)&lt;br /&gt;
plt.ylabel(&amp;quot;Frequency [Hz]&amp;quot;)&lt;br /&gt;
plt.show()&amp;lt;/syntaxhighlight&amp;gt;[[File:16 7.png]]&amp;lt;div class=&amp;quot;figure&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Fixing the problems – Cone of influence masked ===&lt;br /&gt;
Instead of marking the invalid regions in the plot, we want to continue to analyze the data later but without the invalide data. Thus we can mask that part of the tranformations with NaNs.&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;import numpy as np&lt;br /&gt;
import matplotlib.pyplot as plt&lt;br /&gt;
import pywt&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# Calculate the wavelet scales we requested&lt;br /&gt;
def calculate_wavelet_scale(&lt;br /&gt;
    number_of_frequences: int,&lt;br /&gt;
    frequency_range_min: float,&lt;br /&gt;
    frequency_range_max: float,&lt;br /&gt;
    dt: float,&lt;br /&gt;
) -&amp;gt; np.ndarray:&lt;br /&gt;
    s_spacing: np.ndarray = (1.0 / (number_of_frequences - 1)) * np.log2(&lt;br /&gt;
        frequency_range_max / frequency_range_min&lt;br /&gt;
    )&lt;br /&gt;
    scale: np.ndarray = np.power(2, np.arange(0, number_of_frequences) * s_spacing)&lt;br /&gt;
    frequency_axis_request: np.ndarray = frequency_range_min * np.flip(scale)&lt;br /&gt;
&lt;br /&gt;
    return 1.0 / (frequency_axis_request * dt)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def calculate_cone_of_influence(dt: float, frequency_axis: np.ndarray):&lt;br /&gt;
    wave_scales = 1.0 / (frequency_axis * dt)&lt;br /&gt;
    cone_of_influence: np.ndarray = np.ceil(np.sqrt(2) * wave_scales).astype(np.int64)&lt;br /&gt;
    return cone_of_influence&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def get_y_ticks(&lt;br /&gt;
    reduction_to_ticks: int, frequency_axis: np.ndarray, round: int&lt;br /&gt;
) -&amp;gt; tuple[np.ndarray, np.ndarray]:&lt;br /&gt;
    output_ticks = np.arange(&lt;br /&gt;
        0,&lt;br /&gt;
        frequency_axis.shape[0],&lt;br /&gt;
        int(np.floor(frequency_axis.shape[0] / reduction_to_ticks)),&lt;br /&gt;
    )&lt;br /&gt;
    if round &amp;lt; 0:&lt;br /&gt;
        output_freq = frequency_axis[output_ticks]&lt;br /&gt;
    else:&lt;br /&gt;
        output_freq = np.round(frequency_axis[output_ticks], round)&lt;br /&gt;
    return output_ticks, output_freq&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def get_x_ticks(&lt;br /&gt;
    reduction_to_ticks: int, dt: float, number_of_timesteps: int, round: int&lt;br /&gt;
) -&amp;gt; tuple[np.ndarray, np.ndarray]:&lt;br /&gt;
    time_axis = dt * np.arange(0, number_of_timesteps)&lt;br /&gt;
    output_ticks = np.arange(&lt;br /&gt;
        0, time_axis.shape[0], int(np.floor(time_axis.shape[0] / reduction_to_ticks))&lt;br /&gt;
    )&lt;br /&gt;
    if round &amp;lt; 0:&lt;br /&gt;
        output_time_axis = time_axis[output_ticks]&lt;br /&gt;
    else:&lt;br /&gt;
        output_time_axis = np.round(time_axis[output_ticks], round)&lt;br /&gt;
    return output_ticks, output_time_axis&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def mask_cone_of_influence(&lt;br /&gt;
    complex_spectrum: np.ndarray,&lt;br /&gt;
    cone_of_influence: np.ndarray,&lt;br /&gt;
    fill_value: float = np.NaN,&lt;br /&gt;
) -&amp;gt; np.ndarray:&lt;br /&gt;
    assert complex_spectrum.shape[0] == cone_of_influence.shape[0]&lt;br /&gt;
&lt;br /&gt;
    for frequency_id in range(0, cone_of_influence.shape[0]):&lt;br /&gt;
        # Front side&lt;br /&gt;
        start_id: int = 0&lt;br /&gt;
        end_id: int = int(&lt;br /&gt;
            np.min((cone_of_influence[frequency_id], complex_spectrum.shape[1]))&lt;br /&gt;
        )&lt;br /&gt;
        complex_spectrum[frequency_id, start_id:end_id] = fill_value&lt;br /&gt;
&lt;br /&gt;
        start_id = np.max(&lt;br /&gt;
            (&lt;br /&gt;
                complex_spectrum.shape[1] - cone_of_influence[frequency_id] - 1,&lt;br /&gt;
                0,&lt;br /&gt;
            )&lt;br /&gt;
        )&lt;br /&gt;
        end_id = complex_spectrum.shape[1]&lt;br /&gt;
        complex_spectrum[frequency_id, start_id:end_id] = fill_value&lt;br /&gt;
&lt;br /&gt;
    return complex_spectrum&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
f_test: float = 50  # Hz&lt;br /&gt;
number_of_test_samples: int = 1000&lt;br /&gt;
&lt;br /&gt;
# The wavelet we want to use&lt;br /&gt;
mother = pywt.ContinuousWavelet(&amp;quot;cmor1.5-1.0&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
# Parameters for the wavelet transform&lt;br /&gt;
number_of_frequences: int = 25  # frequency bands&lt;br /&gt;
frequency_range_min: float = 15  # Hz&lt;br /&gt;
frequency_range_max: float = 200  # Hz&lt;br /&gt;
dt: float = 1.0 / 1000  # sec&lt;br /&gt;
&lt;br /&gt;
t_test: np.ndarray = np.arange(0, number_of_test_samples) * dt&lt;br /&gt;
test_data: np.ndarray = np.sin(2 * np.pi * f_test * t_test)&lt;br /&gt;
&lt;br /&gt;
wave_scales = calculate_wavelet_scale(&lt;br /&gt;
    number_of_frequences=number_of_frequences,&lt;br /&gt;
    frequency_range_min=frequency_range_min,&lt;br /&gt;
    frequency_range_max=frequency_range_max,&lt;br /&gt;
    dt=dt,&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
complex_spectrum, frequency_axis = pywt.cwt(&lt;br /&gt;
    data=test_data, scales=wave_scales, wavelet=mother, sampling_period=dt&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
cone_of_influence = calculate_cone_of_influence(dt, frequency_axis)&lt;br /&gt;
&lt;br /&gt;
complex_spectrum = mask_cone_of_influence(&lt;br /&gt;
    complex_spectrum=complex_spectrum,&lt;br /&gt;
    cone_of_influence=cone_of_influence,&lt;br /&gt;
    fill_value=np.NaN,&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
plt.imshow(abs(complex_spectrum) ** 2, cmap=&amp;quot;hot&amp;quot;, aspect=&amp;quot;auto&amp;quot;)&lt;br /&gt;
plt.colorbar()&lt;br /&gt;
&lt;br /&gt;
y_ticks, y_labels = get_y_ticks(&lt;br /&gt;
    reduction_to_ticks=10, frequency_axis=frequency_axis, round=1&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
x_ticks, x_labels = get_x_ticks(&lt;br /&gt;
    reduction_to_ticks=10, dt=dt, number_of_timesteps=complex_spectrum.shape[1], round=2&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
plt.yticks(y_ticks, y_labels)&lt;br /&gt;
plt.xticks(x_ticks, x_labels)&lt;br /&gt;
&lt;br /&gt;
plt.xlabel(&amp;quot;Time [sec]&amp;quot;)&lt;br /&gt;
plt.ylabel(&amp;quot;Frequency [Hz]&amp;quot;)&lt;br /&gt;
plt.show()&amp;lt;/syntaxhighlight&amp;gt;[[File:16 8.png]]&amp;lt;div class=&amp;quot;figure&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Davrot</name></author>
	</entry>
</feed>