![](/media/cache/img/default_profile.jpg.50x50_q85.jpg)
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
Revision 0:33908268d9ea, committed 2015-09-11
- Comitter:
- MikamiUitOpen
- Date:
- Fri Sep 11 09:54:45 2015 +0000
- Commit message:
- 1
Changed in this revision
diff -r 000000000000 -r 33908268d9ea BilinearDesignLpfHpf/BilinearDesignLH.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/BilinearDesignLpfHpf/BilinearDesignLH.cpp Fri Sep 11 09:54:45 2015 +0000 @@ -0,0 +1,81 @@ +//------------------------------------------------------------------------------ +// Design of Butterworth LPF and HPF using bilinear transform +// +// 2014/06/29, Copyright (c) 2014 MIKAMI, Naoki +//------------------------------------------------------------------------------ + +#include "BilinearDesignLH.hpp" + +namespace Mikami +{ + // Execute design + // input + // fc: Cutoff frequency + // output + // c : Coefficients for cascade structure + // g : Gain factor for cascade structure + void BilinearDesign::Execute(float fc, Coefs c[], float& g) + { + Butterworth(); + Bilinear(fc); + ToCascade(); + GetGain(); + GetCoefs(c, g); + } + + // Get poles for Butterworth characteristics + void BilinearDesign::Butterworth() + { + float pi_2order = PI_/(2.0f*ORDER_); + for (int j=0; j<ORDER_/2; j++) // Pole with imaginary part >= 0 + { + float theta = (2.0f*j + 1.0f)*pi_2order; + sP_[j] = Complex(-cosf(theta), sinf(theta)); + } + } + + // Bilinear transform + // fc: Cutoff frequency + void BilinearDesign::Bilinear(float fc) + { + float wc = tanf(fc*PI_FS_); + for (int k=0; k<ORDER_/2; k++) + zP_[k] = (1.0f + wc*sP_[k])/(1.0f - wc*sP_[k]); + } + + // Convert to coefficients for cascade structure + void BilinearDesign::ToCascade() + { + for (int j=0; j<ORDER_/2; j++) + { + ck_[j].a1 = 2.0f*real(zP_[j]); // a1m + ck_[j].a2 = -norm(zP_[j]); // a2m + ck_[j].b1 = (PB_ == LPF) ? 2.0f : -2.0f; // b1m + } + } + + // Calculate gain factor + void BilinearDesign::GetGain(){ + float u = (PB_ == LPF) ? 1.0f : -1.0f; + float g0 = 1.0f; + for (int k=0; k<ORDER_/2; k++) + g0 = g0*(1.0f - (ck_[k].a1 + ck_[k].a2*u)*u)/ + (1.0f + (ck_[k].b1 + u)*u); + gain_ = g0; + } + + // Get coefficients + void BilinearDesign::GetCoefs(Coefs c[], float& gain) + { + for (int k=0; k<ORDER_/2; k++) + { + c[k].a1 = ck_[k].a1; + c[k].a2 = ck_[k].a2; + c[k].b1 = ck_[k].b1; + } + gain = gain_; + } +} + + +
diff -r 000000000000 -r 33908268d9ea BilinearDesignLpfHpf/BilinearDesignLH.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/BilinearDesignLpfHpf/BilinearDesignLH.hpp Fri Sep 11 09:54:45 2015 +0000 @@ -0,0 +1,62 @@ +//------------------------------------------------------------------------------ +// Design of Butterworth LPF and HPF using bilinear transform -- Header +// +// 2014/06/29, Copyright (c) 2014 MIKAMI, Naoki +//------------------------------------------------------------------------------ + +#ifndef BILINEAR_BUTTERWORTH_HPP +#define BILINEAR_BUTTERWORTH_HPP + +#include "mbed.h" +#include <complex> // requisite + +namespace Mikami +{ + typedef complex<float> Complex; // define "Complex" + + class BilinearDesign + { + public: + struct Coefs { float a1, a2, b1; }; + enum Type { LPF, HPF }; + + // Constructor + BilinearDesign(int order, float fs, Type pb) + : PI_FS_(PI_/fs), ORDER_(order), PB_(pb) + { + sP_ = new Complex[order/2]; + zP_ = new Complex[order/2]; + ck_ = new Coefs[order/2]; + } + + // Destractor + ~BilinearDesign() + { + delete[] sP_; + delete[] zP_; + delete[] ck_; + } + + // Execution of design + void Execute(float fc, Coefs c[], float& g); + + private: + static const float PI_ = 3.1415926536f; + const float PI_FS_; + const int ORDER_; + const Type PB_; + + Complex* sP_; // Poles on s-plane + Complex* zP_; // Poles on z-plane + Coefs* ck_; // Coefficients of transfer function for cascade form + float gain_; // Gain factor for cascade form + + void Butterworth(); + void Bilinear(float fc); + void ToCascade(); + void GetGain(); + void GetCoefs(Coefs c[], float& gain); + }; +} +#endif // BILINEAR_BUTTERWORTH_HPP +
diff -r 000000000000 -r 33908268d9ea UITDSP_ADDA.lib --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/UITDSP_ADDA.lib Fri Sep 11 09:54:45 2015 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/MikamiUitOpen/code/UITDSP_ADDA/#543daa087bd5
diff -r 000000000000 -r 33908268d9ea UIT_ACM1602NI.lib --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/UIT_ACM1602NI.lib Fri Sep 11 09:54:45 2015 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/MikamiUitOpen/code/UIT_ACM1602NI/#b7c761c179c9
diff -r 000000000000 -r 33908268d9ea UIT_AQM1602.lib --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/UIT_AQM1602.lib Fri Sep 11 09:54:45 2015 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/MikamiUitOpen/code/UIT_AQM1602/#01336babcccd
diff -r 000000000000 -r 33908268d9ea UIT_IIR_Filter.lib --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/UIT_IIR_Filter.lib Fri Sep 11 09:54:45 2015 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/MikamiUitOpen/code/UIT_IIR_Filter/#2533ed0150e7
diff -r 000000000000 -r 33908268d9ea main.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.cpp Fri Sep 11 09:54:45 2015 +0000 @@ -0,0 +1,119 @@ +//-------------------------------------------------------------- +// Cutoff frequency variable LPF and HPF by IIR 8th-order filter +// A0: Signal to be filtered +// A2: Value which controls cutoff frequency +// +// sw: 0, 2 Through +// 1: LPF +// 3: HPF +// 2015/09/11, Copyright (c) 2015 MIKAMI, Naoki +//-------------------------------------------------------------- + +#include "ADC_Interrupt.hpp" // for ADC using interrupt +#include "DAC_MCP4921.hpp" // for DAC MCP4921, MCP4922 +using namespace Mikami; + +#include "BilinearDesignLH.hpp" // for design of IIR filter +#include "IIR_Cascade.hpp" // for IIR filter of cascade structure + +// ACM1602Ni を使う場合は次の define 文をコメントにすること +#define AQM1602 + +#ifdef AQM1602 +#include "AQM1602.hpp" +Aqm1602 Lcd_; +#else +#include "ACM1602NI.hpp" +Acm1602Ni Lcd_; +#endif + +const int FS_ = 24000; // Sampling frequency: 24 kHz +ADC_Intr myAdc_(A0, FS_, A2); +DAC_MCP4921 myDac_; + +const int ORDER_ = 8; +IirCascade<ORDER_> iirLH_; // IIR filter object + +DigitalIn sw1_(D2, PullDown); // 0: disable filter + // 1: enable filter +DigitalIn sw2_(D3, PullDown); + +uint16_t a2_ = 0; // Inputted data from A2 pin + +// Interrupt service routine for ADC +void AdcIsr() +{ + float xn = myAdc_.Read(); // Read from A0 + + myAdc_.Select2ndChannel(); // Select A2 + myAdc_.SoftStart(); // ADC start for A2 input + + // Execute IIR filter + float yn = iirLH_.Execute(xn); + + if (sw1_ == 0) myDac_.Write(xn); // Using no filter + else myDac_.Write(yn); // Using filter + + // Read value which controls cutoff frequency + a2_ = myAdc_.ReadWait_u16(); + + myAdc_.Select1stChannel(); // Select A0 + myAdc_.ClearPending_EnableIRQ();// Clear pending interrupt + // and enable ADC_IRQn +} + +int main() +{ + myDac_.ScfClockTim3(1000000); // cutoff frequency: 10 kHz + + BilinearDesign lpfDsgn(ORDER_, FS_, BilinearDesign::LPF); + BilinearDesign hpfDsgn(ORDER_, FS_, BilinearDesign::HPF); + + myAdc_.SetIntrVec(AdcIsr); // Assign ISR for ADC interrupt + + float fc1 = 0; + while (true) + { + // fc: cutoff frequency, 100 -- 2000 Hz + float fc = 1900.0f*(a2_/4095.6f) + 100.0f; + + if (sw1_ == 0) + { + printf("Through\r\n"); + Lcd_.WriteStringXY("Through ", 0, 0); + wait(0.2f); + Lcd_.ClearLine(0); + fc1 = 0; + } + else + { + if (fabs(fc - fc1) > 10.0f) + { + char str[18]; + if (sw2_ == 0) sprintf(str, "LPF: fc=%4d Hz", int(fc+0.5f)); + else sprintf(str, "HPF: fc=%4d Hz", int(fc+0.5f)); + + printf("%s\r\n", str); + Lcd_.WriteStringXY(str, 0, 0); + fc1 = fc; + + // Design new coefficients based on new fc + BilinearDesign::Coefs coefs[ORDER_/2]; + float g0; + if (sw2_ == 0) lpfDsgn.Execute(fc, coefs, g0); + else hpfDsgn.Execute(fc, coefs, g0); + Biquad::Coefs coefsIir[ORDER_/2]; + // Update new coefficients + for (int n=0; n<ORDER_/2; n++) + { + coefsIir[n].a1 = coefs[n].a1; + coefsIir[n].a2 = coefs[n].a2; + coefsIir[n].b1 = coefs[n].b1; + coefsIir[n].b2 = 1.0f; + } + iirLH_.SetCoefs(g0, coefsIir); + } + } + wait(0.1f); + } +}
diff -r 000000000000 -r 33908268d9ea mbed.bld --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed.bld Fri Sep 11 09:54:45 2015 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/mbed_official/code/mbed/builds/ba1f97679dad \ No newline at end of file