สารบัญ:

QuickFFT: FFT ความเร็วสูงสำหรับ Arduino: 3 ขั้นตอน
QuickFFT: FFT ความเร็วสูงสำหรับ Arduino: 3 ขั้นตอน

วีดีโอ: QuickFFT: FFT ความเร็วสูงสำหรับ Arduino: 3 ขั้นตอน

วีดีโอ: QuickFFT: FFT ความเร็วสูงสำหรับ Arduino: 3 ขั้นตอน
วีดีโอ: How to Use Accelerometers on the Arduino - Ultimate Guide to the Arduino #42 2024, พฤศจิกายน
Anonim
QuickFFT: FFT ความเร็วสูงสำหรับ Arduino
QuickFFT: FFT ความเร็วสูงสำหรับ Arduino

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

หนึ่งในคำแนะนำของฉัน ฉันได้เตรียมรหัสสำหรับ FFT ที่สามารถพบได้ที่นี่: EasyFFT

รหัสนี้สามารถทำ FFT ได้ถึง 128 ตัวอย่างบน Arduino nano ไม่สามารถสุ่มตัวอย่างที่สูงกว่านี้ได้เนื่องจากหน่วยความจำที่จำกัดของ Arduino ฉันได้ปรับเปลี่ยนฟังก์ชันเล็กน้อยเพื่อปรับปรุงความเร็วและลดการใช้หน่วยความจำ การปรับเปลี่ยนนี้ช่วยให้ Arduino ดำเนินการ FFT ได้เร็วขึ้นห้าเท่าและใช้หน่วยความจำเกือบครึ่งหนึ่ง คำแนะนำนี้ไม่ครอบคลุมถึงการทำงานของ FFT สามารถดูข้อมูลอ้างอิงได้ที่ EasyFFT

ขั้นตอนที่ 1: การทำงาน

การทำงาน
การทำงาน
การทำงาน
การทำงาน
การทำงาน
การทำงาน
การทำงาน
การทำงาน

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

ในฟังก์ชันนี้ คลื่นไซน์/โคไซน์จะถูกแทนที่ด้วยคลื่นสี่เหลี่ยม เนื่องจากเราต้องคูณสัญญาณทดสอบด้วยคลื่นสี่เหลี่ยมซึ่งอาจมีค่า 0, 1 หรือ -1 ด้วยเหตุนี้ เราจึงสามารถแทนที่การคูณแบบลอยตัวเป็นการบวกหรือการลบจำนวนเต็มได้ สำหรับการบวกหรือลบจำนวนเต็ม Arduino เร็วขึ้นประมาณ 5 เท่า ทำให้แก้ได้เร็วขึ้นประมาณ 5 เท่า

เนื่องจากการปรับเปลี่ยนนี้ ขณะนี้ค่าช่องเก็บความถี่สามารถจัดเก็บเป็นจำนวนเต็ม (ซึ่งก่อนหน้านี้ลอยอยู่) และเราได้รับประโยชน์จากการใช้หน่วยความจำที่ลดลงอีก ใน Arduino Nano นั้น int ใช้หน่วยความจำ 2 ไบต์ในขณะที่ float ใช้หน่วยความจำ 4 ไบต์ ด้วยข้อได้เปรียบนี้ในโค้ดใหม่ เราจึงสามารถดำเนินการ FFT ได้เกือบ 256 ตัวอย่าง (จากเดิม 128 ตัวอย่าง)

ใน Normal FFT เราจำเป็นต้องเก็บค่า sine เพื่อให้การแก้ปัญหาเร็วขึ้น ในฟังก์ชันใหม่ เนื่องจากเราไม่ต้องการค่าไซน์/โคไซน์อีกต่อไป เราจึงสามารถกำจัดมันและบันทึกหน่วยความจำบางส่วนได้

การดำเนินการ:

การใช้ฟังก์ชันนี้ตรงไปตรงมา เราสามารถคัดลอกฟังก์ชันที่ส่วนท้ายของโค้ด ฟังก์ชั่นนี้สามารถดำเนินการได้โดยใช้คำสั่งด้านล่าง:

float f= Q_FFT(data, 256, 100);ในฟังก์ชัน Q_FFT,

data: เทอมนี้เป็นอาร์เรย์ที่มีค่าสัญญาณ ขนาดตัวอย่างที่แนะนำคือ 2, 4, 8, 32, 64, 128, 256, 512, … เป็นต้นไป ถ้าขนาดตัวอย่างไม่ใช่ของค่าเหล่านี้ จะถูกตัดไปที่ด้านล่างสุดของค่าที่ใกล้ที่สุด ตัวอย่างเช่น ถ้าขนาดกลุ่มตัวอย่าง 75 กว่า FFT จะดำเนินการกับจำนวนตัวอย่าง 64 ตัวอย่าง ขนาดตัวอย่างสูงสุดถูกจำกัดโดย RAM ที่มีอยู่บน Arduino

เทอมที่สองระบุจำนวนตัวอย่างในอาร์เรย์ และเทอมสุดท้ายคือความถี่สุ่มตัวอย่างในหน่วย Hz

ขั้นตอนที่ 2: รหัส

ส่วนนี้อธิบายการดัดแปลงที่ทำในโค้ด EasyFFT ที่ต้องจำไว้ในขณะที่ทำการแก้ไขในโค้ด

1. ตามที่อธิบายไว้ก่อนหน้านี้ จะใช้เลขจำนวนเต็มเพื่อทำ FFT Int ใน Arduino เป็นตัวเลข 16 บิตและสามารถมีค่าได้ตั้งแต่ -32768 ถึง 32768 เมื่อใดก็ตามที่ค่าของ int นี้เกินช่วงนี้จะทำให้เกิดปัญหา เพื่อขจัดปัญหานี้หลังจากการคำนวณระดับ หากค่าใดเกิน 15,000 อาร์เรย์ที่สมบูรณ์จะถูกหารด้วย 100 ซึ่งจะป้องกันไม่ให้ int ล้น

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

3. รหัสนี้ไม่มีโมดูลสำหรับการตรวจจับจุดสูงสุดหลายจุด มันจะเลือกค่าที่มีแอมพลิจูดสูงสุด (ไม่รวมตัวเลขแรกที่เป็น DC offset) หากคุณต้องการพีคหลายจุด คุณสามารถอ้างอิงโค้ด EasyFFT และทำการแก้ไขที่จำเป็นได้ที่นี่ ในกรณีนั้น อาร์เรย์/ตัวแปรบางตัวจำเป็นต้องประกาศเป็นตัวแปรส่วนกลางด้วย

4. ฟังก์ชั่นประกอบด้วยบรรทัดต่อไปนี้:

unsigned int Pow2[13]={1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048};

การประกาศตัวแปรข้างต้นเป็นตัวแปรส่วนกลาง (วางที่จุดเริ่มต้นของโค้ด) จะช่วยประหยัดเวลาได้ 1 มิลลิวินาทีในการดำเนินการทุกครั้ง

5. ไม่เหมือนกับฟังก์ชัน EasyFFT ที่จัดเก็บจุดสูงสุด 5 อันดับแรกไว้ในอาร์เรย์ที่กำหนดไว้ล่วงหน้า ฟังก์ชันนี้จะคืนค่าโฟลต ค่านี้แสดงถึงความถี่ที่มีแอมพลิจูดสูงสุดในหน่วย Hz ดังนั้นการแสดงโค้ดจะออกมาประมาณนี้

float f= Q_FFT(ข้อมูล, 256, 100);

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

ถ้า Fn คือความถี่ที่มีแอมพลิจูดสูงสุด ความถี่สามารถคำนวณได้จากสูตรด้านล่าง

F= จริง = (A n-1 *Fn-1 + An-1 *Fn-1 + An-1 *Fn-1) / (An-1+An+An+1)

โดยที่ An คือแอมพลิจูดของ n ความถี่และ Fn-1 คือค่าความถี่

ขั้นตอนที่ 3: ผลลัพธ์:

ผลลัพธ์
ผลลัพธ์
ผลลัพธ์
ผลลัพธ์

เวลาในการแก้ปัญหาจะแสดงในการเปรียบเทียบภาพด้านบนกับ EasyFFT ความเร็วของมันแสดงด้วยการเปรียบเทียบ

สำหรับข้อมูลตัวอย่างที่มีคลื่นไซน์ 3 คลื่นที่มีความถี่ต่างกันจะแสดงขึ้น ผลลัพธ์จาก QuickFFT ถูกเปรียบเทียบกับผลลัพธ์ของ Scilab ดังที่เราเห็นในภาพ 3 พีคที่มีแอมพลิจูดสูงสุดจับคู่กับเอาต์พุต Scilab อย่างไรก็ตาม เอาต์พุตมีเสียงรบกวนมาก ซึ่งอาจทำให้เข้าใจผิดสำหรับบางแอปพลิเคชัน ดังนั้นจึงควรตรวจสอบรหัสให้ถูกต้องก่อนสมัคร

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

แนะนำ: