CQエレクトロニクス・セミナで使用する遮断周波数可変の LPF/HPF のプログラム

Dependencies:   mbed SerialTxRxIntr DSP_MultirateLinearphase

main.cpp

Committer:
MikamiUitOpen
Date:
2022-03-30
Revision:
2:3955cb401851
Parent:
1:2d08a91b6bf2

File content as of revision 2:3955cb401851:

//------------------------------------------------------------------
//  遮断周波数可変 IIR フィルタ(LPF, HPF)
//      DA 出力はアップサンプリング使用
//      フィルタの係数は PC で計算し,それをマイコン側に転送するタイプ
//
//      ● PC 側のプログラム: F446_VariableLHpfB
//      ● ボーレート:       最初:   9600 baud
//                      通信確立後: 115200 baud
//      ● 入力:  A1
//      ● 出力:  A2
//
//  2022/03/30, Copyright (c) 2022 MIKAMI, Naoki
//------------------------------------------------------------------

#include "MultirateLiPh.hpp"    // DA でアップサンプリング
#include "SerialRxTxIntr.hpp"
#include "IirVariable.hpp"
#include <cctype>           // isalpha(), isdigit() で使用
using namespace Mikami;

const float FS_ = 44.1f;    // 入力の標本化周波数: 44.1 kHz
MultirateLiPh myAdDa_(FS_); // 出力標本化周波数を4倍にするオブジェクト

// 縦続形 IIR フィルタによる可変フィルタのオブジェクト, 次数: 10 次
VariableIir filter_;

void Select(string str);    // 有効,無効,出力 On/Off に対応する処理の選択
void NumericCtrl(string str);   // フィルタ係数の更新

// LPF/HPF の信号処理
void AdcIsr()
{
    float xn = myAdDa_.Input();     // 入力
    float yn = filter_.Execute(xn); // IIR フィルタの実行
    myAdDa_.Output(yn);             // 出力
}

int main()
{   
    SerialRxTxIntr rx(150); // PC との通信用,バッファサイズ:150,9600 baud

    NVIC_SetPriority(ADC_IRQn, 0);  // AD変換終了割り込みの優先度が最高
    NVIC_SetPriority(USART2_IRQn, 1);   

    myAdDa_.Start(&AdcIsr);     // 標本化を開始する
    while (true)
    {
        if (rx.IsEol())         // PC からの指令に対応する処理
        {
            string str = rx.GetBuffer();
            if (str == "VrFcB")
            {
                rx.TxString("ACK\n");   // "ACK" を送り返す
                wait_ms(10);
                rx.Baud(115200);        // 以降は 115,200 baud
            }
            else
            {
                if (isalpha(str[0])) Select(str);
                else                 NumericCtrl(str);
            }
        }
    }
}

// 有効,無効,出力 On/Off に対応する処理の選択
void Select(string str)
{
    if (str == "ACTIVE")  filter_.Validate();   // フィルタ処理有効
    if (str == "THROUGH") filter_.Invalidate(); // フィルタ処理無効
    if (str == "ON")      filter_.SetOn();      // 出力を On
    if (str == "OFF")     filter_.SetOff();     // 出力を Off
}

// フィルタ係数の設定
void NumericCtrl(string str)
{
    static char typeOld = 'L';  // 最初は LPF
    char type;                  // LPF/HPF の区別
    
    const int N = 5;        // 次数の 1/2
    const int L0 = 13;      // 一つの係数当たりの文字数
    float a1, a2;
    Biquad::Coefs cfs[N];   // 転送された文字列から変換された係数

    float b1 = atof(str.substr(0, 2).c_str());
    type = (b1 > 0)? 'L' : 'H';

    for (int n=0; n<N; n++)
    {
        a1 = atof(str.substr(n*2*L0+2, L0).c_str());
        a2 = atof(str.substr((n*2+1)*L0+2, L0).c_str());
        cfs[n] = (Biquad::Coefs){a1, a2, b1, 1};
    }
    float g0 = atof(str.substr(N*2*L0+2, L0).c_str());
    filter_.SetCoefficients(2*N, cfs, g0);  // 係数設定

    // LPF と HPF が切り替わった場合フィルタの遅延器をクリア
    if (type != typeOld) filter_.Clear();
    typeOld = type;
}