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

Dependencies:   mbed SerialTxRxIntr DSP_MultirateLinearphase

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 //------------------------------------------------------------------
00002 //  遮断周波数可変 IIR フィルタ(LPF, HPF)
00003 //      DA 出力はアップサンプリング使用
00004 //      フィルタの係数は PC で計算し,それをマイコン側に転送するタイプ
00005 //
00006 //      ● PC 側のプログラム: F446_VariableLHpfB
00007 //      ● ボーレート:       最初:   9600 baud
00008 //                      通信確立後: 115200 baud
00009 //      ● 入力:  A1
00010 //      ● 出力:  A2
00011 //
00012 //  2022/03/30, Copyright (c) 2022 MIKAMI, Naoki
00013 //------------------------------------------------------------------
00014 
00015 #include "MultirateLiPh.hpp"    // DA でアップサンプリング
00016 #include "SerialRxTxIntr.hpp"
00017 #include "IirVariable.hpp"
00018 #include <cctype>           // isalpha(), isdigit() で使用
00019 using namespace Mikami;
00020 
00021 const float FS_ = 44.1f;    // 入力の標本化周波数: 44.1 kHz
00022 MultirateLiPh myAdDa_(FS_); // 出力標本化周波数を4倍にするオブジェクト
00023 
00024 // 縦続形 IIR フィルタによる可変フィルタのオブジェクト, 次数: 10 次
00025 VariableIir filter_;
00026 
00027 void Select(string str);    // 有効,無効,出力 On/Off に対応する処理の選択
00028 void NumericCtrl(string str);   // フィルタ係数の更新
00029 
00030 // LPF/HPF の信号処理
00031 void AdcIsr()
00032 {
00033     float xn = myAdDa_.Input();     // 入力
00034     float yn = filter_.Execute(xn); // IIR フィルタの実行
00035     myAdDa_.Output(yn);             // 出力
00036 }
00037 
00038 int main()
00039 {   
00040     SerialRxTxIntr rx(150); // PC との通信用,バッファサイズ:150,9600 baud
00041 
00042     NVIC_SetPriority(ADC_IRQn, 0);  // AD変換終了割り込みの優先度が最高
00043     NVIC_SetPriority(USART2_IRQn, 1);   
00044 
00045     myAdDa_.Start(&AdcIsr);     // 標本化を開始する
00046     while (true)
00047     {
00048         if (rx.IsEol())         // PC からの指令に対応する処理
00049         {
00050             string str = rx.GetBuffer();
00051             if (str == "VrFcB")
00052             {
00053                 rx.TxString("ACK\n");   // "ACK" を送り返す
00054                 wait_ms(10);
00055                 rx.Baud(115200);        // 以降は 115,200 baud
00056             }
00057             else
00058             {
00059                 if (isalpha(str[0])) Select(str);
00060                 else                 NumericCtrl(str);
00061             }
00062         }
00063     }
00064 }
00065 
00066 // 有効,無効,出力 On/Off に対応する処理の選択
00067 void Select(string str)
00068 {
00069     if (str == "ACTIVE")  filter_.Validate();   // フィルタ処理有効
00070     if (str == "THROUGH") filter_.Invalidate(); // フィルタ処理無効
00071     if (str == "ON")      filter_.SetOn();      // 出力を On
00072     if (str == "OFF")     filter_.SetOff();     // 出力を Off
00073 }
00074 
00075 // フィルタ係数の設定
00076 void NumericCtrl(string str)
00077 {
00078     static char typeOld = 'L';  // 最初は LPF
00079     char type;                  // LPF/HPF の区別
00080     
00081     const int N = 5;        // 次数の 1/2
00082     const int L0 = 13;      // 一つの係数当たりの文字数
00083     float a1, a2;
00084     Biquad::Coefs cfs[N];   // 転送された文字列から変換された係数
00085 
00086     float b1 = atof(str.substr(0, 2).c_str());
00087     type = (b1 > 0)? 'L' : 'H';
00088 
00089     for (int n=0; n<N; n++)
00090     {
00091         a1 = atof(str.substr(n*2*L0+2, L0).c_str());
00092         a2 = atof(str.substr((n*2+1)*L0+2, L0).c_str());
00093         cfs[n] = (Biquad::Coefs){a1, a2, b1, 1};
00094     }
00095     float g0 = atof(str.substr(N*2*L0+2, L0).c_str());
00096     filter_.SetCoefficients(2*N, cfs, g0);  // 係数設定
00097 
00098     // LPF と HPF が切り替わった場合フィルタの遅延器をクリア
00099     if (type != typeOld) filter_.Clear();
00100     typeOld = type;
00101 }