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
Diff: main.cpp
- Revision:
- 0:b8bffbcb85fd
- Child:
- 1:24c33c8719b2
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.cpp Mon Nov 10 02:45:18 2014 +0000 @@ -0,0 +1,125 @@ +//------------------------------------------------------------------ +// Cutoff frequency variable LPF and HPF by FIR 160th-order filter +// A0: Signal to be filtered +// A2: Value which controls cutoff frequency +// +// 2014/11/10, Copyright (c) 2014 MIKAMI, Naoki +//------------------------------------------------------------------ + +#include "mbed.h" + +#include "ADC_Interrupt.hpp" // for ADC using interrupt +#include "DAC_MCP4922.hpp" // for DAC MCP4922 +#include "ScfClockTim3.hpp" // for clock supplied to SCF +#include "ACM1602NI.hpp" // for LCD display + +#include "WindowingDesignLH.hpp" // for design of IIR filter + +using namespace Mikami; + +const int FS_ = 16000; // Sampling frequency: 16 kHz +ADC_Intr myAdc_(A0, FS_, A1, A2); +DAC_MCP4922 myDac_; + +const int ORDER_ = 160; +float hm_[ORDER_/2+1]; +float xn_[ORDER_+1]; + +DigitalIn sw1_(D2, PullDown); // 0: disable filter + // 1: enable filter +DigitalIn sw2_(D3, PullDown); // 0: LPF + // 1: HPF +WindowingDesign design_(ORDER_, FS_); +DigitalOut dOut_(D7); + +uint16_t a2_ = 0; // Inputted data from A2 pin + +// Interrupt service routine for ADC +void AdcIsr() +{ + dOut_.write(1); + xn_[0] = myAdc_.Read(); // Read from A0 + + myAdc_.Select3rdChannel(); // Select A2 + myAdc_.SoftStart(); // ADC start for A2 input + + //----------------------------------------- + // Execute FIR filter + float yn = hm_[ORDER_/2]*xn_[ORDER_/2]; + for (int k=0; k<ORDER_/2; k++) + yn = yn + hm_[k]*(xn_[k] + xn_[ORDER_-k]); + + for (int k=ORDER_; k>0; k--) + xn_[k] = xn_[k-1]; // move input signals + //----------------------------------------- + + if (sw1_ == 0) myDac_.Write(xn_[0]); // 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 + dOut_.write(0); +} + +int main() +{ + ScfClockTim3(670000); // cutoff frequency: 6.7 kHz + + WindowingDesign lpfDsgn(ORDER_, FS_); + Acm1602Ni lcd; // objetc for display using LCD + + // Clear buffer in FIR filter + for (int n=0; n<=ORDER_; n++) + xn_[n] = 0; + myAdc_.SetIntrVec(AdcIsr); // Assign ISR for ADC interrupt + + float fc1 = 0; + WindowingDesign::Type pb = WindowingDesign::LPF; + 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.ClearLine(1); + lcd.WriteStringXY("Through ", 0, 0); + wait(0.2f); + lcd.ClearLine(0); + fc1 = 0; + } + else + { + if (fabs(fc - fc1) > 10.0f) + { + printf("fc = %4d\r\n", int(fc+0.5f)); + char str[18]; + sprintf(str, "fc = %4d Hz", int(fc+0.5f)); + lcd.WriteStringXY(str, 0, 0); + if (sw2_ == 0) + { + pb = WindowingDesign::LPF; + printf("LPF\r\n"); + lcd.WriteStringXY("LPF", 0, 1); + } + else + { + pb = WindowingDesign::HPF; + printf("HPF\r\n"); + lcd.WriteStringXY("HPF", 0, 1); + } + fc1 = fc; + + // Design new coefficients based on new fc + design_.Design(ORDER_, pb, fc1, hm_); + } + } + wait(0.1f); + } +} +