Interface 2015年4月号 第1部 第7章のプログラム

Dependencies:   USBDevice mbed

Information

FftTest - Interface 2015年4月号 第1部 第7章 のソフトウェア

Program for Section 7 in April 2015 issue of Interface
(Japanese electronics magazine)

概要

このプログラムは、

  • ハイパスフィルタ、ローパスフィルタ、ノッチフィルタ
    を行うFilterTestクラス、
  • FFT (256点)
    を行うFftTestクラス、
    波形をUSBシリアル通信でホストへ送信するmain関数で構成されています。

FilterTest.h, FilterTest.cpp

  • A-Dサンプリング - 1 kSPS
  • ハイパスフィルタ(遮断周波数 0.5 Hz、1次バターワース)
  • ローパスフィルタ(遮断周波数 30 Hz、2次バターワース)
  • ノッチフィルタ(中心周波数 50 Hz、2次)

FftTest.h, FftTest.cpp

  • 256点FFT演算 - クーリー-テューキー アルゴリズム 基数-2 時間間引き
  • ハン窓(ハニング窓)適用
  • パワー値計算
  • 振幅値計算
  • 振幅値正規化(実効値にスケーリング)

main.cpp

  • データ送信レート - 200 SPS
  • メインループ - ポーリングにより、サンプリング、フィルタ処理完了フラグがセットされたら、
    また、FFT完了フラグがセットされたらUSBシリアル通信経由で、ホストへ送信する

シリアル通信フォーマット

 (※)誌面ではパケットサイズ 64 byteとなっていますが、
    64 byteでは、PCのUSBドライバが 4096 byteまで保持し、波形が滑らかに描画できないため、
    Ver.1.0.2で、32 byteに変更しています。

  • 34byte固定長パケット方式
  • 波形データパケット、FFTパケットの2種類
波形データパケットFFTパケット
0x00パケットヘッダ(固定値0xAA)パケットヘッダ(固定値0xAA)
0x01データ種別ID(0x01: 波形データ)(0x02: FFTデータ)
0x02パケット番号(0 - 99繰り返し)レンジ(0: DC - 23 Hz, 1: 23 - 46 Hz, 2: 46 - 70 Hz)
0x03ペイロードサイズ(固定値30)ペイロードサイズ(固定値30)
0x04 - 0x21波形データ(short, big endian)FFTデータ(unsigned short, big endian)

Description

This contains FilterTest class, FftTest class and main function.

FilterTest class:

  • High pass filter, Low pass, Notch filter

FftTest class:

  • FFT (256 points)

Main function:

  • Send waveform and FFT data to host via USB serial class.

FilterTest.h, FilterTest.cpp

  • A-D sampling - 1 kSPS
  • High pass filter - Cut off frequency 0.5 Hz, first order butterworth
  • Low pass filter - Cut off frequency 30 Hz, second order butterworth
  • Notch filter - Center frequency 50 Hz, second order

FftTest.h, FftTest.cpp

  • 256 points FFT - Cooley-Tukey algorithm Radix-2 Decimation-In-Time
  • Apply Hann window
  • Calculate power spectrum
  • Calculate amplitude spectrum
  • Normalize amplitude

main.cpp

  • Data sending rate - 200 SPS
  • Main loop - sending waveform and FFT data via USB serial interface when detecting ready flag.

Packet format for USB serial interface

  • Packet size: 34 bytes(fixed)
  • Two types of packet, waveform packet and FFT packet
Waveform packetFFT packet
0x00Packet header (0xAA (fixed))Packet header (0xAA (fixed))
0x01Data type ID (0x01: Waveform ID)(0x02: FFT ID)
0x02Packet number (0 - 99)Range (0: DC - 23 Hz, 1: 23 - 46 Hz, 2: 46 - 70 Hz)
0x03Payload size (30 (fixed))Payload size (30 (fixed))
0x04 - 0x21Waveform data (short, big endian)FFT data (unsigned short, big endian)
Revision:
0:9779b89a8820
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/FilterTest.cpp	Mon Feb 23 22:19:58 2015 +0000
@@ -0,0 +1,217 @@
+/**
+ *  @file       FilterTest.cpp
+ *  @brief      Calculate filters
+ *              HPF: 1st order / LPF: 2nd order / Notch: 2nd order
+ *  @date       2015.02.22
+ *  @version    1.0.1
+ */
+#include "FilterTest.h"
+
+/** Constructor
+*/
+FilterTest::FilterTest ()
+{
+    set_hpf_coef(INIT_HB, INIT_HA);
+    set_lpf_coef(INIT_LB, INIT_LA1, INIT_LA2);
+    set_brf_coef(INIT_NB, INIT_NA1, INIT_NA2);
+    reset_hpf_buf();
+    reset_lpf_buf();
+    reset_brf_buf();
+}
+
+/** Calculate filter
+ *  @param      val         Input value
+ *  @param      hpf_on      High pass filter enable
+ *  @param      lpf_on      Low pass filter enable
+ *  @param      brf_on      Notch filter enable
+ *  @return                 Output value
+ */
+double FilterTest::calc(double val, int hpf_on, int lpf_on, int brf_on)
+{
+    double retVal = val;
+    /* High pass filter */
+    if(hpf_on) {
+        retVal = hpf(retVal);
+    } else {
+        reset_hpf_buf();
+    }
+    /* Low pass filter */
+    if(lpf_on) {
+        retVal = lpf(retVal);
+    } else {
+        reset_lpf_buf();
+    }
+    /* Notch (Band reject) filter */
+    if(brf_on) {
+        retVal = brf(retVal);
+    } else {
+        reset_brf_buf();
+    }
+    return retVal;
+}
+
+/** Reset delay buffers for high pass filter
+*/
+void FilterTest::reset_hpf_buf()
+{
+    _hw = 0.0;
+}
+
+/** Reset delay buffers for low pass filter
+*/
+void FilterTest::reset_lpf_buf()
+{
+    _lw1 = 0.0;
+    _lw2 = 0.0;
+}
+
+/** Reset delay buffers for notch filter
+*/
+void FilterTest::reset_brf_buf()
+{
+    _nw1 = 0.0;
+    _nw2 = 0.0;
+}
+
+/** Set coefficient for HPF
+ *  @param      hb          Numerator cofficient
+ *  @param      ha          Denominator cofficient
+ *  @retval     true        OK
+ *  @retval     false       NG
+ */
+bool FilterTest:: set_hpf_coef(double hb, double ha)
+{
+    if(hb > 1.0) {
+        return false;
+    } else if((ha > 1.0)||(ha < -1.0)) {
+        return false;
+    } else {
+        _hb = hb;
+        _ha = ha;
+        reset_hpf_buf();
+        return true;
+    }
+}
+
+/** Set coefficient for LPF
+ *  @param      lb          Numerator cofficient
+ *  @param      la1         Denominator cofficient 1
+ *  @param      la2         Denominator cofficient 2
+ *  @retval     true        OK
+ *  @retval     false       NG
+ */
+bool FilterTest:: set_lpf_coef(double lb, double la1, double la2)
+{
+    if(lb > 1.0) {
+        return false;
+    } else if((la1 > 2.0)||(la1 < -2.0)) {
+        return false;
+    } else if(la2 > 1.0) {
+        return false;
+    } else {
+        _lb = lb;
+        _la1 = la1;
+        _la2 = la2;
+        reset_lpf_buf();
+        return true;
+    }
+}
+
+/** Set coefficient for BRF
+ *  @param      nb          Numerator cofficient
+ *  @param      na1         Denominator cofficient 1
+ *  @param      na2         Denominator cofficient 2
+ *  @retval     true        OK
+ *  @retval     false       NG
+ */
+bool FilterTest:: set_brf_coef(double nb, double na1, double na2)
+{
+    if(nb > 1.0) {
+        return false;
+    } else if((na1 > 2.0)||(na1 < -2.0)) {
+        return false;
+    } else if(na2 > 1.0) {
+        return false;
+    } else {
+        _nb = nb;
+        _na1 = na1;
+        _na2 = na2;
+        reset_brf_buf();
+        return true;
+    }
+}
+
+/** High pass filter (1st order)
+ *  @param      x      Input value
+ *  @return            Output value
+ *
+ *       hb   v  +
+ *  x ---I>---+---O-------+--- y
+ *            | hw|-      |
+ *            |  [z]      |
+ *            |   |   ha  |
+ *            +---O---<I--+
+ */
+double FilterTest::hpf(double x)
+{
+    double v, y;
+
+    v = _hb * x;
+    y = v - _hw;
+    _hw = v + _ha * y;
+    return y;
+}
+
+/** Low pass filter (2nd order)
+ *  @param      x      Input value
+ *  @return            Output value
+ *
+ *      lb  v
+ *  x --I>--+-----O-------+--- y
+ *          |  lw1|       |
+ *          |    [z]      |
+ *          |  2  |  -la1 |
+ *          +-I>--O---<I--+
+ *          |  lw2|       |
+ *          |    [z]      |
+ *          |     |  -la2 |
+ *          +-----O---<I--+
+ */
+double FilterTest::lpf(double x)
+{
+    double v, y;
+
+    v = _lb * x;
+    y = v + _lw1;
+    _lw1 = 2 * v - _la1 * y + _lw2;
+    _lw2 = v - _la2 * y;
+    return y;
+}
+
+/** Notch filter (Band reject filter) (2nd order)
+ *  @param      x      Input value
+ *  @return            Output value
+ *
+ *       nb  v
+ *  x -+-I>--+----O-------+--- y
+ *     |     | nw1|       |
+ *     |     |   [z]      |
+ *    +| na1 |    |       |
+ *     O-I>-------O       |
+ *    -|     | nw2|       |
+ *     |     |   [z]      |
+ *     |     |    |  -na2 |
+ *     |     +----O---<I--+
+ *     |                  |
+ *     +------------------+
+ */
+double FilterTest::brf(double x)
+{
+    double v, y;
+
+    v = _nb * x;
+    y = v + _nw1;
+    _nw1 = _na1 * ( x - y ) + _nw2;
+    _nw2 = v - _na2 * y;
+    return y;
+}