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

Dependencies:   mbed

Files at this revision

API Documentation at this revision

Comitter:
MikamiUitOpen
Date:
Mon Sep 23 07:32:10 2019 +0000
Parent:
0:6906f8616429
Child:
2:4bec6b2be809
Commit message:
2

Changed in this revision

Cic3Stage.hpp Show diff for this revision Revisions of this file
SDR_Library/Cic3Stage.hpp Show annotated file Show diff for this revision Revisions of this file
SDR_Library/F446_ADC.cpp Show annotated file Show diff for this revision Revisions of this file
SDR_Library/F446_ADC.hpp Show annotated file Show diff for this revision Revisions of this file
SDR_Library/F446_ADC_Intr.hpp Show annotated file Show diff for this revision Revisions of this file
SDR_Library/F446_DAC.hpp Show annotated file Show diff for this revision Revisions of this file
SDR_Library/FastATan.hpp Show annotated file Show diff for this revision Revisions of this file
SDR_Library/FirFastSymmetry.hpp Show annotated file Show diff for this revision Revisions of this file
SDR_Library/Iir1st.hpp Show annotated file Show diff for this revision Revisions of this file
SDR_Library/IirDcCut.hpp Show annotated file Show diff for this revision Revisions of this file
SDR_Library/InitialMessage.hpp Show annotated file Show diff for this revision Revisions of this file
SDR_Library/QuadOscIir.hpp Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
--- a/Cic3Stage.hpp	Mon Sep 16 14:20:17 2019 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,58 +0,0 @@
-//-------------------------------------------------------------
-//  ダウンサンプリングで使う3段の CIC フィルタ用クラス
-//
-//  2019/04/30, Copyright (c) 2019 MIKAMI, Naoki
-//-------------------------------------------------------------
-
-#include "mbed.h"
-
-#ifndef CIC3_FILTER_CLASS_HPP
-#define CIC3_FILTER_CLASS_HPP
-
-namespace Mikami
-{
-    class Cic3Stage
-    {
-    public:
-        // コンストラクタ
-        //      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)
-        {
-            vn1_ += xn;     // 累算1段目
-            vn2_ += vn1_;   // 累算2段目
-            vn3_ += vn2_;   // 累算3段目
-        }
-
-        // 差分
-        float Difference()
-        {
-            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段目
-
-            return G0_*yn3;
-        }
-
-    private:
-        const float G0_;
-        int32_t vn1_, vn2_, vn3_;       // 累算で使う変数
-        int32_t vn3M1_, yn1M1_, yn2M1_; // 差分で使う変数
-
-        // コピー・コンストラクタ禁止のため
-        Cic3Stage(const Cic3Stage&);
-        // 代入演算子禁止のため
-        Cic3Stage& operator=(const Cic3Stage&);
-    };
-}
-#endif  // CIC3_FILTER_CLASS_HPP
-
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SDR_Library/Cic3Stage.hpp	Mon Sep 23 07:32:10 2019 +0000
@@ -0,0 +1,57 @@
+//-------------------------------------------------------------
+//  ダウンサンプリングで使う3段の CIC フィルタ用クラス
+//
+//  2019/04/30, Copyright (c) 2019 MIKAMI, Naoki
+//-------------------------------------------------------------
+
+#include "mbed.h"
+
+#ifndef CIC3_FILTER_CLASS_HPP
+#define CIC3_FILTER_CLASS_HPP
+
+namespace Mikami
+{
+    class Cic3Stage
+    {
+    public:
+        // コンストラクタ
+        //      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)
+        {
+            vn1_ += xn;     // 累算1段目
+            vn2_ += vn1_;   // 累算2段目
+            vn3_ += vn2_;   // 累算3段目
+        }
+
+        // 差分
+        float Difference()
+        {
+            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段目
+
+            return G0_*yn3;
+        }
+
+    private:
+        const float G0_;
+        int32_t vn1_, vn2_, vn3_;       // 累算で使う変数
+        int32_t vn3M1_, yn1M1_, yn2M1_; // 差分で使う変数
+
+        // コピー・コンストラクタ禁止のため
+        Cic3Stage(const Cic3Stage&);
+        // 代入演算子禁止のため
+        Cic3Stage& operator=(const Cic3Stage&);
+    };
+}
+#endif  // CIC3_FILTER_CLASS_HPP
--- a/SDR_Library/F446_ADC.cpp	Mon Sep 16 14:20:17 2019 +0000
+++ b/SDR_Library/F446_ADC.cpp	Mon Sep 23 07:32:10 2019 +0000
@@ -66,4 +66,3 @@
         TIM->CR1 = TIM_CR1_CEN;         // TIM8 を有効にする
     }
 }
-
--- a/SDR_Library/F446_ADC.hpp	Mon Sep 16 14:20:17 2019 +0000
+++ b/SDR_Library/F446_ADC.hpp	Mon Sep 23 07:32:10 2019 +0000
@@ -43,4 +43,3 @@
     };
 }
 #endif  // ADC_F446_POLLING_HPP
-
--- a/SDR_Library/F446_ADC_Intr.hpp	Mon Sep 16 14:20:17 2019 +0000
+++ b/SDR_Library/F446_ADC_Intr.hpp	Mon Sep 23 07:32:10 2019 +0000
@@ -43,4 +43,3 @@
     };
 }
 #endif  // ADC_F446_INTERRUPT_HPP
-
--- a/SDR_Library/F446_DAC.hpp	Mon Sep 16 14:20:17 2019 +0000
+++ b/SDR_Library/F446_DAC.hpp	Mon Sep 23 07:32:10 2019 +0000
@@ -4,6 +4,7 @@
 //
 //  2019/02/18, Copyright (c) 2019 MIKAMI, Naoki
 //--------------------------------------------------------
+
 #include "mbed.h"
 
 #ifndef DAC_F446_SINGLE_HPP
@@ -43,4 +44,3 @@
     };
 }
 #endif  // DAC_F446_SINGLE_HPP
-
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SDR_Library/FastATan.hpp	Mon Sep 23 07:32:10 2019 +0000
@@ -0,0 +1,77 @@
+//--------------------------------------------------------------
+//  高速低精度 arctan 計算
+//      係数はミニマックス近似で求めたもの
+//      ただし,誤差は絶対誤差で評価した
+//
+//  2019/09/18, Copyright (c) 2019 MIKAMI, Naoki
+//--------------------------------------------------------------
+
+#include "mbed.h"
+
+#ifndef FAST_ARCTAN_LOW_PRECISION_HPP
+#define FAST_ARCTAN_LOW_PRECISION_HPP
+
+namespace Mikami
+{
+    inline float ATanPoly(float x);
+    
+    // 引数の与え方は,atan2() と同じ
+    float FastATan(float y, float x)
+    {
+        static const float PI    = 3.1415926536f;  // π
+        static const float PI_4  = PI/4.0f;        // π/4
+        static const float PI3_4 = 3.0f*PI/4.0f;   // 3π/4
+        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;        // π
+        }
+        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 (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                // π/4 <|θ|<3π/4
+        {
+            float u = ATanPoly(x/y);
+            if (y > 0.0f) return -u + PI_2;
+            else          return -u - PI_2;
+        }
+    }
+
+    inline float ATanPoly(float x)
+    {
+        static const float A1 =  0.9992138f;    // a1
+        static const float A3 = -0.3211750f;    // a3
+        static const float A5 =  0.1462645f;    // a5
+        static const float A7 = -0.03898651f;   // a7
+        
+        float x2 = x*x;
+        float atanx = (((A7*x2 + A5)*x2 + A3)*x2 + A1)*x;
+        
+        return atanx;
+    }
+}
+#endif  // FAST_ARCTAN_LOW_PRECISION_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SDR_Library/FirFastSymmetry.hpp	Mon Sep 23 07:32:10 2019 +0000
@@ -0,0 +1,55 @@
+//-----------------------------------------------------------------
+// SDR で使う FIR フィルタ,係数:対称
+//      ● 処理の高速化のため,入力信号のバッファのサイズを 256,データを指す
+//        インデックスを uint8_t 型としてリング・バッファを実現している.
+//      ● さらに,係数が対称であることを利用して,先に x[k] + x[ORDER-k] と
+//        いう加算を行ってから,係数の乗算を行うようにした.
+//
+// 2019/03/03, Copyright (c) 2019 MIKAMI, Naoki
+//-----------------------------------------------------------------
+
+#include "mbed.h"
+
+#ifndef FIR_DIRECT_FAST_SYMMETRY_HPP
+#define FIR_DIRECT_FAST_SYMMETRY_HPP
+namespace Mikami
+{
+    class FirFastSymmetry
+    {
+    public:
+        // コンストラクタ
+        //      order   フィルタの次数
+        //      hk[]    フィルタの係数
+        FirFastSymmetry(int order, const float hk[])
+            : ORDER_(order), hm_(hk), index_(255)
+        {   for (int k=0; k<SIZE_; k++) un_[k] = 0; }
+
+        // 入力信号をバッファへ書き込む
+        void Store(float xIn) { un_[++index_] = xIn; }
+
+        // FIR フィルタの実行
+        float Execute()
+        {
+            __IO uint8_t ptrM = index_;
+            __IO uint8_t ptrP = index_ - ORDER_;
+            float acc = 0;
+            for (int k=0; k<ORDER_/2; k++)
+                acc += hm_[k]*(un_[ptrM--] + un_[ptrP++]);
+            acc += hm_[ORDER_/2]*un_[ptrM];
+            return acc;
+        }
+
+    private:
+        static const int SIZE_ = 256;   // 入力信号のバッファのサイズ
+        const int ORDER_;               // フィルタの次数
+        const float *const hm_;         // フィルタの係数
+        float un_[SIZE_];               // 入力信号のバッファ
+        __IO uint8_t index_;            // 最新の入力信号を示すインデックス
+
+        // コピー・コンストラクタ禁止のため
+        FirFastSymmetry(const FirFastSymmetry&);
+        // 代入演算子禁止のため
+        FirFastSymmetry& operator=(const FirFastSymmetry&);
+    };
+}
+#endif  // FIR_DIRECT_FAST_SYMMETRY_HPP
--- a/SDR_Library/Iir1st.hpp	Mon Sep 16 14:20:17 2019 +0000
+++ b/SDR_Library/Iir1st.hpp	Mon Sep 23 07:32:10 2019 +0000
@@ -1,7 +1,8 @@
 //-----------------------------------------------------------------
 // 一次の IIR フィルタ
+//      y[n] = a1*y[n-1] + (1 - a1)*x[n]
 //
-// 2019/09/03, Copyright (c) 2019 MIKAMI, Naoki
+// 2019/09/21, Copyright (c) 2019 MIKAMI, Naoki
 //-----------------------------------------------------------------
 
 #include "mbed.h"
@@ -36,4 +37,3 @@
     };
 }
 #endif  // IIR_1ST_HPP
-
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SDR_Library/IirDcCut.hpp	Mon Sep 23 07:32:10 2019 +0000
@@ -0,0 +1,44 @@
+//-----------------------------------------------------------------
+// 直流分除去用 IIR フィルタ
+//      u[n] = a1*u[n-1] + x[n]
+//      y[n] = g0*(u[n] - u[n-1])
+//
+// 2019/09/21, Copyright (c) 2019 MIKAMI, Naoki
+//-----------------------------------------------------------------
+
+#include "mbed.h"
+
+#ifndef IIR_DC_CUT_HPP
+#define IIR_DC_CUT_HPP
+namespace Mikami
+{
+    class IirDcCut
+    {
+    public:
+        // コンストラクタ
+        //      a1  フィルタの係数
+        //      g0  利得定数
+        IirDcCut(float a1, float g0)
+            : A1_(a1), G0_(g0) { un1_ = 0; }
+
+        // フィルタの実行
+        float Execute(float xn)
+        {
+            float un = A1_*un1_ + xn;
+            float yn = (un - un1_)*G0_;
+            un1_ = un;
+            return yn;
+        }
+
+    private:
+        const float A1_;        // フィルタ係数
+        const float G0_;        // 利得定数
+        float un1_;             // 中間の値
+
+        // コピー・コンストラクタ禁止のため
+        IirDcCut(const IirDcCut&);
+        // 代入演算子禁止のため
+        IirDcCut& operator=(const IirDcCut&);
+    };
+}
+#endif  // IIR_DC_CUT_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SDR_Library/InitialMessage.hpp	Mon Sep 23 07:32:10 2019 +0000
@@ -0,0 +1,42 @@
+//-------------------------------------------------------------
+//  実行開始時のターミナルへメッセージの送信
+//
+//  2019/09/17, Copyright (c) 2019 MIKAMI, Naoki
+//-------------------------------------------------------------
+
+#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行目に表示するメッセージ
+//      af      メーッセージが AM 用か FM 用かを指定
+//      sp      メーッセージを出力するシリアルポート
+void InitialMessage(string str, AmFm af, Serial &sp)
+{
+    sp.printf("\r\n");
+    if (af == AM)
+    {
+        sp.printf("SDR で AM 放送を受信します.\r\n");
+        sp.printf((str + "\r\n").c_str());
+        sp.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");
+        sp.printf("'0' ~ '6' のキーで選局できます.\r\n");
+        sp.printf("'0' ~ '6', 'Enter' キー以外は何も反応しません.\r\n");
+    }
+    else
+    {
+        sp.printf("\r\nSDR で FM 復調を実行します.\r\n");
+        sp.printf((str + "\r\n").c_str());
+        sp.printf("0 か 1 を入力してください.\r\n");
+        sp.printf("'0', '1', 'Enter' キー以外は何も反応しません.\r\n");
+    }
+    
+    sp.printf("'Enter' キーは CR/LF するだけです.\r\n\n");
+    sp.putc('0');
+}
+#endif  // INITIAL_MESSAGE_HPP
--- a/SDR_Library/QuadOscIir.hpp	Mon Sep 16 14:20:17 2019 +0000
+++ b/SDR_Library/QuadOscIir.hpp	Mon Sep 23 07:32:10 2019 +0000
@@ -71,4 +71,3 @@
     };
 }
 #endif  // QUAD_PHASE_OSC_IIR_HPP
-
--- a/main.cpp	Mon Sep 16 14:20:17 2019 +0000
+++ b/main.cpp	Mon Sep 23 07:32:10 2019 +0000
@@ -1,13 +1,12 @@
 //-------------------------------------------------------------
-//  中波 AM 放送用 SDR
+//  中波 AM 放送用 SDR,CIC フィルタを使用
+//
+//      ダウンサンプリング(1/90)で使う LPF として CIC フィルタを使用
+//
 //      入力ピン: A1
 //      出力ピン: A2
 //
-//  ダウンサンプリングで使う LPF として CIC フィルタを使用
-//  CIC フィルタの段数:3段
-//  CIC フィルタをクラスにする
-//
-//  2019/09/16, Copyright (c) 2019 MIKAMI, Naoki
+//  2019/09/18, Copyright (c) 2019 MIKAMI, Naoki
 //-------------------------------------------------------------
 
 #include "F446_ADC_Intr.hpp"    // ADC
@@ -15,6 +14,7 @@
 #include "QuadOscIir.hpp"       // 二相発振器
 #include "Cic3Stage.hpp"        // 3段 CIC フィルタ
 #include "Iir1st.hpp"           // 一次の IIR フィルタ
+#include "InitialMessage.hpp"   // 最初のメーッセージ
 using namespace Mikami;
 #pragma diag_suppress 870   // マルチバイト文字使用の警告抑制のため
 
@@ -97,14 +97,7 @@
 
 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');
+    InitialMessage("ダウンサンプリングに CIC フィルタ使用.", AM, pc_);
 
     NVIC_SetPriority(ADC_IRQn,    0);   // 最優先
     NVIC_SetPriority(EXTI4_IRQn,  1);   // 2番目に優先