Nucleo-F446RE 内蔵の AD/DA を使うためのライブラリ.DA からの出力は,標本化周波数の4倍のレートで行う.出力の補間フィルタには直線位相の FIR フィルタを使用. このライブラリを登録した際のプログラム: Demo_F446_AD_DA_MultirateLinearPhase. Library for built-in ADC and DAC in Nucleo-F446RE. Sampling rate for DAC is four times of that for ADC. Interpolation filter for output is linear-phase FIR filter.
Dependents: Demo_F446_AD_DA_MultirateLinearPhase
Diff: F446_LinearPhase.cpp
- Revision:
- 0:ad30ac2b412b
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/F446_LinearPhase.cpp Tue Jul 03 01:29:13 2018 +0000 @@ -0,0 +1,114 @@ +//----------------------------------------------------------- +// 出力を 4 倍にアップサンプリングするクラス +// Nucleo-F446RE 専用 +// 補間処理で使うフィルタとして,直線位相 FIR フィルタを使用 +// +// 2018/07/03, Copyright (c) 2018 MIKAMI, Naoki +//----------------------------------------------------------- + +#include "F446_LinearPhase.hpp" +using namespace Mikami; + +F446_LinearPhase::F446_LinearPhase(int order, const float hk1[], + const float hk2[], const float hk3[]) + : indexW_(0), ORDER_(order), FIR_COUNT_(order/4), + CENTER_(order/(FACTOR_*2)), un_(order/4, 0.0f), + h1_(order/4), h2_(order/4), h3_(order/4) +{ + if (hk1 == NULL) + { + h1_.Assign(HK1_); + h2_.Assign(HK2_); + h3_.Assign(HK3_); + } + else // デフォルト以外の補間用フィルタの係数を使用する + { + h1_.Assign(hk1); + h2_.Assign(hk2); + h3_.Assign(hk3); + } +} + +// 標本化の実行開始 +void F446_LinearPhase::Start(int frequency, PinName pin) +{ + adc_ = new AdcF446(frequency*FACTOR_, pin); // AD変換器の初期化 + wait_us(1000); // ある程度の待ち時間が必要 + adc_->SetIntrVec(&F446_LinearPhase::AdcIsr); // ISR の設定 +} + +// AD変換の結果を取り出す +float F446_LinearPhase::Input() +{ + while (!okIn_) {} // AD変換の結果を取り出せるまで待つ + okIn_ = false; + return xn_; +} + +// 補間用フィルタを実行し,処理結果を出力用バッファへ書き込む +void F446_LinearPhase::Output(float yn) +{ + un_[0] = yn; // 補間フィルタ用バッファの先頭に書き込む + + buf_[ModCounter(indexW_)] = un_[CENTER_]; + buf_[ModCounter(indexW_)] = Interpolator(h1_); + buf_[ModCounter(indexW_)] = Interpolator(h2_); + buf_[ModCounter(indexW_)] = Interpolator(h3_); + + for (int k=FIR_COUNT_-1; k>0; k--) un_[k] = un_[k-1]; +} + +// ADC 変換終了割り込みに対する割り込みサービス・ルーチン +void F446_LinearPhase::AdcIsr() +{ + static int count = 0; + + xn_ = adc_->Read(); // AD変換器の値を読み込む + dac_.Write(buf_[ModCounter(indexR_)]); // 出力バッファの内容を DAC へ書き込む + + if (count == 0) okIn_ = true; // AD変換器からの入力信号は4回に1回使う + count = ++count & MASK_FACTOR_; // 出力時に4倍にアップサンプリングするので, + // 入力を4回に1回行うための処理 +} + +// 補間用 FIR フィルタ +float F446_LinearPhase::Interpolator(float hk[]) +{ + float y = 0; + for (int n=0; n<FIR_COUNT_; n++) y = y + un_[n]*hk[n]; + return y; +} + +// static メンバの実体の宣言/初期化 +AdcF446 *F446_LinearPhase::adc_; +DacF446 F446_LinearPhase::dac_; +Array<float> F446_LinearPhase::buf_(2*FACTOR_, 0.0f); +int F446_LinearPhase::indexR_ = FACTOR_; +float F446_LinearPhase::xn_; +__IO bool F446_LinearPhase::okIn_ = false; + +// デフォルトの補間用フィルタの係数(AD 変換器の標本化周波数は 10 kHz を想定している) +// 使用窓関数 Kaiser 窓 +// 標本化周波数 (kHz) 40.000000 +// 次数 72 +// 種類 LPF +// 遮断周波数 (kHz) 5.000000 +// 減衰量 (dB) 40.00 +const float F446_LinearPhase::HK1_[] = { + 4.431256E-03f, -8.146596E-03f, 1.341366E-02f, -2.077330E-02f, + 3.116614E-02f, -4.650688E-02f, 7.151836E-02f, -1.218529E-01f, + 2.971602E-01f, 8.993316E-01f, -1.751857E-01f, 9.144896E-02f, + -5.727932E-02f, 3.802786E-02f, -2.550498E-02f, 1.678651E-02f, + -1.055827E-02f, 6.120216E-03f}; +const float F446_LinearPhase::HK2_[] = { + 7.405152E-03f, -1.315348E-02f, 2.125564E-02f, -3.257789E-02f, + 4.868468E-02f, -7.290120E-02f, 1.139337E-01f, -2.039652E-01f, + 6.338376E-01f, 6.338376E-01f, -2.039652E-01f, 1.139337E-01f, + -7.290120E-02f, 4.868468E-02f, -3.257789E-02f, 2.125564E-02f, + -1.315348E-02f, 7.405152E-03f}; +const float F446_LinearPhase::HK3_[] = { + 6.120216E-03f, -1.055827E-02f, 1.678651E-02f, -2.550498E-02f, + 3.802786E-02f, -5.727932E-02f, 9.144896E-02f, -1.751857E-01f, + 8.993316E-01f, 2.971602E-01f, -1.218529E-01f, 7.151836E-02f, + -4.650688E-02f, 3.116614E-02f, -2.077330E-02f, 1.341366E-02f, + -8.146596E-03f, 4.431256E-03f};