สารบัญ:

EasyFFT: Fast Fourier Transform (FFT) สำหรับ Arduino: 6 ขั้นตอน
EasyFFT: Fast Fourier Transform (FFT) สำหรับ Arduino: 6 ขั้นตอน

วีดีโอ: EasyFFT: Fast Fourier Transform (FFT) สำหรับ Arduino: 6 ขั้นตอน

วีดีโอ: EasyFFT: Fast Fourier Transform (FFT) สำหรับ Arduino: 6 ขั้นตอน
วีดีโอ: Fast Fourier Transforms with an Oscilloscope (FFT) - Scopes University - (S1E8) 2024, กันยายน
Anonim
Image
Image

การวัดความถี่จากสัญญาณที่จับได้อาจเป็นงานที่ยาก โดยเฉพาะอย่างยิ่งใน Arduino เนื่องจากมีกำลังในการคำนวณต่ำกว่า มีวิธีการต่างๆ ที่ใช้ได้ในการจับภาพการข้ามศูนย์ซึ่งความถี่ถูกจับโดยการตรวจสอบจำนวนครั้งที่สัญญาณข้ามเส้นศูนย์ภายในเวลาที่กำหนด วิธีการดังกล่าวอาจไม่ได้ผลเมื่อสัญญาณเป็นความถี่ต่างๆ รวมกัน

นี่เป็นเรื่องยากที่จะเขียนโค้ดหากคุณไม่ได้มาจากพื้นหลังดังกล่าว แต่การเป็นคนจรจัดโค้ดนี้อาจมีประโยชน์มากสำหรับโครงการต่างๆ ที่เกี่ยวข้องกับดนตรี การวิเคราะห์สัญญาณ แรงจูงใจของโครงการนี้คือการเตรียมโค้ดที่ง่ายต่อการใช้งานบน Arduino โดยไม่ต้องเข้าไปยุ่งเกี่ยวกับเบื้องหลัง

โปรเจ็กต์นี้ไม่ได้อธิบายการทำงานของ FFT แต่อธิบายการใช้งานของฟังก์ชัน FFT กระบวนการเดียวกันนี้อธิบายไว้ในวิดีโอที่แนบมาด้วย

หากคุณสนใจแค่การใช้รหัสและไม่ต้องการคำอธิบาย คุณสามารถข้ามไปยังขั้นตอนที่ 3 ได้โดยตรง

ขั้นตอนที่ 1: รู้เบื้องต้นเกี่ยวกับการแปลงความถี่

บทนำเกี่ยวกับการแปลงความถี่
บทนำเกี่ยวกับการแปลงความถี่
บทนำเกี่ยวกับการแปลงความถี่
บทนำเกี่ยวกับการแปลงความถี่

สัญญาณใดๆ สามารถประกอบขึ้นจากคลื่นไซน์ต่างๆ รวมกันได้ ดังนั้นสัญญาณตามเวลาใดๆ ก็สามารถแสดงเป็นการรวมกันของไซน์ต่างๆ ของแอมพลิจูดที่ต่างกันได้

ฉันพยายามอธิบายการทำงานของ DFT (การแปลงฟูเรียร์แบบไม่ต่อเนื่อง) ในหนึ่งในคำสั่งก่อนหน้า (https://www.instructables.com/id/Arduino-Frequency…) วิธีการเหล่านี้ช้ามากสำหรับแอปพลิเคชันแบบเรียลไทม์ ซึ่งทำให้แทบไม่มีประโยชน์

ในภาพ แสดงสัญญาณซึ่งเป็นการรวมกันของสองความถี่ f2 และ f5 สัญญาณนี้คูณด้วยคลื่นไซน์ทดสอบของค่า f1 ถึง f5

สามารถแสดงทางคณิตศาสตร์ได้ว่า -ผลรวมของการคูณชุดข้อมูลฮาร์มอนิกสองชุดที่มีความถี่ต่างกันมีแนวโน้มเป็นศูนย์ (จำนวนข้อมูลที่สูงขึ้นสามารถนำไปสู่ผลลัพธ์การปะทะได้) ในกรณีของเรา หากความถี่การคูณทั้งสองนี้มีความถี่เท่ากัน (หรือใกล้เคียงกันมาก) ผลรวมของการคูณจะเป็นจำนวนที่ไม่ใช่ศูนย์

ดังนั้นหากสัญญาณของเราถูกคูณด้วยผลรวมของการคูณ f1 จะเป็นศูนย์ (ใกล้ถึงศูนย์สำหรับการใช้งานจริง) คล้ายกับกรณีสำหรับ f3, f4 อย่างไรก็ตาม สำหรับค่านี้ เอาต์พุต f2 และ f5 จะไม่เป็นศูนย์ แต่จะสูงกว่าค่าอื่นๆ อย่างมีนัยสำคัญ

ในที่นี้ สัญญาณจะถูกทดสอบด้วยความถี่ 5 ความถี่ ดังนั้นสัญญาณจะต้องคูณด้วยความถี่ห้าความถี่ การคำนวณที่เข้มข้นดังกล่าวต้องใช้เวลามากขึ้น ทางคณิตศาสตร์แสดงให้เห็นว่าสำหรับจำนวนตัวอย่าง N นั้นใช้การคูณเชิงซ้อน N*N

ขั้นตอนที่ 2: การแปลงฟูริเยร์อย่างรวดเร็ว

เพื่อให้การคำนวณ DFT เร็วขึ้นอัลกอริธึม FFT ได้รับการพัฒนาโดย James Cooley และ John Tukey อัลกอริธึมนี้ถือเป็นหนึ่งในอัลกอริธึมที่สำคัญที่สุดในศตวรรษที่ 20 มันแบ่งสัญญาณออกเป็นส่วนคี่และลำดับคู่ซึ่งทำให้การคำนวณที่จำเป็นลดลง โดยใช้การคูณที่ซับซ้อนที่จำเป็นทั้งหมดสามารถลดลงเป็น NlogN ซึ่งเป็นการปรับปรุงที่สำคัญ

คุณอาจอ้างอิงข้อมูลอ้างอิงที่ฉันอ้างถึงขณะเขียนโค้ดด้านล่างเพื่อความเข้าใจโดยละเอียดเกี่ยวกับคณิตศาสตร์ที่อยู่เบื้องหลัง FFT:

1.

2.

3.

4.

ขั้นตอนที่ 3: คำอธิบายของรหัส

1. ไซน์เร็วและโคไซน์:

การคำนวณ FFT ใช้ค่าของไซน์และโคไซน์ต่างๆ หลายครั้ง ฟังก์ชัน inbuilt ของ Arduino ไม่เร็วพอและต้องใช้เวลาพอสมควรในการให้ค่าที่ต้องการ ซึ่งทำให้โค้ดช้าลงอย่างมาก (เพิ่มเวลาเป็นสองเท่าสำหรับ 64 ตัวอย่าง) เพื่อแก้ปัญหานี้ ค่าไซน์ 0 ถึง 90 องศาจะถูกเก็บไว้เป็นทวีคูณของ 255 การทำเช่นนี้จะขจัดความจำเป็นในการจัดเก็บตัวเลขเป็นทศนิยมและเราสามารถจัดเก็บเป็นไบต์ซึ่งใช้พื้นที่ 1/4 บน Arduino sine_data ต้องวางที่ด้านบนของโค้ดเพื่อประกาศเป็นตัวแปรส่วนกลาง

นอกเหนือจาก sine_data แล้ว อาร์เรย์ที่เรียกว่า f_peaks ถูกประกาศเป็นตัวแปรส่วนกลาง หลังจากรันฟังก์ชัน FFT ทุกครั้งอาร์เรย์นี้จะอัปเดต โดยที่ f_peaks[0] เป็นความถี่ที่โดดเด่นที่สุดและมีค่าเพิ่มเติมในลำดับจากมากไปน้อย

ไบต์ sine_data [91]= { 0, 4, 9, 13, 18, 22, 27, 31, 35, 40, 44, 49, 53, 57, 62, 66, 70, 75, 79, 83, 87, 91 96, 100, 104, 108, 112, 116, 120, 124, 127, 131, 135, 139, 143, 146, 150, 153, 157, 160, 164, 167, 171, 174, 177, 180, 183, 186, 189, 192, 195, 198, 201, 204, 206, 209, 211, 214, 216, 219, 221, 223, 225, 227, 229, 231, 233, 235, 236, 238, 240, 241, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 253, 254, 254, 254, 255, 255, 255, 255 }; ลอย f_peaks[5];

เนื่องจากเราได้เก็บค่าของไซน์ไว้ตั้งแต่ 0 ถึง 90 องศาจึงสามารถคำนวณค่าของไซน์หรือโคไซน์ได้ ด้านล่างทำงานรอบแรกของตัวเลขเป็นศูนย์จุดทศนิยมและส่งกลับค่าจากข้อมูลที่เก็บไว้ วิธีนี้ต้องการการหารแบบลอยตัวเพียงส่วนเดียว สิ่งนี้สามารถลดลงได้อีกโดยการจัดเก็บค่าไซน์โดยตรง (ไม่ใช่ 255 ทวีคูณ) แต่มันกินหน่วยความจำสูงบน Arduino

การใช้ขั้นตอนข้างต้นลดความแม่นยำ แต่ช่วยเพิ่มความเร็ว สำหรับ 64 คะแนน จะให้ข้อได้เปรียบของ 8ms และสำหรับ 128 คะแนน จะให้ประโยชน์ที่ 20ms

ขั้นตอนที่ 4: คำอธิบายของรหัส: ฟังก์ชัน FFT

FFT สามารถทำได้เฉพาะกับขนาดตัวอย่าง 2, 4, 8, 16, 32, 64 และอื่นๆ ถ้าค่าไม่ใช่ 2^n ค่านั้นจะเป็นค่าด้านล่าง ตัวอย่างเช่น หากเราเลือกขนาดตัวอย่างที่ 70 ก็จะพิจารณาเฉพาะ 64 ตัวอย่างแรกและละเว้นส่วนที่เหลือ

ขอแนะนำให้มีขนาดตัวอย่างเป็น 2^n เสมอ ซึ่งสามารถ:

2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, …

สอง floats out_r และ out_im จะใช้หน่วยความจำจำนวนมาก สำหรับ Arduino nano จะไม่ทำงานกับตัวอย่างที่สูงกว่า 128 (และในบางกรณี 128) เนื่องจากหน่วยความจำไม่เพียงพอ

ข้อมูล int ที่ไม่ได้ลงนาม[13]={1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048};

int a, c1, f, o, x; เป็น=N; for(int i=0;i<12;i++) //การคำนวณระดับ { if(data<=a){o=i;} } int in_ps[data[o]={}; // อินพุตสำหรับการจัดลำดับ float out_r[data[o]={}; //ส่วนจริงของการแปลง float out_im[data[o]={}; //ส่วนจินตภาพของการแปลงร่าง

ไหลต่อไปดังนี้:

1. รหัสสร้างบิตย้อนกลับลำดับสำหรับขนาดตัวอย่างที่กำหนด (รายละเอียดเกี่ยวกับการย้อนกลับบิตในการอ้างอิง: ขั้นตอนที่ 2)

2. ป้อนข้อมูลที่สั่งซื้อตามคำสั่งที่สร้างขึ้น

3. FFT ดำเนินการ

4. แอมพลิจูดของจำนวนเชิงซ้อนที่คำนวณได้

5. ตรวจพบจุดสูงสุดและเรียงลำดับจากมากไปน้อย

6. เข้าถึงผลลัพธ์ได้จาก f_peaks

[ในการเข้าถึงข้อมูลอื่น ๆ (นอกเหนือจากความถี่สูงสุด) ควรแก้ไขรหัสเพื่อให้สามารถคัดลอกตัวแปรท้องถิ่นไปยังตัวแปรส่วนกลางที่กำหนดไว้ล่วงหน้าบางส่วน]

ขั้นตอนที่ 5: การทดสอบรหัส

การทดสอบรหัส
การทดสอบรหัส
การทดสอบรหัส
การทดสอบรหัส

ตัวอย่างคลื่นสามเหลี่ยมจะได้รับเป็นอินพุต สำหรับความถี่สุ่มตัวอย่างคลื่นนี้คือ 10 Hz และความถี่ของคลื่นเองคือ 1.25 Hz

ดังที่แสดงจากผลลัพธ์ดิบ ค่าจะตรงกับ FFT ที่คำนวณโดย Scilab อย่างไรก็ตาม ค่าเหล่านี้ไม่ได้เหมือนกันทุกประการกับความแม่นยำต่ำแต่เป็นคลื่นไซน์ที่เร็วกว่า

ในความถี่อาร์เรย์ความถี่เอาต์พุตคือ 1.25 และ 3.75 ไม่จำเป็นต้องได้รับค่าที่แน่นอนทุกครั้ง โดยปกติตัวเลขเหล่านี้เรียกว่าช่องเก็บความถี่ ดังนั้นค่าเอาต์พุตอาจอยู่ที่ใดก็ได้ภายในช่องเก็บที่ระบุ

ความเร็ว:

สำหรับ Arduino nano ต้องใช้:

16 คะแนน: 4ms32 คะแนน: 10ms 64 คะแนน: 26ms 128 คะแนน: 53ms

ขั้นตอนที่ 6: บทสรุป

รหัส FFT นี้สามารถใช้ในแอปพลิเคชันแบบเรียลไทม์ เนื่องจากใช้เวลาประมาณ 30 ms ในการคำนวณให้เสร็จสมบูรณ์ อย่างไรก็ตาม ความละเอียดของมันจำกัดด้วยตัวอย่างจำนวนหนึ่ง จำนวนตัวอย่างถูกจำกัดโดยหน่วยความจำ Arduino โดยการใช้ Arduino Mega หรือความแม่นยำของบอร์ดประสิทธิภาพสูงอื่น ๆ สามารถปรับปรุงได้

หากคุณมีคำถาม ข้อเสนอแนะ หรือการแก้ไขใดๆ โปรดแสดงความคิดเห็น

อัปเดต (2/5/21)

อัปเดต://----------------------------------- ฟังก์ชัน FFT --------------- ----------------------------------------------//float FFT(int in, int N, float Frequency)

ชนิดข้อมูลของ N เปลี่ยนเป็นจำนวนเต็ม (ไบต์ที่มีอยู่) เพื่อรองรับขนาดตัวอย่าง >255 หากขนาดตัวอย่างคือ <=128 ควรใช้ชนิดข้อมูลไบต์

แนะนำ: