Cutoff frequency variable LPF by 160th-order FIR filter designed by window method usin Hamming window for ST Nucleo F401RE.
Dependencies: UIT_ACM1602NI UIT_ADDA mbed
main.cpp@3:54eac4891e35, 2014-11-12 (annotated)
- Committer:
- MikamiUitOpen
- Date:
- Wed Nov 12 10:54:38 2014 +0000
- Revision:
- 3:54eac4891e35
- Parent:
- 1:24c33c8719b2
- Child:
- 5:9dd178ff6239
4
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
MikamiUitOpen | 0:b8bffbcb85fd | 1 | //------------------------------------------------------------------ |
MikamiUitOpen | 1:24c33c8719b2 | 2 | // Cutoff frequency variable LPF by FIR 160th-order filter |
MikamiUitOpen | 0:b8bffbcb85fd | 3 | // A0: Signal to be filtered |
MikamiUitOpen | 0:b8bffbcb85fd | 4 | // A2: Value which controls cutoff frequency |
MikamiUitOpen | 0:b8bffbcb85fd | 5 | // |
MikamiUitOpen | 3:54eac4891e35 | 6 | // 2014/11/12, Copyright (c) 2014 MIKAMI, Naoki |
MikamiUitOpen | 0:b8bffbcb85fd | 7 | //------------------------------------------------------------------ |
MikamiUitOpen | 0:b8bffbcb85fd | 8 | |
MikamiUitOpen | 0:b8bffbcb85fd | 9 | #include "mbed.h" |
MikamiUitOpen | 0:b8bffbcb85fd | 10 | |
MikamiUitOpen | 0:b8bffbcb85fd | 11 | #include "ADC_Interrupt.hpp" // for ADC using interrupt |
MikamiUitOpen | 0:b8bffbcb85fd | 12 | #include "DAC_MCP4922.hpp" // for DAC MCP4922 |
MikamiUitOpen | 0:b8bffbcb85fd | 13 | #include "ACM1602NI.hpp" // for LCD display |
MikamiUitOpen | 0:b8bffbcb85fd | 14 | |
MikamiUitOpen | 0:b8bffbcb85fd | 15 | #include "WindowingDesignLH.hpp" // for design of IIR filter |
MikamiUitOpen | 0:b8bffbcb85fd | 16 | |
MikamiUitOpen | 0:b8bffbcb85fd | 17 | using namespace Mikami; |
MikamiUitOpen | 0:b8bffbcb85fd | 18 | |
MikamiUitOpen | 0:b8bffbcb85fd | 19 | const int FS_ = 16000; // Sampling frequency: 16 kHz |
MikamiUitOpen | 0:b8bffbcb85fd | 20 | ADC_Intr myAdc_(A0, FS_, A1, A2); |
MikamiUitOpen | 0:b8bffbcb85fd | 21 | DAC_MCP4922 myDac_; |
MikamiUitOpen | 0:b8bffbcb85fd | 22 | |
MikamiUitOpen | 0:b8bffbcb85fd | 23 | const int ORDER_ = 160; |
MikamiUitOpen | 0:b8bffbcb85fd | 24 | float hm_[ORDER_/2+1]; |
MikamiUitOpen | 0:b8bffbcb85fd | 25 | float xn_[ORDER_+1]; |
MikamiUitOpen | 0:b8bffbcb85fd | 26 | |
MikamiUitOpen | 0:b8bffbcb85fd | 27 | DigitalIn sw1_(D2, PullDown); // 0: disable filter |
MikamiUitOpen | 0:b8bffbcb85fd | 28 | // 1: enable filter |
MikamiUitOpen | 0:b8bffbcb85fd | 29 | WindowingDesign design_(ORDER_, FS_); |
MikamiUitOpen | 0:b8bffbcb85fd | 30 | DigitalOut dOut_(D7); |
MikamiUitOpen | 0:b8bffbcb85fd | 31 | |
MikamiUitOpen | 0:b8bffbcb85fd | 32 | uint16_t a2_ = 0; // Inputted data from A2 pin |
MikamiUitOpen | 0:b8bffbcb85fd | 33 | |
MikamiUitOpen | 0:b8bffbcb85fd | 34 | // Interrupt service routine for ADC |
MikamiUitOpen | 0:b8bffbcb85fd | 35 | void AdcIsr() |
MikamiUitOpen | 0:b8bffbcb85fd | 36 | { |
MikamiUitOpen | 0:b8bffbcb85fd | 37 | dOut_.write(1); |
MikamiUitOpen | 0:b8bffbcb85fd | 38 | xn_[0] = myAdc_.Read(); // Read from A0 |
MikamiUitOpen | 0:b8bffbcb85fd | 39 | |
MikamiUitOpen | 0:b8bffbcb85fd | 40 | myAdc_.Select3rdChannel(); // Select A2 |
MikamiUitOpen | 0:b8bffbcb85fd | 41 | myAdc_.SoftStart(); // ADC start for A2 input |
MikamiUitOpen | 0:b8bffbcb85fd | 42 | |
MikamiUitOpen | 0:b8bffbcb85fd | 43 | //----------------------------------------- |
MikamiUitOpen | 0:b8bffbcb85fd | 44 | // Execute FIR filter |
MikamiUitOpen | 0:b8bffbcb85fd | 45 | float yn = hm_[ORDER_/2]*xn_[ORDER_/2]; |
MikamiUitOpen | 0:b8bffbcb85fd | 46 | for (int k=0; k<ORDER_/2; k++) |
MikamiUitOpen | 0:b8bffbcb85fd | 47 | yn = yn + hm_[k]*(xn_[k] + xn_[ORDER_-k]); |
MikamiUitOpen | 0:b8bffbcb85fd | 48 | |
MikamiUitOpen | 0:b8bffbcb85fd | 49 | for (int k=ORDER_; k>0; k--) |
MikamiUitOpen | 0:b8bffbcb85fd | 50 | xn_[k] = xn_[k-1]; // move input signals |
MikamiUitOpen | 0:b8bffbcb85fd | 51 | //----------------------------------------- |
MikamiUitOpen | 0:b8bffbcb85fd | 52 | |
MikamiUitOpen | 0:b8bffbcb85fd | 53 | if (sw1_ == 0) myDac_.Write(xn_[0]); // Using no filter |
MikamiUitOpen | 0:b8bffbcb85fd | 54 | else myDac_.Write(yn); // Using filter |
MikamiUitOpen | 0:b8bffbcb85fd | 55 | |
MikamiUitOpen | 0:b8bffbcb85fd | 56 | // Read value which controls cutoff frequency |
MikamiUitOpen | 0:b8bffbcb85fd | 57 | a2_ = myAdc_.ReadWait_u16(); |
MikamiUitOpen | 0:b8bffbcb85fd | 58 | |
MikamiUitOpen | 0:b8bffbcb85fd | 59 | myAdc_.Select1stChannel(); // Select A0 |
MikamiUitOpen | 0:b8bffbcb85fd | 60 | myAdc_.ClearPending_EnableIRQ();// Clear pending interrupt |
MikamiUitOpen | 0:b8bffbcb85fd | 61 | // and enable ADC_IRQn |
MikamiUitOpen | 0:b8bffbcb85fd | 62 | dOut_.write(0); |
MikamiUitOpen | 0:b8bffbcb85fd | 63 | } |
MikamiUitOpen | 0:b8bffbcb85fd | 64 | |
MikamiUitOpen | 0:b8bffbcb85fd | 65 | int main() |
MikamiUitOpen | 0:b8bffbcb85fd | 66 | { |
MikamiUitOpen | 3:54eac4891e35 | 67 | myDac_.ScfClockTim3(670000); // cutoff frequency: 6.7 kHz |
MikamiUitOpen | 0:b8bffbcb85fd | 68 | |
MikamiUitOpen | 0:b8bffbcb85fd | 69 | WindowingDesign lpfDsgn(ORDER_, FS_); |
MikamiUitOpen | 0:b8bffbcb85fd | 70 | Acm1602Ni lcd; // objetc for display using LCD |
MikamiUitOpen | 0:b8bffbcb85fd | 71 | |
MikamiUitOpen | 0:b8bffbcb85fd | 72 | // Clear buffer in FIR filter |
MikamiUitOpen | 0:b8bffbcb85fd | 73 | for (int n=0; n<=ORDER_; n++) |
MikamiUitOpen | 0:b8bffbcb85fd | 74 | xn_[n] = 0; |
MikamiUitOpen | 0:b8bffbcb85fd | 75 | myAdc_.SetIntrVec(AdcIsr); // Assign ISR for ADC interrupt |
MikamiUitOpen | 0:b8bffbcb85fd | 76 | |
MikamiUitOpen | 0:b8bffbcb85fd | 77 | float fc1 = 0; |
MikamiUitOpen | 0:b8bffbcb85fd | 78 | while (true) |
MikamiUitOpen | 0:b8bffbcb85fd | 79 | { |
MikamiUitOpen | 0:b8bffbcb85fd | 80 | // fc: cutoff frequency, 100 -- 2000 Hz |
MikamiUitOpen | 0:b8bffbcb85fd | 81 | float fc = 1900.0f*(a2_/4095.6f) + 100.0f; |
MikamiUitOpen | 0:b8bffbcb85fd | 82 | |
MikamiUitOpen | 0:b8bffbcb85fd | 83 | if (sw1_ == 0) |
MikamiUitOpen | 0:b8bffbcb85fd | 84 | { |
MikamiUitOpen | 0:b8bffbcb85fd | 85 | printf("Through\r\n"); |
MikamiUitOpen | 0:b8bffbcb85fd | 86 | lcd.WriteStringXY("Through ", 0, 0); |
MikamiUitOpen | 0:b8bffbcb85fd | 87 | wait(0.2f); |
MikamiUitOpen | 0:b8bffbcb85fd | 88 | lcd.ClearLine(0); |
MikamiUitOpen | 0:b8bffbcb85fd | 89 | fc1 = 0; |
MikamiUitOpen | 0:b8bffbcb85fd | 90 | } |
MikamiUitOpen | 0:b8bffbcb85fd | 91 | else |
MikamiUitOpen | 0:b8bffbcb85fd | 92 | { |
MikamiUitOpen | 0:b8bffbcb85fd | 93 | if (fabs(fc - fc1) > 10.0f) |
MikamiUitOpen | 0:b8bffbcb85fd | 94 | { |
MikamiUitOpen | 0:b8bffbcb85fd | 95 | printf("fc = %4d\r\n", int(fc+0.5f)); |
MikamiUitOpen | 0:b8bffbcb85fd | 96 | char str[18]; |
MikamiUitOpen | 0:b8bffbcb85fd | 97 | sprintf(str, "fc = %4d Hz", int(fc+0.5f)); |
MikamiUitOpen | 0:b8bffbcb85fd | 98 | lcd.WriteStringXY(str, 0, 0); |
MikamiUitOpen | 0:b8bffbcb85fd | 99 | fc1 = fc; |
MikamiUitOpen | 0:b8bffbcb85fd | 100 | // Design new coefficients based on new fc |
MikamiUitOpen | 1:24c33c8719b2 | 101 | design_.Design(ORDER_, WindowingDesign::LPF, fc1, hm_); |
MikamiUitOpen | 0:b8bffbcb85fd | 102 | } |
MikamiUitOpen | 0:b8bffbcb85fd | 103 | } |
MikamiUitOpen | 0:b8bffbcb85fd | 104 | wait(0.1f); |
MikamiUitOpen | 0:b8bffbcb85fd | 105 | } |
MikamiUitOpen | 0:b8bffbcb85fd | 106 | } |