ディレイライン (Tapped Delay-Line, タップ付き遅延線) は、 現在および過去の信号を蓄えておく記憶装置です。 FIRフィルタにおいて入力信号を蓄えておくなど、 信号処理では多用されます。 そのため、ほとんどのDSPは、 ディレイラインを効率よく実装できる仕掛けを持っています。
最も単純な実装方法は、 タップ数と同じサイズの配列を用意して、 次の時刻に移る際にデータをコピーするものです。 この方式では、Nタップのディレイに対して、 N回の書き込みとN-1回の読み出しが必要になります。 乗算が極端に遅いプロセッサではコピーしてもかまいませんが、 乗算を高速に実行できるプロセッサではコピーの演算量は無視できません。 多くのDSPのようにNタップの畳み込みをN+α命令で処理できるプロセッサでは、 コピーの方が演算量が多くなってしまいます。
リングバッファとは、配列の始点と終点を連結してしまったものです。 端からはみ出すと、反対側の端に入ります。 これを利用すると、コピー無しでディレイラインを実装できます。 下図にその例を示します。 配列の先頭は0と書かれた要素です。 青線のところで 配列の始点と終点を連結しています。 左側が時刻nにおけるディレイラインで、 要素1のx(n)が ディレイラインの先頭になります。 ディレイラインの先頭から順にデータを読み出す時は、 ポインタを1から順に進めていき、 終端であるN-1を超えると始点の0に戻ります。 時刻n+1には、始点を0にずらして、 ここにx(n+1)を書き込みます。
ほとんど全てのDSPが この方式をサポートするハードウェアや命令を持っています。 初期のDSP (例えばNECのμPD77230) は、
汎用プロセッサでリングバッファを処理する場合は、 例えば下記のようなプログラムになります。
int delay_top; double delay[TAPNUM]; double coef[TAPNUM]; double FIR() { int i, p; double sum; if (--delay_top < 0) delay_top += TAPNUM; delay[delay_top] = input(); sum = 0.0; p = delay_top; for (i = 0; i < TAPNUM; i++) { sum += coef[i] * delay[p]; p = ++p % TAPNUM; } return sum; }剰余演算子%を使いたくない場合には、
if (++p == TAPNUM) p = 0;としても良いでしょう。
主な計算は積和演算 (最近はスループット1命令で実行可能) しかないようなループの中に、 剰余や条件分岐のような時間のかかる計算は入れたくない、 ということで開発された汎用プロセッサ向きの実装方法です。 配列のサイズを2倍にすると、ループ内では剰余や条件分岐が不要になります。
この方法の原理を下図に示します。 Nタップのディレイラインに対して、サイズ2Nの配列を作ります。 後半N要素には、前半N要素と同じ値を格納します。 時刻nでは、配列の先頭から2番目がディレイラインの先頭になります。 時刻n+1では、配列の先頭がディレイラインの先頭になります。 時刻n+2では、先頭からはみ出してしまうので、 配列のN番目をディレイラインの先頭にします。