Wizard Notes

Pythonを使った音楽信号分析の技術録、作曲活動に関する雑記

オーディオクロスオーバー向け補完フィルタ(バターワース)でのオールパスフィルタのフィルタ係数算出と検証

以前の記事で,低域・高域を別々に処理するようなマルチバンド処理(オーディオクロスオーバー)の実装方法を紹介しました.

www.wizard-notes.com

www.wizard-notes.com

上記の記事では,補完フィルタのローパス・ハイパスフィルタの並列接続したことで生成できるオールパスフィルタの伝達関数の振幅特性がフラットになることを確認しました。

実用では,フィルタリングの際にこのオールパスフィルタのフィルタ係数を求める必要があります.

2つのIIRフィルタの伝達関数の積を取るのは手間ですが,補完フィルタの場合は多少計算が楽になることが検証できたため,メモとして残します

バターワース型のローパス/ハイパスフィルタのフィルタ係数の対称性

以下の記事の伝達関数を見ると、カットオフ周波数が等しいバターワース型のローパス/ハイパスフィルタの分母項は同じになっています。

ufcpp.net

実際に確認したところ,次数が同じであればローパス/ハイパスの伝達関数の分母項は同じでした.

また,伝達関数の分子項のフィルタ係数は,半分の次数で対称となります.

結局のところ,カットオフ周波数と次数の等しいバターワース型のローパス/ハイパスフィルタの並列回路が成すオールパスのフィルタ係数は,

  • 分母項: ローパスもしくはハイパスフィルタの分母項
  • 分子項: ローパスとハイパスフィルタの分子項の和

として簡単に計算することができます.

実際に周波数応答を目視で確認してみると,分子項と分母項で振幅特性は0dBで対称となり,伝達関数全体としては振幅特性がフラット,すなわち,オールパスフィルタとなっていることが確認できました.

例として,カットオフ周波数 5k Hz, 次数5の時のバターワース型のローパス/ハイパスフィルタの並列回路が成すオールパスのフィルタの周波数応答が以下になります.

f:id:Kurene:20211003193203p:plain:w500

Linkwitz-Riley の場合でも,ベースはバターワースフィルタなので同じ計算手順でオールパスフィルタのフィルタ係数を算出できるはずです.

実際のフィルタ係数

3次のフィルタ係数

fc:     500.0
Low b:  [4.21357017e-05 1.26407105e-04 1.26407105e-04 4.21357017e-05]
High b: [ 0.93122625 -2.79367876  2.79367876 -0.93122625]
Low a:  [ 1.         -2.85755414  2.72507355 -0.86718233]
High a: [ 1.         -2.85755414  2.72507355 -0.86718233]
All b:  [ 0.93126839 -2.79355235  2.79380516 -0.93118412]

fc:     1000.0
Low b:  [0.00031507 0.00094522 0.00094522 0.00031507]
High b: [ 0.86710351 -2.60131054  2.60131054 -0.86710351]
Low a:  [ 1.         -2.71528536  2.46967434 -0.7518684 ]
High a: [ 1.         -2.71528536  2.46967434 -0.7518684 ]
All b:  [ 0.86741859 -2.60036532  2.60225576 -0.86678844]

fc:     2000.0
Low b:  [0.0022177 0.0066531 0.0066531 0.0022177]
High b: [ 0.75131371 -2.25394114  2.25394114 -0.75131371]
Low a:  [ 1.         -2.43191667  2.01412566 -0.56446738]
High a: [ 1.         -2.43191667  2.01412566 -0.56446738]
All b:  [ 0.75353142 -2.24728804  2.26059425 -0.74909601]

fc:     5000.0
Low b:  [0.02485108 0.07455325 0.07455325 0.02485108]
High b: [ 0.4825145 -1.4475435  1.4475435 -0.4825145]
Low a:  [ 1.         -1.598451    1.02946232 -0.23220267]
High a: [ 1.         -1.598451    1.02946232 -0.23220267]
All b:  [ 0.50736558 -1.37299025  1.52209674 -0.45766342]

fc:     10000.0
Low b:  [0.13246609 0.39739826 0.39739826 0.13246609]
High b: [ 0.20561501 -0.61684504  0.61684504 -0.20561501]
Low a:  [ 1.         -0.26786544  0.35232441 -0.02473027]
High a: [ 1.         -0.26786544  0.35232441 -0.02473027]
All b:  [ 0.3380811  -0.21944678  1.0142433  -0.07314893]

4次のフィルタ係数

fc:     500.0
Low b:  [1.46901845e-06 5.87607379e-06 8.81411069e-06 5.87607379e-06
 1.46901845e-06]
High b: [ 0.91110247 -3.64440987  5.46661481 -3.64440987  0.91110247]
Low a:  [ 1.         -3.81386538  5.45872379 -3.47494261  0.83010771]
High a: [ 1.         -3.81386538  5.45872379 -3.47494261  0.83010771]
All b:  [ 0.91110394 -3.644404    5.46662362 -3.644404    0.91110394]

fc:     1000.0
Low b:  [2.15209512e-05 8.60838049e-05 1.29125707e-04 8.60838049e-05
 2.15209512e-05]
High b: [ 0.82999258 -3.31997033  4.97995549 -3.31997033  0.82999258]
Low a:  [ 1.         -3.6278442   4.95122513 -3.01192428  0.68888769]
High a: [ 1.         -3.6278442   4.95122513 -3.01192428  0.68888769]
All b:  [ 0.8300141  -3.31988424  4.98008461 -3.31988424  0.8300141 ]

fc:     2000.0
Low b:  [0.00029137 0.00116546 0.00174819 0.00116546 0.00029137]
High b: [ 0.68811799 -2.75247196  4.12870794 -2.75247196  0.68811799]
Low a:  [ 1.         -3.25656931  4.03376839 -2.24604368  0.47350645]
High a: [ 1.         -3.25656931  4.03376839 -2.24604368  0.47350645]
All b:  [ 0.68840936 -2.7513065   4.13045613 -2.7513065   0.68840936]

fc:     5000.0
Low b:  [0.00737405 0.02949621 0.04424432 0.02949621 0.00737405]
High b: [ 0.38482178 -1.53928712  2.30893068 -1.53928712  0.38482178]
Low a:  [ 1.         -2.15448443  1.98942448 -0.86509739  0.14814218]
High a: [ 1.         -2.15448443  1.98942448 -0.86509739  0.14814218]
All b:  [ 0.39219583 -1.50979091  2.35317499 -1.50979091  0.39219583]

fc:     10000.0
Low b:  [0.06917529 0.27670118 0.41505176 0.27670118 0.06917529]
High b: [ 0.12432291 -0.49729164  0.74593746 -0.49729164  0.12432291]
Low a:  [ 1.         -0.36316417  0.52774422 -0.07801676  0.02024141]
High a: [ 1.         -0.36316417  0.52774422 -0.07801676  0.02024141]
All b:  [ 0.1934982  -0.22059047  1.16098922 -0.22059047  0.1934982 ]

5次のフィルタ係数

fc:     500.0
Low b:  [5.11979794e-08 2.55989897e-07 5.11979794e-07 5.11979794e-07
 2.55989897e-07 5.11979794e-08]
High b: [ 0.89110276 -4.45551379  8.91102758 -8.91102758  4.45551379 -0.89110276]
Low a:  [ 1.         -4.76948342  9.10427938 -8.69409576  4.15336557 -0.79406413]
High a: [ 1.         -4.76948342  9.10427938 -8.69409576  4.15336557 -0.79406413]
All b:  [ 0.89110281 -4.45551353  8.91102809 -8.91102707  4.45551405 -0.89110271]

fc:     1000.0
Low b:  [1.46896340e-06 7.34481698e-06 1.46896340e-05 1.46896340e-05
 7.34481698e-06 1.46896340e-06]
High b: [ 0.7939203  -3.96960152  7.93920303 -7.93920303  3.96960152 -0.7939203 ]
Low a:  [ 1.         -4.53905152  8.26066093 -7.53334038  3.44208742 -0.63030945]
High a: [ 1.         -4.53905152  8.26066093 -7.53334038  3.44208742 -0.63030945]
All b:  [ 0.79392177 -3.96959417  7.93921772 -7.93918834  3.96960886 -0.79391883]

fc:     2000.0
Low b:  [3.82287494e-05 1.91143747e-04 3.82287494e-04 3.82287494e-04
 1.91143747e-04 3.82287494e-05]
High b: [ 0.629391   -3.146955    6.29390999 -6.29390999  3.146955   -0.629391  ]
Low a:  [ 1.         -4.07876493  6.72527084 -5.59474637  2.34559681 -0.39613303]
High a: [ 1.         -4.07876493  6.72527084 -5.59474637  2.34559681 -0.39613303]
All b:  [ 0.62942923 -3.14676385  6.29429228 -6.29352771  3.14714614 -0.62935277]

fc:     5000.0
Low b:  [0.00218185 0.01090923 0.02181846 0.02181846 0.01090923 0.00218185]
High b: [ 0.3060313  -1.53015649  3.06031299 -3.06031299  1.53015649 -0.3060313 ]
Low a:  [ 1.         -2.70699599  3.2483224  -2.06094486  0.68308792 -0.0936504 ]
High a: [ 1.         -2.70699599  3.2483224  -2.06094486  0.68308792 -0.0936504 ]
All b:  [ 0.30821314 -1.51924726  3.08213145 -3.03849453  1.54106572 -0.30384945]

fc:     10000.0
Low b:  [0.03598336 0.17991679 0.35983357 0.35983357 0.17991679 0.03598336]
High b: [ 0.07487759 -0.37438796  0.74877593 -0.74877593  0.37438796 -0.07487759]
Low a:  [ 1.         -0.45769421  0.70673415 -0.1603017   0.06704105 -0.00431185]
High a: [ 1.         -0.45769421  0.70673415 -0.1603017   0.06704105 -0.00431185]
All b:  [ 0.11086095 -0.19447118  1.1086095  -0.38894235  0.55430475 -0.03889424]

検証用Pythonコード

スクリプト本体

import sys
import matplotlib.pyplot as plt
import numpy as np
import scipy.signal
from bode_plot import bode_plot 


def compute_butterworth_filters(fc, sr, order=3):
    b, a = {}, {}
    
    # フィルタ係数・伝達関数算出(バターワースフィルタ)
    b['low'], a['low'] = scipy.signal.butter(order, fc/(sr/2), btype='low')
    w, h_lp           = scipy.signal.freqz(b['low'], a['low'])
    
    b['high'], a['high'] = scipy.signal.butter(order, fc/(sr/2), btype='high')
    w, h_hp            = scipy.signal.freqz(b['high'], a['high'])

    # 低域/高域用ハーフフィルタの並列接続時の伝達関数オールパスフィルタ
    _, h_ap = scipy.signal.freqz(b['low']+b['high'], a['high'])
    
    _, h_ap_n = scipy.signal.freqz(b['low']+b['high'], 1.0)
    _, h_ap_d = scipy.signal.freqz(1.0, a['high'])


    return w, h_lp, h_hp, h_ap, b, a, h_ap_n, h_ap_d
        
        
sr = 44100
order = int(sys.argv[1])
#np.set_printoptions(precision=3)
for fc in [5e2, 1e3, 2e3, 5e3, 1e4]:
    w, _, _, h_ap, b, a, h_ap_n, h_ap_d =  compute_butterworth_filters(fc, sr, order=order)
    print(f"fc:\t{fc}")
    print(f"Low b:\t{b['low']}")
    print(f"High b:\t{b['high']}")
    print(f"Low a:\t{a['low']}")
    print(f"High a:\t{a['high']}")
    print(f"All b:\t{b['low'] + b['high']}")
    print("")
    bode_plot(
        w, 
        [h_ap, h_ap_n, h_ap_d],
        labels=["allpass", "allpass_num", "allpass_denom"],
        sr=sr,
        fc=fc, 
        ylim=[-40,40],
    )

周波数応答プロット

www.wizard-notes.com