インターポレーター

VisualDSP++のライブラリ関数を利用してインターポレーター・クラスを作りました。抽象フィルタークラスで作ったCFilter型のサブクラスです。VisualDSP++のポリフェーズフィルタ・ライブラリ関数は嫌な癖があるのでラッパ・クラスの役割としてこれを遮蔽しました。

プロトタイプ

プライベートなメソッドとしてreroder()を追加しています。これはコンストラクタに与えたcoeffを変更するものです。coeffはインターポレーターのインパルス応答を格納しています。直感的にはここには通常のFIRフィルタのインパルス応答を収めればよいように思えます。しかし、VisualDSP++のインターポレーター関数は、特殊な並びを要求するため、あらかじめユーザーが並べなおさなければなりません。その並べなおしを行うのがreorder()です。

coeffの並べなおしには嫌な点がいくつかあります。

これらをすべて同時に解決することは出来ません。したがって、完全に何もかも遮蔽することはあきらめて、ある程度プログラマに任せることにしました。具体的にはコンストラクタの最後の引数doReorderによって並べ替えの指示が出来るようにしています。doReorderが1ならば並べ替えます。0がデフォルトで、並べ替えはしません。

また、VisualDSP++のインターポレーターは、coeffの長さではなく、フェーズあたりの係数長を要求します。そこで、コンストラクタに与えたtaps引数を内部で割って使っています。この結果tapsはratioの整数倍でなければならないという縛りがあります。

class CInterpolator:public CFilter{
private:
        // coeffを並べなおすプライベート関数
    virtual void reorder( void );
public:
        // coeff : インパルス応答。
        // taps : 総タップ数。ratioの整数倍
        // ratio : オーバーサンプル比(ポリフェーズステージ数)
        // doReorder : 1のとき、coeffの順序を内部データ型にあわせて並べなおす。
        //             0のとき、coeff はfir_interp_fr16の係数に従うと仮定
    CInterpolator( const short coeff[], unsigned int taps, unsigned int ratio, bool doReorder = 0 );
    virtual void  run( short out[], const short in[], unsigned int count );
};

実装

実装は簡単です。runメソッドは単にVisualDSP++の関数を読んでいるだけです。reorder()メソッドは一時領域としてディレイラインを使用しています。

CInterpolator::CInterpolator( const short coeff[], unsigned int taps, unsigned int ratio, bool doReorder )
                        :CFilter::CFilter( coeff, taps/ratio, ratio )
{ 
    if ( doReorder ) 
       this->reorder(); 
}

void CInterpolator::reorder( void )
{
    short * temp, * coeff;
    int i, ratio, taps;
        
        // ディレイラインを一時領域として使用する
    temp = this->s->d;
    coeff = this->s->h;
    ratio = this->s->l;
    taps = this->s->k*ratio;
        // 一般形式のインパルス応答を、fir_decima_fr16用にならべなおす
    i = 0;
    for ( int np = 0; np < ratio; np++ )
        for ( int nc = 0; nc < taps; nc+= ratio )
            temp[ i++ ] = coeff[ np + nc ];
        // 作業領域から並べなおし結果をコピー
    memcpy( coeff, temp, sizeof(short)*taps );
        // 作業用に使ったディレイをきれいにする
    for ( int i=0; i<taps; i++ )
        temp[i] = 0;            
}

void CInterpolator::run( short out[], const short in[], unsigned int count )
{
    fir_interp_fr16(in, out, count, this->s);
}
Blackfin空挺団 | プログラム | EZ-KIT | コア&ペリフェラル | TOPPERS/JSP | こぼれ話 | DSP掲示板