AM中波放送用SDR.CICフィルタのみを使用.CQ出版社「トランジスタ技術」誌,2021年4月号に掲載

Dependencies:   mbed

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) {}
+}