J'essaie de filtrer un signal de fréquence cardiaque bruyant avec Python. Parce que la fréquence cardiaque ne devrait jamais être environ 220 battements par minute, je souhaite éliminer tous les bruits supérieurs à 220 bpm. J'ai converti 220/minute en 3.66666666 Hertz puis converti ce Hertz en rad/s pour obtenir 23.0383461 rad/s.
La fréquence d'échantillonnage de la puce qui prend les données est de 30Hz, donc je l'ai convertie en rad/s pour obtenir 188,495559 rad/s.
Après avoir recherché des informations en ligne, j'ai trouvé des fonctions pour un filtre passe-bande que je voulais transformer en filtre passe-bas. Voici le lien du code de bande passante , donc je l'ai converti pour être ceci:
from scipy.signal import butter, lfilter
from scipy.signal import freqs
def butter_lowpass(cutOff, fs, order=5):
nyq = 0.5 * fs
normalCutoff = cutOff / nyq
b, a = butter(order, normalCutoff, btype='low', analog = True)
return b, a
def butter_lowpass_filter(data, cutOff, fs, order=4):
b, a = butter_lowpass(cutOff, fs, order=order)
y = lfilter(b, a, data)
return y
cutOff = 23.1 #cutoff frequency in rad/s
fs = 188.495559 #sampling frequency in rad/s
order = 20 #order of filter
#print sticker_data.ps1_dxdt2
y = butter_lowpass_filter(data, cutOff, fs, order)
plt.plot(y)
Cela me laisse très perplexe, car je suis presque sûr que la fonction beurre prend en compte la fréquence de coupure et d'échantillonnage en rad/s, mais il semble que j'obtienne une sortie étrange. Est-ce réellement en Hz?
Deuxièmement, quel est le but de ces deux lignes:
nyq = 0.5 * fs
normalCutoff = cutOff / nyq
Je sais que c'est quelque chose qui concerne la normalisation, mais je pensais que le nyquist était deux fois plus rapide que l'échantillonnage, et non une moitié. Et pourquoi utilisez-vous le nyquist comme normalisateur?
Peut-on expliquer plus comment créer des filtres avec ces fonctions?
J'ai tracé le filtre en utilisant
w, h = signal.freqs(b, a)
plt.plot(w, 20 * np.log10(abs(h)))
plt.xscale('log')
plt.title('Butterworth filter frequency response')
plt.xlabel('Frequency [radians / second]')
plt.ylabel('Amplitude [dB]')
plt.margins(0, 0.1)
plt.grid(which='both', axis='both')
plt.axvline(100, color='green') # cutoff frequency
plt.show()
et obtenu ce qui clairement ne coupe pas à 23 rad/s:
Quelques commentaires:
analog=True
dans l'appel à butter
, et vous devez utiliser scipy.signal.freqz
(et non freqs
) pour générer la réponse en fréquence.Voici ma version modifiée de votre script, suivie de l'intrigue qu'il génère.
import numpy as np
from scipy.signal import butter, lfilter, freqz
import matplotlib.pyplot as plt
def butter_lowpass(cutoff, fs, order=5):
nyq = 0.5 * fs
normal_cutoff = cutoff / nyq
b, a = butter(order, normal_cutoff, btype='low', analog=False)
return b, a
def butter_lowpass_filter(data, cutoff, fs, order=5):
b, a = butter_lowpass(cutoff, fs, order=order)
y = lfilter(b, a, data)
return y
# Filter requirements.
order = 6
fs = 30.0 # sample rate, Hz
cutoff = 3.667 # desired cutoff frequency of the filter, Hz
# Get the filter coefficients so we can check its frequency response.
b, a = butter_lowpass(cutoff, fs, order)
# Plot the frequency response.
w, h = freqz(b, a, worN=8000)
plt.subplot(2, 1, 1)
plt.plot(0.5*fs*w/np.pi, np.abs(h), 'b')
plt.plot(cutoff, 0.5*np.sqrt(2), 'ko')
plt.axvline(cutoff, color='k')
plt.xlim(0, 0.5*fs)
plt.title("Lowpass Filter Frequency Response")
plt.xlabel('Frequency [Hz]')
plt.grid()
# Demonstrate the use of the filter.
# First make some data to be filtered.
T = 5.0 # seconds
n = int(T * fs) # total number of samples
t = np.linspace(0, T, n, endpoint=False)
# "Noisy" data. We want to recover the 1.2 Hz signal from this.
data = np.sin(1.2*2*np.pi*t) + 1.5*np.cos(9*2*np.pi*t) + 0.5*np.sin(12.0*2*np.pi*t)
# Filter the data, and plot both the original and filtered signals.
y = butter_lowpass_filter(data, cutoff, fs, order)
plt.subplot(2, 1, 2)
plt.plot(t, data, 'b-', label='data')
plt.plot(t, y, 'g-', linewidth=2, label='filtered data')
plt.xlabel('Time [sec]')
plt.grid()
plt.legend()
plt.subplots_adjust(hspace=0.35)
plt.show()