1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Scipyで多段のフィルタをかけ合わせる

Last updated at Posted at 2022-03-04

背景

ScipyではMATLAB-likeにフィルタを設計するコマンド群が存在します。
計算結果は分母と分子の係数として出てくるのですが、これらを多段に重ねた結果を取得したい場合の対処法をメモします。

実装

numpyのpoly1dを使った多項式計算で簡単にフィルタの掛け合わせが実現できます。
公式の関数がぱっと見当たらなかったので作りましたが、無い訳は無い気がしているので見つけたら追記します。

なお、この方式だと極ゼロ相殺の判定ができないので自分で設計した覚えのないフィルタにこれを使用するのは推奨しません。

import scipy
import numpy as np

def series_filter(b_s,a_s):
    a = np.poly1d([1])
    b = np.poly1d([1])
    
    for ai, bi in zip(a_s,b_s):
        a *=  np.poly1d(ai)
        a *=  np.poly1d(bi)
    return b.coeffs, a.coeffs

使用例

例えばLowpassとノッチを組み合わせるなどすると下記のような離散フィルタを設計できます。

image.png

MATLABと同じfreqzというコマンドで上記の可視化ができるのでお試しあれ。

import matplotlib.pyplot as plt

b1,a1 = scipy.signal.butter(2,10, btype='low',analog=False,fs=1000)
b2,a2 = scipy.signal.butter(2,[20,25], btype='bandstop',analog=False,fs=1000)

b,a = series_filter([b1,b2],[a1,a2])

## 可視化
w, h = signal.freqz(b,a,fs=1000)
fig = plt.figure()
ax1=fig.add_subplot(2,1,1)
ax1.set_title('Digital filter frequency response')
ax1.plot(w, 20 * np.log10(abs(h)), 'b')
ax1.set_ylabel('Amplitude [dB]', color='b')
ax1.set_xlabel('Frequency [rad/sample]')
ax1.grid()
ax1.set_xscale('log')
ax1.set_xlim([0.1,100])
angles = np.unwrap(np.angle(h))/np.pi * 180.0
ax2=fig.add_subplot(2,1,2)
ax2.plot(w, angles, 'g')
ax2.set_ylabel('Angle (deg)', color='g')
ax2.grid()
ax2.axis('tight')
ax2.set_xscale('log')
ax2.set_xlim([0.1,100])
plt.show()
1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?