Interface 2015年4月号 第1部 第5章および第6章のプログラム

Dependencies:   USBDevice mbed

Information

FilterTest - Interface 2015年4月号 第1部 第5章 第6章 のソフトウェア

Program for Section 5 and 6 in April 2015 issue of Interface
(Japanese electronics magazine)

概要

このプログラムは、

  • ハイパスフィルタ、ローパスフィルタ、ノッチフィルタ

を行うFilterTestクラスと、波形をUSBシリアル通信でホストへ送信するmain関数で構成されています。

FilterTest.h, FilterTest.cpp

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

main.cpp

  • データ送信レート - 1 kSPS
  • FilterTestクラスのインスタンスを生成
  • 処理開始メソッドを実行
  • メインループ - ポーリングにより、サンプリング、フィルタ処理完了フラグがセットされたら、
    USBシリアル通信経由で、ホストへ送信する

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

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

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

Description

This contains FilterTest class and main function.

FilterTest class:

  • High pass filter, Low pass, Notch filter

Main function:

  • Send waveform 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

main.cpp

  • Data sending rate - 1 kSPS
  • Executing start procedure method
  • Main loop - sending waveform data via USB serial interface when detecting ready flag.

Packet format for USB serial interface

  • Packet size: 34 bytes(fixed)
  • One type of packet waveform packet
Waveform packet
0x00Packet header (0xAA (fixed))
0x01Data type ID (0x01: Waveform ID)
0x02Packet number (0 - 99)
0x03Payload size (30 (fixed))
0x04 - 0x21Waveform data (short, big endian)
Committer:
t_tatsuoka
Date:
Thu Jul 30 10:23:54 2015 +0000
Revision:
2:c9471599e9eb
Parent:
0:7a4d80e7ea81
Notch filter 60 Hz version

Who changed what in which revision?

UserRevisionLine numberNew contents of line
t_tatsuoka 0:7a4d80e7ea81 1 /**
t_tatsuoka 0:7a4d80e7ea81 2 * @file FilterTest.cpp
t_tatsuoka 0:7a4d80e7ea81 3 * @brief Calculate filters
t_tatsuoka 0:7a4d80e7ea81 4 * HPF: 1st order / LPF: 2nd order / Notch: 2nd order
t_tatsuoka 0:7a4d80e7ea81 5 * @date 2015.02.22
t_tatsuoka 0:7a4d80e7ea81 6 * @version 1.0.1
t_tatsuoka 0:7a4d80e7ea81 7 */
t_tatsuoka 0:7a4d80e7ea81 8 #include "FilterTest.h"
t_tatsuoka 0:7a4d80e7ea81 9
t_tatsuoka 0:7a4d80e7ea81 10 /** Constructor
t_tatsuoka 0:7a4d80e7ea81 11 */
t_tatsuoka 0:7a4d80e7ea81 12 FilterTest::FilterTest ()
t_tatsuoka 0:7a4d80e7ea81 13 {
t_tatsuoka 0:7a4d80e7ea81 14 set_hpf_coef(INIT_HB, INIT_HA);
t_tatsuoka 0:7a4d80e7ea81 15 set_lpf_coef(INIT_LB, INIT_LA1, INIT_LA2);
t_tatsuoka 0:7a4d80e7ea81 16 set_brf_coef(INIT_NB, INIT_NA1, INIT_NA2);
t_tatsuoka 0:7a4d80e7ea81 17 reset_hpf_buf();
t_tatsuoka 0:7a4d80e7ea81 18 reset_lpf_buf();
t_tatsuoka 0:7a4d80e7ea81 19 reset_brf_buf();
t_tatsuoka 0:7a4d80e7ea81 20 }
t_tatsuoka 0:7a4d80e7ea81 21
t_tatsuoka 0:7a4d80e7ea81 22 /** Calculate filter
t_tatsuoka 0:7a4d80e7ea81 23 * @param val Input value
t_tatsuoka 0:7a4d80e7ea81 24 * @param hpf_on High pass filter enable
t_tatsuoka 0:7a4d80e7ea81 25 * @param lpf_on Low pass filter enable
t_tatsuoka 0:7a4d80e7ea81 26 * @param brf_on Notch filter enable
t_tatsuoka 0:7a4d80e7ea81 27 * @return Output value
t_tatsuoka 0:7a4d80e7ea81 28 */
t_tatsuoka 0:7a4d80e7ea81 29 double FilterTest::calc(double val, int hpf_on, int lpf_on, int brf_on)
t_tatsuoka 0:7a4d80e7ea81 30 {
t_tatsuoka 0:7a4d80e7ea81 31 double retVal = val;
t_tatsuoka 0:7a4d80e7ea81 32 /* High pass filter */
t_tatsuoka 0:7a4d80e7ea81 33 if(hpf_on) {
t_tatsuoka 0:7a4d80e7ea81 34 retVal = hpf(retVal);
t_tatsuoka 0:7a4d80e7ea81 35 } else {
t_tatsuoka 0:7a4d80e7ea81 36 reset_hpf_buf();
t_tatsuoka 0:7a4d80e7ea81 37 }
t_tatsuoka 0:7a4d80e7ea81 38 /* Low pass filter */
t_tatsuoka 0:7a4d80e7ea81 39 if(lpf_on) {
t_tatsuoka 0:7a4d80e7ea81 40 retVal = lpf(retVal);
t_tatsuoka 0:7a4d80e7ea81 41 } else {
t_tatsuoka 0:7a4d80e7ea81 42 reset_lpf_buf();
t_tatsuoka 0:7a4d80e7ea81 43 }
t_tatsuoka 0:7a4d80e7ea81 44 /* Notch (Band reject) filter */
t_tatsuoka 0:7a4d80e7ea81 45 if(brf_on) {
t_tatsuoka 0:7a4d80e7ea81 46 retVal = brf(retVal);
t_tatsuoka 0:7a4d80e7ea81 47 } else {
t_tatsuoka 0:7a4d80e7ea81 48 reset_brf_buf();
t_tatsuoka 0:7a4d80e7ea81 49 }
t_tatsuoka 0:7a4d80e7ea81 50 return retVal;
t_tatsuoka 0:7a4d80e7ea81 51 }
t_tatsuoka 0:7a4d80e7ea81 52
t_tatsuoka 0:7a4d80e7ea81 53 /** Reset delay buffers for high pass filter
t_tatsuoka 0:7a4d80e7ea81 54 */
t_tatsuoka 0:7a4d80e7ea81 55 void FilterTest::reset_hpf_buf()
t_tatsuoka 0:7a4d80e7ea81 56 {
t_tatsuoka 0:7a4d80e7ea81 57 _hw = 0.0;
t_tatsuoka 0:7a4d80e7ea81 58 }
t_tatsuoka 0:7a4d80e7ea81 59
t_tatsuoka 0:7a4d80e7ea81 60 /** Reset delay buffers for low pass filter
t_tatsuoka 0:7a4d80e7ea81 61 */
t_tatsuoka 0:7a4d80e7ea81 62 void FilterTest::reset_lpf_buf()
t_tatsuoka 0:7a4d80e7ea81 63 {
t_tatsuoka 0:7a4d80e7ea81 64 _lw1 = 0.0;
t_tatsuoka 0:7a4d80e7ea81 65 _lw2 = 0.0;
t_tatsuoka 0:7a4d80e7ea81 66 }
t_tatsuoka 0:7a4d80e7ea81 67
t_tatsuoka 0:7a4d80e7ea81 68 /** Reset delay buffers for notch filter
t_tatsuoka 0:7a4d80e7ea81 69 */
t_tatsuoka 0:7a4d80e7ea81 70 void FilterTest::reset_brf_buf()
t_tatsuoka 0:7a4d80e7ea81 71 {
t_tatsuoka 0:7a4d80e7ea81 72 _nw1 = 0.0;
t_tatsuoka 0:7a4d80e7ea81 73 _nw2 = 0.0;
t_tatsuoka 0:7a4d80e7ea81 74 }
t_tatsuoka 0:7a4d80e7ea81 75
t_tatsuoka 0:7a4d80e7ea81 76 /** Set coefficient for HPF
t_tatsuoka 0:7a4d80e7ea81 77 * @param hb Numerator cofficient
t_tatsuoka 0:7a4d80e7ea81 78 * @param ha Denominator cofficient
t_tatsuoka 0:7a4d80e7ea81 79 * @retval true OK
t_tatsuoka 0:7a4d80e7ea81 80 * @retval false NG
t_tatsuoka 0:7a4d80e7ea81 81 */
t_tatsuoka 0:7a4d80e7ea81 82 bool FilterTest:: set_hpf_coef(double hb, double ha)
t_tatsuoka 0:7a4d80e7ea81 83 {
t_tatsuoka 0:7a4d80e7ea81 84 if(hb > 1.0) {
t_tatsuoka 0:7a4d80e7ea81 85 return false;
t_tatsuoka 0:7a4d80e7ea81 86 } else if((ha > 1.0)||(ha < -1.0)) {
t_tatsuoka 0:7a4d80e7ea81 87 return false;
t_tatsuoka 0:7a4d80e7ea81 88 } else {
t_tatsuoka 0:7a4d80e7ea81 89 _hb = hb;
t_tatsuoka 0:7a4d80e7ea81 90 _ha = ha;
t_tatsuoka 0:7a4d80e7ea81 91 reset_hpf_buf();
t_tatsuoka 0:7a4d80e7ea81 92 return true;
t_tatsuoka 0:7a4d80e7ea81 93 }
t_tatsuoka 0:7a4d80e7ea81 94 }
t_tatsuoka 0:7a4d80e7ea81 95
t_tatsuoka 0:7a4d80e7ea81 96 /** Set coefficient for LPF
t_tatsuoka 0:7a4d80e7ea81 97 * @param lb Numerator cofficient
t_tatsuoka 0:7a4d80e7ea81 98 * @param la1 Denominator cofficient 1
t_tatsuoka 0:7a4d80e7ea81 99 * @param la2 Denominator cofficient 2
t_tatsuoka 0:7a4d80e7ea81 100 * @retval true OK
t_tatsuoka 0:7a4d80e7ea81 101 * @retval false NG
t_tatsuoka 0:7a4d80e7ea81 102 */
t_tatsuoka 0:7a4d80e7ea81 103 bool FilterTest:: set_lpf_coef(double lb, double la1, double la2)
t_tatsuoka 0:7a4d80e7ea81 104 {
t_tatsuoka 0:7a4d80e7ea81 105 if(lb > 1.0) {
t_tatsuoka 0:7a4d80e7ea81 106 return false;
t_tatsuoka 0:7a4d80e7ea81 107 } else if((la1 > 2.0)||(la1 < -2.0)) {
t_tatsuoka 0:7a4d80e7ea81 108 return false;
t_tatsuoka 0:7a4d80e7ea81 109 } else if(la2 > 1.0) {
t_tatsuoka 0:7a4d80e7ea81 110 return false;
t_tatsuoka 0:7a4d80e7ea81 111 } else {
t_tatsuoka 0:7a4d80e7ea81 112 _lb = lb;
t_tatsuoka 0:7a4d80e7ea81 113 _la1 = la1;
t_tatsuoka 0:7a4d80e7ea81 114 _la2 = la2;
t_tatsuoka 0:7a4d80e7ea81 115 reset_lpf_buf();
t_tatsuoka 0:7a4d80e7ea81 116 return true;
t_tatsuoka 0:7a4d80e7ea81 117 }
t_tatsuoka 0:7a4d80e7ea81 118 }
t_tatsuoka 0:7a4d80e7ea81 119
t_tatsuoka 0:7a4d80e7ea81 120 /** Set coefficient for BRF
t_tatsuoka 0:7a4d80e7ea81 121 * @param nb Numerator cofficient
t_tatsuoka 0:7a4d80e7ea81 122 * @param na1 Denominator cofficient 1
t_tatsuoka 0:7a4d80e7ea81 123 * @param na2 Denominator cofficient 2
t_tatsuoka 0:7a4d80e7ea81 124 * @retval true OK
t_tatsuoka 0:7a4d80e7ea81 125 * @retval false NG
t_tatsuoka 0:7a4d80e7ea81 126 */
t_tatsuoka 0:7a4d80e7ea81 127 bool FilterTest:: set_brf_coef(double nb, double na1, double na2)
t_tatsuoka 0:7a4d80e7ea81 128 {
t_tatsuoka 0:7a4d80e7ea81 129 if(nb > 1.0) {
t_tatsuoka 0:7a4d80e7ea81 130 return false;
t_tatsuoka 0:7a4d80e7ea81 131 } else if((na1 > 2.0)||(na1 < -2.0)) {
t_tatsuoka 0:7a4d80e7ea81 132 return false;
t_tatsuoka 0:7a4d80e7ea81 133 } else if(na2 > 1.0) {
t_tatsuoka 0:7a4d80e7ea81 134 return false;
t_tatsuoka 0:7a4d80e7ea81 135 } else {
t_tatsuoka 0:7a4d80e7ea81 136 _nb = nb;
t_tatsuoka 0:7a4d80e7ea81 137 _na1 = na1;
t_tatsuoka 0:7a4d80e7ea81 138 _na2 = na2;
t_tatsuoka 0:7a4d80e7ea81 139 reset_brf_buf();
t_tatsuoka 0:7a4d80e7ea81 140 return true;
t_tatsuoka 0:7a4d80e7ea81 141 }
t_tatsuoka 0:7a4d80e7ea81 142 }
t_tatsuoka 0:7a4d80e7ea81 143
t_tatsuoka 0:7a4d80e7ea81 144 /** High pass filter (1st order)
t_tatsuoka 0:7a4d80e7ea81 145 * @param x Input value
t_tatsuoka 0:7a4d80e7ea81 146 * @return Output value
t_tatsuoka 0:7a4d80e7ea81 147 *
t_tatsuoka 0:7a4d80e7ea81 148 * hb v +
t_tatsuoka 0:7a4d80e7ea81 149 * x ---I>---+---O-------+--- y
t_tatsuoka 0:7a4d80e7ea81 150 * | hw|- |
t_tatsuoka 0:7a4d80e7ea81 151 * | [z] |
t_tatsuoka 0:7a4d80e7ea81 152 * | | ha |
t_tatsuoka 0:7a4d80e7ea81 153 * +---O---<I--+
t_tatsuoka 0:7a4d80e7ea81 154 */
t_tatsuoka 0:7a4d80e7ea81 155 double FilterTest::hpf(double x)
t_tatsuoka 0:7a4d80e7ea81 156 {
t_tatsuoka 0:7a4d80e7ea81 157 double v, y;
t_tatsuoka 0:7a4d80e7ea81 158
t_tatsuoka 0:7a4d80e7ea81 159 v = _hb * x;
t_tatsuoka 0:7a4d80e7ea81 160 y = v - _hw;
t_tatsuoka 0:7a4d80e7ea81 161 _hw = v + _ha * y;
t_tatsuoka 0:7a4d80e7ea81 162 return y;
t_tatsuoka 0:7a4d80e7ea81 163 }
t_tatsuoka 0:7a4d80e7ea81 164
t_tatsuoka 0:7a4d80e7ea81 165 /** Low pass filter (2nd order)
t_tatsuoka 0:7a4d80e7ea81 166 * @param x Input value
t_tatsuoka 0:7a4d80e7ea81 167 * @return Output value
t_tatsuoka 0:7a4d80e7ea81 168 *
t_tatsuoka 0:7a4d80e7ea81 169 * lb v
t_tatsuoka 0:7a4d80e7ea81 170 * x --I>--+-----O-------+--- y
t_tatsuoka 0:7a4d80e7ea81 171 * | lw1| |
t_tatsuoka 0:7a4d80e7ea81 172 * | [z] |
t_tatsuoka 0:7a4d80e7ea81 173 * | 2 | -la1 |
t_tatsuoka 0:7a4d80e7ea81 174 * +-I>--O---<I--+
t_tatsuoka 0:7a4d80e7ea81 175 * | lw2| |
t_tatsuoka 0:7a4d80e7ea81 176 * | [z] |
t_tatsuoka 0:7a4d80e7ea81 177 * | | -la2 |
t_tatsuoka 0:7a4d80e7ea81 178 * +-----O---<I--+
t_tatsuoka 0:7a4d80e7ea81 179 */
t_tatsuoka 0:7a4d80e7ea81 180 double FilterTest::lpf(double x)
t_tatsuoka 0:7a4d80e7ea81 181 {
t_tatsuoka 0:7a4d80e7ea81 182 double v, y;
t_tatsuoka 0:7a4d80e7ea81 183
t_tatsuoka 0:7a4d80e7ea81 184 v = _lb * x;
t_tatsuoka 0:7a4d80e7ea81 185 y = v + _lw1;
t_tatsuoka 0:7a4d80e7ea81 186 _lw1 = 2 * v - _la1 * y + _lw2;
t_tatsuoka 0:7a4d80e7ea81 187 _lw2 = v - _la2 * y;
t_tatsuoka 0:7a4d80e7ea81 188 return y;
t_tatsuoka 0:7a4d80e7ea81 189 }
t_tatsuoka 0:7a4d80e7ea81 190
t_tatsuoka 0:7a4d80e7ea81 191 /** Notch filter (Band reject filter) (2nd order)
t_tatsuoka 0:7a4d80e7ea81 192 * @param x Input value
t_tatsuoka 0:7a4d80e7ea81 193 * @return Output value
t_tatsuoka 0:7a4d80e7ea81 194 *
t_tatsuoka 0:7a4d80e7ea81 195 * nb v
t_tatsuoka 0:7a4d80e7ea81 196 * x -+-I>--+----O-------+--- y
t_tatsuoka 0:7a4d80e7ea81 197 * | | nw1| |
t_tatsuoka 0:7a4d80e7ea81 198 * | | [z] |
t_tatsuoka 0:7a4d80e7ea81 199 * +| na1 | | |
t_tatsuoka 0:7a4d80e7ea81 200 * O-I>-------O |
t_tatsuoka 0:7a4d80e7ea81 201 * -| | nw2| |
t_tatsuoka 0:7a4d80e7ea81 202 * | | [z] |
t_tatsuoka 0:7a4d80e7ea81 203 * | | | -na2 |
t_tatsuoka 0:7a4d80e7ea81 204 * | +----O---<I--+
t_tatsuoka 0:7a4d80e7ea81 205 * | |
t_tatsuoka 0:7a4d80e7ea81 206 * +------------------+
t_tatsuoka 0:7a4d80e7ea81 207 */
t_tatsuoka 0:7a4d80e7ea81 208 double FilterTest::brf(double x)
t_tatsuoka 0:7a4d80e7ea81 209 {
t_tatsuoka 0:7a4d80e7ea81 210 double v, y;
t_tatsuoka 0:7a4d80e7ea81 211
t_tatsuoka 0:7a4d80e7ea81 212 v = _nb * x;
t_tatsuoka 0:7a4d80e7ea81 213 y = v + _nw1;
t_tatsuoka 0:7a4d80e7ea81 214 _nw1 = _na1 * ( x - y ) + _nw2;
t_tatsuoka 0:7a4d80e7ea81 215 _nw2 = v - _na2 * y;
t_tatsuoka 0:7a4d80e7ea81 216 return y;
t_tatsuoka 0:7a4d80e7ea81 217 }