周波数ワーピングのないオーディオEQクックブック


7

有名なhttp://www.musicdsp.org/files/Audio-EQ-Cookbook.txtは、通常は問題なく動作する一連の[実際の]バイクアッドフィルター計算式を提供します。

ただし、フィルターの周波数がナイキスト周波数に近づくと、フィルターのQ(帯域幅)仕様が大幅に歪みます。

私は、このような強い帯域幅の歪みのないフィルター式を探しています。ピーキング/ベル、バンドパス、ローパス、ハイパス、ハイシェルフ、ノッチフィルターが必要です。これは、以前に歪みの少ないピーキング/ベル/バンドパスフィルター式を購入したのと同じように実行できることを知っていますが、まだ完全ではなく、他のフィルタータイプが必要です。

したがって、価格が適切であれば、私もソリューションの代金を支払う用意があります。

あるいは、Zドメインフィルターで動作する最適化アルゴリズムを紹介してくれたら、それもすばらしいでしょう。残念ながら、ほとんどの通常の最適化アルゴリズムはZ領域ではうまく機能しません-(おそらく周波数応答の計算に使用される周期関数が原因で)望ましい周波数応答に一致するようにパラメーターのセットを最適化できません。


1
離散フィルターのエイリアシングとワーピングアーティファクトを効果的に補正するには、非常に高い次数を使用する必要があります。FIRを使用すると、設計がはるかに簡単になりますが、他の方法もあります。意味のある回答を提供するために、計算上の制約(プラットフォームを含む)が正確に何であるか、および処理要件は何かについて知りたいと思います。なぜこの動作が必要で、オーバーサンプリングでは不十分なのでしょうか?
Jazzmaniac

2
さて、2次のIIRフィルターで取得できるものには制限があります。そこにあるナイキストのプットゲインが0dB以外のものにすることOrfanidisすることにより、別の論文では(つまり、双一次マップにそれを変換する方法ですので、クックブックが0dBでナイキストゲインを置きます)。44.1 kHzのサンプルレート、および2次のバイカッドの場合、Orfanidisの設計よりも優れているとは思いません。
robert bristow-johnson 2014

1
私が知っている最良の方法は、離散領域に直接マッピングするのではなく、ODEソルバーをアナログプロトタイプに適用することです。具体的には、陰解法ソルバーは周波数応答を維持するのに優れています。
Jazzmaniac 2014年

1
@Jazzmaniac:離散時間ドメインで直接設計するのではなく、なぜアナログプロトタイプを使用するのですか?
Matt L.

1
@aleksv:すべての仕様について具体的な設計問題を投稿し、私たちが何を考え出すかを見ることができます。
Matt L.

回答:


5

ここでは、パラメトリックEQの5自由度を簡単に確認する方法を示します。tc electronicのKnud Christensenが約10年前にAES大会この特許で思いついたのは私の意見です。

したがって、クックブック(およびその中のQと帯域幅の問題)を忘れて(s平面で)パラメトリックEQをバンドパスフィルターの合計( Q 値)ワイヤーと平行:

Hs=Gブースト11Qsω0sω02+1Qsω0+1+1

Gブースト=10dB20 ピーク(または谷の場合は谷)のゲイン dB<0)。DCとナイキストでのゲインは0 dBです。これは2次IIRであり、3つの独立したパラメーターがあります。あと2つです。次に、全体的なゲインパラメータを追加します。

Hs=G0Gブースト11Qsω0sω02+1Qsω0+1+1

それはひねる4つのノブです。追加するノブをもう1つ(フィルター次数を上げずに)、独立したパラメーターをさらに追加します。

Knudがここで行うことは、その「ワイヤー」(その末尾の「1「伝達関数内)同じ極、同じでなければならないプロトタイプのシェルビングフィルターQ そして ω0BPFと同じなので、分母は同じです。その棚の伝達関数は次のとおりです。

Hs=Rsω02+RQsω0+1sω02+1Qsω0+1

どこ R10tlt20そして dBで棚の利得差です。これが、DCでのゲインとは異なるようにナイキストでのゲインをオフセットするものです。バイリニア変換後、ナイキストは dB によってブーストされ、DCでのゲインは変更されません。ブーストパラメータと同様に、パラメータは正または負のいずれかになります。 はナイキストでの線形ゲインです。tlttltdBtltG0R

それをすべてまとめると、次のようになります。

Hs=G0Gブースト11Qsω0sω02+1Qsω0+1+Hs=G0Gブースト11Qsω0sω02+1Qsω0+1+Rsω02+RQsω0+1sω02+1Qsω0+1=G0Rsω02+Gブースト+R11Qsω0+1sω02+1Qsω0+1

これをどのように見ても、これには5自由度があり、5つのバイカッド係数はこれらの5つのパラメーターから完全に定義されます。線形変換または台形規則(事実上同じもの)を使用してからマップするか、フィルターの次数を変更しないその他の方法を使用するかどうかは関係ありませ。または帯域幅の定義を変更する必要があるかもしれません。やを補正する必要があるかもしれませんszQω0Q周波数ワーピング効果(blinear変換で得られるような)の場合ですが、2次IIRフィルターを取得するために多額の費用を支払った場合、直接型または転置直接型で実装するか、または台形積分による線形アナログのラティスまたは正規化されたラダーまたはハルチェンバリンの状態変数またはアンドリューシンプソンのモデリングでは、最終的に5つの係数が得られ、これらの5つの独立したパラメーターにマッピングできます。 それはすべて同じです。 ライセンスにお金を払ったかどうか。数学はあなたがライセンスを取得している人からの主張よりも強力です。

そこ時に真のピークや谷の周波数である場合だけFYI、私は解決されはゼロではありません。ピークまたは谷が傾斜によって動かされた周波数は次のとおりです。tlt

ωpeak = ω0 Q2(R1R)Gboost2R+2Q2(R1)+Gboost21R+2Q2(1R1)Gboost2R+2Q2(R1)+Q4(R1R)2(Gboost2R+2Q2(R1))2

あなたが見ることができるとき、次いで、、その結果。ピークゲインも少し調整する必要があるかもしれませんが、まだ調整する必要があります。最初の適切な推測は、または。tlt=0R=1ωピーク=ω0GブーストGブーストGブーストRGブーストGブーストR1


何を証明しようとしているのかよくわかりませんか?2次IIRフィルターは、定義により5自由度を持ちます。パラメータをバイカッド係数にマッピングすると、元の質問への回答にどのように役立ちますか?
aleksv 2014年

したがって、「もちろん、これは私が話している2次IIRフィルターであることが明らかになったため、「非常に高い次数を使用する」離散フィルターのエイリアシングとワーピングアーティファクトを効果的に補償するためにフィルター次数を増やすことはできません。カードでは、あなたが言ったことからわかるように、5つの係数を定義するために誰かにIPをライセンスするためにお金を払ったということです。そして私が言いたいのは、これは完全に解決された問題だということです。あなたがそれを支払ったかどうか。
robert bristow-johnson 2014

私が使用しているピーキングフィルター計算コードも5つのパラメーターを使用しています。DCでのゲイン、左端の周波数とゲイン、ピークの周波数とゲインです。安定した帯域幅を維持するには、エッジ周波数を指定することが重要だと思います。
aleksv 2014年

問題は解決したかもしれませんが、解決策はどこにありますか?支払われますか?
aleksv 2014年

では、オルファニディスの論文を見てみましょう。ただし、上記の数学記号を使用してください。ツイストするノブは5つしかないので、これはできる限りのことです。あなたは何を理解する必要がありますG0 そして A あります。 G0A DCゲインです(0 dBまたは G0A=1、 私は知らないよ)。 A G0 での利益は ω=、しかし、バイリニア変換を使用すると、それはナイキストでのゲインです。したがって、ナイキストでのゲインをどのようにするかを理解する必要があります。ソフォクレスは提案をしています。私がそれに同意するなら、分からない。
robert bristow-johnson 2014

2

@ジャズ、私たちが電気工学で学んだことの1つは、微分方程式の任意の順序を1次の微分方程式のセット(または「システム」)に分解できることです。台形積分の場合、同じ「タイムステップ」Δtすべての連続時間積分で一貫して使用さています。N次数の線形ODE、それをバストアップすることができます N一階微分方程式。次に、これらの1次差分方程式の1つだけを検討します。

ここでも、コンデンサのエミュレーションを検討してください。サンプリング期間をT=1fs と同じであるΔt"台形ルールで使用されます。

i(t)=Cdvdt

または

v(t)=1Cti(u) du

sドメインでは

V(s)=1s(1CI(s)

したがって、離散時間での台形積分は次のとおりです。

vT=1CTあなた dあなた=1CΣk=kTTkTあなた dあなた1CΣk=T2kTT+kT=v1T+1CT21T+T

または離散時間サンプル値として

v[n]=v[n1]+T2C(i[n]+i[n1])

Z変換の適用

V(z)=z1V(z) + T2C(I(z)+z1I(z))

解決する V

V(z)=T21+z11z1(1CI(z))

代替しているようです

1sT21+z11z1

または

s2Tz1z+1

これは、周波数ワーピング補償しないバイリニアが正確に行うことです。


これは通常「例による証明」と呼ばれ、ほとんど一般的ではありません。また、上記のコメントですでにささいなことであると私が言ったケースのみを扱います。繰り返しますが、私は単純な離散再帰を与えない高次の陰解法について話しています。また、回答が元の質問とは関係がないため、このディスカッションに適した場所ではありません。これをODE統合に関する新しい質問に移動した場合、私はそれに貢献したいと思います。
Jazzmaniac

1
いいえ、これは線形差分式では完全に一般的です。電気工学のクラスでずっと前に学んだことについての冒頭の声明を無視しています。(数値的方法と制御理論の両方で、N次数微分方程式は、次のように分解できます。 N一階微分方程式。そして、私は一貫性が必要です。その同じ統合のための台形公式を全体で使用される)。
ロバート・ブリストウ・ジョンソン

私は、高次のODEが一次のODEのシステムに変換されることを十分に認識しています。そして再び、それは私が話していることではありません。単純な単一の例のみを扱いながら、双一次マッピングがクラス全体に超越すると主張するだけなので、このステートメントは証明をこれ以上一般化しません。それでも、あなたの結果が間違っていると言っているのではなく、さまざまなソルバーについて話しています。高次ソルバーは高次DEのソルバーではありません
Jazzmaniac

申し訳ありませんが、Andrew。それは失敗です。台形積分を使用した線形アナログコンポーネントの連続時間動作のモデリングをステップ時間で維持し続けているかどうかは、本当にわかりませΔt サンプリング周期と同じ T=1fs、それは、周波数ワーピングを補償せずに双一次変換を使用するのとまったく 同じ です。同じことと証明が上にあります。
robert bristow-johnson 2014

申し訳ありませんが、ロバート、私はアンドリューではありません。上記の証明は次のようになります。2つのマップAとB、およびいくつかのxがあります。A(x)= cとB(x)= cの両方なので、A = Bです。それは明らかに間違っています。AとBが線形であっても、それはまだ間違っています。線形システムの1次の台形ソルバーが再帰的な離散システムを生成することは正しいですが、それで終わりです。高次の(適応型/暗黙の)インテグレーターに関する私の繰り返しの説明は無視してください。だから、私はあなたの側で失敗をとても見ています。
Jazzmaniac

2

最適化手法を使用して、デジタルフィルターの周波数応答をターゲットのアナログフィルターに近づけることができます。

次の実験では、機械学習でよく使用される最適化アルゴリズムであるAdamを使用して、6次のバンドパスフィルターを最適化します。通過帯域より上の周波数は、コスト関数から除外されます(ゼロの重みが割り当てられます)。最適化されたフィルターの応答は、ナイキストに非常に近い周波数のターゲットよりも高くなりますが、その差は信号ソース(ADCまたはサンプルレートコンバーター)のアンチエイリアスフィルターによって相殺される場合があります。 ここに画像の説明を入力してください ここに画像の説明を入力してください

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors as clr
from scipy import signal

import tensorflow as tf

# Number of sections
M = 3

# Sample rate
f_s = 24000

# Passband center frequency
f0 = 9000

# Number of frequencies to compute
N = 2048

section_colors = np.zeros([M, 3])
for k in range(M):
    section_colors[k] = clr.hsv_to_rgb([(k / (M - 1.0)) / 3.0, 0.5, 0.75])

# Get one of BP poles that maps to LP prototype pole.
def lp_to_bp(s, rbw, w0):
    return w0 * (s * rbw / 2 + 1j * np.sqrt(1.0 - np.power(s * rbw / 2, 2)))

# Frequency response

def freq_response(z, b, a):
    p = b[0]
    q = a[0]
    for k in range(1, len(b)):
        p += b[k] * np.power(z, -k)
    for k in range(1, len(a)):
        q += a[k] * np.power(z, -k)
    return p / q

# Absolute value in decibel

def abs_db(h):
    return 20 * np.log10(np.abs(h))

# Poles of analog low-pass prototype

none, S, none = signal.buttap(M)

# Band limits
c = np.power(2, 1 / 12.0)
f_l = f0 / c
f_u = f0 * c

# Analog frequencies in radians
w0 = 2 * np.pi * f0
w_l = 2 * np.pi * f_l
w_u = 2 * np.pi * f_u

# Relative bandwidth
rbw = (w_u - w_l) / w0

jw0 = 2j * np.pi * f0
z0 = np.exp(jw0 / f_s)

# 1. Analog filter parameters

bc, ac = signal.butter(M, [w_l, w_u], btype='bandpass', analog=True)
ww, H_a = signal.freqs(bc, ac, worN=N)
magnH_a = np.abs(H_a)
f = ww / (2 * np.pi)

omega_d = ww / f_s
z = np.exp(1j * ww / f_s)

# 2. Initial filter design

a = np.zeros([M, 3], dtype=np.double)
b = np.zeros([M, 3], dtype=np.double)
hd = np.zeros([M, N], dtype=np.complex)

# Pre-warp the frequencies

w_l_pw = 2 * f_s * np.tan(np.pi * f_l / f_s)
w_u_pw = 2 * f_s * np.tan(np.pi * f_u / f_s)
w_0_pw = np.sqrt(w_l_pw * w_u_pw)

rbw_pw = (w_u_pw - w_l_pw) / w_0_pw

poles_pw = lp_to_bp(S, rbw_pw, w_0_pw)

# Bilinear transform

T = 1.0 / f_s
poles_d = (1.0 + poles_pw * T / 2) / (1.0 - poles_pw * T / 2)

for k in range(M):
    p = poles_d[k]
    b[k], a[k] = signal.zpk2tf([-1, 1], [p, np.conj(p)], 1)

    g0 = freq_response(z0, b[k], a[k])
    g0 = np.abs(g0)
    b[k] /= g0
    none, hd[k] = signal.freqz(b[k], a[k], worN=omega_d)

plt.figure(2)
plt.title("Initial digital filter (bilinear)")

plt.axis([0, f_s / 2, -90, 10])

plt.plot(f, abs_db(H_a), label='Target response', color='gray', linewidth=0.5)

for k in range(M):
    label = "Section %d" % k
    plt.plot(f, abs_db(hd[k]), color=section_colors[k], alpha=0.5, label=label)

# Combined frequency response of initial digital filter

Hd = np.prod(hd, axis=0)
plt.plot(f, abs_db(Hd), 'k', label='Cascaded filter')
plt.legend(loc='upper left')

plt.figure(3)
plt.title("Initial filter - poles and zeros")
plt.axis([-3, 3, -2.25, 2.25])
unitcircle = plt.Circle((0, 0), 1, color='lightgray', fill=False)
ax = plt.gca()
ax.add_artist(unitcircle)

for k in range(M):
    zeros, poles, gain = signal.tf2zpk(b[k], a[k])
    plt.plot(np.real(poles), np.imag(poles), 'x', color=section_colors[k])
    plt.plot(np.real(zeros), np.imag(zeros), 'o', color='none', markeredgecolor=section_colors[k], alpha=0.5)

# Optimizing filter

tH_a = tf.constant(magnH_a, dtype=tf.float32)

# Assign weights

weight = np.zeros(N)
for i in range(N):
    # In the passband or below?
    if (f[i] <= f_u):
        weight[i] = 1.0

tWeight = tf.constant(weight, dtype=tf.float32)
tZ = tf.placeholder(tf.complex64, [1, N])

# Variables to be changed by optimizer
ta = tf.Variable(a)
tb = tf.Variable(b)
ai = a
bi = b

# TF requires matching types for multiplication;
# cast real coefficients to complex
cta = tf.cast(ta, tf.complex64)
ctb = tf.cast(tb, tf.complex64)

xb0 = tf.reshape(ctb[:, 0], [M, 1])
xb1 = tf.reshape(ctb[:, 1], [M, 1])
xb2 = tf.reshape(ctb[:, 2], [M, 1])

xa0 = tf.reshape(cta[:, 0], [M, 1])
xa1 = tf.reshape(cta[:, 1], [M, 1])
xa2 = tf.reshape(cta[:, 2], [M, 1])

# Numerator:   B = b₀z² + b₁z + b₂
tB = tf.matmul(xb0, tf.square(tZ)) + tf.matmul(xb1, tZ) + xb2

# Denominator: A = a₀z² + a₁z + a₂
tA = tf.matmul(xa0, tf.square(tZ)) + tf.matmul(xa1, tZ) + xa2

# Get combined frequency response
tH = tf.reduce_prod(tB / tA, axis=0)

iterations = 2000
learning_rate = 0.0005

# Cost function
cost = tf.reduce_mean(tWeight * tf.squared_difference(tf.abs(tH), tH_a))
optimizer = tf.train.AdamOptimizer(learning_rate).minimize(cost)

zz = np.reshape(z, [1, N])

with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())

    for epoch in range(iterations):
        loss, j = sess.run([optimizer, cost], feed_dict={tZ: zz})
        if (epoch % 100 == 0):
            print("  Cost: ", j)

    b, a = sess.run([tb, ta])

for k in range(M):
    none, hd[k] = signal.freqz(b[k], a[k], worN=omega_d)

plt.figure(4)
plt.title("Optimized digital filter")

plt.axis([0, f_s / 2, -90, 10])

# Draw the band limits
plt.axvline(f_l, color='black', linewidth=0.5, linestyle='--')
plt.axvline(f_u, color='black', linewidth=0.5, linestyle='--')

plt.plot(f, abs_db(H_a), label='Target response', color='gray', linewidth=0.5)

Hd = np.prod(hd, axis=0)
for k in range(M):
    label = "Section %d" % k
    plt.plot(f, abs_db(hd[k]), color=section_colors[k], alpha=0.5, label=label)

magnH_d = np.abs(Hd)
plt.plot(f, abs_db(Hd), 'k', label='Cascaded filter')
plt.legend(loc='upper left')

plt.figure(5)
plt.title("Optimized digital filter - Poles and Zeros")
plt.axis([-3, 3, -2.25, 2.25])
unitcircle = plt.Circle((0, 0), 1, color='lightgray', fill=False)
ax = plt.gca()
ax.add_artist(unitcircle)

for k in range(M):
    zeros, poles, gain = signal.tf2zpk(b[k], a[k])
    plt.plot(np.real(poles), np.imag(poles), 'x', color=section_colors[k])
    plt.plot(np.real(zeros), np.imag(zeros), 'o', color='none', markeredgecolor=section_colors[k], alpha=0.5)

plt.show()

「通過帯域以上の周波数はコスト関数から除かれる(ゼロウェイトが割り当てられている)」フィルターが一種のハイパスフィルターになる危険性はありませんか?通過帯域を超える周波数は、そのようなコスト関数によってペナルティが与えられることなく、大きなゲインを持つことができます。
Olli Niemitalo

OK、IIは、シンボル回帰法によって最終的な方程式が生成されると考えました。リアルタイムのデリバティブはありませんか?最適化は少し遅い
aleksv

1
@OlliNiemitalo:一部の周波数では、初期フィルターのように、通過帯域の後でゼロに落ちます。
igorinov

1
@aleksv:ここに記載されていない別の閉じた形のソリューションがあります- khabdha.org/wp-content/uploads/2008/03/...
igorinov

1
ではtensorflow-gpu1.12.0最適化は、むしろ発散、収束していません。tensorflow1.12.0は適切に機能しますが、オプティマイザ(Adam)とその学習率の選択のため、そしておそらくコスト関数の定式化のために、最適化は完全には収束しません。係数の最適化に対する最新のアプローチ、つまり自動微分を示しているので、この回答に対する報奨金を授与します。さらに安定した最適化と、リアルタイムで使用するために取得した係数の配置(パラメータースイープなど)を確認します。
Olli Niemitalo

1

10dBピーキングEQの設計を思いつきました。中心周波数が500 Hz〜16 kHz(Fs = 48 kHz)の20個のフィルターを選択しました。以下の一番上のプロットは、RBJのAudio-EQ-Cookbookによる設計です。これは優れていますが、中心周波数がナイキストに近づくと帯域幅の歪みにつながります。下のプロットは、フィルターがアナログプロトタイプフィルターと非常によく一致する新しい設計です。 ここに画像の説明を入力してください

そして、これがクックブック(帯域幅= 4オクターブ、最高 f0=23 kHz): ここに画像の説明を入力してください

次の図は、ローパスフィルターの設計(Q=2f0=16 kHz、 Fs=48kHz)。新しい設計はアナログプロトタイプに近似しているため、従来のローパスフィルターとしては機能しないことに注意してください(ナイキストにゼロはありません)。

ここに画像の説明を入力してください


マット、私は、たとえば、固定で BW、たとえば1オクターブで、さまざまなピーク周波数に対して、ナイキストに近くなります。クックブックは一次補償を行いますがBW 掛ける ω0Tω0T、それはまだ周波数応答があるという事実は変更できませんする必要があり、連続的で、連続導関数を持っているし、それはナイキストについて対称でなければなりませんが。OrfanidisのようにNyquistでゲインを上げても。それ自体が、この歪んだ周波数応答の原因です。
robert bristow-johnson 2014

1
共振周波数がナイキストをわずかに下回っている場合でも、サンプルレートが44.1 kHz のデジタルフィルターがアナログフィルターと一致すると予想しています。 これは20年ほど前に私が心配していたことであり、簡単に考えることができるすべては、双線形変換が行う帯域幅のシュランチを補償することです。次に、Orfanidisは1つの仮定(ナイキストでのゲインが0 dBである)を変更し、それがもう少し役立ちました。しかし、本当に役立つのは、単にサンプルレートを上げることです。
robert bristow-johnson 2014

試みてくれてありがとう。最初のクックブックプロットは私が欲しいものですが、ロバートも述べたように、ナイキストでのゲインはゼロではありません。応答を対数目盛で、たとえば20 Hzからナイキストの範囲で描くことも有益です。オーディオEQがリニア周波数スケールを使用することはほとんどありません。また、帯域幅は通常オクターブ単位で指定されます。バイクアッドはセンター/コーナー周波数が約300 Hzまで問題ありませんが、高くすると問題が明らかになります。
aleksv 2014年

いいえ、つまり、0〜300 Hz、より低い周波数です。ナイキストまでの300 Hzを超えると、これらのクックブックフィルター式は、フィルター形状の歪みを徐々に増加させます。もちろん、サンプルレートは通常どおり44100または48000です。
aleksv 2014年

グラフを対数スケールでプロットする必要があります。迷惑なのは、LOGスケールの帯域幅の歪みです。対数スケールで見た場合、低周波数に歪みはありません。ピーキング、ローパス、ハイシェルフ、ノッチフィルターは、DCで常に0 dB(ユニティ)ゲインを持ちます。
aleksv 2014年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.