Adaptive line enhancer using normalized leaky LMS algorithm. 学習同定法を用いる線スペクトル強調器.係数の更新は leaky LMS 法を使用.

Dependencies:   Array_Matrix F446_AD_DA UIT_AQM1602 mbed

main.cpp

Committer:
MikamiUitOpen
Date:
2017-02-21
Revision:
0:db50a6a3e574

File content as of revision 0:db50a6a3e574:

//---------------------------------------------------------------------------
// 学習同定法による線スペクトル強調器(ALE)
//      係数更新で Leaky LMS 法を使用
//      次数:100 次,遅延器数:5 個
//      作成者,著作権者: 三上直樹 2017/02/21
//---------------------------------------------------------------------------

#include "F446_ADC_Interrupt.hpp"   // AD, DA
#include "AQM1602.hpp"              // LCD 表示器
using namespace Mikami;

const int FS_ = 24000;      // 標本化周波数: 24 kHz

const int ORDER_ = 200;             // 次数
const int DELAY_ = 5;               // 相関除去用の遅延器数
const int N_ALL_ = ORDER_ + DELAY_; // 全体で必要な遅延器数

const float GM_ = 0.996;            // γ
const float S0_ = 0.1;              // 分母が 0 になるのを防止
float alpha_ = 0.2;                 // α

float x_[N_ALL_+1], h_[ORDER_+1];

AdcDual_Intr myAdc_(FS_);   // 参照:"F446_ADC_Interrupt.hpp"
DacDual myDac_;             // 参照:"F446_DAC.hpp"
DigitalOut ledG_(D10, 1);   // LED 緑色

// ADC 変換終了割り込みに対する割り込みサービス・ルーチン
void AdcIsr()
{
    static float mu, err_mu;
    static float ss = 0.0f;

    float xn1, xn2, yn1, yn2;
    myAdc_.Read(xn1, xn2);          // 入力(xn2 は使わない)

    // 左チャンネルの処理(FIR フィルタの計算)
    x_[0] = xn1;
    yn1 = 0.0;
    for(int k=0; k<=ORDER_; k++) yn1 = yn1 + x_[k+DELAY_]*h_[k];

    // ステップ・サイズ・パラメータの計算
    ss = GM_*ss + xn1*xn1;          // パワに比例する値の推定値
    mu = alpha_/(ss + S0_);         // ステップ・サイズ・パラメータの計算
    // 係数の更新
    err_mu = (xn1 - yn1)*mu;        // 誤差*μ
    for(int k=0; k<=ORDER_; k++)
        h_[k] = GM_*h_[k] + err_mu*x_[k+DELAY_];

    // 遅延器内のデータの移動
    for (int k=N_ALL_; k>0; k--) x_[k] = x_[k-1];

    // 右チャンネル出力は入力をそのまま出力する
    yn2 = xn1;

    myDac_.Write(yn1, yn2);         // 出力
}

int main()
{
    printf("\r\nALE using normalized LMS algorithm\r\n");
    AnalogIn a3In(A3);      // VR からの電圧読み取り用
    Aqm1602 lcd;            // LCD 表示器
    lcd.WriteStringXY("ALE", 0, 0);

    // 出力の LPF の遮断周波数を 10 kHz に設定
    myDac_.ScfClock(10000*100);

    // ALE のバッファのクリア
    for (int k=0; k<=N_ALL_; k++) x_[k] = 0.0f;
    for (int k=0; k<=ORDER_; k++) h_[k] = 0.0f;

    // ADC 変換終了割り込みに対する割り込みサービス・ルーチン割り当て
    myAdc_.SetIntrVec(&AdcIsr);

    float vrOld = -1;
    while(1)
    {
        float vrNow = a3In.read();
        if (fabsf(vrOld - vrNow) > 0.02f)
        {
            alpha_ = powf(10.0f, (vrNow-1)*2);
            vrOld = vrNow;

            printf("a0 = %5.3f\r\n", alpha_);
            lcd.ClearLine(1);
            lcd.WriteStringXY("alpha: ", 0, 1);
            lcd.WriteValue("%6.3f", alpha_);
        }
        wait(0.2f);
    }
}