不韋 呂
/
SDR_AM_Rx_CIC
AM中波放送用SDR.CICフィルタのみを使用.CQ出版社「トランジスタ技術」誌,2021年4月号に掲載
Diff: main.cpp
- Revision:
- 0:6906f8616429
- Child:
- 1:30d9fb51dec1
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.cpp Mon Sep 16 14:20:17 2019 +0000 @@ -0,0 +1,125 @@ +//------------------------------------------------------------- +// 中波 AM 放送用 SDR +// 入力ピン: A1 +// 出力ピン: A2 +// +// ダウンサンプリングで使う LPF として CIC フィルタを使用 +// CIC フィルタの段数:3段 +// CIC フィルタをクラスにする +// +// 2019/09/16, Copyright (c) 2019 MIKAMI, Naoki +//------------------------------------------------------------- + +#include "F446_ADC_Intr.hpp" // ADC +#include "F446_DAC.hpp" // DAC +#include "QuadOscIir.hpp" // 二相発振器 +#include "Cic3Stage.hpp" // 3段 CIC フィルタ +#include "Iir1st.hpp" // 一次の IIR フィルタ +using namespace Mikami; +#pragma diag_suppress 870 // マルチバイト文字使用の警告抑制のため + +const float FS_ = 900.0f; // 標本化周波数,単位: kHz +const float T0_ = 1000/FS_; // 標本化間隔,単位:μs +const float A0_ = 8192; // 二相発振器の出力の振幅 + +// 各放送局の搬送波の周波数,単位: kHz +const float F_C_[] = { 594.0e3f, // NHK 第1 + 693.0e3f, // NHK 第2 + 810.0e3f, // AFN Tokyo + 954.0e3f, // TBS ラジオ + 1134.0e3f, // 文化放送 + 1242.0e3f, // ニッポン放送 + 1422.0e3f}; // ラジオ日本 + +AdcF446_Intr adc_(FS_, A1); // ADC オブジェクトの宣言 +DacF446 dac_; // DAC オブジェクトの宣言 +Serial pc_(USBTX, USBRX); // ターミナルに対する受信割込み用 + +QuadOscIir nco_(F_C_[0], T0_, A0_); // NCO (numerically controlled oscillator) + +Iir1st comp_(-0.525f); // CIC フィルタの補償用フィルタ +Iir1st averaging_(0.9995f); // 直流分を求めるためのフィルタ + +const int DS_RATE_ = 90; // 1/90 にダウンサンプリング +Cic3Stage cic3I_(DS_RATE_, A0_); // CIC フィルタ,I 信号用 +Cic3Stage cic3Q_(DS_RATE_, A0_); // CIC フィルタ,Q 信号用 + +// AD 変換終了割り込みに対する割り込みサービス・ルーチン +void AdcIsr() +{ + static int count = 0; + + float xn = adc_.Read(); // ADC の読込み + 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 信号用 + + if (++count >= DS_RATE_) + { + count = 0; + NVIC->STIR |= EXTI4_IRQn; // ソフトウェア割り込み発生 + } +} + +// ダウンサンプラより後の処理に対する割り込みサービス・ルーチン +void SwiIsr() +{ + // CIC フィルタの差分処理 + float yI_n = cic3I_.Difference(); // 差分処理で I 信号を生成 + float yQ_n = cic3Q_.Difference(); // 差分処理で Q 信号を生成 + + float yn = sqrtf(yI_n*yI_n + yQ_n*yQ_n); // 包絡線成分を求める + yn = comp_.Execute(yn); // 補償フィルタ + float dc = averaging_.Execute(yn); // 直流分を求める + + float gain = 0.8f/dc; // AGC 処理の準備 + if (gain > 200.0f) gain = 200.0f; + + // DAC への出力は,直流分を除去し,AGC 処理をしたもの + dac_.Write(gain*(yn - dc)); +} + +// シリアル・ポートの受信割込みに対する処理 +void RxIsr() +{ + unsigned char chr = pc_.getc(); + // 受信した文字が '0' ~ '6' の場合のみ NCO の周波数を変える + if (('0' <= chr) && (chr <= '6')) + { + nco_.Set(F_C_[chr & 0x07]); + pc_.putc(chr); // エコーバック + } + if (chr == '\r') pc_.printf("\r\n"); +} + +int main() +{ + printf("\r\n"); + printf("SDR (CIC フィルタ使用) を実行します.\r\n"); + printf("0: NHK 第1\r\n1: NHK 第2\r\n2: AFN Tokyo\r\n3: TBS ラジオ\r\n" + "4: 文化放送\r\n5: ニッポン放送\r\n6: ラジオ日本\r\n\n"); + printf("'0' ~ '6' のキーで選局できます.\r\n"); + printf("'Enter' キーは CR/LF するだけです.\r\n"); + printf("'0' ~ '6', 'Enter' キー以外は何も反応しません.\r\n\n"); + pc_.putc('0'); + + NVIC_SetPriority(ADC_IRQn, 0); // 最優先 + NVIC_SetPriority(EXTI4_IRQn, 1); // 2番目に優先 + NVIC_SetPriority(USART2_IRQn, 2); + + // ADC に対する割り込みサービス・ルーチンの設定 + adc_.SetIntrVec(&AdcIsr); + + // EXTI4 によるソフトウェア割り込みに対応する設定 + NVIC_SetVector(EXTI4_IRQn, (uint32_t)SwiIsr); + NVIC_EnableIRQ(EXTI4_IRQn); + + // シリアル・ポートの受信割込みの設定 + pc_.format(); // default: 8 bits, nonparity, 1 stop bit + pc_.attach(&RxIsr); + + while (true) {} +}