不韋 呂
/
SDR_AM_Rx_CIC
AM中波放送用SDR.CICフィルタのみを使用.CQ出版社「トランジスタ技術」誌,2021年4月号に掲載
Revision 2:4bec6b2be809, committed 2020-08-29
- Comitter:
- MikamiUitOpen
- Date:
- Sat Aug 29 11:19:03 2020 +0000
- Parent:
- 1:30d9fb51dec1
- Child:
- 3:878a48f15e89
- Commit message:
- 3
Changed in this revision
--- a/SDR_Library/Cic3Stage.hpp Mon Sep 23 07:32:10 2019 +0000 +++ b/SDR_Library/Cic3Stage.hpp Sat Aug 29 11:19:03 2020 +0000 @@ -1,7 +1,7 @@ //------------------------------------------------------------- // ダウンサンプリングで使う3段の CIC フィルタ用クラス // -// 2019/04/30, Copyright (c) 2019 MIKAMI, Naoki +// 2020/08/02, Copyright (c) 2020 MIKAMI, Naoki //------------------------------------------------------------- #include "mbed.h" @@ -15,43 +15,42 @@ { public: // コンストラクタ - // rate ダウンサンプリングの率,1/10 にダウンサンプリングする場合は 10 - // amp 二相発振器の出力の振幅 + // rate ダウンサンプリングの率,1/10 にダウンサンプリングする場合は 10 + // amp 直交信号発生器の出力の振幅 Cic3Stage(int rate, float amp) : G0_(1.0f/(amp*rate*rate*rate)), vn1_(0), vn2_(0), vn3_(0), vn3M1_(0), yn1M1_(0), yn2M1_(0) {} - // 累算 - void Accumulate(int16_t xn) + // 積分器 + void Integrate(int16_t xn) { - vn1_ += xn; // 累算1段目 - vn2_ += vn1_; // 累算2段目 - vn3_ += vn2_; // 累算3段目 + vn1_ += xn; // 積分器1段目 + vn2_ += vn1_; // 積分器2段目 + vn3_ += vn2_; // 積分器3段目 } - // 差分 - float Difference() + // くし形フィルタ + float CombFilter() { - int32_t yn1 = vn3_ - vn3M1_; // 差分1段目 - int32_t yn2 = yn1 - yn1M1_; // 差分2段目 - int32_t yn3 = yn2 - yn2M1_; // 差分3段目 + int32_t yn1 = vn3_ - vn3M1_; // くし形フィルタ1段目 + int32_t yn2 = yn1 - yn1M1_; // くし形フィルタ2段目 + int32_t yn3 = yn2 - yn2M1_; // くし形フィルタ3段目 - vn3M1_ = vn3_; // 現在の値を保存,差分1段目 - yn1M1_ = yn1; // 現在の値を保存,差分2段目 - yn2M1_ = yn2; // 現在の値を保存,差分3段目 + vn3M1_ = vn3_; // 現在の値を保存,くし形フィルタ1段目 + yn1M1_ = yn1; // 現在の値を保存,くし形フィルタ2段目 + yn2M1_ = yn2; // 現在の値を保存,くし形フィルタ3段目 return G0_*yn3; } private: const float G0_; - int32_t vn1_, vn2_, vn3_; // 累算で使う変数 - int32_t vn3M1_, yn1M1_, yn2M1_; // 差分で使う変数 + int32_t vn1_, vn2_, vn3_; // 積分器で使う変数 + int32_t vn3M1_, yn1M1_, yn2M1_; // くし形フィルタで使う変数 - // コピー・コンストラクタ禁止のため + // コピー・コンストラクタ,代入演算子の禁止のため Cic3Stage(const Cic3Stage&); - // 代入演算子禁止のため Cic3Stage& operator=(const Cic3Stage&); }; } -#endif // CIC3_FILTER_CLASS_HPP +#endif // CIC3_FILTER_CLASS_HPP \ No newline at end of file
--- a/SDR_Library/F446_ADC.cpp Mon Sep 23 07:32:10 2019 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,68 +0,0 @@ -//------------------------------------------------------------- -// F446 内蔵 ADC をポーリング方式で使うためのクラス -// ADC2 を使用(固定) -// -// 2019/07/15, Copyright (c) 2019 MIKAMI, Naoki -//------------------------------------------------------------- - -#include "F446_ADC.hpp" -#include "PeripheralPins.h" // PinMap_ADC を使う場合に必要 -#pragma diag_suppress 870 // マルチバイト文字使用の警告抑制のため -// PeripheralPins.c は以下よりたどって行けば取得可能 -// https://gitlab.exmachina.fr/fw-libs/mbed-os/tree/5.8.1 - -namespace Mikami -{ - // コンストラクタ - AdcF446::AdcF446(float fSampling, PinName pin) : myAdc_(ADC2) - { - AnalogIn adc_(pin); // GPIO を ADC 用に切り替えるために必要 - // この時点で ADC1 の CR2 の ADON ビットは 0 になっている - __HAL_RCC_ADC1_CLK_DISABLE(); // ADC1 に供給されているクロックを停止する - - __HAL_RCC_ADC2_CLK_ENABLE(); // ADC2 にクロックを供給する - // __HAL_RCC_ADC2_CLK_ENABLE() の定義:stm32f4xx_hal_rcc_ex.h - - // pin に対応するチャンネルを使うための設定 - myAdc_->SQR3 = STM_PIN_CHANNEL(pinmap_function(pin, PinMap_ADC)); - // pinmap_function() のヘッダファイル: mbed\hal\pinmap.h - // STM_PIN_CHANNEL() の定義:PinNamesTypes.h - - // ADC の CR1 の設定 - myAdc_->CR1 = 0x0; // AD 変換終了割り込みを禁止 - // ADC の CR2 の設定 - myAdc_->CR2 = ADC_EXTERNALTRIGCONVEDGE_RISING // 外部トリガの立ち上がりで開始される - | ADC_EXTERNALTRIGCONV_T8_TRGO // 外部トリガ: Timer8 TRGO event - | ADC_CR2_ADON; // ADC を有効にする - - // AD 変換器の外部トリガに使うタイマ (TIM8) の設定 - SetTim8(fSampling); - } - - // AD 変換された値を読み込む - float AdcF446::Read() - { - while ((ADC2->SR & ADC_SR_EOC) != ADC_SR_EOC) {} - return ToFloat(myAdc_->DR); - } - - // AD 変換器の外部トリガに使うタイマ (TIM8) の設定 - // fSampling 標本化周波数 [kHz] - void AdcF446::SetTim8(float fSampling) - { - __HAL_RCC_TIM8_CLK_ENABLE(); // クロック供給. "stm32f4xx_hal_rcc.h" 参照 - TIM_TypeDef* const TIM = TIM8; - - TIM->CR2 = TIM_TRGO_UPDATE; // Update event を TRGO (trigger output) とする - - float arrF = (SystemCoreClock/fSampling)/1000.0f; - if (arrF >65535) - { - fprintf(stderr, "%8.2f kHz : 標本化周波数が低すぎます.\r\n", fSampling); - while (true) {} - } - TIM->ARR = floor(arrF + 0.5f) - 1; // Auto-reload レジスタの設定 - TIM->PSC = 0; // Prescaler の設定 - TIM->CR1 = TIM_CR1_CEN; // TIM8 を有効にする - } -}
--- a/SDR_Library/F446_ADC.hpp Mon Sep 23 07:32:10 2019 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,45 +0,0 @@ -//------------------------------------------------------------- -// F446 内蔵 ADC をポーリング方式で使うためのクラス(ヘッダ) -// -// 2019/07/15, Copyright (c) 2019 MIKAMI, Naoki -//------------------------------------------------------------- - -#include "mbed.h" - -#ifndef ADC_F446_POLLING_HPP -#define ADC_F446_POLLING_HPP - -namespace Mikami -{ - class AdcF446 - { - public: - // コンストラクタ - // fSampling 標本化周波数 [kHz] - // pin 入力ピンの名前 - AdcF446(float fSampling, PinName pin); - - virtual ~AdcF446() {} - - // AD 変換された値を読み込む - // -1.0f <= AD変換された値 < 1.0f - virtual float Read(); - - protected: - ADC_TypeDef* const myAdc_; // AD 変換器に対応するポインタ - - float ToFloat(uint16_t x) { return AMP_*(x - 2048); } - - private: - static const float AMP_ = 1.0f/2048.0f; - // AD 変換器の外部トリガに使うタイマ (TIM8) の設定 - // fSampling 標本化周波数 [kHz] - void SetTim8(float fSampling); - - // コピー・コンストラクタ禁止のため - AdcF446(const AdcF446&); - // 代入演算子禁止のため - AdcF446& operator=(const AdcF446&); - }; -} -#endif // ADC_F446_POLLING_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SDR_Library/F446_ADC_Base.cpp Sat Aug 29 11:19:03 2020 +0000 @@ -0,0 +1,65 @@ +//------------------------------------------------------------- +// F446 内蔵 用抽象基底クラス +// ADC2 を使用(固定) +// +// 2020/07/24, Copyright (c) 2020 MIKAMI, Naoki +//------------------------------------------------------------- + +#include "F446_ADC_Base.hpp" +#include "PeripheralPins.h" // PinMap_ADC を使う場合に必要 +#pragma diag_suppress 870 // マルチバイト文字使用の警告抑制のため +// PeripheralPins.c は以下よりたどって行けば取得可能 +// https://gitlab.exmachina.fr/fw-libs/mbed-os/tree/5.8.1 + +namespace Mikami +{ + // コンストラクタ + AdcF446_Base::AdcF446_Base(float fSampling, PinName pin) : myAdc_(ADC2) + { + // pin に対応する GPIOx_MODER をアナログ・モードに設定する + pin_function(pin, STM_MODE_ANALOG); + // pin_function() が定義されている pinmap.c が含まれるディレクトリ: + // mbed-dev\targets\TARGET_STM + + __HAL_RCC_ADC2_CLK_ENABLE(); // ADC2 にクロックを供給する + // __HAL_RCC_ADC2_CLK_ENABLE() の定義:stm32f4xx_hal_rcc_ex.h + + // 1 チャンネルのみ使用の設定 + myAdc_->SQR1 &= ~ADC_SQR1_L; + + // pin に対応するチャンネルを使うための設定 + myAdc_->SQR3 = STM_PIN_CHANNEL(pinmap_function(pin, PinMap_ADC)); + // pinmap_function() のヘッダファイル: mbed\hal\pinmap.h + // STM_PIN_CHANNEL() の定義:PinNamesTypes.h + + // ADC の CR1 の設定 + myAdc_->CR1 = 0x0; // AD 変換終了割り込みを禁止 + // ADC の CR2 の設定 + myAdc_->CR2 = ADC_EXTERNALTRIGCONVEDGE_RISING // 外部トリガの立ち上がりで開始される + | ADC_EXTERNALTRIGCONV_T8_TRGO // 外部トリガ: Timer8 TRGO event + | ADC_CR2_ADON; // ADC を有効にする + + // AD 変換器の外部トリガに使うタイマ (TIM8) の設定 + SetTim8(fSampling); + } + + // AD 変換器の外部トリガに使うタイマ (TIM8) の設定 + // fSampling 標本化周波数 [kHz] + void AdcF446_Base::SetTim8(float fSampling) + { + __HAL_RCC_TIM8_CLK_ENABLE(); // クロック供給. "stm32f4xx_hal_rcc.h" 参照 + TIM_TypeDef* const TIM = TIM8; + + TIM->CR2 = TIM_TRGO_UPDATE; // Update event を TRGO (trigger output) とする + + float arrF = (SystemCoreClock/fSampling)/1000.0f; + if (arrF >65535) + { + fprintf(stderr, "%8.2f kHz : 標本化周波数が低すぎます.\r\n", fSampling); + while (true) {} + } + TIM->ARR = floor(arrF + 0.5f) - 1; // Auto-reload レジスタの設定 + TIM->PSC = 0; // Prescaler の設定 + TIM->CR1 = TIM_CR1_CEN; // TIM8 を有効にする + } +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SDR_Library/F446_ADC_Base.hpp Sat Aug 29 11:19:03 2020 +0000 @@ -0,0 +1,44 @@ +//------------------------------------------------------------- +// F446 内蔵 ADC 用抽象基底クラス(ヘッダ) +// +// 2020/07/24, Copyright (c) 2020 MIKAMI, Naoki +//------------------------------------------------------------- + +#include "mbed.h" + +#ifndef ADC_F446_POLLING_HPP +#define ADC_F446_POLLING_HPP + +namespace Mikami +{ + class AdcF446_Base + { + public: + // コンストラクタ + // fSampling 標本化周波数 [kHz] + // pin 入力ピンの名前 + AdcF446_Base(float fSampling, PinName pin); + + virtual ~AdcF446_Base() {} + + // AD 変換された値を読み込む(純粋仮想関数) + virtual float Read() = 0; + + protected: + ADC_TypeDef* const myAdc_; // AD 変換器に対応するポインタ + + float ToFloat(uint16_t x) { return AMP_*(x - 2048); } + + private: + static const float AMP_ = 1.0f/2048.0f; + + // AD 変換器の外部トリガに使うタイマ (TIM8) の設定 + // fSampling 標本化周波数 [kHz] + void SetTim8(float fSampling); + + // コピー・コンストラクタ,代入演算子の禁止のため + AdcF446_Base(const AdcF446_Base&); + AdcF446_Base& operator=(const AdcF446_Base&); + }; +} +#endif // ADC_F446_POLLING_HPP \ No newline at end of file
--- a/SDR_Library/F446_ADC_Intr.hpp Mon Sep 23 07:32:10 2019 +0000 +++ b/SDR_Library/F446_ADC_Intr.hpp Sat Aug 29 11:19:03 2020 +0000 @@ -1,25 +1,25 @@ //------------------------------------------------------------- // F446 内蔵 ADC を割込み方式で使うための派生クラス -// 基底クラス: AdcF446 +// 基底クラス: AdcF446_Base // -// 2019/07/16, Copyright (c) 2019 MIKAMI, Naoki +// 2020/07/24, Copyright (c) 2020 MIKAMI, Naoki //------------------------------------------------------------- -#include "F446_ADC.hpp" +#include "F446_ADC_Base.hpp" #ifndef ADC_F446_INTERRUPT_HPP #define ADC_F446_INTERRUPT_HPP namespace Mikami { - class AdcF446_Intr : public AdcF446 + class AdcF446_Intr : public AdcF446_Base { public: // コンストラクタ - // fSampling 標本化周波数 [kHz] - // pin 入力ピンの名前 + // fSampling 標本化周波数 [kHz] + // pin 入力ピンの名前 AdcF446_Intr(float fSampling, PinName pin) - : AdcF446(fSampling, pin) + : AdcF446_Base(fSampling, pin) { myAdc_->CR1 |= ADC_CR1_EOCIE; } // AD 変換終了割り込みを許可 virtual ~AdcF446_Intr() {} @@ -36,10 +36,9 @@ virtual float Read() { return ToFloat(myAdc_->DR); } private: - // コピー・コンストラクタ禁止のため + // コピー・コンストラクタ,代入演算子禁止の禁止のため AdcF446_Intr(const AdcF446_Intr&); - // 代入演算子禁止のため AdcF446_Intr& operator=(const AdcF446_Intr&); }; } -#endif // ADC_F446_INTERRUPT_HPP +#endif // ADC_F446_INTERRUPT_HPP \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SDR_Library/F446_DAC.cpp Sat Aug 29 11:19:03 2020 +0000 @@ -0,0 +1,24 @@ +//-------------------------------------------------------- +// STM32F446 内蔵の DAC 用のクラス +// 出力端子: A2 (PA_4) に固定 +// +// 2020/07/23, Copyright (c) 2020 MIKAMI, Naoki +//-------------------------------------------------------- + +#include "F446_DAC.hpp" +#include "pinmap.h" // pin_function() で使用 + +namespace Mikami +{ + // コンストラクタ + DacF446::DacF446() : DAC_(DAC) + { + // A2 に対応する GPIOx_MODER をアナログ・モードに設定する + pin_function(A2, STM_MODE_ANALOG); + + __HAL_RCC_DAC_CLK_ENABLE(); // DAC にクロックを供給する + // __HAL_RCC_DAC_CLK_ENABLE() の定義:stm32f4xx_hal_rcc_ex.h + + DAC_->CR = DAC_CR_EN1; // DAC を有効にする + } +} \ No newline at end of file
--- a/SDR_Library/F446_DAC.hpp Mon Sep 23 07:32:10 2019 +0000 +++ b/SDR_Library/F446_DAC.hpp Sat Aug 29 11:19:03 2020 +0000 @@ -1,8 +1,8 @@ //-------------------------------------------------------- -// STM32F446 内蔵の DAC 用のクラス -// 出力端子: A2 (PA_4) +// STM32F446 内蔵の DAC 用のクラス(ヘッダ) +// 出力端子: A2 (PA_4) に固定 // -// 2019/02/18, Copyright (c) 2019 MIKAMI, Naoki +// 2020/07/23, Copyright (c) 2020 MIKAMI, Naoki //-------------------------------------------------------- #include "mbed.h" @@ -16,31 +16,27 @@ { public: // コンストラクタ, A2 に接続される CH1 のみを有効にする - DacF446() : da_(A2) { DAC->CR = DAC_CR_EN1; } + DacF446(); virtual ~DacF446() {} // -1.0f <= data <= 1.0f void Write(float data) { WriteDac1(ToUint16(data)); } - // 0 <= data <= 4095 - void Write(uint16_t data) { WriteDac1(__USAT(data, BIT_WIDTH_)); } - private: static const int BIT_WIDTH_ = 12; - AnalogOut da_; + DAC_TypeDef* const DAC_; // DA 変換器に対応する構造体のポインタ // DAC の CH1 へ右詰めで出力する - void WriteDac1(uint16_t val) { DAC->DHR12R1 = val; } + void WriteDac1(uint16_t val) { DAC_->DHR12R1 = val; } // 飽和処理を行い uint16_t 型のデータを戻り値とする uint16_t ToUint16(float val) { return __USAT((val + 1.0f)*2048.0f, BIT_WIDTH_); } - // コピー・コンストラクタ禁止のため + // コピー・コンストラクタ,代入演算子の禁止のため DacF446(const DacF446&); - // 代入演算子禁止のため DacF446& operator=(const DacF446&); }; } -#endif // DAC_F446_SINGLE_HPP +#endif // DAC_F446_SINGLE_HPP \ No newline at end of file
--- a/SDR_Library/FastATan.hpp Mon Sep 23 07:32:10 2019 +0000 +++ b/SDR_Library/FastATan.hpp Sat Aug 29 11:19:03 2020 +0000 @@ -3,7 +3,7 @@ // 係数はミニマックス近似で求めたもの // ただし,誤差は絶対誤差で評価した // -// 2019/09/18, Copyright (c) 2019 MIKAMI, Naoki +// 2020/08/12, Copyright (c) 2020 MIKAMI, Naoki //-------------------------------------------------------------- #include "mbed.h" @@ -24,40 +24,27 @@ static const float PI_2 = PI/2.0f; // π/2 if ( (x == 0.0f) && (y == 0.0f) ) return 0.0f; - if (y == 0.0f) - { - if (x > 0.0f) return 0.0f; // 0 - else return PI; // π - } + if (y == 0.0f) return (x > 0.0f) ? 0.0f : PI; + float abs_x = fabsf(x); float abs_y = fabsf(y); if (abs_x == abs_y) { - if (x > 0.0f) - { - if (y > 0.0f) return PI_4; // π/4 - else return -PI_4; // -π/4 - } - else - { - if (y > 0.0f) return PI3_4; // 3π/4 - else return -PI3_4; // -3π/4 - } + if (x > 0.0f) return (y > 0.0f) ? PI_4 : -PI_4; + else return (y > 0.0f) ? PI3_4 : -PI3_4; } if (abs_x > abs_y) // |θ|< π/4,3π/4<|θ|<π { float u = ATanPoly(y/x); if (x > 0.0f) return u; - if (y > 0.0f) return u + PI; - else return u - PI; + else return (y > 0.0f) ? u + PI : u - PI; } else // π/4 <|θ|<3π/4 { float u = ATanPoly(x/y); - if (y > 0.0f) return -u + PI_2; - else return -u - PI_2; + return (y > 0.0f) ? -u + PI_2 : -u - PI_2; } } @@ -74,4 +61,4 @@ return atanx; } } -#endif // FAST_ARCTAN_LOW_PRECISION_HPP +#endif // FAST_ARCTAN_LOW_PRECISION_HPP \ No newline at end of file
--- a/SDR_Library/FirFastSymmetry.hpp Mon Sep 23 07:32:10 2019 +0000 +++ b/SDR_Library/FirFastSymmetry.hpp Sat Aug 29 11:19:03 2020 +0000 @@ -1,12 +1,12 @@ -//----------------------------------------------------------------- +//---------------------------------------------------------------------------- // SDR で使う FIR フィルタ,係数:対称 // ● 処理の高速化のため,入力信号のバッファのサイズを 256,データを指す // インデックスを uint8_t 型としてリング・バッファを実現している. // ● さらに,係数が対称であることを利用して,先に x[k] + x[ORDER-k] と // いう加算を行ってから,係数の乗算を行うようにした. // -// 2019/03/03, Copyright (c) 2019 MIKAMI, Naoki -//----------------------------------------------------------------- +// 2020/07/28, Copyright (c) 2020 MIKAMI, Naoki +//---------------------------------------------------------------------------- #include "mbed.h" @@ -18,10 +18,10 @@ { public: // コンストラクタ - // order フィルタの次数 + // order フィルタの次数,次数は偶数とする // hk[] フィルタの係数 - FirFastSymmetry(int order, const float hk[]) - : ORDER_(order), hm_(hk), index_(255) + FirFastSymmetry(uint8_t order, const float hk[]) + : ORDER_(order), ORDER2_(order/2), hm_(hk), index_(255) { for (int k=0; k<SIZE_; k++) un_[k] = 0; } // 入力信号をバッファへ書き込む @@ -33,23 +33,23 @@ __IO uint8_t ptrM = index_; __IO uint8_t ptrP = index_ - ORDER_; float acc = 0; - for (int k=0; k<ORDER_/2; k++) + for (int k=0; k<ORDER2_; k++) acc += hm_[k]*(un_[ptrM--] + un_[ptrP++]); - acc += hm_[ORDER_/2]*un_[ptrM]; + acc += hm_[ORDER2_]*un_[ptrM]; return acc; } private: static const int SIZE_ = 256; // 入力信号のバッファのサイズ - const int ORDER_; // フィルタの次数 + const uint8_t ORDER_; // フィルタの次数 + const uint8_t ORDER2_; // フィルタの次数の半分 const float *const hm_; // フィルタの係数 float un_[SIZE_]; // 入力信号のバッファ __IO uint8_t index_; // 最新の入力信号を示すインデックス - // コピー・コンストラクタ禁止のため + // コピー・コンストラクタ,代入演算子の禁止のため FirFastSymmetry(const FirFastSymmetry&); - // 代入演算子禁止のため FirFastSymmetry& operator=(const FirFastSymmetry&); }; } -#endif // FIR_DIRECT_FAST_SYMMETRY_HPP +#endif // FIR_DIRECT_FAST_SYMMETRY_HPP \ No newline at end of file
--- a/SDR_Library/Iir1st.hpp Mon Sep 23 07:32:10 2019 +0000 +++ b/SDR_Library/Iir1st.hpp Sat Aug 29 11:19:03 2020 +0000 @@ -2,7 +2,7 @@ // 一次の IIR フィルタ // y[n] = a1*y[n-1] + (1 - a1)*x[n] // -// 2019/09/21, Copyright (c) 2019 MIKAMI, Naoki +// 2020/08/05, Copyright (c) 2020 MIKAMI, Naoki //----------------------------------------------------------------- #include "mbed.h" @@ -16,7 +16,7 @@ public: // コンストラクタ // a1 フィルタの係数 - Iir1st(float a1) : A1_(a1), B0_(1.0f - a1) { yn_ = 0; } + Iir1st(float a1) : A1_(a1), B0_(1.0f - a1), yn_(0) {} // フィルタの実行 float Execute(float xn) @@ -30,10 +30,9 @@ const float B0_; // フィルタ係数 float yn_; // 出力 - // コピー・コンストラクタ禁止のため + // コピー・コンストラクタ,代入演算子の禁止のため Iir1st(const Iir1st&); - // 代入演算子禁止のため Iir1st& operator=(const Iir1st&); }; } -#endif // IIR_1ST_HPP +#endif // IIR_1ST_HPP \ No newline at end of file
--- a/SDR_Library/IirDcCut.hpp Mon Sep 23 07:32:10 2019 +0000 +++ b/SDR_Library/IirDcCut.hpp Sat Aug 29 11:19:03 2020 +0000 @@ -3,7 +3,7 @@ // u[n] = a1*u[n-1] + x[n] // y[n] = g0*(u[n] - u[n-1]) // -// 2019/09/21, Copyright (c) 2019 MIKAMI, Naoki +// 2020/08/17, Copyright (c) 2020 MIKAMI, Naoki //----------------------------------------------------------------- #include "mbed.h" @@ -19,7 +19,7 @@ // a1 フィルタの係数 // g0 利得定数 IirDcCut(float a1, float g0) - : A1_(a1), G0_(g0) { un1_ = 0; } + : A1_(a1), G0_(g0), un1_(0) {} // フィルタの実行 float Execute(float xn) @@ -33,12 +33,11 @@ private: const float A1_; // フィルタ係数 const float G0_; // 利得定数 - float un1_; // 中間の値 + float un1_; // 遅延器の値 - // コピー・コンストラクタ禁止のため + // コピー・コンストラクタ,代入演算子の禁止のため IirDcCut(const IirDcCut&); - // 代入演算子禁止のため IirDcCut& operator=(const IirDcCut&); }; } -#endif // IIR_DC_CUT_HPP +#endif // IIR_DC_CUT_HPP \ No newline at end of file
--- a/SDR_Library/InitialMessage.hpp Mon Sep 23 07:32:10 2019 +0000 +++ b/SDR_Library/InitialMessage.hpp Sat Aug 29 11:19:03 2020 +0000 @@ -6,11 +6,8 @@ #include "mbed.h" #pragma diag_suppress 870 // マルチバイト文字使用の警告抑制のため - #include <string> -#ifndef INITIAL_MESSAGE_HPP -#define INITIAL_MESSAGE_HPP enum AmFm { AM, FM }; // メッセージが AM 用か FM 用かを指定する // str 2行目に表示するメッセージ @@ -38,5 +35,4 @@ sp.printf("'Enter' キーは CR/LF するだけです.\r\n\n"); sp.putc('0'); -} -#endif // INITIAL_MESSAGE_HPP +} \ No newline at end of file
--- a/SDR_Library/QuadOscIir.hpp Mon Sep 23 07:32:10 2019 +0000 +++ b/SDR_Library/QuadOscIir.hpp Sat Aug 29 11:19:03 2020 +0000 @@ -1,7 +1,7 @@ //-------------------------------------------------------------- -// IIR フィルタを利用する二相発振器のクラス +// IIR フィルタを利用する直交信号発生器のクラス // -// 2019/04/11, Copyright (c) 2019 MIKAMI, Naoki +// 2020/07/30, Copyright (c) 2020 MIKAMI, Naoki //-------------------------------------------------------------- #include "mbed.h" @@ -15,59 +15,44 @@ { public: // コンストラクタ - // f0: 周波数,単位:Hz - // ts: 標本化間隔,単位:μs - // amp: 振幅 + // f0 周波数,単位:Hz + // ts 標本化間隔,単位:μs + // amp 振幅 QuadOscIir(float f0, float ts, float amp = 1) : TS_(ts*1.0E-6f), A0_(amp) { Set(f0); } - // sin/cos 発生,実行時間の実測値:91 ns + // sin/cos 発生 void Generate(float &sinX, float &cosX) { - RecursivePart(); - sinX = b1S_*un2_; - cosX = A0_*un1_ + b1C_*un2_; - } - - // sin 発生,実行時間の実測値:69 ns - float GenerateSin() - { - RecursivePart(); - return b1S_*un2_; - } + float vn = a1_*vn1_ - vn2_; + sinX = b1S_*vn1_; + cosX = A0_*vn + b1C_*vn1_; - // cis 発生,実行時間の実測値:80 ns - float GenerateCos() - { - RecursivePart(); - return A0_*un1_ + b1C_*un2_; + vn2_ = vn1_; // v[n-2] ← v[n-1] + vn1_ = vn; // v[n-1] ← v[n] } // 出力周波数の設定,周波数を変更し再スタートする場合も使える // f0:周波数,単位:Hz void Set(float f0) { - static const float pi2 = 6.283185f; - a1_ = 2.0f*cosf(pi2*f0*TS_); - b1S_ = A0_*sinf(pi2*f0*TS_); - b1C_ = -A0_*cosf(pi2*f0*TS_); - un1_ = 1.0f; - un2_ = 0.0f; + static const float PI2 = 6.283185f; + a1_ = 2.0f*cosf(PI2*f0*TS_); + b1S_ = A0_*sinf(PI2*f0*TS_); + b1C_ = -A0_*cosf(PI2*f0*TS_); + vn1_ = 1.0f; + vn2_ = 0.0f; } private: const float TS_; // 標本化間隔 const float A0_; // 振幅 float a1_, b1S_, b1C_; - float un1_, un2_; + float vn1_, vn2_; - // u[n] = a1*u[n-1] - u[n-2] の計算 - void RecursivePart() - { - float un = a1_*un1_ - un2_; - un2_ = un1_; // u[n-2] ← u[n-1] - un1_ = un; // u[n-1] ← u[n] - } + // コピー・コンストラクタ,代入演算子の禁止のため + QuadOscIir(const QuadOscIir&); + QuadOscIir& operator=(const QuadOscIir&); }; } -#endif // QUAD_PHASE_OSC_IIR_HPP +#endif // QUAD_PHASE_OSC_IIR_HPP \ No newline at end of file
--- a/main.cpp Mon Sep 23 07:32:10 2019 +0000 +++ b/main.cpp Sat Aug 29 11:19:03 2020 +0000 @@ -6,12 +6,12 @@ // 入力ピン: A1 // 出力ピン: A2 // -// 2019/09/18, Copyright (c) 2019 MIKAMI, Naoki +// 2020/08/17, Copyright (c) 2020 MIKAMI, Naoki //------------------------------------------------------------- #include "F446_ADC_Intr.hpp" // ADC #include "F446_DAC.hpp" // DAC -#include "QuadOscIir.hpp" // 二相発振器 +#include "QuadOscIir.hpp" // 直交信号発生器 #include "Cic3Stage.hpp" // 3段 CIC フィルタ #include "Iir1st.hpp" // 一次の IIR フィルタ #include "InitialMessage.hpp" // 最初のメーッセージ @@ -20,9 +20,9 @@ const float FS_ = 900.0f; // 標本化周波数,単位: kHz const float T0_ = 1000/FS_; // 標本化間隔,単位:μs -const float A0_ = 8192; // 二相発振器の出力の振幅 +const float A0_ = 8192; // 直交信号発生器の出力の振幅 -// 各放送局の搬送波の周波数,単位: kHz +// 各放送局の搬送波の周波数,単位: Hz const float F_C_[] = { 594.0e3f, // NHK 第1 693.0e3f, // NHK 第2 810.0e3f, // AFN Tokyo @@ -53,9 +53,9 @@ float sinX, cosX; nco_.Generate(sinX, cosX); // sin, cos 発生 - // cos/sin を乗算したデータに対する CIC フィルタの累算処理 - cic3I_.Accumulate((int16_t)(xn*cosX)); // I 信号用 - cic3Q_.Accumulate((int16_t)(xn*sinX)); // Q 信号用 + // cos/sin を乗算したデータに対する CIC フィルタの積分処理 + cic3I_.Integrate((int16_t)(xn*cosX)); // I 信号用 + cic3Q_.Integrate((int16_t)(xn*sinX)); // Q 信号用 if (++count >= DS_RATE_) { @@ -67,22 +67,22 @@ // ダウンサンプラより後の処理に対する割り込みサービス・ルーチン void SwiIsr() { - // CIC フィルタの差分処理 - float yI_n = cic3I_.Difference(); // 差分処理で I 信号を生成 - float yQ_n = cic3Q_.Difference(); // 差分処理で Q 信号を生成 + // CIC フィルタのくし形フィルタの部分による処理 + float yI_n = cic3I_.CombFilter(); // くし形フィルタ処理で I 信号を生成 + float yQ_n = cic3Q_.CombFilter(); // くし形フィルタ処理で Q 信号を生成 float yn = sqrtf(yI_n*yI_n + yQ_n*yQ_n); // 包絡線成分を求める yn = comp_.Execute(yn); // 補償フィルタ float dc = averaging_.Execute(yn); // 直流分を求める + yn = yn - dc; // 直流分除去 float gain = 0.8f/dc; // AGC 処理の準備 if (gain > 200.0f) gain = 200.0f; - // DAC への出力は,直流分を除去し,AGC 処理をしたもの - dac_.Write(gain*(yn - dc)); + dac_.Write(gain*yn); } -// シリアル・ポートの受信割込みに対する処理 +// シリアル・ポートの受信割込みに対する割り込みサービス・ルーチン void RxIsr() { unsigned char chr = pc_.getc(); @@ -97,11 +97,11 @@ int main() { - InitialMessage("ダウンサンプリングに CIC フィルタ使用.", AM, pc_); + InitialMessage("ダウンサンプリングに CIC フィルタを使用.", AM, pc_); NVIC_SetPriority(ADC_IRQn, 0); // 最優先 NVIC_SetPriority(EXTI4_IRQn, 1); // 2番目に優先 - NVIC_SetPriority(USART2_IRQn, 2); + NVIC_SetPriority(USART2_IRQn, 2); // 3番目に優先 // ADC に対する割り込みサービス・ルーチンの設定 adc_.SetIntrVec(&AdcIsr); @@ -115,4 +115,4 @@ pc_.attach(&RxIsr); while (true) {} -} +} \ No newline at end of file