dsPIC33FJ64GP802 (9) --- DSP 命令と DSP ライブラリ (7)

 IIRTransposed() での処理の様子と伝達関数の表現との対応を、2 次セクション 1 段の場合について下に示します。
 「標準型」の構成を「転置」、つまり信号の向きを反対に (出力を入力に、入力を出力に)、「分岐」を「加算」に、「加算」を「分岐」に置き換えて得られる構成です。 (最初はフィルタ係数の 0.5 倍スケーリングはない「基本型」を転置し、後からフィルタ係数のスケーリングにともなう変更を加えたものです)
 転置型では、まず伝達関数の分子側の計算を先に行い、伝達関数の分母側の計算を後に行います。


 「標準型」では、ふたつある遅延要素は、単に同じ内容の 1 サンプル・ディレイと 2 サンプル・ディレイに過ぎませんでしたが、「転置型」では、ふたつの遅延要素の内容自体が異なっています。
 フィルタ入力値のスケーリングは、分子側の係数 b0、b1、b2 を一斉にスケーリングすれば達成できるので、「標準型」の場合と違って、「initalGain」の機能はありません。
 「finalShift」の機能は存在していて、1/4 倍、1/2 倍、1 倍、2 倍、4 倍、… などの設定が可能です。
 2 次セクションを 2 段縦続接続した場合の図を下に示します。

 セクション間の信号のやり取りは、いったん、内部の 16 ビット・ワーキング・レジスタに書き戻されて受け渡されます。
 遅延要素の配列は独立に「2 本」必要であり、その先頭アドレスは、IIRTransposedStruct 構造体の「delayBase1」フィールドと「delayBase2」フィールドで指定しますが、配列領域として必要なサイズは 2 次セクション 1 段あたりそれぞれ 1 ワードとなります。 もちろん、2 本の配列領域は、互いに重ならない必要があります。
 モジュロ・アドレッシングは使っていないので、配列のアライメントは要素が 16 ビット・ワードである配列に対して「自然」な値の、2 バイト以上にする必要はありません。
 フィルタ係数の配列の先頭アドレスは、「coeffsBase」で指定しますが、これもモジュロ・アドレッシングではないので、アライメントは「2 バイト」で十分です。
 IIR フィルタ係数は 2 次セクション 1 段あたり 5 個で、1 段目から順に1.15 (Q15) フォーマットで、

b10/2、b11/2、a11/2、b12/2、a12/2、
b20/2、b21/2、a21/2、b22/2、a22/2、

のように並べます。  (あるいは 2 で割らない元の数を Q14 フォーマットで記述)
 FIR フィルタの場合と同様に、IIR フィルタでもフィルタ係数を X-データ・メモリ領域に置く場合と、PSV 機能を使ってプログラム領域に置く場合の 2 種の方法がとれます。
 IIRTransposedStruct 構造体の「coeffsPage」フィールドに「COEFFS_IN_DATA」を指定すれば X-データ・メモリに、PSV のページを指定すればプログラム領域に係数の配列を置くことになります。
 関数の実行サイクル数はフィルタ係数を X-データ・メモリに置く場合とプログラム領域に置く場合とで異なっていて、それぞれ次のようになっています。

  • X-データ領域にフィルタ係数を置く場合

35 + N * (11 + 11 * S)

  • プログラム領域にフィルタ係数を置く場合

38 + N * (12 + 16 * S)

 ここで、N は入出力サンプル数、S は 2 次セクションの段数です。
 「標準型」の場合、「S」に比例する項は (7 * S)、「転置型」の場合、(11 * S) ですから、「転置型」にメリットがないように思われますが、「転置型」では伝達関数の分子の計算から始めるので「スケーリング」がしやすいというメリットがあります。
 実際、PSoC5LP の「Filter」コンポーネントでも、分子側の計算から始める DSP プログラムおよび、それに適したスケーリングが施されたフィルタ係数が求められているようです。
 「Filter」コンポーネントで得られるフィルタ係数を、そのまま IIRTransposed() 関数で使って良好に動作し、信号がクリップするなどの不具合はありませんでした。
 「無償」で使える IIR フィルタ設計プログラムや web サービスで、IIRCanonic() での使用に適したスケーリングまでやってくれるものは見あたらないので、スケーリングは「自前」でやるしかないようです。