Як написати фільтр низьких частот для вибіркового сигналу в Python?


16

У мене є сигнал, який взяв вибірки кожні 1 нс (1е-9 сек) і мав, скажімо, 1е4 бали. Мені потрібно фільтрувати високі частоти з цього сигналу. Скажімо, мені потрібно фільтрувати частоти вище 10 МГц. Я хочу, щоб для частот, нижчих за частоту відсічення, сигнал передавались без змін. Це означає, що коефіцієнт посилення фільтра буде 1 на частотах, менших від частоти відсічення. Я хотів би мати можливість вказати порядок фільтру. Я маю на увазі, фільтр першого порядку має нахил 20 дБ / десятиліття (відключення електроенергії) після частоти відсічення, фільтр другого порядку має нахил 40 дБ / дек після частоти відсічення тощо. Висока продуктивність коду важлива.

Відповіді:


19

Частотна характеристика фільтра, розробленого за допомогою функції масла, є:

Відповідь фільтра Баттерворта

Але немає причин обмежувати фільтр постійною монотонною конструкцією фільтра. Якщо ви бажаєте більшого ослаблення в зоні зупинки і більш крутому перехідному діапазоні, існують інші варіанти. Для отримання додаткової інформації щодо визначення фільтра за допомогою iirdesing див. Це . Як показано на графіках частотного відгуку для вершкового масла, частота відсікання (-3 дБ точки) далека від мети. Це може бути зменшено шляхом відбору проб перед фільтруванням (конструкторські функції матимуть складний час з таким вузьким фільтром, 2% пропускної здатності). Давайте подивимось на фільтрацію вихідної швидкості вибірки із вказаним відсіченням.

import numpy as np
from scipy import signal
from matplotlib import pyplot as plt

from scipy.signal import fir_filter_design as ffd
from scipy.signal import filter_design as ifd

# setup some of the required parameters
Fs = 1e9           # sample-rate defined in the question, down-sampled

# remez (fir) design arguements
Fpass = 10e6       # passband edge
Fstop = 11.1e6     # stopband edge, transition band 100kHz
Wp = Fpass/(Fs)    # pass normalized frequency
Ws = Fstop/(Fs)    # stop normalized frequency

# iirdesign agruements
Wip = (Fpass)/(Fs/2)
Wis = (Fstop+1e6)/(Fs/2)
Rp = 1             # passband ripple
As = 42            # stopband attenuation

# Create a FIR filter, the remez function takes a list of 
# "bands" and the amplitude for each band.
taps = 4096
br = ffd.remez(taps, [0, Wp, Ws, .5], [1,0], maxiter=10000) 

# The iirdesign takes passband, stopband, passband ripple, 
# and stop attenuation.
bc, ac = ifd.iirdesign(Wip, Wis, Rp, As, ftype='ellip')  
bb, ab = ifd.iirdesign(Wip, Wis, Rp, As, ftype='cheby2') 

Оригінальні фільтри швидкості вибірки

Як згадувалося, оскільки ми намагаємось фільтрувати такий невеликий відсоток пропускної здатності, фільтр не матиме різкого відсічення. У цьому випадку фільтр низьких частот ми можемо зменшити пропускну здатність, щоб отримати фільтр, що виглядає краще. Функція повторної вибірки python / scipy.signal може бути використана для зменшення пропускної здатності.

Зверніть увагу, що функція повторної вибірки виконуватиме фільтрацію для запобігання збитку. Попередня фільтрація також може бути виконана (щоб зменшити згладжування), і в цьому випадку ми можемо просто перепропонувати на 100 і виконати , але питання про створення фільтрів. У цьому прикладі ми зменшимо вибірку на 25 та створимо новий фільтр

R = 25;            # how much to down sample by
Fsr = Fs/25.       # down-sampled sample rate
xs = signal.resample(x, len(x)/25.)

Якщо ми оновимо параметри проектування для фільтра FIR, новий відповідь є.

# Down sampled version, create new filter and plot spectrum
R = 25.             # how much to down sample by
Fsr = Fs/R          # down-sampled sample rate
Fstop = 11.1e6      # modified stopband
Wp = Fpass/(Fsr)    # pass normalized frequency
Ws = Fstop/(Fsr)    # stop normalized frequency
taps = 256
br = ffd.remez(taps, [0, Wp, Ws, .5], [1,0], maxiter=10000) 

Невизначений зразок фільтра

Фільтр, що працює на даних пробових даних, має кращу характеристику. Ще одна перевага використання фільтра FIR полягає в тому, що у вас буде лінійна фазова відповідь.


1
Дякую. Як ви створюєте графік спектру сигналу?
Олексій

Дякую за чудову відповідь! Цікаво, чи можна пояснити, як застосувати фільтр FIR на основі коефіцієнтів, обчислених за допомогою Remez? У мене виникають проблеми з розумінням того, що filtfiltпотрібно для aпараметра.
ali_m

Після того як ви коефіцієнти від конструкції фільтра, ( б для КИХ Ь і для ІДК) , ви можете використовували кілька різних функцій для виконання фільтрації: lfilter , скручувати , filtfilt . Зазвичай всі ці функції працюють аналогічно: y = filtfilt (b, a, x) Якщо у вас є фільтр FIR, просто встановіть a = 1 , x - вхідний сигнал, b - коефіцієнти FIR. Ця публікація також може допомогти.
Крістофер Фелтон

5

Це працює?

from __future__ import division
from scipy.signal import butter, lfilter

fs = 1E9 # 1 ns -> 1 GHz
cutoff = 10E6 # 10 MHz
B, A = butter(1, cutoff / (fs / 2), btype='low') # 1st order Butterworth low-pass
filtered_signal = lfilter(B, A, signal, axis=0)

Ти маєш рацію, хоча документація не дуже повна. Схоже butter, це обгортка iirfilter, яку краще документувати :

N: int Порядок фільтра. Wn: array_like Скалярна або довжина-2 послідовності, що дають критичні частоти.

Однак більшість цих матеріалів клоновані з matlab, тому ви також можете переглянути їх документацію :

нормалізована частота відсічення Wn повинна бути числом від 0 до 1, де 1 відповідає частоті Найкіста, π радіанів на зразок.

Оновлення:

Я додав документацію для цих функцій. :) Github робить це легко.


1

Не знаєте, що це за ваша заявка, але ви можете перевірити Gnuradio: http://gnuradio.org/doc/doxygen/classgr__firdes.html

Блоки обробки сигналів записуються на C ++ (хоча графіки потоків Gnuradio є в Python), але ви сказали, що важлива висока продуктивність.


1

Я маю хороші результати з цим фільтром FIR. Помічає, що він застосовує фільтр двічі, рухаючись "вперед" і "назад", щоб компенсувати зміщення сигналу ( filtfiltфункція не працювала, не знаю, чому):

def firfilt(interval, freq, sampling_rate):
    nfreq = freq/(0.5*sampling_rate)
    taps =  sampling_rate + 1
    a = 1
    b = scipy.signal.firwin(taps, cutoff=nfreq)
    firstpass = scipy.signal.lfilter(b, a, interval)
    secondpass = scipy.signal.lfilter(b, a, firstpass[::-1])[::-1]
    return secondpass

Великий ресурс для розробки і використання фільтра, звідки я взяв цей код, і звідки можна взяти смуговий і приклади фільтрів привіт-пас, є ЕТА .


Я не вірю, що вперед та назад фільтрування фільтра FIR є багато вигоди. IIR-фільтр може отримати вигоду від прямого / зворотного (filtfilt), оскільки ви можете отримати лінійну фазу з нелінійного фазового фільтра шляхом зворотного фільтрування.
Крістофер Фелтон

2
@ChristopherFelton Я просто повертаю назад, щоб синхронізувати RAW-електроміографічний сигнал із згладженою версією самого себе. Я знаю, що міг би просто перенести сигнал, але фільтрація двічі закінчується меншою проблемою. Варто зауважити, що другий прохід майже не змінює вже відфільтрований перший прохід ... Дякую за зауваження!
heltonbiker

Ага, так. Щоб зняти затримку (групова затримка), добре.
Крістофер Фелтон

1

Я не маю прав на коментарі ...

@endolith: Я використовую те саме, що і ви, за винятком використання scipy.signal.filtfilt (B, A, x), де x - вхідний вектор, який потрібно фільтрувати - наприклад, numpy.random.normal (size = (N)) . filtfilt робить прямий і зворотний прохід сигналу. Для повноти (більшість таких же, як @endolith):

import numpy as np
import scipy.signal as sps

input = np.random.normal(size=(N)) # Random signal as example
bz, az = sps.butter(FiltOrder, Bandwidth/(SamplingFreq/2)) # Gives you lowpass Butterworth as default
output = sps.filtfilt(bz, az, input) # Makes forward/reverse filtering (linear phase filter)

filtfilt, як це також запропонував @heltonbiker, вимагає масивів коефіцієнтів, я вважаю. Якщо вам потрібно виконати смугову фільтрацію на складному базовому діапазоні, потрібна більш задіяна конфігурація, але це, здається, тут не є проблемою.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.