สารบัญ:

1024 ตัวอย่าง FFT Spectrum Analyzer โดยใช้ Atmega1284: 9 ขั้นตอน
1024 ตัวอย่าง FFT Spectrum Analyzer โดยใช้ Atmega1284: 9 ขั้นตอน

วีดีโอ: 1024 ตัวอย่าง FFT Spectrum Analyzer โดยใช้ Atmega1284: 9 ขั้นตอน

วีดีโอ: 1024 ตัวอย่าง FFT Spectrum Analyzer โดยใช้ Atmega1284: 9 ขั้นตอน
วีดีโอ: Build Your Own Spectrum Analyzer GNU RADIO Win10 2024, พฤศจิกายน
Anonim
1024 ตัวอย่าง FFT Spectrum Analyzer โดยใช้ Atmega1284
1024 ตัวอย่าง FFT Spectrum Analyzer โดยใช้ Atmega1284
1024 ตัวอย่าง FFT Spectrum Analyzer โดยใช้ Atmega1284
1024 ตัวอย่าง FFT Spectrum Analyzer โดยใช้ Atmega1284

บทช่วยสอนที่ค่อนข้างง่ายนี้ (โดยพิจารณาถึงความซับซ้อนของหัวข้อนี้) จะแสดงให้คุณเห็นว่าคุณสามารถสร้างเครื่องวิเคราะห์สเปกตรัมตัวอย่าง 1024 ตัวอย่างที่ง่ายมากโดยใช้บอร์ดประเภท Arduino (1284 Narrow) และพล็อตเตอร์แบบอนุกรมได้อย่างไร บอร์ดที่เข้ากันได้กับ Arduino ชนิดใดก็ได้ แต่ยิ่งมี RAM มาก ความละเอียดความถี่ที่ดีที่สุดที่คุณจะได้รับ มันจะต้องมี RAM มากกว่า 8 KB เพื่อคำนวณ FFT ด้วยตัวอย่าง 1024

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

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

เราจะเน้นที่นี่ในส่วนซอฟต์แวร์ หากคุณต้องการสร้างวงจรถาวรสำหรับแอปพลิเคชันเฉพาะ คุณจะต้องขยายและกรองสัญญาณ การปรับสภาพล่วงหน้านี้ขึ้นอยู่กับสัญญาณที่คุณต้องการศึกษาโดยสิ้นเชิง ขึ้นอยู่กับแอมพลิจูด อิมพีแดนซ์ ความถี่สูงสุด ฯลฯ… คุณสามารถตรวจสอบ

ขั้นตอนที่ 1: การติดตั้งไลบรารี

เราจะใช้ห้องสมุด ArduinoFFT ที่เขียนโดย Enrique Condes เนื่องจากเราต้องการสำรอง RAM ให้มากที่สุด เราจะใช้สาขาการพัฒนาของที่เก็บนี้ ซึ่งอนุญาตให้ใช้ประเภทข้อมูล float (แทนที่จะเป็นสองเท่า) เพื่อเก็บข้อมูลตัวอย่างและข้อมูลที่คำนวณได้ ดังนั้นเราต้องติดตั้งด้วยตนเอง ไม่ต้องกังวล เพียงดาวน์โหลดไฟล์เก็บถาวรและคลายการบีบอัดในโฟลเดอร์ไลบรารี Arduino ของคุณ (เช่น ในการกำหนดค่าเริ่มต้นของ Windows 10: C:\Users\_your_user_name_\Documents\Arduino\libraries)

คุณสามารถตรวจสอบว่าไลบรารีได้รับการติดตั้งอย่างถูกต้องโดยรวบรวมหนึ่งในตัวอย่างที่มีให้ เช่น "FFT_01.ino"

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

คำเตือน: หากคุณไม่สามารถทนเห็นสัญกรณ์ทางคณิตศาสตร์ใดๆ ได้ คุณอาจต้องการข้ามไปยังขั้นตอนที่ 3 อย่างไรก็ตาม หากคุณไม่เข้าใจทั้งหมด ให้พิจารณาข้อสรุปที่ส่วนท้ายของส่วน

สเปกตรัมความถี่ได้มาจากอัลกอริธึม Fast Fourier Transform FFT คือการใช้งานดิจิทัลที่ใกล้เคียงกับแนวคิดทางคณิตศาสตร์ของการแปลงฟูริเยร์ ภายใต้แนวคิดนี้ เมื่อคุณได้รับวิวัฒนาการของสัญญาณตามแกนเวลา คุณจะทราบการแทนค่าในโดเมนความถี่ ซึ่งประกอบด้วยค่าที่ซับซ้อน (จริง + จินตภาพ) แนวคิดเป็นแบบส่วนกลับกัน ดังนั้นเมื่อคุณทราบการแสดงโดเมนความถี่ คุณสามารถเปลี่ยนกลับเป็นโดเมนเวลาและรับสัญญาณกลับมาเหมือนกับก่อนการแปลง

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

คุณคุ้นเคยกับแนวคิดอีควอไลเซอร์อย่างแน่นอน ย้อนกลับไปในปี 1980 ด้วย Graphic EQ เราจะได้ผลลัพธ์แบบเดียวกัน แต่ด้วย 1024 แบนด์แทนที่จะเป็น 16 และความละเอียดที่เข้มกว่ามาก เมื่ออีควอไลเซอร์ให้มุมมองเพลงทั่วโลก การวิเคราะห์สเปกตรัมแบบละเอียดจะช่วยให้คำนวณความเข้มของแต่ละแบนด์ 1024 ได้อย่างแม่นยำ

แนวคิดที่สมบูรณ์แบบ แต่:

  1. เนื่องจาก FFT เป็นเวอร์ชันดิจิทัลของการแปลงฟูริเยร์ จึงใกล้เคียงกับสัญญาณดิจิทัลและทำให้ข้อมูลบางส่วนหายไป ดังนั้น พูดอย่างเคร่งครัด ผลลัพธ์ของ FFT หากแปลงกลับด้วยอัลกอริธึม FFT กลับหัว จะไม่ให้สัญญาณดั้งเดิมอย่างแน่นอน
  2. ทฤษฎียังพิจารณาสัญญาณที่ไม่จำกัด แต่นั่นเป็นสัญญาณที่คงอยู่ตลอดไป เนื่องจากเราจะแปลงเป็นดิจิทัลในช่วงระยะเวลาหนึ่งเท่านั้น (เช่น ตัวอย่าง) เราจะแนะนำข้อผิดพลาดเพิ่มเติมบางอย่าง
  3. ในที่สุดความละเอียดของการแปลงแอนะล็อกเป็นดิจิทัลจะส่งผลต่อคุณภาพของค่าที่คำนวณได้

ในทางปฏิบัติ

1) ความถี่ในการสุ่มตัวอย่าง (สังเกต fs)

เราจะสุ่มตัวอย่างสัญญาณ นั่นคือ วัดแอมพลิจูดทุกๆ 1/fs วินาที fs คือความถี่ในการสุ่มตัวอย่าง ตัวอย่างเช่น หากเราสุ่มตัวอย่างที่ 8 KHz ตัวแปลง ADC (ตัวแปลงอนาล็อกเป็นดิจิตอล) ที่อยู่บนชิปจะให้การวัดทุกๆ 1/8000 วินาที

2) จำนวนตัวอย่าง (หมายเหตุ N หรือตัวอย่างในรหัส)

เนื่องจากเราจำเป็นต้องรับค่าทั้งหมดก่อนที่จะเรียกใช้ FFT เราจึงต้องเก็บค่าเหล่านี้ไว้ ดังนั้นเราจะจำกัดจำนวนตัวอย่าง อัลกอริธึม FFT ต้องการตัวอย่างจำนวนหนึ่งซึ่งเป็นกำลัง 2 ยิ่งเรามีตัวอย่างมากเท่าไหร่ก็ยิ่งดีเท่านั้น แต่ต้องใช้หน่วยความจำมาก ยิ่งเราจะต้องจัดเก็บข้อมูลที่แปลงแล้วซึ่งเป็นค่าที่ซับซ้อนมากเท่านั้น ไลบรารี Arduino FFT ช่วยประหยัดพื้นที่บางส่วนโดยใช้

  • หนึ่งอาร์เรย์ชื่อ "vReal" เพื่อจัดเก็บข้อมูลตัวอย่างแล้วจึงเป็นส่วนจริงของข้อมูลที่แปลงแล้ว
  • อาร์เรย์หนึ่งชื่อ "vImag" เพื่อจัดเก็บส่วนจินตภาพของข้อมูลที่แปลงแล้ว

จำนวน RAM ที่ต้องการเท่ากับ 2 (อาร์เรย์) * 32 (บิต) * N (ตัวอย่าง)

ดังนั้นใน Atmega1284 ของเราที่มี RAM ขนาด 16 KB ที่ดี เราจะจัดเก็บค่าสูงสุด N = 16000*8/64 = 2000 ค่า เนื่องจากจำนวนค่าต้องเป็นกำลัง 2 เราจะเก็บค่าได้สูงสุด 1024 ค่า

3) ความละเอียดความถี่

FFT จะคำนวณค่าสำหรับแถบความถี่มากเท่ากับจำนวนตัวอย่าง แบนด์เหล่านี้จะครอบคลุมตั้งแต่ 0 HZ ถึงความถี่สุ่มตัวอย่าง (fs) ดังนั้น ความละเอียดความถี่คือ:

ความละเอียด = fs / N

ความละเอียดจะดีกว่าเมื่อต่ำกว่า ดังนั้นเพื่อความละเอียดที่ดีกว่า (ต่ำกว่า) เราต้องการ:

  • ตัวอย่างเพิ่มเติม และ/หรือ
  • fs ที่ต่ำกว่า

แต่…

4) fs ขั้นต่ำ

เนื่องจากเราต้องการเห็นความถี่จำนวนมาก บางความถี่สูงกว่า "ความถี่พื้นฐาน" มาก เราจึงตั้งค่า fs ให้ต่ำเกินไปไม่ได้ อันที่จริงมีทฤษฎีบทการสุ่มตัวอย่าง Nyquist–Shannon ที่บังคับให้เรามีความถี่การสุ่มตัวอย่างสูงกว่าความถี่สูงสุดสองเท่าที่เราต้องการทดสอบ

ตัวอย่างเช่น หากเราต้องการวิเคราะห์คลื่นความถี่ทั้งหมดตั้งแต่ 0 Hz จนถึง 15 KHz ซึ่งเป็นความถี่สูงสุดโดยประมาณที่มนุษย์ส่วนใหญ่ได้ยินอย่างชัดเจน เราต้องตั้งค่าความถี่สุ่มตัวอย่างที่ 30 KHz ที่จริงแล้ว ช่างอิเล็กทรอนิกส์มักจะตั้งไว้ที่ 2.5 (หรือ 2.52) * ความถี่สูงสุด ในตัวอย่างนี้ จะเป็น 2.5 * 15 KHz = 37.5 KHz ความถี่สุ่มตัวอย่างปกติในเสียงระดับมืออาชีพคือ 44.1 KHz (การบันทึกเสียงซีดี) 48 KHz และอื่นๆ

บทสรุป:

จุดที่ 1 ถึง 4 นำไปสู่: เราต้องการใช้ตัวอย่างให้ได้มากที่สุด ในกรณีของเราที่มีอุปกรณ์ RAM ขนาด 16 KB เราจะพิจารณาตัวอย่าง 1024 ตัวอย่าง เราต้องการสุ่มตัวอย่างที่ความถี่การสุ่มตัวอย่างต่ำที่สุดเท่าที่จะทำได้ ตราบใดที่สูงพอที่จะวิเคราะห์ความถี่สูงสุดที่เราคาดหวังในสัญญาณของเรา (อย่างน้อย 2.5 * ความถี่นี้)

ขั้นตอนที่ 3: จำลองสัญญาณ

การจำลองสัญญาณ
การจำลองสัญญาณ

สำหรับการลองครั้งแรก เราจะปรับเปลี่ยนตัวอย่าง TFT_01.ino เล็กน้อยที่ให้ไว้ในคลัง เพื่อวิเคราะห์สัญญาณที่ประกอบด้วย

  • ความถี่พื้นฐานตั้งไว้ที่ 440 Hz (ดนตรี A)
  • ฮาร์โมนิกที่ 3 ที่ครึ่งหนึ่งของกำลังของปัจจัยพื้นฐาน ("-3 dB")
  • ฮาร์โมนิกที่ 5 ที่ 1/4 ของกำลังของพื้นฐาน ("-6 dB)

คุณสามารถเห็นในภาพด้านบนสัญญาณผลลัพธ์ ดูเหมือนสัญญาณจริงมากซึ่งบางครั้งสามารถเห็นได้บนออสซิลโลสโคป (ฉันจะเรียกมันว่า "แบทแมน") ในสถานการณ์ที่มีการตัดสัญญาณไซน์

ขั้นตอนที่ 4: การวิเคราะห์สัญญาณจำลอง - การเข้ารหัส

0) รวมห้องสมุด

#รวม "arduinoFFT.h"

1) คำจำกัดความ

ในส่วนการประกาศ เรามี

const ไบต์ adcPin = 0; // A0

const uint16_t ตัวอย่าง = 1024; // ค่านี้ต้องเป็นกำลังสองเสมอ uint16_t samplingFrequency = 8000; // จะส่งผลต่อค่าสูงสุดของตัวจับเวลาใน timer_setup() SYSCLOCK/8/samplingFrequency ควรเป็นจำนวนเต็ม

เนื่องจากสัญญาณมีฮาร์โมนิกที่ 5 (ความถี่ของฮาร์มอนิกนี้ = 5 * 440 = 2200 Hz) เราจึงต้องตั้งค่าความถี่สุ่มตัวอย่างให้สูงกว่า 2.5*2200 = 5500 Hz ที่นี่ฉันเลือก 8000 Hz

นอกจากนี้เรายังประกาศอาร์เรย์ที่เราจะเก็บข้อมูลดิบและคำนวณ

float vReal[ตัวอย่าง];

float vImag[ตัวอย่าง];

2) การสร้างอินสแตนซ์

เราสร้างวัตถุ ArduinoFFT ArduinoFFT เวอร์ชัน dev ใช้เทมเพลตเพื่อให้เราสามารถใช้ float หรือประเภทข้อมูลคู่ Float (32 บิต) ก็เพียงพอแล้วสำหรับความแม่นยำโดยรวมของโปรแกรมของเรา

ArduinoFFT FFT = ArduinoFFT (vReal, vImag, ตัวอย่าง, ความถี่สุ่มตัวอย่าง);

3) จำลองสัญญาณโดยการเติมอาร์เรย์ vReal แทนที่จะเติมด้วยค่า ADC

ที่จุดเริ่มต้นของลูป เราเติมอาร์เรย์ vReal ด้วย:

float cycles = (((ตัวอย่าง) * signalFrequency) / samplingFrequency); //จำนวนรอบสัญญาณที่สุ่มตัวอย่างจะอ่าน

สำหรับ (uint16_t i = 0; i < ตัวอย่าง; i++) { vReal = float((amplitude * (sin((i * (TWO_PI * cycles)) / ตัวอย่าง))));/* สร้างข้อมูลด้วยค่าบวกและ ค่าลบ*/ vReal += float((แอมพลิจูด * (sin((3 * i * (TWO_PI * รอบ)) / ตัวอย่าง))) / 2.0);/* สร้างข้อมูลด้วยค่าบวกและค่าลบ*/ vReal += float((แอมพลิจูด * (sin((5 * i * (TWO_PI * รอบ)) / ตัวอย่าง))) / 4.0);/* สร้างข้อมูลด้วยค่าบวกและค่าลบ*/ vImag = 0.0; //ส่วนจินตภาพจะต้องเป็นศูนย์ในกรณีที่มีการวนซ้ำเพื่อหลีกเลี่ยงการคำนวณที่ไม่ถูกต้องและการโอเวอร์โฟลว์ }

เราเพิ่มการแปลงคลื่นพื้นฐานให้เป็นดิจิทัลและฮาร์โมนิกทั้งสองแบบที่มีแอมพลิจูดน้อยกว่า กว่าที่เราจะเริ่มต้นอาร์เรย์จินตภาพด้วยศูนย์ เนื่องจากอาร์เรย์นี้ถูกเติมโดยอัลกอริทึม FFT เราจึงต้องล้างข้อมูลอีกครั้งก่อนการคำนวณใหม่แต่ละครั้ง

4) การคำนวณ FFT

จากนั้นเราคำนวณ FFT และความหนาแน่นของสเปกตรัม

FFT.windowing(FFTWindow::Hamming, FFTDirection::ไปข้างหน้า);

FFT.compute(FFTDirection::Forward); /* คำนวณ FFT */ FFT.complexToMagnitude(); /* ขนาดคำนวณ */

การดำเนินการ FFT.windowing(…) จะแก้ไขข้อมูลดิบเนื่องจากเราเรียกใช้ FFT ในจำนวนตัวอย่างที่จำกัด ตัวอย่างแรกและตัวอย่างสุดท้ายแสดงความไม่ต่อเนื่อง (ด้านใดด้านหนึ่ง "ไม่มีอะไร") นี่คือที่มาของข้อผิดพลาด การดำเนินการ "windowing" มีแนวโน้มที่จะลดข้อผิดพลาดนี้

FFT.compute(…) โดยมีทิศทาง "ไปข้างหน้า" คำนวณการเปลี่ยนแปลงจากโดเมนเวลาเป็นโดเมนความถี่

จากนั้นเราจะคำนวณค่าขนาด (เช่น ความเข้ม) สำหรับแต่ละแถบความถี่ ตอนนี้อาร์เรย์ vReal เต็มไปด้วยค่าขนาด

5) การวาดภาพพล็อตเตอร์แบบอนุกรม

มาพิมพ์ค่าบนพล็อตเตอร์แบบอนุกรมโดยเรียกใช้ฟังก์ชัน printVector(…)

PrintVector(vReal, (ตัวอย่าง >> 1), SCL_FREQUENCY);

นี่เป็นฟังก์ชันทั่วไปที่ช่วยให้สามารถพิมพ์ข้อมูลด้วยแกนเวลาหรือแกนความถี่ได้

นอกจากนี้เรายังพิมพ์ความถี่ของแถบที่มีขนาดสูงสุด

ลอย x = FFT.majorPeak();

Serial.print("f0="); Serial.print(x, 6); Serial.println("Hz");

ขั้นตอนที่ 5: การวิเคราะห์สัญญาณจำลอง - ผลลัพธ์

การวิเคราะห์สัญญาณจำลอง - ผลลัพธ์
การวิเคราะห์สัญญาณจำลอง - ผลลัพธ์

เราเห็นเดือยแหลม 3 อันที่สอดคล้องกับความถี่พื้นฐาน (f0) ฮาร์โมนิกที่ 3 และ 5 โดยมีขนาดครึ่งหนึ่งและ 1/4 ของขนาด f0 ตามที่คาดไว้ เราสามารถอ่านได้ที่ด้านบนของหน้าต่าง f0= 440.430114 Hz ค่านี้ไม่ใช่ 440 Hz อย่างแน่นอน เนื่องจากเหตุผลทั้งหมดที่อธิบายไว้ข้างต้น แต่ใกล้เคียงกับค่าจริงมาก ไม่จำเป็นต้องแสดงทศนิยมที่ไม่มีนัยสำคัญมากนัก

ขั้นตอนที่ 6: การวิเคราะห์สัญญาณจริง - การเดินสาย ADC

การวิเคราะห์สัญญาณจริง - การเดินสาย ADC
การวิเคราะห์สัญญาณจริง - การเดินสาย ADC

เนื่องจากเรารู้วิธีดำเนินการในทางทฤษฎี เราจึงต้องการวิเคราะห์สัญญาณจริง

การเดินสายไฟนั้นง่ายมาก เชื่อมต่อกราวด์เข้าด้วยกันและสายสัญญาณเข้ากับพิน A0 ของบอร์ดของคุณผ่านตัวต้านทานแบบอนุกรมที่มีค่า 1 KOhm ถึง 10 KOhm

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

สำหรับการสาธิตนี้ ฉันใช้ตัวสร้างฟังก์ชันเพื่อป้อนสัญญาณไซน์ที่มีความถี่ 440 Hz และแอมพลิจูดประมาณ 5 โวลต์ (จะดีที่สุดถ้าแอมพลิจูดอยู่ระหว่าง 3 ถึง 5 โวลต์ ดังนั้น ADC จะใช้ใกล้เต็มสเกล) ผ่านตัวต้านทาน 1.2 KOhm.

ขั้นตอนที่ 7: การวิเคราะห์สัญญาณจริง - การเข้ารหัส

0) รวมห้องสมุด

#รวม "arduinoFFT.h"

1) คำประกาศและการแสดงตัวอย่าง

ในส่วนการประกาศ เราจะกำหนดอินพุต ADC (A0) จำนวนตัวอย่างและความถี่ในการสุ่มตัวอย่าง เช่นเดียวกับในตัวอย่างก่อนหน้า

const ไบต์ adcPin = 0; // A0

const uint16_t ตัวอย่าง = 1024; // ค่านี้ต้องเป็นกำลังสองเสมอ uint16_t samplingFrequency = 8000; // จะส่งผลต่อค่าสูงสุดของตัวจับเวลาใน timer_setup() SYSCLOCK/8/samplingFrequency ควรเป็นจำนวนเต็ม

เราสร้างวัตถุ ArduinoFFT

ArduinoFFT FFT = ArduinoFFT (vReal, vImag, ตัวอย่าง, ความถี่สุ่มตัวอย่าง);

2) ตั้งเวลาและการตั้งค่า ADC

เราตั้งเวลา 1 เพื่อให้หมุนรอบที่ความถี่สุ่มตัวอย่าง (8 KHz) และเพิ่มการขัดจังหวะในการเปรียบเทียบเอาต์พุต

โมฆะ timer_setup(){

// รีเซ็ตตัวจับเวลา 1 TCCR1A = 0; TCCR1B = 0; TCNT1 = 0; TCCR1B = บิต (CS11) | บิต (WGM12); // CTC, prescaler ของ 8 TIMSK1 = บิต (OCIE1B); OCR1A = ((16000000 / 8) / ความถี่สุ่มตัวอย่าง) -1; }

และตั้ง ADC ไว้อย่างนั้น

  • ใช้ A0 เป็นอินพุต
  • ทริกเกอร์โดยอัตโนมัติในแต่ละเอาต์พุตของตัวจับเวลา 1 ตัวเปรียบเทียบการจับคู่B
  • สร้างการขัดจังหวะเมื่อการแปลงเสร็จสิ้น

นาฬิกา ADC ถูกตั้งค่าไว้ที่ 1 MHz โดยการปรับสัญญาณนาฬิกาของระบบ (16 MHz) ล่วงหน้าเป็น 16 เนื่องจากทุกการแปลงใช้เวลาประมาณ 13 นาฬิกาที่เต็มสเกล การแปลงสามารถทำได้ที่ความถี่ 1/13 = 0.076 MHz = 76 KHz ความถี่ในการสุ่มตัวอย่างควรต่ำกว่า 76 KHz อย่างมาก เพื่อให้ ADC มีเวลาสุ่มตัวอย่างข้อมูล (เราเลือก fs = 8 KHz)

เป็นโมฆะ adc_setup () {

ADCSRA = บิต (ADEN) | บิต (ADIE) | บิต (ADIF); // เปิด ADC ต้องการขัดจังหวะเมื่อเสร็จสิ้น ADCSRA |= bit (ADPS2); // Prescaler ของ 16 ADMUX = บิต (REFS0) | (adcPin & 7); // การตั้งค่าอินพุต ADC ADCSRB = บิต (ADTS0) | บิต (ADTS2); // ตัวจับเวลา/ตัวนับ1 เปรียบเทียบการจับคู่ B ทริกเกอร์ต้นทาง ADCSRA |= บิต (ADATE); // เปิดการทริกเกอร์อัตโนมัติ }

เราประกาศตัวจัดการขัดจังหวะที่จะเรียกหลังจากการแปลง ADC แต่ละครั้งเพื่อเก็บข้อมูลที่แปลงแล้วในอาร์เรย์ vReal และการล้างการขัดจังหวะ

// ADC กรอก ISR

ISR (ADC_vect) { vReal [resultNumber ++] = ADC; ถ้า (จำนวนผลลัพธ์ == ตัวอย่าง) { ADCSRA = 0; // ปิด ADC } } EMPTY_INTERRUPT (TIMER1_COMPB_vect);

คุณสามารถมีคำอธิบายโดยละเอียดเกี่ยวกับการแปลง ADC บน Arduino (analogRead)

3) ตั้งค่า

ในฟังก์ชันการตั้งค่า เราจะล้างตารางข้อมูลจินตภาพและเรียกใช้ฟังก์ชันการตั้งค่าตัวจับเวลาและ ADC

ศูนย์ฉัน(); // ฟังก์ชั่นที่ตั้งค่าเป็น 0 ของข้อมูลจินตภาพทั้งหมด - อธิบายไว้ในส่วนก่อนหน้า

timer_setup(); adc_setup();

3) วนรอบ

FFT.dcRemoval(); // ลบองค์ประกอบ DC ของสัญญาณนี้เนื่องจาก ADC อ้างอิงถึงกราวด์

FFT.windowing(FFTWindow::Hamming, FFTDirection::ไปข้างหน้า); // ชั่งน้ำหนักข้อมูล FFT.compute(FFTDirection::Forward); // คำนวณ FFT FFT.complexToMagnitude(); // ขนาดการคำนวณ // การพิมพ์สเปกตรัมและความถี่พื้นฐาน f0 PrintVector(vReal, (ตัวอย่าง >> 1), SCL_FREQUENCY); ลอย x = FFT.majorPeak(); Serial.print("f0="); Serial.print(x, 6); Serial.println("Hz");

เรานำส่วนประกอบ DC ออกเนื่องจาก ADC อ้างอิงถึงกราวด์และสัญญาณอยู่กึ่งกลางประมาณ 2.5 โวลต์โดยประมาณ

จากนั้นเราคำนวณข้อมูลตามที่อธิบายไว้ในตัวอย่างก่อนหน้านี้

ขั้นตอนที่ 8: การวิเคราะห์สัญญาณจริง - ผลลัพธ์

การวิเคราะห์สัญญาณจริง - ผลลัพธ์
การวิเคราะห์สัญญาณจริง - ผลลัพธ์

อันที่จริงเราเห็นความถี่เดียวในสัญญาณง่ายๆ นี้ ความถี่พื้นฐานที่คำนวณได้คือ 440.118194 Hz ค่านี้เป็นค่าประมาณที่ใกล้เคียงมากของความถี่จริง

ขั้นตอนที่ 9: แล้วสัญญาณไซน์ที่ถูกตัดแล้วล่ะ

สิ่งที่เกี่ยวกับสัญญาณไซนัสแบบคลิปหนีบ?
สิ่งที่เกี่ยวกับสัญญาณไซนัสแบบคลิปหนีบ?

ตอนนี้ให้โอเวอร์ไดรฟ์ ADC เล็กน้อยโดยการเพิ่มแอมพลิจูดของสัญญาณที่สูงกว่า 5 โวลต์ดังนั้นจึงถูกตัดออก อย่าผลักดันมากเกินไปที่จะไม่ทำลายอินพุต ADC!

เราสามารถเห็นฮาร์โมนิกบางอย่างปรากฏขึ้น การตัดสัญญาณจะสร้างส่วนประกอบที่มีความถี่สูง

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

แนะนำ: