Cutoff frequency variable LPF and HPF by IIR 6th-order Butterworth filter for ST Nucleo F401RE.
Dependencies: UITDSP_ADDA UIT_ACM1602NI UIT_AQM1602 UIT_IIR_Filter mbed
main.cpp@0:33908268d9ea, 2015-09-11 (annotated)
- Committer:
- MikamiUitOpen
- Date:
- Fri Sep 11 09:54:45 2015 +0000
- Revision:
- 0:33908268d9ea
1
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
MikamiUitOpen | 0:33908268d9ea | 1 | //-------------------------------------------------------------- |
MikamiUitOpen | 0:33908268d9ea | 2 | // Cutoff frequency variable LPF and HPF by IIR 8th-order filter |
MikamiUitOpen | 0:33908268d9ea | 3 | // A0: Signal to be filtered |
MikamiUitOpen | 0:33908268d9ea | 4 | // A2: Value which controls cutoff frequency |
MikamiUitOpen | 0:33908268d9ea | 5 | // |
MikamiUitOpen | 0:33908268d9ea | 6 | // sw: 0, 2 Through |
MikamiUitOpen | 0:33908268d9ea | 7 | // 1: LPF |
MikamiUitOpen | 0:33908268d9ea | 8 | // 3: HPF |
MikamiUitOpen | 0:33908268d9ea | 9 | // 2015/09/11, Copyright (c) 2015 MIKAMI, Naoki |
MikamiUitOpen | 0:33908268d9ea | 10 | //-------------------------------------------------------------- |
MikamiUitOpen | 0:33908268d9ea | 11 | |
MikamiUitOpen | 0:33908268d9ea | 12 | #include "ADC_Interrupt.hpp" // for ADC using interrupt |
MikamiUitOpen | 0:33908268d9ea | 13 | #include "DAC_MCP4921.hpp" // for DAC MCP4921, MCP4922 |
MikamiUitOpen | 0:33908268d9ea | 14 | using namespace Mikami; |
MikamiUitOpen | 0:33908268d9ea | 15 | |
MikamiUitOpen | 0:33908268d9ea | 16 | #include "BilinearDesignLH.hpp" // for design of IIR filter |
MikamiUitOpen | 0:33908268d9ea | 17 | #include "IIR_Cascade.hpp" // for IIR filter of cascade structure |
MikamiUitOpen | 0:33908268d9ea | 18 | |
MikamiUitOpen | 0:33908268d9ea | 19 | // ACM1602Ni を使う場合は次の define 文をコメントにすること |
MikamiUitOpen | 0:33908268d9ea | 20 | #define AQM1602 |
MikamiUitOpen | 0:33908268d9ea | 21 | |
MikamiUitOpen | 0:33908268d9ea | 22 | #ifdef AQM1602 |
MikamiUitOpen | 0:33908268d9ea | 23 | #include "AQM1602.hpp" |
MikamiUitOpen | 0:33908268d9ea | 24 | Aqm1602 Lcd_; |
MikamiUitOpen | 0:33908268d9ea | 25 | #else |
MikamiUitOpen | 0:33908268d9ea | 26 | #include "ACM1602NI.hpp" |
MikamiUitOpen | 0:33908268d9ea | 27 | Acm1602Ni Lcd_; |
MikamiUitOpen | 0:33908268d9ea | 28 | #endif |
MikamiUitOpen | 0:33908268d9ea | 29 | |
MikamiUitOpen | 0:33908268d9ea | 30 | const int FS_ = 24000; // Sampling frequency: 24 kHz |
MikamiUitOpen | 0:33908268d9ea | 31 | ADC_Intr myAdc_(A0, FS_, A2); |
MikamiUitOpen | 0:33908268d9ea | 32 | DAC_MCP4921 myDac_; |
MikamiUitOpen | 0:33908268d9ea | 33 | |
MikamiUitOpen | 0:33908268d9ea | 34 | const int ORDER_ = 8; |
MikamiUitOpen | 0:33908268d9ea | 35 | IirCascade<ORDER_> iirLH_; // IIR filter object |
MikamiUitOpen | 0:33908268d9ea | 36 | |
MikamiUitOpen | 0:33908268d9ea | 37 | DigitalIn sw1_(D2, PullDown); // 0: disable filter |
MikamiUitOpen | 0:33908268d9ea | 38 | // 1: enable filter |
MikamiUitOpen | 0:33908268d9ea | 39 | DigitalIn sw2_(D3, PullDown); |
MikamiUitOpen | 0:33908268d9ea | 40 | |
MikamiUitOpen | 0:33908268d9ea | 41 | uint16_t a2_ = 0; // Inputted data from A2 pin |
MikamiUitOpen | 0:33908268d9ea | 42 | |
MikamiUitOpen | 0:33908268d9ea | 43 | // Interrupt service routine for ADC |
MikamiUitOpen | 0:33908268d9ea | 44 | void AdcIsr() |
MikamiUitOpen | 0:33908268d9ea | 45 | { |
MikamiUitOpen | 0:33908268d9ea | 46 | float xn = myAdc_.Read(); // Read from A0 |
MikamiUitOpen | 0:33908268d9ea | 47 | |
MikamiUitOpen | 0:33908268d9ea | 48 | myAdc_.Select2ndChannel(); // Select A2 |
MikamiUitOpen | 0:33908268d9ea | 49 | myAdc_.SoftStart(); // ADC start for A2 input |
MikamiUitOpen | 0:33908268d9ea | 50 | |
MikamiUitOpen | 0:33908268d9ea | 51 | // Execute IIR filter |
MikamiUitOpen | 0:33908268d9ea | 52 | float yn = iirLH_.Execute(xn); |
MikamiUitOpen | 0:33908268d9ea | 53 | |
MikamiUitOpen | 0:33908268d9ea | 54 | if (sw1_ == 0) myDac_.Write(xn); // Using no filter |
MikamiUitOpen | 0:33908268d9ea | 55 | else myDac_.Write(yn); // Using filter |
MikamiUitOpen | 0:33908268d9ea | 56 | |
MikamiUitOpen | 0:33908268d9ea | 57 | // Read value which controls cutoff frequency |
MikamiUitOpen | 0:33908268d9ea | 58 | a2_ = myAdc_.ReadWait_u16(); |
MikamiUitOpen | 0:33908268d9ea | 59 | |
MikamiUitOpen | 0:33908268d9ea | 60 | myAdc_.Select1stChannel(); // Select A0 |
MikamiUitOpen | 0:33908268d9ea | 61 | myAdc_.ClearPending_EnableIRQ();// Clear pending interrupt |
MikamiUitOpen | 0:33908268d9ea | 62 | // and enable ADC_IRQn |
MikamiUitOpen | 0:33908268d9ea | 63 | } |
MikamiUitOpen | 0:33908268d9ea | 64 | |
MikamiUitOpen | 0:33908268d9ea | 65 | int main() |
MikamiUitOpen | 0:33908268d9ea | 66 | { |
MikamiUitOpen | 0:33908268d9ea | 67 | myDac_.ScfClockTim3(1000000); // cutoff frequency: 10 kHz |
MikamiUitOpen | 0:33908268d9ea | 68 | |
MikamiUitOpen | 0:33908268d9ea | 69 | BilinearDesign lpfDsgn(ORDER_, FS_, BilinearDesign::LPF); |
MikamiUitOpen | 0:33908268d9ea | 70 | BilinearDesign hpfDsgn(ORDER_, FS_, BilinearDesign::HPF); |
MikamiUitOpen | 0:33908268d9ea | 71 | |
MikamiUitOpen | 0:33908268d9ea | 72 | myAdc_.SetIntrVec(AdcIsr); // Assign ISR for ADC interrupt |
MikamiUitOpen | 0:33908268d9ea | 73 | |
MikamiUitOpen | 0:33908268d9ea | 74 | float fc1 = 0; |
MikamiUitOpen | 0:33908268d9ea | 75 | while (true) |
MikamiUitOpen | 0:33908268d9ea | 76 | { |
MikamiUitOpen | 0:33908268d9ea | 77 | // fc: cutoff frequency, 100 -- 2000 Hz |
MikamiUitOpen | 0:33908268d9ea | 78 | float fc = 1900.0f*(a2_/4095.6f) + 100.0f; |
MikamiUitOpen | 0:33908268d9ea | 79 | |
MikamiUitOpen | 0:33908268d9ea | 80 | if (sw1_ == 0) |
MikamiUitOpen | 0:33908268d9ea | 81 | { |
MikamiUitOpen | 0:33908268d9ea | 82 | printf("Through\r\n"); |
MikamiUitOpen | 0:33908268d9ea | 83 | Lcd_.WriteStringXY("Through ", 0, 0); |
MikamiUitOpen | 0:33908268d9ea | 84 | wait(0.2f); |
MikamiUitOpen | 0:33908268d9ea | 85 | Lcd_.ClearLine(0); |
MikamiUitOpen | 0:33908268d9ea | 86 | fc1 = 0; |
MikamiUitOpen | 0:33908268d9ea | 87 | } |
MikamiUitOpen | 0:33908268d9ea | 88 | else |
MikamiUitOpen | 0:33908268d9ea | 89 | { |
MikamiUitOpen | 0:33908268d9ea | 90 | if (fabs(fc - fc1) > 10.0f) |
MikamiUitOpen | 0:33908268d9ea | 91 | { |
MikamiUitOpen | 0:33908268d9ea | 92 | char str[18]; |
MikamiUitOpen | 0:33908268d9ea | 93 | if (sw2_ == 0) sprintf(str, "LPF: fc=%4d Hz", int(fc+0.5f)); |
MikamiUitOpen | 0:33908268d9ea | 94 | else sprintf(str, "HPF: fc=%4d Hz", int(fc+0.5f)); |
MikamiUitOpen | 0:33908268d9ea | 95 | |
MikamiUitOpen | 0:33908268d9ea | 96 | printf("%s\r\n", str); |
MikamiUitOpen | 0:33908268d9ea | 97 | Lcd_.WriteStringXY(str, 0, 0); |
MikamiUitOpen | 0:33908268d9ea | 98 | fc1 = fc; |
MikamiUitOpen | 0:33908268d9ea | 99 | |
MikamiUitOpen | 0:33908268d9ea | 100 | // Design new coefficients based on new fc |
MikamiUitOpen | 0:33908268d9ea | 101 | BilinearDesign::Coefs coefs[ORDER_/2]; |
MikamiUitOpen | 0:33908268d9ea | 102 | float g0; |
MikamiUitOpen | 0:33908268d9ea | 103 | if (sw2_ == 0) lpfDsgn.Execute(fc, coefs, g0); |
MikamiUitOpen | 0:33908268d9ea | 104 | else hpfDsgn.Execute(fc, coefs, g0); |
MikamiUitOpen | 0:33908268d9ea | 105 | Biquad::Coefs coefsIir[ORDER_/2]; |
MikamiUitOpen | 0:33908268d9ea | 106 | // Update new coefficients |
MikamiUitOpen | 0:33908268d9ea | 107 | for (int n=0; n<ORDER_/2; n++) |
MikamiUitOpen | 0:33908268d9ea | 108 | { |
MikamiUitOpen | 0:33908268d9ea | 109 | coefsIir[n].a1 = coefs[n].a1; |
MikamiUitOpen | 0:33908268d9ea | 110 | coefsIir[n].a2 = coefs[n].a2; |
MikamiUitOpen | 0:33908268d9ea | 111 | coefsIir[n].b1 = coefs[n].b1; |
MikamiUitOpen | 0:33908268d9ea | 112 | coefsIir[n].b2 = 1.0f; |
MikamiUitOpen | 0:33908268d9ea | 113 | } |
MikamiUitOpen | 0:33908268d9ea | 114 | iirLH_.SetCoefs(g0, coefsIir); |
MikamiUitOpen | 0:33908268d9ea | 115 | } |
MikamiUitOpen | 0:33908268d9ea | 116 | } |
MikamiUitOpen | 0:33908268d9ea | 117 | wait(0.1f); |
MikamiUitOpen | 0:33908268d9ea | 118 | } |
MikamiUitOpen | 0:33908268d9ea | 119 | } |