Adaptive line enhancer (ALE) using leaky LMS algorithm. Step size parameter can be controled using input voltage of AD converter.

Dependencies:   UITDSP_ADDA UIT_ACM1602NI UIT_AQM1602 mbed

main.cpp

Committer:
MikamiUitOpen
Date:
2015-07-25
Revision:
0:f81c448ea76b

File content as of revision 0:f81c448ea76b:

//--------------------------------------------------------------
// FIR フィルタによる適応線スペクトル強調器(ALE)
//      アルゴリズム: Leaky LMS
//
// VR でステップサイズ・パラメータを 10^-5 ~ 10^-2 の範囲で変更できます.
// ステップサイズ・パラメータが大きすぎると出力が発散する場合があります.
// そのような場合は,ステップサイズ・パラメータを小さくした後,リセットボタ
// ンを押してください.
//
//      A0: 雑音の混入した周期信号
//      A2: ステップサイズ・パラメータ(μ)を変更するための入力
//      出力: MCP4921 または MCP4922
// 2015/07/13, Copyright (c) 2015 MIKAMI, Naoki
//--------------------------------------------------------------

#include "ADC_Interrupt.hpp"    // for ADC using interrupt
#include "DAC_MCP4921.hpp"      // for DAC MCP4921, MCP4922

using namespace Mikami;
const int FS_ = 16000;      // Sampling frequency: 16 kHz
ADC_Intr myAdc_(A0, FS_, A1, A2);   // for AD
DAC_MCP4921 myDac_;         // for DA
DigitalIn sw_(D2, PullDown);

// ACM1602Ni を使う場合は次の define 文をコメントにすること
#define AQM1602

#ifdef AQM1602
#include "AQM1602.hpp"
Aqm1602 Lcd_;
#else
#include "ACM1602NI.hpp"
Acm1602Ni Lcd_;
#endif

const int ORDER_ = 100;      // Order of FIR filter
const int DELAY_ = 5;        // Number of delay to reduce correlation
const int N_ALL_ = ORDER_ + DELAY_ + 1;

float mu_;                  // Step size parameter (μ)
float err_mu_;              // error*μ;
uint16_t a2_ = 0;           // Inputted data from A2 pin
float xn_[N_ALL_], hm_[ORDER_+1];

// Interrupt service routine for ADC
void AdcIsr()
{   
    const float GAMMA = 0.996f;
    xn_[0] = myAdc_.Read();     // Read from A0

    myAdc_.Select3rdChannel();  // Select A2   
    myAdc_.SoftStart();         // ADC start for A2 input

    //-----------------------------------------
    // ALE の処理

    // FIR フィルタの実行
    float yn = 0;
    for (int k=0; k<=ORDER_; k++)
        yn = yn + hm_[k]*xn_[k+DELAY_];

    // 係数の更新
    err_mu_ = (xn_[0] - yn)*mu_;
    for (int k=0; k<=ORDER_; k++)
        hm_[k] = GAMMA*hm_[k] + err_mu_*xn_[k+DELAY_];
        
    // FIR フィルタの遅延器および相関除去用遅延器のデータの移動
    for (int k=N_ALL_-1; k>0; k--)
        xn_[k] = xn_[k-1];
    //-----------------------------------------
        if ((sw_ & 0x01) == 0)
            myDac_.Write(xn_[0]);    // 入力をそのまま出力
        else
            myDac_.Write(yn);        // ALE の結果を出力

    // μを変更するための値を読み込む
    a2_ = myAdc_.ReadWait_u16();

    myAdc_.Select1stChannel();      // Select A0
    myAdc_.ClearPending_EnableIRQ();// Clear pending interrupt
                                    // and enable ADC_IRQn
}

int main()
{
    myDac_.ScfClockTim3(500000);    // cutoff frequency: 5 kHz
    Lcd_.Clear();
    Lcd_.WriteStringXY("ALE", 0, 0);
    printf("\r\nAdaptive Line Enhancer\r\n");
       
    for (int n=0; n<N_ALL_; n++) xn_[n] = 0;
    for (int n=0; n<=ORDER_; n++) hm_[n] = 0;
    
    myAdc_.SetIntrVec(AdcIsr);  // Assign ISR for ADC interrupt

    while (true)
    {
        // VR から読み込んだ値でμを変更する
        float power = 3.0f*a2_/4095.0f - 5;
        mu_ = powf(10.0f, power);

        printf("mu = %8.2e, error*mu = %8.2e\r\n", mu_, err_mu_);

        char str[17];
        sprintf(str, "mu: %8.2e", mu_);
        Lcd_.WriteStringXY(str, 0, 1);

        wait(0.5f);
    }
}