CQエレクトロニクス・セミナで使用するグラフィック・イコライザ のプログラム
Dependencies: mbed SerialTxRxIntr DSP_MultirateLinearphase
Revision 0:b3c94b253ae5, committed 2022-02-25
- Comitter:
- MikamiUitOpen
- Date:
- Fri Feb 25 02:18:16 2022 +0000
- Child:
- 1:c30bdcb9ba69
- Commit message:
- 1
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DSP_MultirateLinearphase.lib Fri Feb 25 02:18:16 2022 +0000 @@ -0,0 +1,1 @@ +https://os.mbed.com/users/MikamiUitOpen/code/DSP_MultirateLinearphase/#f7bfe38c93ab
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/GraphicEqualizer/BiquadGrEq.hpp Fri Feb 25 02:18:16 2022 +0000 @@ -0,0 +1,50 @@ +//-------------------------------------------------------------- +// グラフィックイコライザで使う 1D タイプの 2 次のフィルタ +// このクラスでは,係数は実行中に書き換えられることを想定している +// +// v[n] = x[n] + a1*v[n-1] + a2*v[n-2] +// y[n] = b0*v[n] + b1*v[n-1] + b2*v[n-2] +// x[n] : 入力信号 +// y[n] : 出力信号 +// +// 2022/02/18, Copyright (c) 2022 MIKAMI, Naoki +//-------------------------------------------------------------- + +#include "mbed.h" + +#ifndef IIR_BIQUAD_GREQ_HPP +#define IIR_BIQUAD_GREQ_HPP + +// 2 次の IIR フィルタ +namespace Mikami +{ + class BiquadGrEq + { + public: + struct Coefs { float a1, a2, b0, b1, b2; }; + + BiquadGrEq(const Coefs ck = (Coefs){0, 0, 0, 0, 0}) + : c_(ck), vn1_(0), vn2_(0) {} + + void SetCoefficients(const Coefs ck) { c_ = ck; } + + float Execute(float xn) + { + float vn = xn + c_.a1*vn1_ + c_.a2*vn2_; + float yn = c_.b0*vn + c_.b1*vn1_ + c_.b2*vn2_; + + vn2_ = vn1_; + vn1_ = vn; + + return yn; + } + + private: + Coefs c_; + float vn1_, vn2_; + + // コピー・コンストラクタ禁止 + BiquadGrEq(const BiquadGrEq&); + }; +} +#endif // IIR_BIQUAD_GREQ_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/GraphicEqualizer/GraphicEqualizer.cpp Fri Feb 25 02:18:16 2022 +0000 @@ -0,0 +1,30 @@ +//-------------------------------------------------------------- +// グラフィックイコライザのクラス +// フィルらの係数を設定しない場合は,出力は出ない +// +// 2022/02/19, Copyright (c) 2022 MIKAMI, Naoki +//-------------------------------------------------------------- + +#include "GraphicEqualizer.hpp" + +namespace Mikami +{ + // コンストラクタ + GrEqualizer::GrEqualizer(int bands, float fs, float qVal) + : BANDS_(bands), Q_VAL_(qVal), + biquad_(bands), f0_(bands) + { + for (int n=0; n<BANDS_; n++) f0_[n] = 62.5f*powf(2, n); + SetOff(); + Validate(); + } + + // グラフィック・イコライザの実行 + float GrEqualizer::Filtering(float xn) + { + float yn = xn; + for (int n=0; n<BANDS_; n++) + yn = biquad_[n].Execute(yn); + return yn; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/GraphicEqualizer/GraphicEqualizer.hpp Fri Feb 25 02:18:16 2022 +0000 @@ -0,0 +1,57 @@ +//-------------------------------------------------------------- +// グラフィックイコライザのクラス(ヘッダ) +// フィルらの係数を設定しない場合は,出力は出ない +// +// 2022/02/19, Copyright (c) 2022 MIKAMI, Naoki +//-------------------------------------------------------------- + +#include "Array.hpp" +#include "BiquadGrEq.hpp" + +#ifndef GRAPHIC_EQALIZER_HPP +#define GRAPHIC_EQALIZER_HPP + +namespace Mikami +{ + class GrEqualizer + { + public: + // コンストラクタ + GrEqualizer(int bands, float fs, float qVal = 1.0f/sqrtf(2.0f)); + // グラフィック・イコライザの実行 + float Execute(float xn) { return (this->*fPtr_)((this->*fPtr2_)(xn)); } + + // 指定したチャンネルの係数を設定する + void SetCoefficients(int band, BiquadGrEq::Coefs coefs) + { biquad_[band].SetCoefficients(coefs); } + + // グラフィック・イコライザの処理を有効にする + void Validate() { fPtr_ = &GrEqualizer::Filtering; } + // グラフィック・イコライザの処理を無効にする + void Invalidate() { fPtr_ = &GrEqualizer::Through; } + // 出力を On にする + void SetOn() { fPtr2_ = &GrEqualizer::On; } + // 出力を Off にする + void SetOff() { fPtr2_ = &GrEqualizer::Off; } + + private: + const int BANDS_; // バンドの数 + const float Q_VAL_; // Q 値 + + Array<BiquadGrEq> biquad_; + Array<float> f0_; + + float (GrEqualizer::*fPtr_)(float); // イコライザ処理の有無 + float (GrEqualizer::*fPtr2_)(float); // 出力の On/Off + + float Through(float xn) { return xn; } // そのまま出力 + float Filtering(float xn); // フィルタを実行して出力 + float On(float xn) { return xn; } // 出力: On + float Off(float xn) { return 0; } // 出力: Off + + // コピー・コンストラクタ,代入演算子禁止禁止のため + GrEqualizer(const GrEqualizer&); + GrEqualizer& operator=(const GrEqualizer&); + }; +} +#endif // GRAPHIC_EQALIZER_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SerialTxRxIntr.lib Fri Feb 25 02:18:16 2022 +0000 @@ -0,0 +1,1 @@ +https://os.mbed.com/users/MikamiUitOpen/code/SerialTxRxIntr/#268977533f95
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.cpp Fri Feb 25 02:18:16 2022 +0000 @@ -0,0 +1,79 @@ +//---------------------------------------------------------------------- +// グラフィック・イコライザ,DA 出力はアップサンプリング使用 +// フィルタの係数の計算をマイコン側でも行うタイプ +// +// PC 側のプログラム: F446_GraphicEqualizerB +// +// 2022/02/19, Copyright (c) 2022 MIKAMI, Naoki +//---------------------------------------------------------------------- + +#include "MultirateLiPh.hpp" // DA でアップサンプリング +#include "SerialRxTxIntr.hpp" +#include "GraphicEqualizer.hpp" +#include <cctype> // isalpha(), isdigit() で使用 +using namespace Mikami; + +const float FS_ = 44.1f; // 入力の標本化周波数: 44.1 kHz +MultirateLiPh myAdDa_(FS_); // 出力標本化周波数を4倍にするオブジェクト + +const int BANDS_ = 9; // グラフィック・イコライザのバンド数 +GrEqualizer grEq_(BANDS_, FS_*1000); // グラフィック・イコライザ用オブジェクト + +void Select(string str); // 有効,無効,平坦化,出力 On/Off に対応する処理の選択 +void NumericCtrl(string str); // 帯域ごとの利得調整 + +// グラフィック・イコライザの信号処理 +void AdcIsr() +{ + float xn = myAdDa_.Input()*0.25f; // 入力 + float yn = grEq_.Execute(xn); // グラフィック・イコライザの処理 + myAdDa_.Output(yn); // 出力 +} + +int main() +{ + SerialRxTxIntr rx(72); // PC との通信用,9600 baud,バッファサイズ:72 + + 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 == "GrEqB") rx.TxString("ACK\n"); // "ACK" を送り返す + else + { + if (isalpha(str[0])) Select(str); + if (isdigit(str[0])) NumericCtrl(str); + // 第1文字がアルファベットでも数字でもない場合は何もしない + } + } + } +} + +// 有効,無効,平坦化,出力 On/Off に対応する処理の選択 +void Select(string str) +{ + if (str == "ACTIVE") grEq_.Validate(); // フィルタ処理有効 + if (str == "THROUGH") grEq_.Invalidate(); // フィルタ処理無効 + if (str == "ON") grEq_.SetOn(); // 出力を On + if (str == "OFF") grEq_.SetOff(); // 出力を Off +} + +// 帯域ごとの利得調整 +void NumericCtrl(string str) +{ + // 最初の2文字はフィルタの番号 + int band = atoi(str.substr(0, 2).c_str()); // フィルタの番号 + // 次の文字からは係数の値 + const int N = 5; // 係数の個数 + const int L0 = 13; // 一つの係数に対する文字数 + float c[N]; + for (int n=0; n<N; n++) + c[n] = atof(str.substr(n*L0+2, L0).c_str()); + grEq_.SetCoefficients(band, + (BiquadGrEq::Coefs){c[0], c[1], c[2], c[3], c[4]}); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed.bld Fri Feb 25 02:18:16 2022 +0000 @@ -0,0 +1,1 @@ +https://os.mbed.com/users/mbed_official/code/mbed/builds/65be27845400 \ No newline at end of file