Interface 2015年4月号 第1部 第5章および第6章のプログラム
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 | |
0x00 | Packet header (0xAA (fixed)) |
0x01 | Data type ID (0x01: Waveform ID) |
0x02 | Packet number (0 - 99) |
0x03 | Payload size (30 (fixed)) |
0x04 - 0x21 | Waveform data (short, big endian) |
FilterTest.cpp@0:7a4d80e7ea81, 2015-02-21 (annotated)
- Committer:
- t_tatsuoka
- Date:
- Sat Feb 21 19:28:57 2015 +0000
- Revision:
- 0:7a4d80e7ea81
Ver. 1.0.1 Published initial version
Who changed what in which revision?
User | Revision | Line number | New 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 | } |