takanaka kouzou
/
SDR_AM_Rx_CIC_FIR
AM中波放送用SDR.CICフィルタと通常のFIRフィルタを組み合わせて使用.CQ出版社「トランジスタ技術」誌に掲載予定
main.cpp@0:9c28f5905a1a, 2020-08-29 (annotated)
- Committer:
- MikamiUitOpen
- Date:
- Sat Aug 29 11:25:01 2020 +0000
- Revision:
- 0:9c28f5905a1a
- Child:
- 1:ca43ee5ea802
1
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
MikamiUitOpen | 0:9c28f5905a1a | 1 | //------------------------------------------------------------- |
MikamiUitOpen | 0:9c28f5905a1a | 2 | // 中波 AM 放送用 SDR,CIC フィルタと通常の FIR フィルタ使用 |
MikamiUitOpen | 0:9c28f5905a1a | 3 | // |
MikamiUitOpen | 0:9c28f5905a1a | 4 | // 1/9 にダウンサンプリング:CIC フィルタ使用 |
MikamiUitOpen | 0:9c28f5905a1a | 5 | // 1/4 にダウンサンプリング:通常の FIR フィルタ使用 |
MikamiUitOpen | 0:9c28f5905a1a | 6 | // |
MikamiUitOpen | 0:9c28f5905a1a | 7 | // 入力ピン: A1 |
MikamiUitOpen | 0:9c28f5905a1a | 8 | // 出力ピン: A2 |
MikamiUitOpen | 0:9c28f5905a1a | 9 | // |
MikamiUitOpen | 0:9c28f5905a1a | 10 | // 2020/08/08, Copyright (c) 2020 MIKAMI, Naoki |
MikamiUitOpen | 0:9c28f5905a1a | 11 | //------------------------------------------------------------- |
MikamiUitOpen | 0:9c28f5905a1a | 12 | |
MikamiUitOpen | 0:9c28f5905a1a | 13 | #include "F446_ADC_Intr.hpp" // ADC |
MikamiUitOpen | 0:9c28f5905a1a | 14 | #include "F446_DAC.hpp" // DAC |
MikamiUitOpen | 0:9c28f5905a1a | 15 | #include "QuadOscIir.hpp" // 直交信号発生器 |
MikamiUitOpen | 0:9c28f5905a1a | 16 | #include "Cic3Stage.hpp" // 3段 CIC フィルタ |
MikamiUitOpen | 0:9c28f5905a1a | 17 | #include "CoefficientsLpf.hpp" // FIR フィルタの係数 |
MikamiUitOpen | 0:9c28f5905a1a | 18 | #include "FirFastSymmetry.hpp" // 係数対称 FIR フィルタ |
MikamiUitOpen | 0:9c28f5905a1a | 19 | #include "Iir1st.hpp" // 一次の IIR フィルタ |
MikamiUitOpen | 0:9c28f5905a1a | 20 | #include "InitialMessage.hpp" // 最初のメーッセージ |
MikamiUitOpen | 0:9c28f5905a1a | 21 | using namespace Mikami; |
MikamiUitOpen | 0:9c28f5905a1a | 22 | #pragma diag_suppress 870 // マルチバイト文字使用の警告抑制のため |
MikamiUitOpen | 0:9c28f5905a1a | 23 | |
MikamiUitOpen | 0:9c28f5905a1a | 24 | const float FS_ = 900.0f; // 標本化周波数,単位: kHz |
MikamiUitOpen | 0:9c28f5905a1a | 25 | const float T0_ = 1000/FS_; // 標本化間隔,単位:μs |
MikamiUitOpen | 0:9c28f5905a1a | 26 | const float A0_ = 8192; // 直交信号発生器の出力の振幅 |
MikamiUitOpen | 0:9c28f5905a1a | 27 | |
MikamiUitOpen | 0:9c28f5905a1a | 28 | // 各放送局の搬送波の周波数,単位: Hz |
MikamiUitOpen | 0:9c28f5905a1a | 29 | const float F_C_[] = { 594.0e3f, // NHK 第1 |
MikamiUitOpen | 0:9c28f5905a1a | 30 | 693.0e3f, // NHK 第2 |
MikamiUitOpen | 0:9c28f5905a1a | 31 | 810.0e3f, // AFN Tokyo |
MikamiUitOpen | 0:9c28f5905a1a | 32 | 954.0e3f, // TBS ラジオ |
MikamiUitOpen | 0:9c28f5905a1a | 33 | 1134.0e3f, // 文化放送 |
MikamiUitOpen | 0:9c28f5905a1a | 34 | 1242.0e3f, // ニッポン放送 |
MikamiUitOpen | 0:9c28f5905a1a | 35 | 1422.0e3f}; // ラジオ日本 |
MikamiUitOpen | 0:9c28f5905a1a | 36 | |
MikamiUitOpen | 0:9c28f5905a1a | 37 | AdcF446_Intr adc_(FS_, A1); // ADC オブジェクトの宣言 |
MikamiUitOpen | 0:9c28f5905a1a | 38 | DacF446 dac_; // DAC オブジェクトの宣言 |
MikamiUitOpen | 0:9c28f5905a1a | 39 | Serial pc_(USBTX, USBRX); // ターミナルに対する受信割込み用 |
MikamiUitOpen | 0:9c28f5905a1a | 40 | |
MikamiUitOpen | 0:9c28f5905a1a | 41 | QuadOscIir nco_(F_C_[0], T0_, A0_); // NCO (numerically controlled oscillator) |
MikamiUitOpen | 0:9c28f5905a1a | 42 | |
MikamiUitOpen | 0:9c28f5905a1a | 43 | Iir1st averaging_(0.9998f); // 直流分を求めるためのフィルタ |
MikamiUitOpen | 0:9c28f5905a1a | 44 | |
MikamiUitOpen | 0:9c28f5905a1a | 45 | const int DS_RATE1_ = 9; // 1/9 にダウンサンプリング |
MikamiUitOpen | 0:9c28f5905a1a | 46 | Cic3Stage cic3I_(DS_RATE1_, A0_); // CIC フィルタ,I 信号用 |
MikamiUitOpen | 0:9c28f5905a1a | 47 | Cic3Stage cic3Q_(DS_RATE1_, A0_); // CIC フィルタ,Q 信号用 |
MikamiUitOpen | 0:9c28f5905a1a | 48 | |
MikamiUitOpen | 0:9c28f5905a1a | 49 | const int DS_RATE2_ = 4; // 1/4 にダウンサンプリング |
MikamiUitOpen | 0:9c28f5905a1a | 50 | FirFastSymmetry lpfI_(ORDER_FIR_, HN_); // FIR フィルタ,I 信号用 |
MikamiUitOpen | 0:9c28f5905a1a | 51 | FirFastSymmetry lpfQ_(ORDER_FIR_, HN_); // FIR フィルタ,Q 信号用 |
MikamiUitOpen | 0:9c28f5905a1a | 52 | |
MikamiUitOpen | 0:9c28f5905a1a | 53 | // AD 変換終了割り込みに対する割り込みサービス・ルーチン |
MikamiUitOpen | 0:9c28f5905a1a | 54 | void AdcIsr() |
MikamiUitOpen | 0:9c28f5905a1a | 55 | { |
MikamiUitOpen | 0:9c28f5905a1a | 56 | static int count = 0; |
MikamiUitOpen | 0:9c28f5905a1a | 57 | |
MikamiUitOpen | 0:9c28f5905a1a | 58 | float xn = adc_.Read(); // ADC の読込み |
MikamiUitOpen | 0:9c28f5905a1a | 59 | float sinX, cosX; |
MikamiUitOpen | 0:9c28f5905a1a | 60 | nco_.Generate(sinX, cosX); // sin, cos 発生 |
MikamiUitOpen | 0:9c28f5905a1a | 61 | |
MikamiUitOpen | 0:9c28f5905a1a | 62 | // cos/sin を乗算したデータに対する CIC フィルタの積分処理 |
MikamiUitOpen | 0:9c28f5905a1a | 63 | cic3I_.Integrate((int16_t)(xn*cosX)); // I 信号 |
MikamiUitOpen | 0:9c28f5905a1a | 64 | cic3Q_.Integrate((int16_t)(xn*sinX)); // Q 信号 |
MikamiUitOpen | 0:9c28f5905a1a | 65 | |
MikamiUitOpen | 0:9c28f5905a1a | 66 | if (++count >= DS_RATE1_) |
MikamiUitOpen | 0:9c28f5905a1a | 67 | { |
MikamiUitOpen | 0:9c28f5905a1a | 68 | count = 0; |
MikamiUitOpen | 0:9c28f5905a1a | 69 | NVIC->STIR |= EXTI3_IRQn; // ソフトウェア割り込み発生 |
MikamiUitOpen | 0:9c28f5905a1a | 70 | } |
MikamiUitOpen | 0:9c28f5905a1a | 71 | } |
MikamiUitOpen | 0:9c28f5905a1a | 72 | |
MikamiUitOpen | 0:9c28f5905a1a | 73 | // EXTI3_IRQ に対する割込みサービス・ルーチン |
MikamiUitOpen | 0:9c28f5905a1a | 74 | // CIC フィルタのくし形フィルタの処理と FIR フィルタの入力の処理 |
MikamiUitOpen | 0:9c28f5905a1a | 75 | void IsrCIC() |
MikamiUitOpen | 0:9c28f5905a1a | 76 | { |
MikamiUitOpen | 0:9c28f5905a1a | 77 | static int count = 0; |
MikamiUitOpen | 0:9c28f5905a1a | 78 | |
MikamiUitOpen | 0:9c28f5905a1a | 79 | float yI_n = cic3I_.CombFilter(); // くし形フィルタ |
MikamiUitOpen | 0:9c28f5905a1a | 80 | float yQ_n = cic3Q_.CombFilter(); // くし形フィルタ |
MikamiUitOpen | 0:9c28f5905a1a | 81 | |
MikamiUitOpen | 0:9c28f5905a1a | 82 | lpfI_.Store(yI_n); // FIR フィルタのバッファへ保存,I 信号 |
MikamiUitOpen | 0:9c28f5905a1a | 83 | lpfQ_.Store(yQ_n); // FIR フィルタのバッファへ保存,Q 信号 |
MikamiUitOpen | 0:9c28f5905a1a | 84 | |
MikamiUitOpen | 0:9c28f5905a1a | 85 | if (++count >= DS_RATE2_) |
MikamiUitOpen | 0:9c28f5905a1a | 86 | { |
MikamiUitOpen | 0:9c28f5905a1a | 87 | count = 0; |
MikamiUitOpen | 0:9c28f5905a1a | 88 | NVIC->STIR |= EXTI4_IRQn; // ソフトウェア割り込み発生 |
MikamiUitOpen | 0:9c28f5905a1a | 89 | } |
MikamiUitOpen | 0:9c28f5905a1a | 90 | } |
MikamiUitOpen | 0:9c28f5905a1a | 91 | |
MikamiUitOpen | 0:9c28f5905a1a | 92 | // EXTI4_IRQ に対する割込みサービス・ルーチン |
MikamiUitOpen | 0:9c28f5905a1a | 93 | // FIR フィルタの実行とAM復調の処理 |
MikamiUitOpen | 0:9c28f5905a1a | 94 | void IsrFIR() |
MikamiUitOpen | 0:9c28f5905a1a | 95 | { |
MikamiUitOpen | 0:9c28f5905a1a | 96 | float yI_n = lpfI_.Execute(); // FIR フィルタによる LPF 実行 |
MikamiUitOpen | 0:9c28f5905a1a | 97 | float yQ_n = lpfQ_.Execute(); // FIR フィルタによる LPF 実行 |
MikamiUitOpen | 0:9c28f5905a1a | 98 | |
MikamiUitOpen | 0:9c28f5905a1a | 99 | float yn = sqrtf(yI_n*yI_n + yQ_n*yQ_n); // 包絡線成分を求める |
MikamiUitOpen | 0:9c28f5905a1a | 100 | float dc = averaging_.Execute(yn); // 直流分を求める |
MikamiUitOpen | 0:9c28f5905a1a | 101 | yn = yn - dc; // 直流分除去 |
MikamiUitOpen | 0:9c28f5905a1a | 102 | |
MikamiUitOpen | 0:9c28f5905a1a | 103 | float gain = 0.8f/dc; |
MikamiUitOpen | 0:9c28f5905a1a | 104 | if (gain > 200.0f) gain = 200.0f; |
MikamiUitOpen | 0:9c28f5905a1a | 105 | dac_.Write(gain*yn); |
MikamiUitOpen | 0:9c28f5905a1a | 106 | } |
MikamiUitOpen | 0:9c28f5905a1a | 107 | |
MikamiUitOpen | 0:9c28f5905a1a | 108 | // シリアル・ポートの受信割込みに対する割り込みサービス・ルーチン |
MikamiUitOpen | 0:9c28f5905a1a | 109 | void RxIsr() |
MikamiUitOpen | 0:9c28f5905a1a | 110 | { |
MikamiUitOpen | 0:9c28f5905a1a | 111 | unsigned char chr = pc_.getc(); |
MikamiUitOpen | 0:9c28f5905a1a | 112 | // 受信した文字が '0' ~ '6' の場合のみ NCO の周波数を変える |
MikamiUitOpen | 0:9c28f5905a1a | 113 | if (('0' <= chr) && (chr <= '6')) |
MikamiUitOpen | 0:9c28f5905a1a | 114 | { |
MikamiUitOpen | 0:9c28f5905a1a | 115 | nco_.Set(F_C_[chr & 0x07]); |
MikamiUitOpen | 0:9c28f5905a1a | 116 | pc_.putc(chr); // エコーバック |
MikamiUitOpen | 0:9c28f5905a1a | 117 | } |
MikamiUitOpen | 0:9c28f5905a1a | 118 | if (chr == '\r') pc_.printf("\r\n"); |
MikamiUitOpen | 0:9c28f5905a1a | 119 | } |
MikamiUitOpen | 0:9c28f5905a1a | 120 | |
MikamiUitOpen | 0:9c28f5905a1a | 121 | int main() |
MikamiUitOpen | 0:9c28f5905a1a | 122 | { |
MikamiUitOpen | 0:9c28f5905a1a | 123 | InitialMessage("ダウンサンプリングに CIC フィルタと FIR フィルタを使用.", AM, pc_); |
MikamiUitOpen | 0:9c28f5905a1a | 124 | |
MikamiUitOpen | 0:9c28f5905a1a | 125 | NVIC_SetPriority(ADC_IRQn, 0); // 最優先 |
MikamiUitOpen | 0:9c28f5905a1a | 126 | NVIC_SetPriority(EXTI3_IRQn, 1); // 2番目に優先 |
MikamiUitOpen | 0:9c28f5905a1a | 127 | NVIC_SetPriority(USART2_IRQn, 2); // 3番目に優先 |
MikamiUitOpen | 0:9c28f5905a1a | 128 | NVIC_SetPriority(EXTI4_IRQn, 3); // 4番目に優先 |
MikamiUitOpen | 0:9c28f5905a1a | 129 | |
MikamiUitOpen | 0:9c28f5905a1a | 130 | // ADC に対する割り込みサービス・ルーチンの設定 |
MikamiUitOpen | 0:9c28f5905a1a | 131 | adc_.SetIntrVec(&AdcIsr); |
MikamiUitOpen | 0:9c28f5905a1a | 132 | |
MikamiUitOpen | 0:9c28f5905a1a | 133 | // EXTI3 によるソフトウェア割り込みに対応する設定 |
MikamiUitOpen | 0:9c28f5905a1a | 134 | NVIC_SetVector(EXTI3_IRQn, (uint32_t)IsrCIC); |
MikamiUitOpen | 0:9c28f5905a1a | 135 | NVIC_EnableIRQ(EXTI3_IRQn); |
MikamiUitOpen | 0:9c28f5905a1a | 136 | |
MikamiUitOpen | 0:9c28f5905a1a | 137 | // EXTI4 によるソフトウェア割り込みに対応する設定 |
MikamiUitOpen | 0:9c28f5905a1a | 138 | NVIC_SetVector(EXTI4_IRQn, (uint32_t)IsrFIR); |
MikamiUitOpen | 0:9c28f5905a1a | 139 | NVIC_EnableIRQ(EXTI4_IRQn); |
MikamiUitOpen | 0:9c28f5905a1a | 140 | |
MikamiUitOpen | 0:9c28f5905a1a | 141 | // シリアル・ポートの受信割込みの設定 |
MikamiUitOpen | 0:9c28f5905a1a | 142 | pc_.format(); // default: 8 bits, nonparity, 1 stop bit |
MikamiUitOpen | 0:9c28f5905a1a | 143 | pc_.attach(&RxIsr); |
MikamiUitOpen | 0:9c28f5905a1a | 144 | |
MikamiUitOpen | 0:9c28f5905a1a | 145 | while (true) {} |
MikamiUitOpen | 0:9c28f5905a1a | 146 | } |