# Scipy Signal – Helpful Tutorial

In this Python tutorial, we will learn about the “Scipy Signal” and cover the following topics.

• Scipy Signal
• Scipy Signal Butter
• Scipy Signal Processing
• Scipy Signal Find peaks
• Scipy Signal Convolve
• Scipy Signal Correlate
• Scipy Signal Ifilter
• Scipy Signal Impulse
• Scipy Signal Square
• Scipy Signal Spectrogram

## Scipy Signal

The Scipy has a library `scipy.signal` to modify, analyze and process the signal like video signal, audio signal, etc.

It has many functions or methods to deal with different kinds of signal problems in the following categories :

• B-splines
• Convolutional
• Filter design
• Filtering
• Continuous-time linear systems
• Matlab-style IIR filter design
• Discrete-time linear systems
• Window functions
• LTI representations
• Waveforms
• Chirp Z-transform and Zoom FFT
• Spectral analysis
• Wavelets
• Peak finding

Each category contains lots of functions, so here we will cover the commonly used methods of some categories.

## Scipy Signal Butter

Scipy has a method `butter()` to apply the Butterworth filter to the signal. In other words, we can create the design of the digital or analog Butterworth filter of Nth order that flattens the frequency.

The syntax is given below.

``scipy.signal.butter(N, Wn, btype='low', analog=False, output='ba', fs=None)``

Where parameters are:

• N(int): It is used to specify the filter’s order.
• Wn(array_data): It is used to specify the critical frequencies of highpass and lowpass filters.
• btype: Used to specify which kind of filters to use like bandstop, highpass, lowpass, and bandpass.
• analog(boolean): if it is true, then the analog filter is used, otherwise, in the case of false, a digital filter is used.
• output: It is used to specify the output type like zpk ( ploe-zero), sos (second-order sections), and ba (backward compatibility).

Let’s take an example by following the below steps:

Import the required libraries using the below python code.

``````from scipy.signal import butter
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline ``````

Create the time duration of the signal using the below code.

``t_duration = np.linspace(0,0.5,2000,False)``

Generate a signal of 20 and 40 Hz frequency using the below code.

``sign = np.sin(2*np.pi*20*t_duration) + np.sin(2*np.pi*40*t_duration)``

Plot the created signal using the below code.

``````fig, (ax1) = plt.subplots(1, 1, sharex=True)
ax1.plot(t_duration, sign)
ax1.set_title('20 and 40 Hz Sinusoid')
ax1.axis([0, 0.5, -2, 2.5])``````

Create a Butterworth high pass filter of 25 Hz and apply it to the above-created signal using the below code.

``````from scipy import signal
sos = butter(15, 20, 'hp', fs=2000, output='sos')
filtd = signal.sosfilt(sos, sign)``````

Plot the signal after applying the filter using the below code.

``````fig, (ax2) = plt.subplots(1, 1, sharex=True)
ax2.plot(t_duration, filtd)
ax2.set_title('After applying 20 Hz high-pass filter')
ax2.axis([0, 0.5, -2, 2.5])
ax2.set_xlabel('Time (seconds)')
plt.tight_layout()
plt.show()``````

This is how to apply Butterworth on the signal.

## Scipy Signal Find peaks

The Scipy has a method `find_peaks()` within a module `scipy.signal` that returns all the peaks on the basis of given peak properties.

The syntax is given below.

``scipy.signal.find_peaks(x, height=1, prominence=4,  distance=2, width=2, threshold=1, rel_height=0.5, wlen=1, )``

Where parameters are:

• x(sequence): It is used to accept the signal having peaks.
• height(sequence,ndarray, number): It is used to provide the peak height.
• threshold(sequence, ndarray, number): It is used to provide the peak threshold.
• distance(number): It is used to provide the minimum horizontal distance between adjacent peaks.
• prominence(sequence,ndarray, number): It is used to provide peak prominence.
• width(sequence,ndarray, number): It is used to provide the width of the peak.
• wlen(int): It is used to calculate the peak prominence.
• rel_height(int): It is used to calculate the peak height.

Let’s take an example by following the below steps:

Import the required library using the below python code.

``````from scipy.signal import find_peaks
from scipy.misc import electrocardiogram
import matplotlib.pyplot as plt
%matplotlib inline``````

Generate an electrocardiogram using the below code.

``value = electrocardiogram()[1000:5000]``

Now the peaks using the below code.

``````peak, _ = find_peaks(value, height=0)
plt.plot(value)
plt.plot(peak, value[peak], "*")
plt.plot(np.zeros_like(value), "--", color="green")
plt.show()``````

This is how to find all peaks of the signal.

## Scipy Signal Convolve

The Scipy has a method `convolve()` in module `scipy.signal` that returns the third signal by combining two signals.

The syntax is given below.

``scipy.signal.convolve(in1, in2, mode='full', method='auto')``

Where parameters are:

• in1(array_data): It is used to input the first signal in the form of an array.
• in2(array_data): It is used to input the second signal in the form of an array, the dimension must be the same as the first input array.
• mode: It is used to specify the string that determines the size of the output. The mode can be `same`, `full` and `valid`.
• method: It is used to specify the method that computes the convolution. The method can be `auto`, `direct` and `fft`.

Let’s understand with an example by following the below steps:

Import the required library using the below python code.

``````from scipy.signal import convolve
import scipy.signal
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline``````

Create two different signals using the below code.

``````signal_1 = np.repeat([1., 2., 1.], 50)
signal_2 = np.repeat([2., 4., 5.], 50)``````

Now add both signals to create a third signal using the below code.

``conv = signal.convolve(signal_1, signal_2, mode='same') / sum(signal_2)``

Let’s plot the above signals using the below code.

``````fig, (ax_actual, ax_sig_1, ax_conv) = plt.subplots(3, 1, sharex=True)
ax_actual.plot(signal_1)
ax_actual.set_title('Actual pulse')
ax_actual.margins(0, 0.1)
ax_sig_1.plot(signal_2)
ax_sig_1.set_title(' It is the Filter impulse response')
ax_sig_1.margins(0, 0.1)
ax_conv.plot(conv)
ax_conv.set_title('Convolved signal')
ax_conv.margins(0, 0.1)
fig.tight_layout()
fig.show()``````

This how-to generates the third signal by combining two different signals.

## Scipy Signal Correlate

The Scipy has a method `correlate()` within a module `scipy.signal` that is similar to the method `scipy.signal.convolve()`. It also generates the third signal by adding two signals and the generated signal is known as `cross correlation`.

The syntax is given below.

``scipy.signal.correlate(in1, in2, mode='full', method='auto')``

Where parameters are:

• in1(array_data): It is used to input the first signal in the form of an array.
• in2(array_data): It is used to input the second signal in the form of an array, the dimension must be the same as the first input array.
• mode: It is used to specify the string that determines the size of the output. The mode can be `same`, `full` and `valid`.
• method: It is used to specify the method that computes the convolution. The method can be `auto`, `direct` and `fft`.

Let’s understand with an example by following the below steps:

Import the required library using the below python code.

``````from scipy.signal import correlate
from scipy import signal
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline``````

Create two different signals using the below code.

``````signal_1 = np.repeat([1., 2., 1.], 50)
signal_2 = np.repeat([2., 4., 5.], 50)``````

Now add both signals to create a third signal using the below code.

``conv = signal.correlate(signal_1, signal_2, mode='same') / sum(signal_2)``

Let’s plot the above signals using the below code.

``````fig, (ax_actual, ax_sig_1, ax_conv) = plt.subplots(3, 1, sharex=True)
ax_actual.plot(signal_1)
ax_actual.set_title('Actual pulse')
ax_actual.margins(0, 0.1)
ax_sig_1.plot(signal_2)
ax_sig_1.set_title(' It is the Filter impulse response')
ax_sig_1.margins(0, 0.1)
ax_conv.plot(conv)
ax_conv.set_title('Correlated signal')
ax_conv.margins(0, 0.1)
fig.tight_layout()
fig.show()``````

This is how to correlate the signals using Scipy in Python.

## Scipy Signal Ifilter

The Scipy has a method `ifilter()` within module `scipy.signal` that clean the signal data in one dimension using the filter `Finite Impulse Respose` (FIR) or `Infinite Impulse Response`.

The syntax is given below.

``scipy.signal.lfilter(b, a, x, axis=- 1, zi=None)``

Where parameters are:

• b(array_data): It is a one-dimension sequence of vectors containing numerator coefficients.
• a(array_data): It is a one-dimension sequence of vectors containing denominator coefficients.
• x(array_data): It is ndarray as an input.
• axis(int): It is the name of the axis of the given array one to which a linear filter is applied.
• zi(array_data): It is used to specify the initial condition to hold up the filter.

The above method returns two values `y` and `zi`.

Let’s see with an example using the below steps:

Import the required libraries using the below python code.

``````from scipy.signal import lfilter,butter,filtfilt
import matplotlib.pyplot as plt
import numpy as np``````

Create a noisy signal that we are going to filter using the below code.

``````rng = np.random.default_rng()
array_data = np.linspace(-2, 2, 302)
sin_data = (np.sin(2*np.pi*0.65*array_data*(1-array_data) + 1.1) +
0.2*np.sin(2*np.pi*2.1*array_data + 1) +
0.20*np.cos(2*np.pi*2.58*array_data))
noisy_data = sin_data + rng.standard_normal(len(array_data)) * 0.07``````

Design Lowpass Butterworth filter of order 4 using the below code.

``num_coff, deno_coff = butter(4, 0.06)``

Let’s implement the filter on the noisy data.

``````zi = lfilter_zi(num_coff, deno_coff)
z, _ = lfilter(num_coff, deno_coff, noisy_data, zi=zi*noisy_data)``````

Implement the filter again.

``z2, _ =lfilter(num_coff, deno_coff, z, zi=zi*z)``

Now implement the filtfilt filter.

``y = filtfilt(num_coff, deno_coff, noisy_data)``

Plot all signals using the below code.

``````plt.figure
plt.plot(array_data, noisy_data, 'b', alpha=0.75)
plt.plot(array_data, z, 'r--', array_data, z2, 'r', array_data, y, 'k')
plt.legend(('This is noisy one', 'lfilter, once', 'lfilter, twice',
'This is filtfilt one'), loc='best')
plt.grid(True)
plt.show()``````

This is how to filter the noisy signal using the method `lfilter()`.

## Scipy Signal Impulse

The Scipy has a method `impulse()` within scipy module `scipy.signal` that is the retort of the continuous-time system in reply to external changes.

The syntax is given below.

``scipy.signal.impulse(system, X0=None, T=None, N=None)``

Where parameters are:

• system(tuple of array_data): It is used to define the systems.
• X0(array_data): It is the initial state array vector.
• T(array_data): It is the time points.
• N(int): To calculate the no of time points, use this parameter.

The method returns two values `T` and `yout`.

Let’s see with an example by following the below steps:

Import the required libraries using the below python code.

``````import matplotlib.pyplot as plt
from scipy.signal import impulse``````

Create a system using the below code.

``````sys = ([2.1], [2.1, 3.1, 2.1])
time_pts, impulse_res = signal.impulse(sys)``````

Now plot the generated impulse using the below code.

``plt.plot(time_pts,impulse_res)``

This is how to use the impulse method of the module `scipy.signal`.

## Scipy Signal Square

The Scipy module `scipy.signal` contains a method `square()` that generates the waveform as a square wave.

The syntax is given below.

``scipy.signal.square(t, duty=0.5)``

Where parameters are:

• t(array_data): It is array data as input.
• duty(array_data): It is used to define the duty cycle, by default it is 0.5.

The method returns `y` of type ndarray that contains the square wave.

Let’s generate a square waveform by following the below steps:

Import the required libraries using the below python code.

``````import matplotlib.pyplot as plt
import numpy as np
from scipy.signal import square``````

Create an array of data and square wave data using the below code.

``````array_data = np.linspace(0, 2, 1000, endpoint=False)
square_wave =  square(2 * np.pi * 2 * array_data)``````

Now plot the created square waveform using the below code.

``````plt.plot(array_data,square_wave)
plt.ylim(-1.5, 1.5)``````

This is how to create a square waveform using Scipy in the Python program.

## Scipy Signal Spectrogram

The Scipy has a method `spectrogram()` in a module `scipy.signal` that shows the strength of a signal over time on different frequencies of a specific waveform.

The syntax is given below.

``scipy.signal.spectrogram(x, fs=1.0, window=('tukey', 1), nperseg=None, noverlap=None, nfft=None, detrend='constant', return_onesided=False, axis=- 1, mode='psd')``

Where parameters are:

• x(array_data): It is time series.
• fs(float): Used to provide time-series sampling frequency.
• window(array_data, tuple, string): It is used to specify what kind of window we want to implement.
• nperseg(int): To specify the length of every segment.
• nooverlap(int): It is used to specify the no of points to overlay among segments.
• nfft(int): It is the size of the FFT.
• detrend(False, string, function): Used to specify how to remove the trend from each segment.
• return_onesided(boolean): To get the side of the spectrum of data. If true, then it returns the one-sided, otherwise in the case of false returns the two-sided.
• axis(int): It is used to specify the along which axis to calculate the spectrogram.
• mode(string): To specify how we want the expected value like angle, magnitude, phase, complex, and PSD.

The method returns three values `f` (frequencies as an array), `t`(segment times as array) and `sxx`(spectrogram).

Let’ understand with an example by following the below steps:

Import the required libraries using the below python code.

``````from scipy.signal import spectrogram
import matplotlib.pyplot as plt
import numpy as np
from scipy.fft import fftshift``````

Defining the values of the required parameters to generate the signal using the below code.

``````rng = np.random.default_rng()
sample_fre = 9e3
n = 1e3
amp = 3 * np.sqrt(3)
noisep = 0.02 * sample_fre / 3
time_data = np.arange(n) / float(sample_fre)
mode = 600*np.cos(3*np.pi*0.4*time_data)
car_rier = amp * np.sin(3*np.pi*4e4*time_data + mode)
gen_noise = rng.normal(scale=np.sqrt(noisep), size=time_data.shape)
gen_noise *= np.exp(-time_data/5)
signal_data = car_rier + gen_noise``````

Now calculate and show the spectrogram using the below code.

``````sample_freq, segment_time, spectrogram = spectrogram(signal_data, sample_fre)
plt.ylabel('It is frequency in Hertz')
plt.xlabel('It is time in second')
plt.show()``````

This is how to compute the spectrogram using scipy in Python.

Also, take a look at some more Scipy tutorials.

So, in this tutorial, we have learned about the “Scipy Signal” and covered the following topics.

• Scipy Signal
• Scipy Signal Butter
• Scipy Signal Processing
• Scipy Signal Find peaks
• Scipy Signal Convolve
• Scipy Signal Correlate
• Scipy Signal Ifilter
• Scipy Signal Impulse
• Scipy Signal Square
• Scipy Signal Spectrogram