Smile Engineering Blog

ジェイエスピーからTipsや技術特集、プロジェクト物語を発信します

FIRフィルタを固定小数点化してみる

「FIRのフレーム処理」 では、FIRフィルタのフレーム化(実装)を紹介しましたが、今回は組み込み向けの話しをしたいと思います。

信号処理の組み込みと言えば、まずはDSP*1を思いつきますが、 RISC CPUによるSIMD*2VLIW*3のように、並列処理により信号処理が高速に行われる時代になりました。

そしてDSPにも高速なFPU*4を持ったものや、SIMDやVILWが使われる時代で、ハイスペックなDSPが登場し再度注目を集めていると思います。

固定小数点DSP

f:id:jspnet:20191015234008p:plain:left ハイスペックなDSPならば開発は楽ですが、製品の価格競争を考えると、 組み込みの分野では固定小数点DSPという選択肢がまだ残っているのが現状だと思います。特に音の分野では低遅延が求められると、処理の順番(依存関係)を解消するのが難しく、並列処理をしたくてもアルゴリズム的に限界があります。また、音声のデータに関しても16bitのリニアPCMとして固定小数点で扱う場合が多いです。

組み込み向けのリファレンスコード(デジタル信号処理向けのリファレンスコード)

信号処理の組み込み分野では、デバイスに搭載されるプロセッサーのインストラクションアーキテクチャに適したソフトウェアが求められ、CPUのリソースとソフトウェアの品質のトレードオフになります。そして固定小数点DSPの場合、固定小数点化したリファレンスコードを作成し評価した後、リファレンスコードと同等な性能を維持するようにポーティングを進める方法が多く、特に固定小数点ではリファレンスに対しBitExactが一つの手法になっています。

basic_op (固定小数点DSP向けの命令関数)

basic_opと聞いてピンとくる方には説明は不要ですが、 固定小数点DSPへの組み込みを目的としたリファレンスコードでは、DSPの命令に対応した演算がC言語の関数の形で用意されている場合が多いです。代表的なものでは、ETSI*5という団体で用意されているbasic_opです。これは3GPPのWebサイトなどから入手可能です(3GPP)。

また、WindowsLinuxでbasic_opを利用して固定小数点のソースコードを書くことにより、PCで評価が可能になります。そして、一番ありがたいことは、DSPメーカがbasic_opをIntrinsic(組み込み関数)としてサポートしていることです(サポートしている場合が多いです)。例えば、定番だったTI社(Texas Instruments)の、C55xシリーズでは、CCS*6で「gsm.h」としてサポートされインクルードすることで、PCで開発したbasic_opのコードがそのままポーティングできます。

FIRフィルタの固定小数点化

今回は、basic_opを使用して、FIRフィルタを固定小数点化してみました。具体的には畳み込みの部分になります。 浮動小数点のソースコードはこちら( 「FIRのフレーム処理」)。

サンプルコード【C言語

#define FIR_TAP   15  //  目的に合わせて調整する (今回は15で試してみます)
#include "typedef.h"   // basic_op固定小数点用ヘッダファイル
#include "basic_op.h"  // basic_op固定小数点用ヘッダファイル

// FIRフィルタ固定小数点化(フレーム処理)
void fir_frame_int16(Word16* coef, Word16 *mem, int n, Word16 *in, Word16 *out)
{
    int flen;
    Word32 L_sum;
    Word16 *buff;
    Word16 *p_coef;
    Word16 *p_buff;

    // buff update
    memcpy(mem, &mem[n], sizeof(short)*(FIR_TAP - 1));
    memcpy(&mem[FIR_TAP - 1], in, sizeof(short)*n);

    // convolution
    buff = &mem[FIR_TAP - 1];
    while (n--) {
        L_sum = 0;
        p_coef = coef;
        p_buff = buff++;
        flen = FIR_TAP;
        while (flen--) {
            // sum += *p_coef++ * *p_buff--;
            L_sum = L_mac(L_sum, *p_coef++, *p_buff--);  // 固定小数点化(basic_op)
        }
        *out++ = round(L_sum);   // 固定小数点化(basic_op)
    }
}

フィルタ係数はこちら FIRフィルタを作って周波数特性を検証

*1:Digital Signal Processor

*2:Single Instruction Multiple Data

*3:Very Long Instruction Word

*4:浮動小数点ユニット

*5:EuropeanTelecommunications Standards Institute

*6:TI社が提供している統合開発環境Code Composer Studio