ファンクション・ジェネレータ

Dependencies:   mbed SerialTxRxIntr MyTicker7 Array_Matrix

Files at this revision

API Documentation at this revision

Comitter:
MikamiUitOpen
Date:
Sat Oct 17 10:05:58 2020 +0000
Child:
1:ea5aa7f3d68c
Commit message:
1

Changed in this revision

CoefficientsIIR_Cascade.hpp Show annotated file Show diff for this revision Revisions of this file
F446_DAC.cpp Show annotated file Show diff for this revision Revisions of this file
F446_DAC.hpp Show annotated file Show diff for this revision Revisions of this file
FastSin.hpp Show annotated file Show diff for this revision Revisions of this file
IIR_Cascade/Array_Matrix.lib Show annotated file Show diff for this revision Revisions of this file
IIR_Cascade/Biquad.cpp Show annotated file Show diff for this revision Revisions of this file
IIR_Cascade/Biquad.hpp Show annotated file Show diff for this revision Revisions of this file
IIR_Cascade/IIR_Cascade.cpp Show annotated file Show diff for this revision Revisions of this file
IIR_Cascade/IIR_Cascade.hpp Show annotated file Show diff for this revision Revisions of this file
MSeq16.hpp Show annotated file Show diff for this revision Revisions of this file
MyTicker7.lib Show annotated file Show diff for this revision Revisions of this file
SerialTxRxIntr.lib 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
mbed.bld Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CoefficientsIIR_Cascade.hpp	Sat Oct 17 10:05:58 2020 +0000
@@ -0,0 +1,21 @@
+//----------------------------------------------------------------------
+//  IIR フィルタの係数,縦続形,float 型
+//
+//  2020/10/17, Copyright (c) 2020 MIKAMI, Naoki
+//----------------------------------------------------------------------
+
+#include "Biquad.hpp"
+using namespace Mikami;
+
+// 低域通過フィルタ
+// 連立チェビシェフ特性
+// 次数    : 4 次
+// 標本化周波数:400.00 kHz
+// 遮断周波数 : 20.00 kHz
+// 通過域のリップル: 0.50 dB
+// 阻止域の減衰量 :40.00 dB
+const int ORDER_ = 4;
+const Biquad::Coefs hk_[] = {
+    { 1.712306E+00f, -7.512093E-01f, -9.111378E-01f, 1.0f},
+    { 1.819915E+00f, -9.194769E-01f, -1.719255E+00f, 1.0f}};
+const float G0_ = 1.196187E-02f;    // 利得定数
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/F446_DAC.cpp	Sat Oct 17 10:05:58 2020 +0000
@@ -0,0 +1,28 @@
+//-------------------------------------------------------------
+//  STM32F446 内蔵の DAC 用のクラス
+//      DAC_OUT1: A2  (PA_4)
+//      DAC_OUT2: D13 (PA_5)
+//
+//  2020/10/17, Copyright (c) 2020 MIKAMI, Naoki
+//-------------------------------------------------------------
+
+#include "F446_DAC.hpp"
+
+namespace Mikami
+{
+    DacF446::DacF446(PinName pin) : da_(pin)
+    {
+        MBED_ASSERT((pin == A2) || (pin == D13));
+
+        if (pin == A2)
+        {
+            DAC->CR = DAC_CR_EN1;
+            fpWriteDac = &DacF446::WriteDac1;
+        }
+        else
+        {
+            DAC->CR = DAC_CR_EN2;
+            fpWriteDac = &DacF446::WriteDac2;
+        }
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/F446_DAC.hpp	Sat Oct 17 10:05:58 2020 +0000
@@ -0,0 +1,57 @@
+//-------------------------------------------------------------
+//  STM32F446 内蔵の DAC 用のクラス(ヘッダ)
+//      選択可能な入力端子:
+//          A2  (PA_4): ---- デフォルト
+//          D13 (PA_5): このポートはマイコンボードの LED も
+//                       ドライブするので使わない方がよい
+//
+//  2020/10/17, Copyright (c) 2020 MIKAMI, Naoki
+//-------------------------------------------------------------
+
+#include "mbed.h"
+
+#ifndef STM32F446xx
+#error Not NUCLEO-F446RE.
+#endif
+
+#ifndef F446_DAC_SINGLE_HPP
+#define F446_DAC_SINGLE_HPP
+
+namespace Mikami
+{
+    class DacF446
+    {
+    public:
+        // コンストラクタ
+        explicit DacF446(PinName pin = A2);
+
+        virtual ~DacF446() {}
+
+        // -1.0f <= data <= 1.0f
+        void Write(float data) { WriteDac(ToUint16(data)); }
+
+        // 0 <= data <= 4095
+        void Write(uint16_t data) { WriteDac(__USAT(data, BIT_WIDTH_)); }
+
+    private:
+        void (DacF446::*fpWriteDac)(uint16_t);
+
+        static const int BIT_WIDTH_ = 12;
+        AnalogOut da_;
+
+        // DAC の片方のチェンネルへ出力する
+        void WriteDac1(uint16_t val) { DAC->DHR12R1 = val; }    // CH1 へ
+        void WriteDac2(uint16_t val) { DAC->DHR12R2 = val; }    // CH2 へ
+        
+        void WriteDac(uint16_t val) { (this->*fpWriteDac)(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  // F446_DAC_SINGLE_HPP
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/FastSin.hpp	Sat Oct 17 10:05:58 2020 +0000
@@ -0,0 +1,26 @@
+//-----------------------------------------------------------
+//  FastSin() 関数
+//      sin(π/2)x) の値の計算
+//
+//  2020/06/01, Copyright (c) 2020 MIKAMI, Naoki
+//-----------------------------------------------------------
+
+#ifndef FASTSIN_POLYNOMIAL_HPP
+#define FASTSIN_POLYNOMIAL_HPP
+
+namespace Mikami
+{
+    // 引数の範囲: -2 <= x <= 2
+    inline float FastSin(float x)
+    {
+        static const float A1 =  1.570320019210f;
+        static const float A3 = -0.642113166941f;
+        static const float A5 =  0.071860854119f;
+
+        if (x >  1.0f) x =  2.0f - x;
+        if (x < -1.0f) x = -2.0f - x;
+        float x2 = x*x;
+        return ((A5*x2 + A3)*x2 + A1)*x;
+    }
+}
+#endif  // FASTSIN_POLYNOMIAL_HPP
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/IIR_Cascade/Array_Matrix.lib	Sat Oct 17 10:05:58 2020 +0000
@@ -0,0 +1,1 @@
+https://os.mbed.com/users/MikamiUitOpen/code/Array_Matrix/#d9dea7748b27
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/IIR_Cascade/Biquad.cpp	Sat Oct 17 10:05:58 2020 +0000
@@ -0,0 +1,41 @@
+//--------------------------------------------------------------
+// 縦続形 IIR フィルタの構成要素として使う 2 次の IIR フィルタ
+//      b0 は 1 と仮定している
+//
+// 2020/02/12, Copyright (c) 2020 MIKAMI, Naoki
+//--------------------------------------------------------------
+
+#include "Biquad.hpp"
+
+namespace Mikami
+{
+    // デフォルト・コンストラクタ
+    //      係数は構造体 Ceofs で与える
+    Biquad::Biquad(const Coefs ck)
+        : a1_(ck.a1), a2_(ck.a2), b1_(ck.b1), b2_(ck.b2) { Clear(); }       
+
+    // 係数を個別に与えるコンストラクタ
+    Biquad::Biquad(float a1, float a2, float b1, float b2)
+        : a1_(a1), a2_(a2), b1_(b1), b2_(b2) { Clear(); }
+
+    // 2 次のフィルタを実行する
+    float Biquad::Execute(float xn)
+    {
+        float un = xn + a1_*un1_ + a2_*un2_;
+        float yn = un + b1_*un1_ + b2_*un2_;
+    
+        un2_ = un1_;
+        un1_ = un;
+
+        return yn;
+    }
+
+    // 係数を設定する
+    void Biquad::SetCoefs(const Coefs ck)
+    {
+        a1_ = ck.a1;
+        a2_ = ck.a2;
+        b1_ = ck.b1;
+        b2_ = ck.b2;
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/IIR_Cascade/Biquad.hpp	Sat Oct 17 10:05:58 2020 +0000
@@ -0,0 +1,45 @@
+//--------------------------------------------------------------
+// 縦続形 IIR フィルタの構成要素として使う 2 次の IIR フィルタ(ヘッダ)
+//      b0 は 1 と仮定している
+//
+// 2020/02/12, Copyright (c) 2020 MIKAMI, Naoki
+//--------------------------------------------------------------
+
+#ifndef IIR_BIQUAD_HPP
+#define IIR_BIQUAD_HPP
+
+#include "mbed.h"
+
+namespace Mikami
+{
+    class Biquad
+    {
+    public:
+        // フィルタの係数をまとめて扱うための構造体
+        struct Coefs { float a1, a2, b1, b2; };
+
+        // デフォルト・コンストラクタ
+        //      係数は構造体 Ceofs で与える
+        Biquad(const Coefs ck = (Coefs){0, 0, 0, 0});
+
+        // 係数を個別に与えるコンストラクタ
+        Biquad(float a1, float a2, float b1, float b2);
+
+        // 2 次のフィルタを実行する
+        float Execute(float xn);
+
+        // 係数を設定する
+        void SetCoefs(const Coefs ck);
+
+        // 内部変数(遅延器)のクリア
+        void Clear() { un1_ = un2_ = 0; }
+
+    private:
+        float a1_, a2_, b1_, b2_;
+        float un1_, un2_;
+
+        // コピー・コンストラクタ禁止のため
+        Biquad(const Biquad&);
+    };
+}
+#endif  // IIR_BIQUAD_HPP
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/IIR_Cascade/IIR_Cascade.cpp	Sat Oct 17 10:05:58 2020 +0000
@@ -0,0 +1,40 @@
+//---------------------------------------------------
+//  縦続形 IIR フィルタ
+//
+// 2020/05/30, Copyright (c) 2020 MIKAMI, Naoki
+//---------------------------------------------------
+
+#include "IIR_Cascade.hpp"
+
+namespace Mikami
+{
+    // コンストラクタ
+    IirCascade::IirCascade(int order, const Biquad::Coefs ck[], float g0)
+    {   
+        SetCoefs(order, ck, g0);
+        Clear();
+    }
+
+    // フィルタ処理を実行する
+    float IirCascade::Execute(float xn)
+    {
+        float yn = g0_*xn;
+        for (int k=0; k<hOrder_; k++) yn = bq_[k].Execute(yn);
+        return yn;
+    }
+
+    // 係数の設定
+    void IirCascade::SetCoefs(int order, const Biquad::Coefs ck[], float g0)
+    {
+            printf("SetCoefs called!\r\n");
+        if (hOrder_ != ((order+1)>>1))
+        {
+            hOrder_ = (order+1)>>1;
+            bq_.SetSize(hOrder_);
+            Clear();
+                printf("Order changed!\r\n");
+        }
+        g0_ = g0;
+        for (int k=0; k<hOrder_; k++) bq_[k].SetCoefs(ck[k]);
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/IIR_Cascade/IIR_Cascade.hpp	Sat Oct 17 10:05:58 2020 +0000
@@ -0,0 +1,42 @@
+//---------------------------------------------------
+//  縦続形 IIR フィルタ(ヘッダ)
+//
+// 2020/05/30, Copyright (c) 2020 MIKAMI, Naoki
+//---------------------------------------------------
+
+#ifndef IIR_CASCADE_HPP
+#define IIR_CASCADE_HPP
+
+#include "Biquad.hpp"
+#include "Array.hpp"    // Array クラスが定義されている
+
+namespace Mikami
+{
+    class IirCascade
+    {
+    public:
+        // コンストラクタ
+        IirCascade(int order = 0, const Biquad::Coefs ck[] = NULL,
+                   float g0 = 1);
+
+        // フィルタ処理を実行する
+        float Execute(float xn);
+
+        // 係数の設定
+        void SetCoefs(int order, const Biquad::Coefs ck[], float g0);
+
+        // 内部変数(遅延器)のクリア
+        void Clear()
+        {   for (int k=0; k<hOrder_; k++) bq_[k].Clear(); }
+
+    private:
+        int hOrder_;        // 次数/2
+        Array<Biquad> bq_;  // Biquad クラスのオブジェクトの配列
+        float g0_;          // 利得定数
+
+        // コピー・コンストラクタ,代入演算子禁止禁止のため
+        IirCascade(const IirCascade&);
+        IirCascade& operator=(const IirCascade&);
+    };
+}
+#endif  // IIR_CASCADE_HPP
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MSeq16.hpp	Sat Oct 17 10:05:58 2020 +0000
@@ -0,0 +1,42 @@
+//---------------------------------------------------------
+//  M 系列信号発生器(N = 16)
+//
+//  2020/10/17, Copyright (c) 2020 MIKAMI, Naoki
+//---------------------------------------------------------
+
+#include "mbed.h"
+
+#ifndef MSEQ16_HPP
+#define MSEQ16_HPP
+
+namespace Mikami
+{
+    class MSeq16
+    {
+    public:
+        MSeq16() : reg_(1) {}
+
+        // 戻り値: 1 => 1, 0 => -1
+        int Execute()
+        {
+            if ((reg_ & B_M_) == B_M_)
+            {
+                reg_ = ((reg_ ^ XOR_) << 1) | 1;    // 1 の場合の処理
+                return 1;
+            }
+            else
+            {
+                reg_ = reg_ << 1;                   // 0 の場合の処理
+                return -1;
+            }
+        }
+    private:
+        static const uint16_t XOR_ = (1 << (2-1))
+                                   | (1 << (3-1))
+                                   | (1 << (5-1));  // XOR の位置に対応する定数
+        static const uint16_t B_M_ = 1 << (16-1);   // 16 段目に相当するビットを調べる
+        
+        uint16_t reg_;
+    };
+}
+#endif  // MSEQ16_HPP
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MyTicker7.lib	Sat Oct 17 10:05:58 2020 +0000
@@ -0,0 +1,1 @@
+https://os.mbed.com/users/MikamiUitOpen/code/MyTicker7/#f4269105fae0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SerialTxRxIntr.lib	Sat Oct 17 10:05:58 2020 +0000
@@ -0,0 +1,1 @@
+https://os.mbed.com/users/MikamiUitOpen/code/SerialTxRxIntr/#deeef404ff49
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Sat Oct 17 10:05:58 2020 +0000
@@ -0,0 +1,151 @@
+//----------------------------------------------------------------------
+//  ファンクション・ジェネレータ (Nucleo-F446RE 用)
+//
+//  設定できる項目
+//      波形の種類:  正弦波,矩形波,合成矩形波(フーリエ級数の5倍波までの和)
+//      振幅:         0.00 ~ 1.00 倍
+//      周波数:       10 Hz ~ 10 kHz
+//      ノイズ付加の有無
+//  標本化間隔:2.5 μs
+//  使用タイマ:TIM7
+//  信号出力のピン:      A2
+//  同期信号出力のピン:  A5
+//
+//  このプログラムの前のバージョン:F446_FunctionGenerator_7
+//
+//  PC 側のプログラム
+//      F446_FunctionGenerator
+//
+//  注意
+//      PC から送信されるコマンド等が不正かどうかはチェックしていない
+//
+//  2020/10/17, Copyright (c) 2020 MIKAMI, Naoki
+//----------------------------------------------------------------------
+
+#include "F446_DAC.hpp"
+#include "SerialRxTxIntr.hpp"
+#include "MyTicker7.hpp"
+#include "FastSin.hpp"
+#include "MSeq16.hpp"
+#include "IIR_Cascade.hpp"
+#include "CoefficientsIIR_Cascade.hpp"
+#include  <cctype>          // isalpha() で使用
+#pragma diag_suppress 870   // マルチバイト文字使用の警告抑制のため
+
+using namespace Mikami;
+                        
+const float T0_ = 2.5f;         // 出力の標本化間隔: 2.5 μs
+const float TS_ = T0_*1.0e-6f;
+const float C0_ = 4.0f;
+const float C0_2_ = C0_/2.0f;
+
+DacF446 dac_;                   // DA 変換器オブジェクト
+MyTicker7 timer_(T0_);          // タイマ割り込み用クラスのオブジェクト,TIM7 を利用
+SerialRxTxIntr rxTx_;           // Serial クラスの受送信割込み用オブジェクト
+DigitalOut syncOut_(A5);        // 同期信号出力用
+
+float phi_ = 0;
+float dPhi_ = C0_*1000*TS_;     // 周波数決める変数,開始時は 1 kHz;
+float volume_ = 0.5f;           // 出力の振幅を決める変数,開始時は 0.5
+bool sw_ = false;               // 出力 ON/OFF のスイッチ,開始時は off
+float volNoize_ = 0.5f;         // ノイズの大きさを決める変数
+
+// ノイズ付加に関する関数等
+MSeq16 mSeq_;
+IirCascade filter_(ORDER_, hk_, G0_);
+float Noise() { return volNoize_*filter_.Execute(0.5f*mSeq_.Execute()); }
+float NoiseFree() { return 0; }
+float (*fpNoize[])() = { Noise, NoiseFree };
+float (*fpN)() = fpNoize[1];    // 起動時はノイズなし 
+
+// 発生する信号を定義する関数
+// 正弦波
+float Sin(float sinx) { return volume_*sinx + fpN(); }
+// 矩形波
+float Rect(float sinx)
+{
+    float x = (sinx >= 0) ? volume_ : -volume_;
+    return x + volNoize_*fpN();
+}
+// 矩形波(5倍波まで)
+float Compo(float sinx)
+{
+    static const float ONE_3 = 1.0f/3.0f;   // フーリエ合成で使用
+    static const float ONE_5 = 0.2f;        // フーリエ合成で使用
+
+    float sinx2 = sinx*sinx;
+    float sin3x = (-4.0f*sinx2 + 3.0f)*sinx;
+    float sin5x = ((16.0f*sinx2 - 20.0f)*sinx2 + 5.0f)*sinx;
+
+    return volume_*(sinx + ONE_3*sin3x + ONE_5*sin5x) + fpN();
+}
+
+float (*fp[])(float x) = { Sin, Rect, Compo };
+float (*fpS)(float x) = fp[0];  // 起動時は正弦波
+
+// タイマ割り込みに対する割込みサービス・ルーチン
+void TimerIsr()
+{
+    float sinx = FastSin(phi_); // 基本波発生
+    float yn = fpS(sinx);       // 指定した信号を発生
+    
+    // 同期信号出力
+    syncOut_ = (sinx >= 0) ? 1 : 0;
+
+    if (sw_) dac_.Write(yn);    // 出力:ON
+    else     dac_.Write(0.0f);  // 出力:OFF
+
+    phi_ += dPhi_;
+    if (phi_ >= C0_2_) phi_ = phi_ - C0_;   // オーバーフロー防止
+}
+
+int main()
+{
+    // 以下の割り込み優先順位の設定を忘れないこと
+    NVIC_SetPriority(TIM7_IRQn, 0);
+    NVIC_SetPriority(USART2_IRQn, 1);   // USART2 割り込み:次に優先
+
+    timer_.Attach(&TimerIsr);       // タイマ割り込み設定
+    
+    while (true)    // PC からの指令に対応する処理
+    {
+        if (rxTx_.IsEol())          // 受信バッファのデータが有効になった場合の処理
+        {
+            string str = rxTx_.GetBuffer();
+            for (int n=0; n<str.size(); n++) str[n] = toupper(str[n]);
+            if (isalpha(str[0]))    // 先頭が A ~ Z, a ~ z の場合
+            {
+                if (str == "FG")
+                    rxTx_.TxString("ACK\n");    // PC からの "FG" に対して "ACK" を送信する
+
+                if (str == "ON")    sw_ = true;
+                if (str == "OFF")   sw_ = false;  
+
+                if (str == "SIN")   fpS = fp[0];
+                if (str == "RECT")  fpS = fp[1];
+                if (str == "COMPO") fpS = fp[2];
+
+                if (str == "NSON")  fpN = fpNoize[0];
+                if (str == "NSOFF") fpN = fpNoize[1];
+            }
+            else                    // 先頭が A ~ Z, a ~ z 以外の場合
+            {
+                char c1 = str[0];   // 先頭の文字を取得
+                float x = atof(str.substr(1, str.size()-1).c_str());
+                if (x >= 0.0f)
+                {
+                    if (c1 == '#')              // 出力振幅の変更
+                        volume_ = x*0.9f;
+                    if (c1 == '$')              // 周波数の変更
+                    {
+                        x = (x < 10) ? 10 : x;
+                        x = (x > 10000) ? 10000 : x;
+                        dPhi_ = C0_*x*TS_;
+                    }
+                    if (c1 == '%')              // ノイズの大きさの変更
+                        volNoize_ = (x < 1.0f) ? x : 1.0f;
+                }
+            }
+        }
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Sat Oct 17 10:05:58 2020 +0000
@@ -0,0 +1,1 @@
+https://os.mbed.com/users/mbed_official/code/mbed/builds/3a7713b1edbc
\ No newline at end of file