2
$\begingroup$

For one of my DSP projects, I decided to use python to perform signal processing. While I am new to python, I understand that it is a very powerful and versatile language. For my processing, I opted to use Scipy's signal library to perform the signal processing, where I designed an analog, Butterworth lowpass filter. When it was time to apply the filter, using the "signal.lfilter" command, I received the following error:

"Traceback (most recent call last):
  File "C:\Users\bessi\Desktop\crying.py", line 39, in <module>
    f = signal.lfilter(b, a, data, axis = 0)
  File "C:\Users\bessi\AppData\Local\Programs\Python\Python37-32\lib\site-packages\scipy\signal\signaltools.py", line 1397, in lfilter
    return sigtools._linear_filter(b, a, x, axis)
ValueError: selected axis is out of range"

The lines of code associated with the design and application of the filter, are as follows, with the first line, being the line that creates the lowpass filter, while the second line, with the lfilter command, is where the error occurs (line 39)

b, a = signal.butter(4, 21980, 'low', analog = True, output='ba') 

f = signal.lfilter(b, a, data)

(Data is the input, sampled signal. )

This value error has been confusing me all evening, as it is saying that my axis parameter is invalid. What confuses me even more, is the fact that the axis input argument for the function has a default value of '-1' which I did not originally tamper with. I tried to adjust the axis value, and even tried to hardcode values, however, this same error keeps showing up. Hoping someone can offer some advice/assistance.

The links for the lfilter command: https://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.lfilter.html#scipy.signal.lfilter

Link for the scipy filter creation: https://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.butter.html#scipy.signal.butter

$\endgroup$
1
  • 1
    $\begingroup$ Upon further investigation, I have realized that the issue was not necessarily my code, but the order of the matrix of the input data. I assumed that my matrix was a [1 x n] matrix (1 row, with n columns) but upon investigation, I realized that my matrix was [n x 1], meaning that there was only one column, with 'n' rows in it. My issue was solved by transposing my matrix, which was the result of another function. $\endgroup$ Commented Nov 21, 2019 at 3:37

1 Answer 1

1
$\begingroup$

What is the shape of your data? It's probably empty. Try print(data.shape) if it's a Numpy array.

Another remark, lfilter interprets the b and a as the coefficients of a discrete-time transfer function, so you cannot use it with your analog Butterworth filter coefficients.

You only need to worry about the axis parameter if your input data is multidimensional.

For example:

#!/usr/bin/env python3

import matplotlib.pyplot as plt
from numpy import random, log10, angle, pi, transpose, arange, unwrap
from scipy.signal import butter, lfilter, freqz

f_s = 96000 # sample frequency
f_c = 21980 # cut-off frequency

b, a = butter(4, 2 * f_c / f_s)            # Design digital Butterworth filter

if True:
    x = random.randn(1000, 1)              # Generate Gaussian noise (column)
    y = lfilter(b, a, x, axis=1)           # Filter the signal
    plt.plot(x, label='Noise')
    plt.plot(y, label='Filtered')
    print(x.shape)
else:
    x = random.randn(1, 1000)              # Generate Gaussian noise (row)
    y = lfilter(b, a, x, axis=0)           # Filter the signal
    plt.plot(transpose(x), label='Noise')
    plt.plot(transpose(y), label='Filtered')
    print(x.shape)

plt.legend()
plt.show()

# Calculate the frequency response
w, h = freqz(b, a, worN=4096)
w *= f_s / (2 * pi)                        # Convert from rad/sample to Hz

# Plot the amplitude response
plt.subplot(2, 1, 1)
plt.suptitle('Bode Plot')
plt.plot(w, 20 * log10(abs(h)))            # Convert modulus to dB
plt.ylabel('Magnitude [dB]')
plt.xlim(0, f_s / 2)
plt.ylim(-60, 10)
plt.axvline(f_c, color='red')
plt.axhline(-3.01, linewidth=0.8, color='black', linestyle=':')

# Plot the phase response
plt.subplot(2, 1, 2)
plt.plot(w, 180 * unwrap(angle(h)) / pi)   # Convert argument to degrees
plt.xlabel('Frequency [Hz]')
plt.ylabel('Phase [°]')
plt.xlim(0, f_s / 2)
plt.ylim(-360, 0)
plt.yticks(arange(-360, 45, 90))
plt.axvline(f_c, color='red')

plt.show()
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.