Python'da örneklenmiş sinyal için alçak geçiren filtre nasıl yazılır?


16

Her 1 ns (1e-9 sn) örneklenmiş bazı sinyaller var ve diyelim ki 1e4 puan var. Bu sinyalden yüksek frekansları filtrelemem gerekiyor. Diyelim ki 10 MHz'den daha yüksek frekansları filtrelemeliyim. Kesim frekansı sinyalinden düşük frekanslar için değişmeden geçilmesini istiyorum. Bu, kesme frekansından daha düşük frekanslar için filtrenin kazancının 1 olacağı anlamına gelir. Filtre sırasını belirleyebilmek istiyorum. Yani, birinci dereceden filtre kesme frekansı sonra 20 db / on eğim (güç kapalı), ikinci dereceli filtre kesme frekansı sonra 40 db / dec eğim var ve böylece. Yüksek kod performansı önemlidir.

Yanıtlar:


19

Tereyağı işlevi kullanılarak tasarlanan filtre için frekans yanıtı :

Butterworth Filtre Yanıtı

Ancak, filtreyi sabit bir monotonik filtre tasarımıyla sınırlamak için bir neden yoktur. Stop bandında ve daha dik geçiş bandında daha yüksek bir zayıflama istiyorsanız, başka seçenekler de vardır. Kullanarak bir filtre belirtmeye ilişkin daha fazla bilgi için iirdesing bkz bu . Tereyağı tasarımı için frekans tepki çizimlerinde gösterildiği gibi , kesme frekansı (-3dB noktası) hedeften uzaktır. Bu, filtrelemeden önce aşağı örnekleme ile hafifletilebilir (tasarım işlevleri, böyle dar bir filtreyle, bant genişliğinin% 2'si ile zor bir zaman geçirecektir). Orijinal numune hızını belirtilen kesim ile filtrelemeye bakalım.

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') 

Orijinal Numune Oranı Filtreleri

Belirtildiği gibi, bant genişliğinin bu kadar küçük bir yüzdesini filtrelemeye çalıştığımız için filtrenin keskin bir kesimi olmayacaktır. Bu durumda, düşük geçiş filtresi, daha iyi görünümlü bir filtre elde etmek için bant genişliğini azaltabiliriz. Bant genişliğini azaltmak için python / scipy.signal resample işlevi kullanılabilir.

Yeniden örnekleme işlevinin, örtüşme önlemek için filtreleme yapacağını unutmayın. Ön filtreleme de yapılabilir (takma adı azaltmak için) ve bu durumda 100 ile yeniden örnekleyebilir ve yapılabiliriz , ancak filtre oluşturmakla ilgili soru soruldu. Bu örnek için 25'e kadar örnek atarız ve yeni bir filtre oluştururuz

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

FIR filtresinin tasarım parametrelerini güncellersek yeni yanıt gelir.

# 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) 

Altörneklenmiş Filtre Yanıtı

Aşağı örneklenmiş veriler üzerinde çalışan filtrenin daha iyi bir yanıtı vardır. FIR filtresi kullanmanın bir diğer yararı da doğrusal faz tepkisine sahip olmanızdır.


1
Teşekkür ederim. Sinyal spektrum grafiği nasıl oluşturulur?
Alex

Mükemmel bir cevap için çok teşekkürler! Remez kullanarak hesaplanan katsayılara dayalı bir FIR filtresinin nasıl uygulanacağını açıklayabilir misiniz? Parametre filtfiltiçin ne istediğini anlamakta zorlanıyorum a.
ali_m

Eğer (bir filtre tasarımı, gelen katsayıları edindikten sonra b FIR için b ve a : IIR için) Eğer filtreleme gerçekleştirmek için birkaç farklı fonksiyonları kullanılabilir olabilir lfilter , convolve , filtfilt . Genellikle tüm bu işlevler benzer şekilde çalışır: y = filtfilt (b, a, x) Basitçe a = 1 olarak ayarlanmış bir FIR filtreniz varsa , x giriş sinyalidir, b FIR katsayılarıdır. Bu yazı da yardımcı olabilir.
Christopher Felton

5

Bu çalışıyor mu?

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)

Haklısın, ancak belgeler tam değil. Görünüşe butteriçin bir sarıcı iirfilter, daha iyi belgelenmiştir :

N: int Filtrenin sırası. Wn: array_like Kritik frekansları veren skaler veya uzunluk-2 dizisi.

Bununla birlikte, bu materyallerin çoğu matlab'dan klonlanmıştır, bu yüzden belgelerine de bakabilirsiniz :

normalleştirilmiş kesme frekansı Wn, 0 ile 1 arasında bir sayı olmalıdır, burada 1, Nyquist frekansına karşılık gelir, örnek başına π radyan.

Güncelleme:

Bu işlevler için belgeler ekledim . :) Github bunu kolaylaştırır.



1

Bu FIR filtresiyle iyi sonuçlar elde ediyorum. Filtre ofsetini telafi etmek için filtreyi iki kez uyguladığını, "ileri" ve "geri" gittiğini fark eder ( filtfiltişlev çalışmadı, nedenini bilmiyorum):

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

Filtre tasarımı ve kullanımı için mükemmel bir kaynak, I, bu kod aldı burada ve bant-geçiren ve yüksek geçirgen filtre örnekleri alınabilir nerede olduğu BU .


Bir FIR filtresini ileri ve geri filtrelemenin çok yararı olduğuna inanmıyorum. Bir IIR filtresi ileri / geri (filtreleme) avantajından yararlanabilir, çünkü ters filtreleme ile doğrusal olmayan faz filtresinden doğrusal faz elde edebilirsiniz.
Christopher Felton

2
@ChristopherFelton Bir RAW elektromiyografik sinyali kendi düzgünleştirilmiş haliyle senkronize etmek için tersine çeviriyorum. Sinyali değiştirebileceğimi biliyorum, ancak iki kez filtreleme daha az sorun yaratıyor. İkinci geçişin zaten filtrelenmiş ilk geçişi neredeyse değiştirmediğini fark etmekte fayda var ... Dikkat ettiğiniz için teşekkürler!
heltonbiker

Ahh, evet. Gecikmeyi (grup gecikmesi) kaldırmak için iyi bir nokta.
Christopher Felton

1

Yorum haklarım yok ...

@endolith: I kullanılması dışında sizin gibi kullanımı scipy.signal.filtfilt (B, A, X) X giriş vektörü filtre edilecek olan - örneğin numpy.random.normal (boyut = (N)) . filtfilt , sinyalin ileri ve geri geçişini sağlar. Tamlık uğruna (çoğu @endolith ile aynıdır):

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)

@heltonbiker tarafından da önerildiği gibi filtfilt, inandığım katsayı dizileri gerektiriyor. Karmaşık temel bantta bant geçiren filtreleme gerçekleştirmeniz gerekiyorsa, daha fazla yapılandırmaya ihtiyaç vardır, ancak bu burada bir sorun olarak görünmemektedir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.