I'm new with Python and I'm completely stuck when filtering a signal. This is the code:
import numpy as np
import matplotlib.pyplot as plt
from scipy import signal
fs=105e6
fin=70.1e6
N=np.arange(0,21e3,1)
# Create a input sin signal of 70.1 MHz sampled at 105 MHz
x_in=np.sin(2*np.pi*(fin/fs)*N)
# Define the "b" and "a" polynomials to create a CIC filter (R=8,M=2,N=6)
b=np.zeros(97)
b[[0,16,32,48,64,80,96]]=[1,-6,15,-20,15,-6,1]
a=np.zeros(7)
a[[0,1,2,3,4,5,6]]=[1,-6,15,-20,15,-6,1]
w,h=signal.freqz(b,a)
plt.plot(w/max(w),20*np.log10(abs(h)/np.nanmax(h)))
plt.title('CIC Filter Response')
output_nco_cic=signal.lfilter(b,a,x_in)
plt.figure()
plt.plot(x_in)
plt.title('Input Signal')
plt.figure()
plt.plot(output_nco_cic)
plt.title('Filtered Signal')
And the plots:
As you can see, although the filter transfer function is correct, the output isn't. And I can't see why my code isn't working. I've coded the same in Matlab and the output looks ok.
Thaks for the help!
The code is fine, and lfilter works fine on the float64 arrays that it creates. But the denominator polynomial "a" has all its roots at z = 1, which makes the filter "conditionally stable". Due to numerically inaccuracy, it will eventually diverge. And the input signal at 70.1 MHz is way outside the passband, so it doesn't show up much in the output. If you change the input to 0.701 MHz or thereabouts, and shorten the signal to 1000 samples instead of 21000, you'll see that it works as-is. Try these changes and you'll see what happens after that: fin=70.1e4 N=np.arange(0,2000,1) (and to get rid of the divide by zero complaint, add 1.0e-12 inside the log10)
To do a CIC right, you need an implementation that deals correctly with the conditionally stable poles.
I don't find it confusing that this didn't work with Python, but I do find it confusing that it worked with Matlab.
CIC filters don't work with floating point numbers.
UPDATE:
Interestingly, at least with the version of scipy I have, lfilter doesn't work with integer arrays -- I get a NotImplemented error. Here is a numpy version of a CIC filter that is about twice as fast as a pure Python implementation on my machine: