alx
alx

Reputation: 844

Filter gives negative values (SciPy filter)

I have one problem with filtering my dataset (np array) with scipy.signal.butter (or ellip). My data has only positive values, but after filtering, there are negative values in the output array. The code and graphics are shown below. Question: why do negative values appear and how can I fix it? Thank you in advance!

Load the data:

 data_s = pd.read_csv('C:/Users/HP/Desktop/Python and programming/Jupyter/Filter/320_Hz.dat', header=None, squeeze=True)
    data = data_s.values
    #"turn over" the negative parts
    for i in range(len(data)): 
        if data[i] < 0:
            data[i] = abs(data[i]) * 2

Filt:

F_rate = 320.0
sample_time = 1 / F_rate

low = 79.9
high = 80.1
low_d = low / (0.5 * F_rate)
high_d = high / (0.5 * F_rate)

Wn = [low_d,high_d] 
#b, a = signal.ellip(4, 3, 40, Wn, 'bandpass', analog=False) 
b,a = signal.butter(6, Wn, 'bandpass', analog=False)

output = signal.filtfilt(b, a, data) 
print(output)
plt.magnitude_spectrum(output, Fs=F_rate)

Out:

[  7.93572645e-12   1.82355646e-12  -8.99759647e-11 ...,  -5.01622276e+03
   1.18142432e+04   4.98038137e+03]

Spectrum of output data:

enter image description here

Input data:

enter image description here

Output data (negative values):

enter image description here

Upvotes: 0

Views: 2011

Answers (1)

MB-F
MB-F

Reputation: 23637

why do negative values appear

Filtering can, in general, produce values outside of the input range. In particular, filtering the data with a band-pass removes low frequency components. The most low frequency component one can imagine is the mean, which is completely removed. In other words: a band-pass filter centers the data at zero. This is only possible if the data contains both of positive and negative values.

how can I fix it?

This one is tricky. To tell how to "fix" it one would need to why the data is filtered and why the output should be only positive. There is not really anything to fix, because the filter is doing exactly what it is suppodes to do.

These are some of the available options:

  • Fix your expectations and accept that you get negative values.
  • Maybe you do not need a band-pass? Use a high-pass filter that only removes high frequencies but does not touch low frequencies.
  • Add np.min(output) or some other offset to the output
  • Apply the same transform to the output that was used on the input: if data[i] < 0: data[i] = abs(data[i]) * 2 (although this feels like a very strange thing to do from my signal processing perspective)

Upvotes: 1

Related Questions