Frequency shifter for DISCO-F746. Input: MEMS mic, Output: CN10 OUT. DISCO-F746 による周波数シフタ.入力:MEMS マイク,出力:CN10 OUT

Dependencies:   F746_GUI F746_SAI_IO mbed

Files at this revision

API Documentation at this revision

Comitter:
MikamiUitOpen
Date:
Mon Mar 19 03:19:35 2018 +0000
Child:
1:af3546588b73
Commit message:
1

Changed in this revision

F746_GUI.lib Show annotated file Show diff for this revision Revisions of this file
F746_SAI_IO.lib Show annotated file Show diff for this revision Revisions of this file
MyAcousticEffector_MIC/Biquad.hpp Show annotated file Show diff for this revision Revisions of this file
MyAcousticEffector_MIC/DC_Cut_Coefficients.hpp Show annotated file Show diff for this revision Revisions of this file
MyAcousticEffector_MIC/FrequencyShifter.hpp Show annotated file Show diff for this revision Revisions of this file
MyAcousticEffector_MIC/GuiChanger.hpp Show annotated file Show diff for this revision Revisions of this file
MyAcousticEffector_MIC/HilbertTransform.hpp Show annotated file Show diff for this revision Revisions of this file
MyAcousticEffector_MIC/InitializeGUI.hpp Show annotated file Show diff for this revision Revisions of this file
MyAcousticEffector_MIC/ProcessingBase.hpp Show annotated file Show diff for this revision Revisions of this file
MyAcousticEffector_MIC/WaveformDisplay.hpp Show annotated file Show diff for this revision Revisions of this file
MyAcousticEffector_MIC/coefsHilbert162.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
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/F746_GUI.lib	Mon Mar 19 03:19:35 2018 +0000
@@ -0,0 +1,1 @@
+https://os.mbed.com/users/MikamiUitOpen/code/F746_GUI/#50b8f7654c36
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/F746_SAI_IO.lib	Mon Mar 19 03:19:35 2018 +0000
@@ -0,0 +1,1 @@
+https://os.mbed.com/users/MikamiUitOpen/code/F746_SAI_IO/#61e2c3cc79a3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MyAcousticEffector_MIC/Biquad.hpp	Mon Mar 19 03:19:35 2018 +0000
@@ -0,0 +1,57 @@
+//--------------------------------------------------------------
+//  縦続形 IIR フィルタで使う 1D タイプの 2 次のフィルタ
+//  Biquad filter of 1D type for IIR filter of cascade structure
+//      このクラスでは,係数は実行中に書き換えられることを想定している
+//
+//      u[n] = x[n] + a1*u[n-1] + a2*u[n-2]
+//      y[n] = u[n] + b1*u[n-1] + b2*u[n-2]
+//          x[n] :  input signal
+//          y[n] :  output signal
+//          b0 = 1
+//
+// 2017/03/26, Copyright (c) 2017 MIKAMI, Naoki
+//--------------------------------------------------------------
+
+#ifndef IIR_BIQUAD_HPP
+#define IIR_BIQUAD_HPP
+
+#include "mbed.h"
+
+// 2nd order IIR filter
+namespace Mikami
+{
+    class Biquad
+    {
+    public:
+        struct Coefs { float a1, a2, b1, b2; };
+
+        Biquad(const Coefs ck = (Coefs){0, 0, 0, 0})
+        {
+            SetCoefficients(ck);
+            Clear();
+        }
+        
+        void SetCoefficients(const Coefs cf) { cf_ = cf; }
+
+        float Execute(float xn)
+        {
+            float un = xn + cf_.a1*un1_ + cf_.a2*un2_;
+            float yn = un + cf_.b1*un1_ + cf_.b2*un2_;
+        
+            un2_ = un1_;
+            un1_ = un;
+
+            return yn;
+        }
+
+        void Clear() { un1_ = un2_ = 0; }
+
+    private:
+        Coefs cf_;
+        float un1_, un2_;
+
+        // disallow copy constructor
+        Biquad(const Biquad&);
+    };
+}
+#endif  // IIR_BIQUAD_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MyAcousticEffector_MIC/DC_Cut_Coefficients.hpp	Mon Mar 19 03:19:35 2018 +0000
@@ -0,0 +1,18 @@
+//--------------------------------------------------------------
+//  直流分除去フィルタの係数,次数:2
+//--------------------------------------------------------------
+#include "Biquad.hpp"
+
+// 高域通過フィルタ
+// バタワース特性
+// 次数    : 2 次
+// 標本化周波数: 16.00 kHz
+// 遮断周波数 :  0.05 kHz
+
+using namespace Mikami;
+
+const Biquad::Coefs dcCut_ =
+    { 1.972234E+00f, -9.726140E-01f, -2.0f, 1.0f};
+const float dcCutG0_ = 9.862119E-01f;
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MyAcousticEffector_MIC/FrequencyShifter.hpp	Mon Mar 19 03:19:35 2018 +0000
@@ -0,0 +1,60 @@
+//--------------------------------------------------------------
+//  ヒルベルト変換フィルタを使う周波数シフタ
+//
+//  2018/03/19, Copyright (c) 2018 MIKAMI, Naoki
+//--------------------------------------------------------------
+
+#ifndef HILBERT_FREQUENCY_CONVERTER_HPP
+#define HILBERT_FREQUENCY_CONVERTER_HPP
+
+#include "ProcessingBase.hpp"
+#include "Biquad.hpp"               // 直流分除去フィルタ用
+#include "DC_Cut_Coefficients.hpp"  // 直流分除去フィルタの係数
+#include "HilbertTransform.hpp"     // ヒルベルト変換用フィルタ
+#include "coefsHilbert162.hpp"      // ヒルベルト変換用フィルタの係数
+
+namespace Mikami
+{
+    class FrqShifterHilbert : public ProcessingBase
+    {
+    public:
+        FrqShifterHilbert(float fS, float fShift = 0)
+            : dcCutFilter_(dcCut_), hilbertFIR_(ORDER_HILBERT_, hmHilbert_),
+              FS_(fS), PI2_(3.1415926536f*2),
+              phi_(0), dPhi_(fShift*PI2_/FS_)
+        {   SetFrequency(fShift); }
+
+        virtual float Execute(float xn)
+        {
+            float un = dcCutFilter_.Execute(xn*dcCutG0_);   // 直流分除去フィルタ
+            float yI, yQ;
+            hilbertFIR_.Execute(un, yI, yQ);                // ヒルベルト変換用フィルタ
+
+            float yn = yI*cosf(phi_) - yQ*sinf(phi_);
+
+            phi_ = phi_ + dPhi_;
+            if (phi_ > PI2_) phi_ = phi_ - PI2_;
+
+            return yn;
+        }
+
+        // 周波数のシフト量を設定
+        void SetFrequency(float fShift)
+        {   dPhi_ = fShift*PI2_/FS_; }
+
+    private:
+        //
+        Biquad dcCutFilter_;    // 直流分除去フィルタ
+        Hilbert hilbertFIR_;    // ヒルベルト変換用フィルタ
+
+        const float FS_;
+        const float PI2_;
+
+        float phi_, dPhi_;
+
+        // disallow copy constructor and assignment operator
+        FrqShifterHilbert(const FrqShifterHilbert& );
+        FrqShifterHilbert& operator=(const FrqShifterHilbert& );
+    };
+}
+#endif  // HILBERT_FREQUENCY_CONVERTER_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MyAcousticEffector_MIC/GuiChanger.hpp	Mon Mar 19 03:19:35 2018 +0000
@@ -0,0 +1,24 @@
+//--------------------------------------------------------------
+//  信号処理の種類に応じた GUI 部品の状態を変更する
+//
+//  2018/03/18, Copyright (c) 2018 MIKAMI, Naoki
+//--------------------------------------------------------------
+
+#ifndef GUI_CHANGER_HPP
+#define GUI_CHANGER_HPP
+
+// Through の場合
+void SetThrough(SeekBar *barFqCh, NumericLabel<int> *frqLabel)
+{
+    barFqCh->Inactivate();
+    frqLabel->Redraw(GuiBase::ENUM_INACTIVE_TEXT);
+}
+
+// 周波数シフトの場合
+void SetFrqShifter(SeekBar *barFqCh, NumericLabel<int> *frqLabel)
+{
+    barFqCh->Activate();
+    frqLabel->Redraw(GuiBase::ENUM_TEXT);
+}
+
+#endif  // GUI_CHANGER_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MyAcousticEffector_MIC/HilbertTransform.hpp	Mon Mar 19 03:19:35 2018 +0000
@@ -0,0 +1,52 @@
+//--------------------------------------------------------------
+//  ヒルベルト変換用フィルタ
+//
+//  Copyright (c) 2018 MIKAMI, Naoki,  2018/03/19
+//--------------------------------------------------------------
+
+#ifndef HILBERT_TRANSFORM_HPP
+#define HILBERT_TRANSFORM_HPP
+
+#include "mbed.h"
+
+namespace Mikami
+{
+    class Hilbert
+    {
+    public:
+        // order: 4K+2 とすること, K: 整数
+        Hilbert(int order, const float hk[])
+            : ORDER_(order), HN_(order+1, hk), xn_(order+1, 0.0f)
+        {
+            if ( ((order-2) % 4) != 0)
+                fprintf(stderr, "order must be 4*K+2, K: integer\r\n");
+        }
+        
+        // yI: 同相信号
+        // yQ: 直角位相信号
+        void Execute(float xin, float& yI, float& yQ)
+        {
+            yQ = 0.0;
+            xn_[0] = xin;
+
+            for (int k=0; k<=ORDER_/4; k++)
+                yQ = yQ + HN_[k]*(xn_[2*k] - xn_[ORDER_-2*k]);
+            yI = xn_[ORDER_/2];             // 同相信号
+
+            for (int k=ORDER_; k>0; k--)
+                xn_[k] = xn_[k-1];          // 遅延器の入力信号の移動        
+        }
+        
+    private:
+        const int ORDER_;       // 次数
+        const Array<float> HN_; // 係数
+        Array<float> xn_;       // 入力信号用バッファ
+
+        // disallow copy constructor and assignment operator
+        Hilbert(const Hilbert&);
+        Hilbert& operator=(const Hilbert&);
+    };
+}
+#endif  // HILBERT_TRANSFORM_HPP
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MyAcousticEffector_MIC/InitializeGUI.hpp	Mon Mar 19 03:19:35 2018 +0000
@@ -0,0 +1,60 @@
+//--------------------------------------------------------------
+//  Hilbert 変換フィルタを利用する MEMS マイクの入力に対して周波数シフタ
+//  で使う GUI 等の初期化
+//
+//  2018/03/18, Copyright (c) 2018 MIKAMI, Naoki
+//--------------------------------------------------------------
+
+#ifndef EFFECTOR_INIT_GUI_HPP
+#define EFFECTOR_INIT_GUI_HPP
+
+#include "F746_GUI.hpp"
+#include "WaveformDisplay.hpp"
+using namespace Mikami;
+
+void InitializeGUI(
+        ButtonGroup *(&onOff), ButtonGroup *(&menu),
+        SeekBar *(&barFqCh), NumericLabel<int> *(&frqLabel),
+        WaveformDisplay *(&dispIn),
+        WaveformDisplay *(&dispOut))
+{
+    Label myLabel(240, 8, "Frequency shifter", Label::CENTER, Font16);
+
+    // ButtonGroup 用の定数
+    const uint16_t BG_LEFT = 360;
+    const uint16_t BG_WIDTH = 110;
+    const uint16_t BG_HEIGHT = 45;
+
+    // ButtonGroup: "ON", "OFF"
+    onOff = new ButtonGroup(BG_LEFT, 40, BG_WIDTH/2, BG_HEIGHT,
+                            2, (string[]){"ON", "OFF"}, 0, 0, 2, 1);
+
+    // ButtonGroup: "THROUGH", "F_SHIFTER"
+    menu = new ButtonGroup(BG_LEFT, 110, BG_WIDTH, BG_HEIGHT,
+                           2, (string[]){"THROUGH", "VOICE CHANGER"},
+                           0, 10, 1, 0);
+
+    // SeekBar 用の定数
+    const uint16_t SB_LEFT = BG_LEFT - 300;
+    const uint16_t SB_WIDTH = 256;
+    const uint16_t Y0_E = 195;
+    const uint16_t Y0_F = Y0_E + BG_HEIGHT + 5;
+
+    // 周波数シフタ用
+    barFqCh = new SeekBar(SB_LEFT, Y0_F, SB_WIDTH,
+                          0, 200, 100, "0", "", "200");
+    barFqCh->Inactivate();
+    frqLabel =  new NumericLabel<int>(
+                    SB_LEFT+SB_WIDTH/2, Y0_F-28, "+%d Hz",
+                    barFqCh->GetIntValue(), Label::CENTER);
+    frqLabel->Redraw(GuiBase::ENUM_INACTIVE_TEXT);
+
+    // 波形表示用
+    Label inLabel(SB_LEFT-40, 55, "IN");
+    dispIn = new WaveformDisplay(
+                 GuiBase::GetLcd(), SB_LEFT, 60, 256, 9);
+    Label outLabel(SB_LEFT-40, 125, "OUT");
+    dispOut = new WaveformDisplay(
+                  GuiBase::GetLcd(), SB_LEFT, 130, 256, 9);
+}
+#endif  // EFFECTOR_INIT_GUI_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MyAcousticEffector_MIC/ProcessingBase.hpp	Mon Mar 19 03:19:35 2018 +0000
@@ -0,0 +1,22 @@
+//--------------------------------------------------------------
+//  信号処理のための基底クラス
+//
+//  2017/04/06, Copyright (c) 2017 MIKAMI, Naoki
+//--------------------------------------------------------------
+
+#ifndef PROCESSING_BASE_HPP
+#define PROCESSING_BASE_HPP
+
+namespace Mikami
+{
+    class ProcessingBase
+    {
+    public:
+        ProcessingBase() {}
+        virtual ~ProcessingBase() {}
+
+        virtual float Execute(float xn)
+        { return xn; }
+    };
+}
+#endif  // PROCESSING_BASE_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MyAcousticEffector_MIC/WaveformDisplay.hpp	Mon Mar 19 03:19:35 2018 +0000
@@ -0,0 +1,74 @@
+//-----------------------------------------------------------
+//  Class for waveform display
+//
+//  2017/04/06, Copyright (c) 2016 MIKAMI, Naoki
+//-----------------------------------------------------------
+
+#ifndef F746_WAVEFORM_DISPLAY_HPP
+#define F746_WAVEFORM_DISPLAY_HPP
+
+#include "Array.hpp"
+
+namespace Mikami
+{
+    class WaveformDisplay
+    {
+    public:
+        WaveformDisplay(LCD_DISCO_F746NG &lcd,
+                        uint16_t x0, uint16_t y0, int nData,
+                        uint16_t rShift)
+            : X0_(x0), Y0_(y0), R_SHIFT_(rShift),
+              H1_(Y0_+LIMIT_+1), H2_(Y0_-LIMIT_-1),
+              lcd_(lcd) { Axis(nData); }
+
+        void Execute(const Array<int16_t> &xn)
+        {
+            lcd_.SetTextColor(GuiBase::ENUM_BACK);
+            lcd_.FillRect(X0_, Y0_-LIMIT_-1,
+                          xn.Length(), (LIMIT_+1)*2+1);
+            Axis(xn.Length());
+            lcd_.SetTextColor(LINE_COLOR_);
+            uint16_t x1 = X0_;
+            uint16_t y1 = Clip(xn[0]);
+            for (int n=1; n<xn.Length(); n++)
+            {
+                uint16_t x2 = X0_ + n;
+                uint16_t y2 = Clip(xn[n]);
+                lcd_.DrawLine(x1, y1, x2, y2);
+                if ((y1 == H1_) || (y1 == H2_))
+                    lcd_.DrawPixel(x1, y1, LCD_COLOR_RED);
+                x1 = x2;
+                y1 = y2;
+            }
+        }
+
+    private:
+        static const uint16_t LIMIT_ = 32;
+        static const uint32_t LINE_COLOR_ = LCD_COLOR_CYAN;
+        const uint16_t X0_, Y0_;
+        const uint16_t R_SHIFT_;
+        const uint16_t H1_, H2_;
+
+        LCD_DISCO_F746NG& lcd_;
+
+        // Clipping
+        uint16_t Clip(int16_t xn)
+        {
+            int16_t x = xn >> R_SHIFT_;
+            if (x >  LIMIT_ ) x =  LIMIT_ + 1;
+            if (x < -LIMIT_ ) x = -(LIMIT_ + 1) ;
+            return Y0_ - x;
+        }
+
+        void Axis(int nData)
+        {
+            lcd_.SetTextColor(LCD_COLOR_WHITE);
+            lcd_.DrawLine(X0_-5, Y0_, X0_+nData+5, Y0_);
+        }
+
+        // disallow copy constructor and assignment operator
+        WaveformDisplay(const WaveformDisplay& );
+        WaveformDisplay& operator=(const WaveformDisplay& );
+    };
+}
+#endif  // F746_WAVEFORM_DISPLAY_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MyAcousticEffector_MIC/coefsHilbert162.hpp	Mon Mar 19 03:19:35 2018 +0000
@@ -0,0 +1,28 @@
+//--------------------------------------------------------------
+//  ヒルベルト変換用 FIR フィルタの係数
+//  次数:162
+//--------------------------------------------------------------
+
+// 標本化周波数 (kHz)        16.000000
+// 次数                            162
+//                             帯域 1
+// 下側帯域端周波数 (kHz)     0.100000
+// 上側帯域端周波数 (kHz)     7.900000
+// 利得                       1.000000
+// 重み                       1.000000
+// 偏差                       0.016871
+// 偏差 [dB]                  0.145317
+
+const int ORDER_HILBERT_ = 162;
+const float hmHilbert_[(ORDER_HILBERT_-2)/4+1] = {
+         -9.452293E-03f, -2.143468E-03f, -2.386095E-03f, -2.645189E-03f,
+         -2.926359E-03f, -3.222066E-03f, -3.543330E-03f, -3.886371E-03f,
+         -4.251500E-03f, -4.642029E-03f, -5.061504E-03f, -5.510610E-03f,
+         -5.990406E-03f, -6.504444E-03f, -7.055964E-03f, -7.649082E-03f,
+         -8.287499E-03f, -8.976063E-03f, -9.719625E-03f, -1.052535E-02f,
+         -1.140120E-02f, -1.235730E-02f, -1.340540E-02f, -1.456034E-02f,
+         -1.583971E-02f, -1.726622E-02f, -1.886917E-02f, -2.068668E-02f,
+         -2.276868E-02f, -2.518285E-02f, -2.802285E-02f, -3.142147E-02f,
+         -3.557408E-02f, -4.078067E-02f, -4.752620E-02f, -5.664814E-02f,
+         -6.972917E-02f, -9.016101E-02f, -1.267624E-01f, -2.118692E-01f,
+         -6.365072E-01f};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Mon Mar 19 03:19:35 2018 +0000
@@ -0,0 +1,97 @@
+//--------------------------------------------------------------
+//  MEMS マイクの入力に対して周波数シフトを行う
+//      Hilbert 変換フィルタを利用する方法
+//
+//  使用しているライブラリのリビジョン:
+//          F746_GUI            Rev.33
+//          F746_SAI_IO         Rev.12
+//          mbed                Rev.161
+//
+//  2018/03/19, Copyright (c) 2018 MIKAMI, Naoki
+//--------------------------------------------------------------
+
+#include "InitializeGUI.hpp"
+#include "SAI_InOut.hpp"
+#include "FrequencyShifter.hpp"
+#include "GuiChanger.hpp"
+using namespace Mikami;
+
+int main()
+{
+    const int FS = AUDIO_FREQUENCY_16K;    // 標本化周波数: 16 kHz
+    // 入出力の準備
+    SaiIO mySai(SaiIO::BOTH, 256, FS,
+                INPUT_DEVICE_DIGITAL_MICROPHONE_2);
+
+    ButtonGroup *onOff; // "ON", "OFF"
+    ButtonGroup *menu;  // "THROUGH", "F_SHIFTER"
+    SeekBar *barFqCh;   // シフトする周波数を設定するシークバー
+    NumericLabel<int> *frqLabel;
+    WaveformDisplay *displayIn, *displayOut;
+
+    // GUI 部品の初期化
+    InitializeGUI(onOff, menu, barFqCh, frqLabel, displayIn, displayOut);
+
+    // 処理に応じて GUI 部品の状態を変更する関数の割り当て
+    void (*fPtr[])(SeekBar*, NumericLabel<int>*)
+        = { SetThrough, SetFrqShifter };
+    ProcessingBase through;             // 0: 信号処理なしで出力
+    FrqShifterHilbert shifter(FS, 100); // 1: 周波数シフト(シフトの初期値:100 Hz)
+
+    ProcessingBase *func[2] = { &through, &shifter };
+
+    Array<int16_t> snIn(mySai.GetLength());     // 入力波形表示で使用
+    Array<int16_t> snOut(mySai.GetLength());    // 出力波形表示で使用
+
+    mySai.RecordIn();   // 入力開始
+    mySai.PlayOut();    // 出力開始
+    mySai.PauseOut();   // 出力一時停止
+
+    int menuNum = 0;
+    while (true)
+    {
+        // On/OFF の設定
+        int num;
+        if (onOff->GetTouchedNumber(num))
+        {
+            if (num == 0) mySai.ResumeOut();    // 出力再開
+            else          mySai.PauseOut();
+        }
+
+        // メニューにより GUI の状態を設定しなおす
+        if (menu->GetTouchedNumber(menuNum))
+            fPtr[menuNum](barFqCh, frqLabel);
+
+        // 周波数シフトの値の設定
+        if ( (menuNum == 1) && (barFqCh->Slide()) )
+        {
+            frqLabel->Draw(barFqCh->GetIntValue());
+            shifter.SetFrequency(barFqCh->GetIntValue());
+        }
+
+        //---------------------------------------------
+        // 1フレーム分の信号処理を行い,その結果を出力する
+        if (mySai.IsCompleted())
+        {
+            for (int n=0; n<mySai.GetLength(); n++)
+            {
+                int16_t xL, xR;
+                mySai.Input(xL, xR);
+                int16_t xn = xL + xR;
+                snIn[n] = xn;   // 表示用
+
+                //-------------------------------------------------------
+                int16_t yn = func[menuNum]->Execute(xn);    // 信号処理実行
+                //-------------------------------------------------------
+
+                mySai.Output(yn, yn);   // 左右チャンネルに同じ信号を出力
+                snOut[n] = yn;  // 表示用
+            }
+
+            displayIn->Execute(snIn);   // 入力波形の表示
+            displayOut->Execute(snOut); // 出力波形の表示
+        }
+        // 1フレーム分の信号処理はここまで
+        //---------------------------------------------
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Mon Mar 19 03:19:35 2018 +0000
@@ -0,0 +1,1 @@
+https://os.mbed.com/users/mbed_official/code/mbed/builds/aa5281ff4a02
\ No newline at end of file