![](/media/cache/img/default_profile.jpg.50x50_q85.jpg)
Cutoff frequency variable LPF by IIR 6th-order Butterworth filter for ST Nucleo F401RE.
Dependencies: UIT_IIR_Filter UIT_ACM1602NI UITDSP_ADDA mbed UIT_AQM1602
main.cpp@5:b291c4653eb9, 2014-12-07 (annotated)
- Committer:
- MikamiUitOpen
- Date:
- Sun Dec 07 05:45:07 2014 +0000
- Revision:
- 5:b291c4653eb9
- Parent:
- 4:460f2285dd87
- Child:
- 6:116f72cda0f4
6
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
MikamiUitOpen | 0:a9412b9e85b7 | 1 | //-------------------------------------------------------------- |
MikamiUitOpen | 0:a9412b9e85b7 | 2 | // Cutoff frequency variable LPF by IIR 6th-order filter |
MikamiUitOpen | 0:a9412b9e85b7 | 3 | // A0: Signal to be filtered |
MikamiUitOpen | 0:a9412b9e85b7 | 4 | // A2: Value which controls cutoff frequency |
MikamiUitOpen | 0:a9412b9e85b7 | 5 | // |
MikamiUitOpen | 4:460f2285dd87 | 6 | // 2014/11/15, Copyright (c) 2014 MIKAMI, Naoki |
MikamiUitOpen | 0:a9412b9e85b7 | 7 | //-------------------------------------------------------------- |
MikamiUitOpen | 0:a9412b9e85b7 | 8 | |
MikamiUitOpen | 0:a9412b9e85b7 | 9 | #include "mbed.h" |
MikamiUitOpen | 0:a9412b9e85b7 | 10 | |
MikamiUitOpen | 0:a9412b9e85b7 | 11 | #include "ADC_Interrupt.hpp" // for ADC using interrupt |
MikamiUitOpen | 0:a9412b9e85b7 | 12 | #include "DAC_MCP4922.hpp" // for DAC MCP4922 |
MikamiUitOpen | 0:a9412b9e85b7 | 13 | #include "ACM1602NI.hpp" // for LCD display |
MikamiUitOpen | 0:a9412b9e85b7 | 14 | |
MikamiUitOpen | 0:a9412b9e85b7 | 15 | #include "BilinearDesignLH.hpp" // for design of IIR filter |
MikamiUitOpen | 0:a9412b9e85b7 | 16 | #include "IIR_Cascade.hpp" // for IIR filter of cascade structure |
MikamiUitOpen | 0:a9412b9e85b7 | 17 | |
MikamiUitOpen | 0:a9412b9e85b7 | 18 | using namespace Mikami; |
MikamiUitOpen | 0:a9412b9e85b7 | 19 | |
MikamiUitOpen | 0:a9412b9e85b7 | 20 | const int FS_ = 24000; // Sampling frequency: 24 kHz |
MikamiUitOpen | 0:a9412b9e85b7 | 21 | ADC_Intr myAdc_(A0, FS_, A1, A2); |
MikamiUitOpen | 0:a9412b9e85b7 | 22 | DAC_MCP4922 myDac_; |
MikamiUitOpen | 0:a9412b9e85b7 | 23 | |
MikamiUitOpen | 0:a9412b9e85b7 | 24 | const int ORDER_ = 6; |
MikamiUitOpen | 0:a9412b9e85b7 | 25 | IirCascade<ORDER_/2> iirLpf_; // IIR filter object |
MikamiUitOpen | 0:a9412b9e85b7 | 26 | |
MikamiUitOpen | 0:a9412b9e85b7 | 27 | DigitalIn sw1_(D2, PullDown); // 0: disable filter |
MikamiUitOpen | 0:a9412b9e85b7 | 28 | // 1: enable filter |
MikamiUitOpen | 0:a9412b9e85b7 | 29 | |
MikamiUitOpen | 0:a9412b9e85b7 | 30 | uint16_t a2_ = 0; // Inputted data from A2 pin |
MikamiUitOpen | 0:a9412b9e85b7 | 31 | |
MikamiUitOpen | 0:a9412b9e85b7 | 32 | // Interrupt service routine for ADC |
MikamiUitOpen | 0:a9412b9e85b7 | 33 | void AdcIsr() |
MikamiUitOpen | 0:a9412b9e85b7 | 34 | { |
MikamiUitOpen | 0:a9412b9e85b7 | 35 | float xn = myAdc_.Read(); // Read from A0 |
MikamiUitOpen | 0:a9412b9e85b7 | 36 | |
MikamiUitOpen | 0:a9412b9e85b7 | 37 | myAdc_.Select3rdChannel(); // Select A2 |
MikamiUitOpen | 0:a9412b9e85b7 | 38 | myAdc_.SoftStart(); // ADC start for A2 input |
MikamiUitOpen | 0:a9412b9e85b7 | 39 | |
MikamiUitOpen | 0:a9412b9e85b7 | 40 | // Execute IIR filter |
MikamiUitOpen | 0:a9412b9e85b7 | 41 | float yn = iirLpf_.Execute(xn); |
MikamiUitOpen | 0:a9412b9e85b7 | 42 | |
MikamiUitOpen | 0:a9412b9e85b7 | 43 | if (sw1_ == 0) myDac_.Write(xn); // Using no filter |
MikamiUitOpen | 0:a9412b9e85b7 | 44 | else myDac_.Write(yn); // Using filter |
MikamiUitOpen | 0:a9412b9e85b7 | 45 | |
MikamiUitOpen | 0:a9412b9e85b7 | 46 | // Read value which controls cutoff frequency |
MikamiUitOpen | 0:a9412b9e85b7 | 47 | a2_ = myAdc_.ReadWait_u16(); |
MikamiUitOpen | 0:a9412b9e85b7 | 48 | |
MikamiUitOpen | 0:a9412b9e85b7 | 49 | myAdc_.Select1stChannel(); // Select A0 |
MikamiUitOpen | 0:a9412b9e85b7 | 50 | myAdc_.ClearPending_EnableIRQ();// Clear pending interrupt |
MikamiUitOpen | 0:a9412b9e85b7 | 51 | // and enable ADC_IRQn |
MikamiUitOpen | 0:a9412b9e85b7 | 52 | } |
MikamiUitOpen | 0:a9412b9e85b7 | 53 | |
MikamiUitOpen | 0:a9412b9e85b7 | 54 | int main() |
MikamiUitOpen | 0:a9412b9e85b7 | 55 | { |
MikamiUitOpen | 0:a9412b9e85b7 | 56 | const int ORDER = 6; |
MikamiUitOpen | 3:4086d5ad6e7a | 57 | myDac_.ScfClockTim3(1000000); // cutoff frequency: 10 kHz |
MikamiUitOpen | 0:a9412b9e85b7 | 58 | |
MikamiUitOpen | 5:b291c4653eb9 | 59 | BilinearDesign lpfDsgn(ORDER, FS_, BilinearDesign::LPF); |
MikamiUitOpen | 0:a9412b9e85b7 | 60 | Acm1602Ni lcd; // objetc for display using LCD |
MikamiUitOpen | 0:a9412b9e85b7 | 61 | |
MikamiUitOpen | 0:a9412b9e85b7 | 62 | myAdc_.SetIntrVec(AdcIsr); // Assign ISR for ADC interrupt |
MikamiUitOpen | 0:a9412b9e85b7 | 63 | |
MikamiUitOpen | 0:a9412b9e85b7 | 64 | float fc1 = 0; |
MikamiUitOpen | 0:a9412b9e85b7 | 65 | while (true) |
MikamiUitOpen | 0:a9412b9e85b7 | 66 | { |
MikamiUitOpen | 4:460f2285dd87 | 67 | // fc: cutoff frequency, 100 -- 2000 Hz |
MikamiUitOpen | 4:460f2285dd87 | 68 | float fc = 1900.0f*(a2_/4095.6f) + 100.0f; |
MikamiUitOpen | 0:a9412b9e85b7 | 69 | |
MikamiUitOpen | 1:e9b451a71ebf | 70 | if (sw1_ == 0) |
MikamiUitOpen | 0:a9412b9e85b7 | 71 | { |
MikamiUitOpen | 1:e9b451a71ebf | 72 | printf("Through\r\n"); |
MikamiUitOpen | 1:e9b451a71ebf | 73 | lcd.WriteStringXY("Through ", 0, 0); |
MikamiUitOpen | 1:e9b451a71ebf | 74 | wait(0.2f); |
MikamiUitOpen | 1:e9b451a71ebf | 75 | lcd.ClearLine(0); |
MikamiUitOpen | 1:e9b451a71ebf | 76 | fc1 = 0; |
MikamiUitOpen | 1:e9b451a71ebf | 77 | } |
MikamiUitOpen | 1:e9b451a71ebf | 78 | else |
MikamiUitOpen | 1:e9b451a71ebf | 79 | { |
MikamiUitOpen | 1:e9b451a71ebf | 80 | if (fabs(fc - fc1) > 10.0f) |
MikamiUitOpen | 1:e9b451a71ebf | 81 | { |
MikamiUitOpen | 1:e9b451a71ebf | 82 | printf("fc = %4d\r\n", int(fc+0.5f)); |
MikamiUitOpen | 1:e9b451a71ebf | 83 | char str[18]; |
MikamiUitOpen | 1:e9b451a71ebf | 84 | sprintf(str, "fc = %4d Hz", int(fc+0.5f)); |
MikamiUitOpen | 1:e9b451a71ebf | 85 | lcd.WriteStringXY(str, 0, 0); |
MikamiUitOpen | 1:e9b451a71ebf | 86 | fc1 = fc; |
MikamiUitOpen | 0:a9412b9e85b7 | 87 | |
MikamiUitOpen | 1:e9b451a71ebf | 88 | // Design new coefficients based on new fc |
MikamiUitOpen | 5:b291c4653eb9 | 89 | BilinearDesign::Coefs coefsLpf[ORDER/2]; |
MikamiUitOpen | 1:e9b451a71ebf | 90 | float g0; |
MikamiUitOpen | 1:e9b451a71ebf | 91 | lpfDsgn.Execute(fc, coefsLpf, g0); |
MikamiUitOpen | 0:a9412b9e85b7 | 92 | |
MikamiUitOpen | 1:e9b451a71ebf | 93 | // Update new coefficients |
MikamiUitOpen | 1:e9b451a71ebf | 94 | Biquad::Coefs coefsIir[ORDER/2]; |
MikamiUitOpen | 1:e9b451a71ebf | 95 | for (int n=0; n<ORDER/2; n++) |
MikamiUitOpen | 1:e9b451a71ebf | 96 | { |
MikamiUitOpen | 1:e9b451a71ebf | 97 | coefsIir[n].a1 = coefsLpf[n].a1; |
MikamiUitOpen | 1:e9b451a71ebf | 98 | coefsIir[n].a2 = coefsLpf[n].a2; |
MikamiUitOpen | 1:e9b451a71ebf | 99 | coefsIir[n].b1 = coefsLpf[n].b1; |
MikamiUitOpen | 1:e9b451a71ebf | 100 | coefsIir[n].b2 = 1.0f; |
MikamiUitOpen | 1:e9b451a71ebf | 101 | } |
MikamiUitOpen | 1:e9b451a71ebf | 102 | iirLpf_.SetCoefs(g0, coefsIir); |
MikamiUitOpen | 0:a9412b9e85b7 | 103 | } |
MikamiUitOpen | 0:a9412b9e85b7 | 104 | } |
MikamiUitOpen | 0:a9412b9e85b7 | 105 | wait(0.1f); |
MikamiUitOpen | 0:a9412b9e85b7 | 106 | } |
MikamiUitOpen | 0:a9412b9e85b7 | 107 | } |