วิเคราะห์เสียงโดยใช้ Fast Fourier Transform


109

ฉันกำลังพยายามสร้างตัววิเคราะห์สเปกตรัมแบบกราฟิกใน python

ฉันกำลังอ่าน 1024 ไบต์ของ 16 บิตดูอัลแชนเนล 44,100 เฮิรตซ์สตรีมเสียงอัตราตัวอย่างและเฉลี่ยแอมพลิจูดของ 2 แชนเนลเข้าด้วยกัน ตอนนี้ฉันมีกางเกงขาสั้นลายเซ็น 256 ตัว ตอนนี้ฉันต้องการสร้าง fft ล่วงหน้าบนอาร์เรย์นั้นโดยใช้โมดูลเช่น numpy และใช้ผลลัพธ์เพื่อสร้างตัววิเคราะห์สเปกตรัมกราฟิกซึ่งในการเริ่มต้นจะเป็นเพียง 32 บาร์

ฉันได้อ่านบทความวิกิพีเดียเรื่อง Fast Fourier Transform และ Discrete Fourier Transform แล้ว แต่ฉันยังไม่ชัดเจนว่าอาร์เรย์ผลลัพธ์นั้นหมายถึงอะไร นี่คือลักษณะของอาร์เรย์หลังจากที่ฉันสร้าง fft ไว้ล่วงหน้าบนอาร์เรย์ของฉันโดยใช้ numpy:

   [ -3.37260500e+05 +0.00000000e+00j   7.11787022e+05 +1.70667403e+04j
   4.10040193e+05 +3.28653370e+05j   9.90933073e+04 +1.60555003e+05j
   2.28787050e+05 +3.24141951e+05j   2.09781047e+04 +2.31063376e+05j
  -2.15941453e+05 +1.63773851e+05j  -7.07833051e+04 +1.52467334e+05j
  -1.37440802e+05 +6.28107674e+04j  -7.07536614e+03 +5.55634993e+03j
  -4.31009964e+04 -1.74891657e+05j   1.39384348e+05 +1.95956947e+04j
   1.73613033e+05 +1.16883207e+05j   1.15610357e+05 -2.62619884e+04j
  -2.05469722e+05 +1.71343186e+05j  -1.56779748e+04 +1.51258101e+05j
  -2.08639913e+05 +6.07372799e+04j  -2.90623668e+05 -2.79550838e+05j
  -1.68112214e+05 +4.47877871e+04j  -1.21289916e+03 +1.18397979e+05j
  -1.55779104e+05 +5.06852464e+04j   1.95309737e+05 +1.93876325e+04j
  -2.80400414e+05 +6.90079265e+04j   1.25892113e+04 -1.39293422e+05j
   3.10709174e+04 -1.35248953e+05j   1.31003438e+05 +1.90799303e+05j...

ฉันสงสัยว่าตัวเลขเหล่านี้แสดงถึงอะไรกันแน่และฉันจะแปลงตัวเลขเหล่านี้เป็นเปอร์เซ็นต์ของความสูงสำหรับแต่ละแท่ง 32 แท่งได้อย่างไร นอกจากนี้ฉันควรเฉลี่ย 2 ช่องด้วยกันหรือไม่?

คำตอบ:


209

อาร์เรย์ที่คุณแสดงคือค่าสัมประสิทธิ์การแปลงฟูริเยร์ของสัญญาณเสียง ค่าสัมประสิทธิ์เหล่านี้สามารถใช้เพื่อรับเนื้อหาความถี่ของเสียงได้ FFT ถูกกำหนดไว้สำหรับฟังก์ชันอินพุตที่มีมูลค่าซับซ้อนดังนั้นค่าสัมประสิทธิ์ที่คุณได้รับจะเป็นจำนวนจินตภาพแม้ว่าอินพุตของคุณจะเป็นค่าจริงทั้งหมดก็ตาม เพื่อให้ได้พลังงานในแต่ละความถี่คุณต้องคำนวณขนาดของค่าสัมประสิทธิ์ FFT สำหรับแต่ละความถี่ นี่ไม่ใช่แค่องค์ประกอบที่แท้จริงของสัมประสิทธิ์คุณต้องคำนวณรากที่สองของผลรวมของกำลังสองของส่วนประกอบจริงและจินตภาพ นั่นคือถ้าสัมประสิทธิ์ของคุณคือ a + b * j ขนาดของมันจะเป็น sqrt (a ^ 2 + b ^ 2)

เมื่อคุณคำนวณขนาดของค่าสัมประสิทธิ์ FFT แต่ละค่าแล้วคุณต้องหาความถี่เสียงที่แต่ละสัมประสิทธิ์ FFT เป็นของความถี่เสียง N point FFT จะให้เนื้อหาความถี่ของสัญญาณของคุณที่ N ความถี่ที่มีระยะห่างเท่า ๆ กันเริ่มต้นที่ 0 เนื่องจากความถี่ในการสุ่มตัวอย่างของคุณคือ 44100 ตัวอย่าง / วินาที และจำนวนจุดใน FFT ของคุณคือ 256 ระยะห่างความถี่ของคุณคือ 44100/256 = 172 Hz (โดยประมาณ)

ค่าสัมประสิทธิ์แรกในอาร์เรย์ของคุณคือค่าสัมประสิทธิ์ความถี่ 0 นั่นคือระดับพลังงานเฉลี่ยสำหรับทุกความถี่ ค่าสัมประสิทธิ์ส่วนที่เหลือของคุณจะนับจาก 0 เป็นทวีคูณ 172 Hz จนกว่าคุณจะได้ถึง 128 ใน FFT คุณสามารถวัดความถี่ได้ไม่เกินครึ่งหนึ่งของจุดตัวอย่างของคุณ อ่านลิงก์เหล่านี้เกี่ยวกับNyquist FrequencyและNyquist-Shannon Sampling Theoremหากคุณเป็นคนตะกละสำหรับการลงโทษและต้องการทราบสาเหตุ แต่ผลลัพธ์พื้นฐานคือความถี่ต่ำของคุณจะถูกจำลองหรือใช้นามแฝงในถังความถี่ที่สูงขึ้น ดังนั้นความถี่จะเริ่มจาก 0 เพิ่มขึ้น 172 Hz สำหรับแต่ละค่าสัมประสิทธิ์จนถึงค่าสัมประสิทธิ์ N / 2 จากนั้นลดลง 172 Hz จนถึงค่าสัมประสิทธิ์ N - 1

นั่นน่าจะเป็นข้อมูลที่เพียงพอในการเริ่มต้น หากคุณต้องการข้อมูลเบื้องต้นเกี่ยวกับ FFT ที่เข้าถึงได้ง่ายกว่าที่ให้ไว้ใน Wikipedia คุณสามารถลองทำความเข้าใจกับ Digital Signal Processing: 2nd Ed . มันเป็นประโยชน์มากสำหรับฉัน

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

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


1
ส่วนใหญ่ฉันสามารถค้นหาคำอธิบายที่ซับซ้อนเกินไปของ FFT ทางออนไลน์นี่เป็นคำอธิบายที่ยอดเยี่ยมและง่าย ๆ ว่าจำนวนจุดตัวอย่างมีผลต่อผลลัพธ์ของ FFT อย่างไร ขอบคุณสำหรับสิ่งนี้!
echolocation

26

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

สำหรับการแบ่งออกเป็นแท่งไม่ควรทำตามที่แอนติแนะนำโดยการแบ่งข้อมูลเท่า ๆ กันตามจำนวนบาร์ สิ่งที่มีประโยชน์ที่สุดคือการแบ่งข้อมูลออกเป็นส่วนอ็อกเทฟโดยแต่ละอ็อกเทฟจะมีความถี่สองเท่าของความถี่ก่อนหน้า (กล่าวคือ 100hz คือหนึ่งอ็อกเทฟที่สูงกว่า 50 เฮิร์ตซึ่งเป็นหนึ่งอ็อกเทฟที่สูงกว่า 25 เฮิร์ต)

ขึ้นอยู่กับจำนวนบาร์ที่คุณต้องการคุณแบ่งช่วงทั้งหมดออกเป็นช่วงอ็อกเทฟ 1 / X ขึ้นอยู่กับความถี่กลางที่กำหนดของ A บนแถบคุณจะได้รับขีด จำกัด บนและล่างของแถบจาก:

upper limit = A * 2 ^ ( 1 / 2X )
lower limit = A / 2 ^ ( 1 / 2X )

ในการคำนวณความถี่ศูนย์ที่อยู่ติดกันถัดไปคุณใช้การคำนวณที่คล้ายกัน:

next lower =  A / 2 ^ ( 1 / X )
next higher = A * 2 ^ ( 1 / X )

จากนั้นคุณเฉลี่ยข้อมูลที่พอดีกับช่วงเหล่านี้เพื่อรับแอมพลิจูดสำหรับแต่ละแถบ

ตัวอย่างเช่นเราต้องการแบ่งออกเป็น 1/3 ช่วงอ็อกเทฟและเริ่มต้นด้วยความถี่กลาง 1khz

Upper limit = 1000 * 2 ^ ( 1 / ( 2 * 3 ) ) = 1122.5
Lower limit = 1000 / 2 ^ ( 1 / ( 2 * 3 ) ) =  890.9

ให้ตัวอย่าง 44100hz และ 1024 (43hz ระหว่างจุดข้อมูลแต่ละจุด) เราควรเฉลี่ยออกเป็นค่า 21 ถึง 26 (890.9 / 43 = 20.72 ~ 21 และ 1122.5 / 43 = 26.10 ~ 26)

(1/3 แท่งคู่แปดจะทำให้คุณได้ประมาณ 30 บาร์ระหว่าง ~ 40hz ถึง ~ 20khz) ดังที่คุณสามารถหาได้ในตอนนี้เมื่อเราสูงขึ้นเราจะเฉลี่ยช่วงของตัวเลขที่มากขึ้น โดยทั่วไปแถบต่ำจะมีจุดข้อมูลเพียง 1 จุดหรือจำนวนเล็กน้อย ในขณะที่แท่งที่สูงกว่าอาจเป็นค่าเฉลี่ยของหลายร้อยจุด เหตุผลก็คือ 86hz นั้นเป็นอ็อกเทฟที่สูงกว่า 43hz ... ในขณะที่ 10086hz นั้นฟังดูใกล้เคียงกับ 10043hz


10

สิ่งที่คุณมีคือตัวอย่างที่มีความยาวของเวลาคือ 256/44100 = 0.00580499 วินาที ซึ่งหมายความว่าความละเอียดความถี่ของคุณคือ 1 / 0.00580499 = 172 Hz ค่า 256 ที่คุณได้รับจาก Python นั้นสอดคล้องกับความถี่โดยทั่วไปจาก 86 Hz ถึง 255 * 172 + 86 Hz = 43946 Hz ตัวเลขที่คุณได้ออกมาเป็นจำนวนเชิงซ้อน (ดังนั้น "j" ที่อยู่ท้ายจำนวนทุกวินาที)

แก้ไข: แก้ไขข้อมูลที่ไม่ถูกต้อง

คุณต้องแปลงจำนวนเชิงซ้อนให้เป็นแอมพลิจูดโดยคำนวณ sqrt (i 2 + j 2 ) โดยที่ i และ j เป็นส่วนจริงและจินตภาพ

ถ้าคุณต้องการมี 32 บาร์เท่าที่ฉันเข้าใจฉันเข้าใจว่าใช้ค่าเฉลี่ยของแอมพลิจูดต่อเนื่องสี่แอมพลิจูดได้ 256/4 = 32 บาร์ตามที่คุณต้องการ


4
โปรดทราบว่าถ้า c เป็นจำนวนเชิงซ้อน sqrt (c.real 2 + c.imag 2) == abs (c)
tzot

0

FFT ส่งคืนค่าที่ซับซ้อน N ซึ่งคุณสามารถคำนวณไฟล์module=sqrt(real_part^2+imaginary_part^2). เพื่อให้ได้ค่าสำหรับแต่ละวงคุณต้องรวมโมดูลเกี่ยวกับฮาร์โมนิกทั้งหมดภายในวง ด้านล่างนี้คุณสามารถดูตัวอย่างเกี่ยวกับเครื่องวิเคราะห์สเปกตรัม 10 บาร์ ต้องห่อรหัส c เพื่อให้ได้โมดูล pyd python

float *samples_vett;
float *out_filters_vett;
int Nsamples;
float band_power = 0.0;
float harmonic_amplitude=0.0;
int i, out_index;

out_index=0;


for (i = 0; i < Nsamples / 2 + 1; i++)       
        {
            if (i == 1 || i == 2 || i == 4 || i == 8 || i == 17 || i == 33 || i == 66 || i == 132 || i == 264 || i == 511)
            {
                out_filters_vett[out_index] = band_power; 
                band_power = 0; 
                out_index++;  
            }

            harmonic_amplitude = sqrt(pow(ttfr_out_vett[i].r, 2) + pow(ttfr_out_vett[i].i, 2));
            band_power += harmonic_amplitude;

        }

ฉันออกแบบและสร้างเครื่องวิเคราะห์สเปกตรัมแถบ led 10 ตัวโดย Python แทนที่จะใช้ไลบรารีแม่ชี (ใหญ่เกินไปและไร้ประโยชน์ที่จะได้รับเพียง FFT) โมดูล python pyd (เพียง 27KB) เพื่อรับ FFT และเพื่อแยกสเปกตรัมเสียงทั้งหมดไปยังวงดนตรี

นอกจากนี้ในการอ่านเสียงเอาต์พุตจะมีการสร้างโมดูล WASapi portaudio pyd แบบวนกลับ คุณสามารถดูโครงการ (แผนภาพบล็อก) ในภาพ 10BarsSpectrumAnalyzerWithWASapi.jpg

เพิ่งเพิ่มวิดีโอแนะนำในช่อง YouTube ของฉัน: วิธีออกแบบและสร้าง Python Spectrum Analyzer 10 Led Bar ที่ชาญฉลาดมาก

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.