25 พ.ค. 2022 เวลา 04:35 • วิทยาศาสตร์ & เทคโนโลยี
ประยุกต์ FIR Filter ด้วย T-FILTER
#FIR Filter, #DEV C++, #MS-Excel
Reference:
FIR Filter หรือ Finite impulse response (FIR) filter คือ ฟิลเตอร์ซึ่งตอบสนองต่ออิมพัลซ์แบบจำกัด ตอบสนองต่อ Impulse ด้วยระยะเวลาหนึ่ง แล้วค่าตอบสนองจะเป็น 0 เมื่อระยะเวลาผ่านไป ข้อดีของ FIR Filter คือ
ไม่มี Feedback การปัดเศษคำนวนก็จะถูกจำกัดที่ค่าหนึ่งเสมอ
เสถียร ไม่ออลซิเลต พิจารณาเอาต์พุตเป็นผลมาจาก ผลรวมของผลคูณอินพุต(คูณอินพุตกับตัวประกอบ) ทำให้เอาต์พุตจะมีค่าน้อยกว่าผลรวมของตัวประกอบทั้งหมดคูณกับค่าที่มากที่สุดที่เป็นไปได้
ออกแบบง่าย
ข้อเสีย
ทำงานช้าและเกิด Delay ยิ่งตัวประกอบ (Co-Efficient) มากยิ่งช้า
เครื่องมือ T-Filter
T-Filter เป็นเวปแอปสำหรับออกแบบ FIR Filter โดยใช้วิธีออกแบบของ Parks-McClellan สามารถปรับแต่งจำนวน Taps ได้ง่าย ซึ่งตรงกับจุดประสงค์ที่จะเอา Co-Efficient ไปใช้ใน Microcontroller 8-Bits
Dev C++
Dev C++ เป็น IDE-Integrated Development Environment สำหรับ C/C++ เราจะจำลอง Code ทดสอบผล การทดสอบโดย Dev C++ ใช้ โค้ดที่ได้จาก T-Filter แล้วเก็บผลลัพธ์ลง Text File แล้วนำไปพล็อตกราฟบน MS-Excel
จุดประสงค์คือการนำ Filter ไปใช้ใน Microcontroller 8-Bit ใช้สำหรับกรองความถี่ที่ปนเข้ามาทาง ADC ซึ่งพยายามกรองความถี่ให้เหลือเฉพาะส่วนที่เป็น DC มากที่สุด การทำงานของ Filter ต้องใช้เวลาคำนวนน้อยและมี Sampling Frequency ต่ำ ต้องพยายามคำนวนให้น้อยที่สุด (แต่ก็หลีกเลี่ยงการคำนวนแบบทศนิยมไม่ได้) ในส่วนนี้จะนำประยุกต์เป็น Data Acquisition
ข้อมูลจะถูกส่งต่อให้คอมพิวเตอร์แต่การส่งข้อมูลจะส่งด้วยความเร็วต่ำทำให้ไม่สามารถเก็บข้อมูลมากจนสามารถทำ Filter บนคอมพิวเตอร์ได้ จึงย้าย Filter มาลงบนไมโครคอนโทรลเลอร์
เริ่มต้นจากการออกแบบ Filter
ตีความคร่าวๆ ว่า ความถี่น้อยกว่า 10Hz คือ ส่วนที่ต้องการ และความถี่ช่วง 20–75 Hz คือส่วนที่ไม่ต้องการ (Sampling มีค่า 150 Hz)
ต้องการค่า Attenuation ที่ -80 dB แต่ต้องใช้ Co-Efficient ถึง 35 ค่า ถ้าคิดเป็นหน่วนความจำที่ต้องใช้คือ 35 x 4 = 140 Bytes อาจจะใช้หน่วยความจำมากไป(ใช้ส่วน Program Memory) แต่ไม่เป็นไรรอดูผลก่อนแล้วค่อยปรับแต่ง Filter ทีหลังได้
กำหนดค่าที่ต้องการใช้งานเข้าไปในตารางล่างซ้าย ตามตัวอย่างนี้ช่วงความถี่ 0–10Hz กำหนดให้ Gain เป็น 1 Ripple กว้าง 5 dB และ ช่วง 20Hz- 75Hz Gain เป็น 0 Attenuation มีค่า -80dB
นั่นคือเมื่อความถี่อยู่ในช่วง 20 Hz-75Hz จะถูกลดขนาด Amplitude ลง เมื่อเรียบร้อยแล้วกด Design Filter ถ้าทุกอย่าง OK ช่อง act. rpl (คิดว่า เป็น Acutal Ripple) จะมีสีเขียว หลังจากนั้นเลือกแท็ป Source Code จะปรากฏหน้าต่างตามรูปข้างล่าง
ในขั้นตอนนี้เราจะต้องกำหนดชื่อ Filter ในช่อง Name of Filter กำหนดชนิดตัวแปรในช่อง Number of format และกำหนดชนิดของตัวแปรทศนิยมตามชนิดคอมไพลเลอร์ที่ใช้ เช่น float, double, FLOAT_T, DOUBLE_T เป็นต้น
ส่วนเช็คบ๊อก Unroll convolution loop สามารถเลือกได้ว่าจะทำคอนโวลูชั่นด้วยลูปหรือไม่ต้องทำลูป ขึ้นอยู่กับความเร็วและความยาวของ Co-Eff ถ้าทำลูปโค้ดจะสั้นแต่ใช้เวลามากขึ้นแต่ถ้าไม่ทำลูป จะใช้เวลาทำคอนโวลูชั่นน้อยแต่ใช้หน่วยความจำเขียนโค้ดเยอะ
สำหรับกรณีนี้ตัวชื่อ Filter ว่า Lowpass ตัวแปรประเภท floating point และ ชื่อตัวแปรว่า float ดังรูปข้างล่าง
เตรียมโปรเจก Dev C++
1.สร้างโปรเจก โดยเปิด Dev C++ แล้วเลือก File -> New -> Project
2. เลือกโปรเจกเป็น C Project และเลือกไอค่อน Console Application ตั้งชื่อโปรเจกว่าอะไรก็ได้หรือไม่ต้องตั้งก็ได้ ส่วนนี้ตั้งชื่อเป็น LowpassFilter (พิมพ์แทน Project2)
3. เลือกโฟลเดอร์สำหรับันทึกโปรเจกแล้วกด Save
4. เราจะได้โปรเจกลักษณะดังรูปข้างล่างนี้
5. สร้างไฟล์ LowpassFilter.c และ LowpassFilter.h แล้วเพิ่มเข้ามาในโปรเจกให้คัดลอกโค้ดลงไฟล์เรียบร้อย ส่วนที่ไฟล์ main.c ให้บันทึกไฟล์ สามารถเปลี่ยนชื่อไฟล์เป็นชื่ออื่นได้ตามความเหมาะสม เมื่อมาถึงในขั้นตอนนี้ โปรเจกจะประกอบด้วยไฟล์ทั้งหมด 3 ไฟล์คือ main.c, LowpassFilter.c และ LowpassFilter.h
6. เริ่มเขียน Code ทดสอบ โดย T-Filter จะสร้างตัวแปรสตรักเจอร์ให้ใช้ (ตัวแปรที่ T-Filterสร้างขึ้นมาให้เรียกใช้) สามารถเปิดดูได้จากไฟล์ LowpassFilter.h ตัวอย่างนี้ชื่อว่า LowpassFilter
ในตัวอย่างนี้สร้างตัวแปรชื่อว่า lpfilter แล้วให้ลองกำหนดค่าเริ่มต่นก่อนเรียกใช้โดยเรียกฟังก์ชั่น LowpassFilter_init(&lpfilter); ให้ทดลองคอมไพล์ ถ้าไม่ติดปัญหาใดๆ ก็เริ่มเขียนฟังก์ชั่นอื่นๆ ต่อได้เลย
โค้ดทั้งหมด
#include
#include
#include "LowpassFilter.h"
#include
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
#define SIN_DEG_SIZE (11)
SIN_DEG_TABLE[SIN_DEG_SIZE] = {127,147,166,185,202,217,230,240,248,252,254}; //Sin 0 = 127 Sin 90 = 254, Sin 270 = 0
float interpolation(unsigned int Value){
unsigned int x;
float y=0.00;
float xmin,xmax,ymin,ymax;
unsigned int Index = Value / 9;
xmin = Index*9;
xmax = (Index+1)*9;
ymin = SIN_DEG_TABLE[Index];
ymax = SIN_DEG_TABLE[(Index+1)];
y = (float)(ymin)+((float)Value-(float)xmin)*(((float)ymax-(float)ymin)/((float)xmax-(float)xmin));
return y;
}
int SIN_Degree(int Degree){
Degree = Degree%360;
if(Degree < 90){
return (int)(interpolation(Degree));
}else if(Degree >= 90 && Degree < 180){
return (int)(interpolation(180-Degree));
}else if(Degree >= 180 && Degree < 270){
return (int)(254-interpolation(Degree-180));
}else if(Degree >= 270 && Degree < 360) {
return (int)(254-interpolation(360-Degree));
}
return -1;
}
#define NUM_FILTER (75) //Create 75 Filter
#define TEST_FREQ_SIZE (1024) //Test Frequency Array size
#define OUTPUT_FILE_NAME "FirfilterOutput.txt"
#define FREQUENCY_RESOLUTION (150)//Hz
#define SAMPLING_FREQUENCY (150)//Hz
#define PI (22.0/7.0)
int main(int argc, char *argv[]) {
FILE *fp;
int counter; //general purpose counter
int eachFrequencyArray=0;
float input[NUM_FILTER][TEST_FREQ_SIZE];
float frequencyArray[NUM_FILTER];
LowpassFilter lpfilter[NUM_FILTER]; //Create Filter
fp=fopen(OUTPUT_FILE_NAME,"w");
for(counter =0; counter Most left Order name
for(counter=0;counter Column Name
}
for(eachFrequencyArray = 0; eachFrequencyArray< TEST_FREQ_SIZE; eachFrequencyArray++){
fprintf(fp,"%.4d\t",eachFrequencyArray);
for(counter =0; counter< NUM_FILTER; counter++){
LowpassFilter_put ((LowpassFilter*)(&lpfilter[counter]), input[counter][eachFrequencyArray]); //Insert value
fprintf(fp,"%15.9f\t%15.9f\t",input[counter][eachFrequencyArray],LowpassFilter_get( (LowpassFilter*)&lpfilter[counter])); //get value and print to file
}
fprintf(fp,"\n"); //Text File Format
}
fprintf(fp,"\n"); //Text File Format
fflush(fp); //Write all buffer to File
fclose(fp); //Close file
return 0;
}
7. เมื่อเขียนโค้ดเสร็จแล้วให้รันได้เลย โปรแกรมที่เขียนจะสร้างเท็กซ์ไฟล์ขึ้นซึ่งเก็บผลลัพธ์และค่าความถี่อินพุต
8. นำผลลัพธ์ที่ได้ไปพล็อตกราฟใน MS-Excel จะได้ตัวอย่างตามรูปข้างล่างนี้
กราฟข้างบนแทนความถี่ 9 Hz, 10Hz, 15Hz, 40Hz, 50Hz, 60Hz, 74Hz ตามลำดับ กราฟที่มีแอมปลิจูดมากคือ 9Hz, 10Hz แอมปลิจูดเกือบถึง 1 นั่นคือ ไม่ถูกฟิลเตอร์ลดแอมปลิจูดลง ส่วนกราฟ 15Hz แอมปลิจูดลดลงประมาณครึ่งหนึ่งซึ่งความถี่ 15Hz อยู่ในช่วง Transition ก่อน Cutoff ที่ 20 Hz ความถี่ 40Hz, 50Hz, 60Hz, 74Hz ไม่สามารถสังเกตแอมปลิจูดได้เนื่องจาถูกฟิลเตอร์ลดแอมปลิจูดทิ้งทั้งหมด
ผลการจำลองฟิลเตอร์จาก Dev C++ แสดงให้เห็นว่าฟิลเตอร์สามารถทำงานได้ตามที่ออกแบบไว้คือช่วงต่ำกว่า 10Hz ความถี่ผ่านได้หมด ช่วงมากกว่า 20Hz จะถูกกรองไม่ให้ผ่าน และความถี่ช่วง 10Hz-20Hz เป็นช่วงที่ฟิลเตอร์จะลดแอมปลิจูดลง
สังเกตว่า ค่าอินพุตสูงสุดจะเป็น 1 ค่าต่ำสุดเป็น 0 เมื่อนำไปประยุกต์ใช้จะต้องแปลงค่าอินพุตให้อยู่ในช่วง [0,1] ซึ่งอินพุตอาจได้จาก ADC ซึ่งมีค่าอยู่ในช่วง [0,255] หรือ [0,1024] เป็นต้น
เมื่อจำลองระบบ ทดสอบระบบจนได้ผลตามต้องการแล้ว สามารถก๊อปปี้โค้ดไปใช้กับ Microcontroller ได้ ซึ่งอาจจะต้องปรับแต่ง Syntax ตามชนิดไมโครคอนโทรลเลอร์นั้น สำหรับข้อมูลจากการทดสอบแบบจำลองนี้จะถูกนำไปใช้กับ PIC16F เพื่อกรองความถี่ที่ปนมากับ ADC ผ่านทางสายสัญญาณ สายกำลัง หรือเกิดขึ้นจากภาคการทำงานต่างๆ บนแผงวงจรเอง
ขอจบเท่านี้ครับ
March 23, 2022
โฆษณา