web-dev-qa-db-fra.com

Python Filtre passe-haut

J'ai implémenté un filtre passe-haut dans python en utilisant ce code:

from scipy.signal import butter, filtfilt
import numpy as np

def butter_highpass(cutoff, fs, order=5):
    nyq = 0.5 * fs
    normal_cutoff = cutoff / nyq
    b, a = butter(order, normal_cutoff, btype='high', analog=False)
    return b, a

def butter_highpass_filter(data, cutoff, fs, order=5):
    b, a = butter_highpass(cutoff, fs, order=order)
    y = filtfilt(b, a, data)
    return y

rawdata = np.loadtxt('sampleSignal.txt', skiprows=0)
signal = rawdata
fs = 100000.0

cutoff = 100
order = 6
conditioned_signal = butter_highpass_filter(signal, cutoff, fs, order)

J'applique ce filtre sur un signal de tension de 100 kHz et cela fonctionne très bien pour des fréquences de coupure> = 60 Hz. Mais cela ne fonctionne pas ci-dessous. Je voudrais couper toutes les fréquences inférieures à 10 Hz. Des indices où est mon erreur? Ce que j'ai observé est que plus l'ordre du filtre est bas, plus la fréquence de coupure peut être basse.

L'échantillon de signal peut être trouvé ici.

7
ChrisG

J'espère que cela pourra vous aider:

import numpy as np
import pandas as pd
from scipy import signal
import matplotlib.pyplot as plt
def sine_generator(fs, sinefreq, duration):
    T = duration
    nsamples = fs * T
    w = 2. * np.pi * sinefreq
    t_sine = np.linspace(0, T, nsamples, endpoint=False)
    y_sine = np.sin(w * t_sine)
    result = pd.DataFrame({ 
        'data' : y_sine} ,index=t_sine)
    return result

def butter_highpass(cutoff, fs, order=5):
    nyq = 0.5 * fs
    normal_cutoff = cutoff / nyq
    b, a = signal.butter(order, normal_cutoff, btype='high', analog=False)
    return b, a

def butter_highpass_filter(data, cutoff, fs, order=5):
    b, a = butter_highpass(cutoff, fs, order=order)
    y = signal.filtfilt(b, a, data)
    return y

fps = 30
sine_fq = 10 #Hz
duration = 10 #seconds
sine_5Hz = sine_generator(fps,sine_fq,duration)
sine_fq = 1 #Hz
duration = 10 #seconds
sine_1Hz = sine_generator(fps,sine_fq,duration)

sine = sine_5Hz + sine_1Hz

filtered_sine = butter_highpass_filter(sine.data,10,fps)

plt.figure(figsize=(20,10))
plt.subplot(211)
plt.plot(range(len(sine)),sine)
plt.title('generated signal')
plt.subplot(212)
plt.plot(range(len(filtered_sine)),filtered_sine)
plt.title('filtered signal')
plt.show()
14
Konstantin Purtov

Comme ma réputation est faible, je ne peux pas commenter votre question - "Quelle est la relation entre la coupure et l'ordre des filtres?" Ce n'est pas une réponse à votre question d'origine.

Pour un filtre FIR, pour une fréquence de coupure donnée, la pente du tracé de réponse impulsionnelle (| H (f) | vs f) est plus forte pour un filtre d'ordre supérieur. Ainsi, pour obtenir une atténuation plus élevée pour la plage de fréquence indésirable, vous augmentez l'ordre du filtre. Mais que se passe-t-il lorsque l'ordre du filtre est si élevé que la réponse impulsionnelle est une fonction boîte idéale? Vous verrez un effet d'interférence inter-symboles (ISI dans les communications numériques). L'intensité de cet effet augmente lorsque le rapport de la fréquence de coupure à la fréquence d'échantillonnage diminue (pensez à la relation entre la largeur de la fonction boîte dans le domaine fréquentiel et la largeur du lobe principal de la fonction sinc).

J'ai d'abord observé cela lorsque j'ai essayé d'implémenter un filtre IIR passe-bas à bande très étroite sur un microcontrôleur TI DSP. La bibliothèque TI a implémenté le filtre en tant que structure bi-quad en cascade pour gérer les effets de troncature bien connus. Cela n'a toujours pas résolu le problème car le problème n'est pas dû à la seule troncature. La façon dont j'ai résolu ce problème était d'utiliser un filtre anti-aliasing suivi d'un sous-échantillonnage du signal d'entrée, suivi du filtre IIR passe-bas souhaité.

Je comprends que vous implémentez un HPF, qui est un LPF traduit dans le domaine fréquentiel. J'espère que cela répond à certaines de vos questions. Faites-moi savoir si le sous-échantillonnage vous convient.

4
Sriharsha Madala

J'ajoute une fonction pour vérifier ci-dessus le code de Konstantin Purtov , afin que vous puissiez voir la relation entre l'ordre et la fréquence de coupure. Le code provient principalement de Warren Weckesser .

import scipy
import sys  
from scipy import signal
from scipy import pi
from scipy.io.wavfile import write
import matplotlib.pyplot as plt
import numpy as np    
from scipy.signal import butter, lfilter, freqz   


# ----- ----- ----- -----    
def butter_highpass(cutoff, fs, order=5):
    nyq = 0.5 * fs
    normal_cutoff = cutoff / nyq
    b, a = signal.butter(order, normal_cutoff, btype='high', analog=False)
    return b, a

def butter_highpass_filter(data, cutoff, fs, order=5):
    b, a = butter_highpass(cutoff, fs, order=order)
    y = signal.filtfilt(b, a, data)
    return y


# ----- -----    
# (1)
def foo(sel):
    if (sel == 1):
        # Filter requirements.
        order = 6
        fs = 300.0  # sample rate, Hz
        cutoff = 10  # desired cutoff frequency of the filter, Hz

        # Get the filter coefficients so we can check its frequency response.
        b, a = butter_highpass(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("High Filter Frequency Response")
        plt.xlabel('Frequency [Hz]')
        plt.grid()

        # Demonstrate the use of the filter.
        # First make some data to be filtered.
        T = 0.5  # seconds
        n = int(T * fs)  # total number of samples
        t = np.linspace(0, T, n, endpoint=False)
        # "Noisy" data.  We want to recover the 20 Hz signal from this.
        data = np.sin(1.2 * 2 * np.pi * t) + 1.5 * np.cos(5 * 2 * np.pi * t) + 0.5 * np.sin(20.0 * 2 * np.pi * t)

        # Filter the data, and plot both the original and filtered signals.
        y = butter_highpass_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()
    else:
        print ('Please, choose among choices, thanks.')


# ----- -----
def main():
    sel = int (sys.argv[1])
    foo(sel)


# ----- ----- ----- ----- ----- -----
if __name__ == '__main__':
    main()
0
Cloud Cho