簡體   English   中英

如何實現像scipy.signal.lfilter這樣的過濾器

[英]How to implement a filter like scipy.signal.lfilter

我在python中創建了一個原型,我正在轉換為iOS應用程序。 不幸的是,scipy和numpy的所有優點都沒有在objective-C中提供。 所以,顯然我需要從頭開始在目標C中實現一個過濾器。 作為第一步,我試圖在python中從頭開始實現IIR。 如果我能理解如何在python中完成它,我將能夠用C編寫代碼。

作為旁注,我很感激有關在iOS中進行過濾的資源的任何建議。 作為習慣於習慣使用matlab和python的C的新手,我很震驚,像Audio Toolboxes和Accelerate Frameworks以及Amazing Audio Engines這樣的東西沒有scipy.signal.filtfilt,也不像scipy那樣過濾設計函數。信號。等等

因此,在下面的代碼中,我以五種方式實現了過濾器。 1)scipy.signal.lfilter(用於比較),2)使用由Matlab的黃油函數計算的A,B,C,D矩陣的狀態空間形式。 3)使用由scipy.signal.tf2ss計算的A,B,C,D矩陣的狀態空間形式。 4)直接表格I,5)直接表格II。

如您所見,使用Matlab矩陣的狀態空間形式足以讓我在我的應用程序中使用它。 但是,我仍然在尋求理解為什么其他人不能這么好地工作。

import numpy as np
from scipy.signal  import butter, lfilter, tf2ss

# building the test signal, a sum of two sines;
N = 32 
x = np.sin(np.arange(N)/6. * 2 * np.pi)+\
    np.sin(np.arange(N)/32. * 2 * np.pi)
x = np.append([0 for i in range(6)], x)

# getting filter coefficients from scipy 
b,a = butter(N=6, Wn=0.5)

# getting matrices for the state-space form of the filter from scipy.
A_spy, B_spy, C_spy, D_spy = tf2ss(b,a)

# matrices for the state-space form as generated by matlab (different to scipy's)
A_mlb = np.array([[-0.4913, -0.5087, 0, 0, 0, 0],
        [0.5087, 0.4913, 0, 0, 0, 0],
        [0.1490, 0.4368, -0.4142, -0.5858, 0, 0],
        [0.1490, 0.4368, 0.5858, 0.4142, 0, 0],
        [0.0592, 0.1735, 0.2327, 0.5617, -0.2056, -0.7944],
        [0.0592, 0.1735, 0.2327, 0.5617, 0.7944, 0.2056]])

B_mlb = np.array([0.7194, 0.7194, 0.2107, 0.2107, 0.0837, 0.0837])

C_mlb = np.array([0.0209, 0.0613, 0.0823, 0.1986, 0.2809, 0.4262])

D_mlb = 0.0296

# getting results of scipy lfilter to test my implementation against
y_lfilter = lfilter(b, a, x)

# initializing y_df1, the result of the Direct Form I method.
y_df1 = np.zeros(6) 

# initializing y_df2, the result of the Direct Form II method.
# g is an array also used in the calculation of Direct Form II
y_df2 = np.array([])
g = np.zeros(6)

# initializing z and y for the state space version with scipy matrices.
z_ss_spy = np.zeros(6)
y_ss_spy = np.array([])

# initializing z and y for the state space version with matlab matrices.
z_ss_mlb = np.zeros(6)
y_ss_mlb = np.array([])


# applying the IIR filter, in it's different implementations
for n in range(N):
    # The Direct Form I
    y_df1 = np.append(y_df1, y_df1[-6:].dot(a[:0:-1]) + x[n:n+7].dot(b[::-1]))

    # The Direct Form II
    g = np.append(g, x[n] + g[-6:].dot(a[:0:-1]))
    y_df2 = np.append(y_df2, g[-7:].dot(b[::-1]))

    # State space with scipy's matrices
    y_ss_spy = np.append(y_ss_spy, C_spy.dot(z_ss_spy) + D_spy * x[n+6])
    z_ss_spy = A_spy.dot(z_ss_spy) + B_spy * x[n+6]

    # State space with matlab's matrices
    y_ss_mlb = np.append(y_ss_mlb, C_mlb.dot(z_ss_mlb) + D_mlb * x[n+6])
    z_ss_mlb = A_mlb.dot(z_ss_mlb) + B_mlb * x[n+6]


# getting rid of the zero padding in the results
y_lfilter = y_lfilter[6:]
y_df1 = y_df1[6:]
y_df2 = y_df2[6:]


# printing the results 
print "{}\t{}\t{}\t{}\t{}".format('lfilter','matlab ss', 'scipy ss', 'Direct Form I', 'Direct Form II')
for n in range(N-6):
    print "{}\t{}\t{}\t{}\t{}".format(y_lfilter[n], y_ss_mlb[n], y_ss_spy[n], y_df1[n], y_df2[n])

並輸出:

lfilter         matlab ss       scipy ss        Direct Form I   Direct Form II
0.0             0.0             0.0             0.0             0.0
0.0313965294015 0.0314090254837 0.0313965294015 0.0313965294015 0.0313965294015
0.225326252712  0.22531468279   0.0313965294015 0.225326252712  0.225326252712
0.684651781013  0.684650012268  0.0313965294015 0.733485689277  0.733485689277
1.10082931381   1.10080090424   0.0313965294015 1.45129994748   1.45129994748
0.891192957678  0.891058879496  0.0313965294015 2.00124367289   2.00124367289
0.140178897557  0.139981099035  0.0313965294015 2.17642377522   2.17642377522
-0.162384434762 -0.162488434882 0.225326252712  2.24911228252   2.24911228252
0.60258601688   0.602631573263  0.225326252712  2.69643931422   2.69643931422
1.72287292534   1.72291129518   0.225326252712  3.67851039998   3.67851039998
2.00953056605   2.00937857026   0.225326252712  4.8441925268    4.8441925268
1.20855478679   1.20823164284   0.225326252712  5.65255635018   5.65255635018
0.172378732435  0.172080718929  0.225326252712  5.88329450124   5.88329450124
-0.128647387408 -0.128763927074 0.684651781013  5.8276996139    5.8276996139
0.47311062085   0.473146568232  0.684651781013  5.97105082682   5.97105082682
1.25980235112   1.25982698592   0.684651781013  6.48492462347   6.48492462347
1.32273336715   1.32261397627   0.684651781013  7.03788646586   7.03788646586
0.428664985784  0.428426965442  0.684651781013  7.11454966484   7.11454966484
-0.724128943343 -0.724322419906 0.684651781013  6.52441390718   6.52441390718
-1.16886662032  -1.16886884238  1.10082931381   5.59188293911   5.59188293911
-0.639469994539 -0.639296371149 1.10082931381   4.83744942709   4.83744942709
0.153883055505  0.154067363252  1.10082931381   4.46863620556   4.46863620556
0.24752293493   0.247568224184  1.10082931381   4.18930262192   4.18930262192
-0.595875437915 -0.595952759718 1.10082931381   3.51735265599   3.51735265599
-1.64776590859  -1.64780228552  1.10082931381   2.29229811755   2.29229811755
-1.94352867959  -1.94338167159  0.891192957678  0.86412577159   0.86412577159

看看FIR wiki ,這個公式:

http://upload.wikimedia.org/math/0/7/b/07bf4449cbc8a0d4735633a8f9001584.png

所以首先你自己生成一個漢明窗口(我仍然使用python,但你可以將它轉換為c / cpp):

def getHammingWin(n):
    ham=[0.54-0.46*np.cos(2*np.pi*i/(n-1)) for i in range(n)]
    ham=np.asanyarray(ham)
    ham/=ham.sum()
    return ham

然后你自己的低通濾波器:

def myLpf(data, hamming):

    N=len(hamming)
    res=[]
    for n, v in enumerate(data):
        y=0
        for i in range(N):
            if n<i:
                break
            y+=hamming[i]*data[n-i]
        res.append(y)
    return np.asanyarray(res)
    pass

所以,我終於找到了我正在尋找的加速框架的一部分。

我首先實現了過濾器以進行下采樣; 您需要在下采樣之前進行過濾以避免混疊。 Accelerate的vDSP_zrdesamp是我一直想要的功能。

此外,單獨進行過濾, ipodEQ音頻單元通常是正確的選擇:(子類型kAudioUnitSubType_AUiPodEQ

如果您確實需要通過臨時實現過濾器,那么狀態空間形式似乎是最好的。

仍然沒有答案:為什么我的直接形式I和II實現不能按預期工作?

為什么我的直接形式I和II實現不能按預期工作?

也許您在直接表格I直接表格II中出現的錯誤是由於數值精度問題。 下面的代碼在Direct Transpose Form II中實現了一個過濾器,它在數值上更穩定(我在某些地方讀到這個我記不住了):

d = [0]*4
filtered = [0]

for x in df['dado_sem_spike'].values:

    y    = ((b[0] * x)              + d[3]) / a[0]
    d[3] =  (b[1] * x) - (a[1] * y) + d[2]
    d[2] =  (b[2] * x) - (a[2] * y) + d[1]
    d[1] =  (b[3] * x) - (a[3] * y) + d[0]
    d[0] =  (b[4] * x) - (a[4] * y)
    filtered.append(y)

我實施了這個表格,因為直接表格I沒有給出好的結果。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM