ทำความเข้าใจกับเอาต์พุต FFT


88

ฉันต้องการความช่วยเหลือในการทำความเข้าใจผลลัพธ์ของการคำนวณ DFT / FFT

ฉันเป็นวิศวกรซอฟต์แวร์ที่มีประสบการณ์และต้องการตีความการอ่านค่ามาตรความเร่งของสมาร์ทโฟนบางอย่างเช่นการค้นหาความถี่หลัก น่าเสียดายที่ฉันเข้าเรียนในชั้นเรียน EE ของวิทยาลัยส่วนใหญ่เมื่อสิบห้าปีที่แล้ว แต่ฉันได้อ่าน DFT และ FFT ในช่วงหลายวันที่ผ่านมา (เห็นได้ชัดว่ามีประโยชน์เพียงเล็กน้อย)

ได้โปรดไม่มีคำตอบของ "ไปเรียน EE" ฉันวางแผนที่จะทำเช่นนั้นจริงๆถ้านายจ้างจะจ่ายเงินให้ฉัน :)

นี่คือปัญหาของฉัน:

ฉันจับสัญญาณได้ที่ 32 Hz นี่คือตัวอย่าง 1 วินาทีจาก 32 คะแนนซึ่งฉันได้สร้างแผนภูมิไว้ใน Excel

ใส่คำอธิบายภาพที่นี่

จากนั้นฉันได้รับโค้ด FFT ที่เขียนด้วยภาษา Java จาก Columbia University (หลังจากทำตามคำแนะนำในโพสต์เรื่อง " FFT ที่เชื่อถือได้และรวดเร็วใน Java ")

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

Before: 

Re: [0.887  1.645  2.005  1.069  1.069  0.69  1.046  1.847  0.808  0.617  0.792  1.384  1.782  0.925  0.751  0.858  0.915  1.006  0.985  0.97  1.075  1.183  1.408  1.575  1.556  1.282  1.06  1.061  1.283  1.701  1.101  0.702  ]

Im: [0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  ]

After: 

Re: [37.054  1.774  -1.075  1.451  -0.653  -0.253  -1.686  -3.602  0.226  0.374  -0.194  -0.312  -1.432  0.429  0.709  -0.085  0.0090  -0.085  0.709  0.429  -1.432  -0.312  -0.194  0.374  0.226  -3.602  -1.686  -0.253  -0.653  1.451  -1.075  1.774  ]

Im: [0.0  1.474  -0.238  -2.026  -0.22  -0.24  -5.009  -1.398  0.416  -1.251  -0.708  -0.713  0.851  1.882  0.379  0.021  0.0  -0.021  -0.379  -1.882  -0.851  0.713  0.708  1.251  -0.416  1.398  5.009  0.24  0.22  2.026  0.238  -1.474  ]

ดังนั้นในตอนนี้ฉันไม่สามารถสร้างหัวหรือก้อยของเอาต์พุตได้ ฉันเข้าใจแนวคิด DFT เช่นส่วนที่แท้จริงคือแอมพลิจูดของคลื่นโคไซน์ของส่วนประกอบและส่วนจินตภาพเป็นแอมพลิจูดของคลื่นไซน์ส่วนประกอบ ฉันยังสามารถติดตามแผนภาพนี้ได้จากหนังสือที่ยอดเยี่ยม " The Scientist and Engineer's Guide to Digital Signal Processing ": ใส่คำอธิบายภาพที่นี่

ดังนั้นคำถามเฉพาะของฉันคือ:

  1. จากเอาต์พุตของ FFT ฉันจะหา "ความถี่ที่เกิดขึ้นบ่อยที่สุด" ได้อย่างไร? นี่เป็นส่วนหนึ่งของการวิเคราะห์ข้อมูลมาตรความเร่งของฉัน ฉันควรอ่านอาร์เรย์จริง (โคไซน์) หรืออาร์เรย์ (ไซน์) ในจินตนาการ

  2. ฉันมีอินพุต 32 จุดในโดเมนเวลา เอาต์พุตของ FFT ควรเป็นอาร์เรย์ 16 องค์ประกอบสำหรับเรียลและอาร์เรย์ 16 องค์ประกอบสำหรับจินตภาพไม่ใช่หรือ เหตุใดโปรแกรมจึงให้เอาต์พุตอาร์เรย์จริงและจินตภาพทั้งสองขนาด 32

  3. เกี่ยวกับคำถามก่อนหน้าฉันจะแยกวิเคราะห์ดัชนีในอาร์เรย์เอาต์พุตได้อย่างไร จากการป้อนข้อมูลของตัวอย่าง 32 ตัวอย่างที่ 32 Hz ความเข้าใจของฉันคือเอาต์พุตอาร์เรย์ 16 องค์ประกอบควรมีดัชนีกระจายอย่างสม่ำเสมอถึง 1/2 ของอัตราการสุ่มตัวอย่าง (32 Hz) ดังนั้นฉันจึงเข้าใจถูกต้องหรือไม่ว่าแต่ละองค์ประกอบ ของอาร์เรย์แสดงถึง (32 Hz * 1/2) / 16 = 1 Hz?

  4. เหตุใดเอาต์พุต FFT จึงมีค่าเป็นลบ ฉันคิดว่าค่าต่างๆแสดงถึงแอมพลิจูดของไซนัส ตัวอย่างเช่นผลลัพธ์ของ Real [3] = -1.075 ควรหมายถึงแอมพลิจูดที่ -1.075 สำหรับคลื่นโคไซน์ของความถี่ 3 ถูกต้องหรือไม่? แอมพลิจูดเป็นลบได้อย่างไร?


คุณต้องการคำนวณอะไรจากการอ่านค่าความเร่ง: ความเร็วระยะทาง? เสียงรบกวนของการอ่านค่ามาตรวัดความเร่งเป็นไปตามการกระจายแบบเกาส์เซียนและฉันไม่เห็นว่าคลื่นไซน์ที่เหมาะสมจะแก้ไขได้อย่างไร
อาลี

2
แท็ก java ควรถูกลบออกเนื่องจากเป็นภาษาทั่วไปมากกว่าภาษาเฉพาะ
user3791372

เมื่อมองไปที่มหาวิทยาลัยโคลัมเบียมันไม่มีประสิทธิภาพเลย เป็นการใช้งาน Cooley-Tucky แบบธรรมดาที่ไม่ได้เพิ่มประสิทธิภาพด้วยตารางการค้นหาผีเสื้อและการย้อนกลับบิตทำได้ด้วยตนเองแทนที่จะใช้ฟังก์ชันไลบรารีที่มีอยู่
Mark Jeronimus

@MarkJeronimus: คุณสามารถแนะนำการใช้งาน FFT ที่มีประสิทธิภาพใน Java ได้หรือไม่? ถ้าฉันจำได้อย่างถูกต้องเหตุผลที่ฉันใช้รหัสมหาวิทยาลัยโคลัมเบียคือไลบรารี FFTW ซับซ้อนเกินกว่าที่จะทำงานบนสมาร์ทโฟน Android
stackoverflowuser2010

ฉันพบการใช้งานที่ 'ปรับให้เหมาะสมที่สุด' กระจัดกระจาย แต่โดยพื้นฐานแล้วเป็นเพียงอัลกอริทึมเดียวต่อขนาด N ดังนั้นหากคุณต้องการขนาดที่หลากหลายคุณต้องมีกิจวัตรเหล่านั้นทั้งหมด ในทางปฏิบัติฉันใช้ Intel Integrated Performance Primitives เป็นหลัก (ใช่จาก Java ถึง JNA) แต่ก็ไม่ฟรี ที่บ้านฉันใช้อัลกอริทึมเดียวกับที่คุณเชื่อมโยง แต่เขียนตั้งแต่เริ่มต้นในปี 2548 โดยใช้ตำราเรียน มันเป็นเพียง FFT (Fast Fourier Transform) ไม่มีอะไรที่ 'Fast' เกี่ยวกับเรื่องนี้เพื่อปรับชื่อ 'Fast FFT'
Mark Jeronimus

คำตอบ:


86
  1. คุณไม่ควรมองหาส่วนที่เป็นจริงหรือในจินตนาการของจำนวนเชิงซ้อน (อาร์เรย์จริงและจินตภาพของคุณคืออะไร) แต่คุณต้องการค้นหาขนาดของความถี่ที่กำหนดเป็น sqrt (จริง * จริง + จินต *) ตัวเลขนี้จะเป็นบวกเสมอ ตอนนี้สิ่งที่คุณต้องค้นหาคือค่าสูงสุด (ละเว้นรายการแรกในอาร์เรย์ของคุณนั่นคือ DC offset ของคุณและไม่มีข้อมูลที่ขึ้นกับความถี่)

  2. คุณได้ผลลัพธ์ 32 จริงและ 32 จินตภาพเนื่องจากคุณใช้ FFT ที่ซับซ้อนถึงซับซ้อน จำไว้ว่าคุณได้แปลงตัวอย่าง 32 ค่าให้เป็นค่า 64 (หรือ 32 ค่าเชิงซ้อน) โดยขยายส่วนจินตภาพเป็นศูนย์ ส่งผลให้เอาต์พุต FFT แบบสมมาตรซึ่งผลลัพธ์ความถี่เกิดขึ้นสองครั้ง เมื่อพร้อมใช้งานในเอาต์พุต 0 ถึง N / 2 และเมื่อทำมิเรอร์แล้วในเอาต์พุต N / 2 ถึง N ในกรณีของคุณวิธีที่ง่ายที่สุดคือละเว้นเอาต์พุต N / 2 ถึง N คุณไม่จำเป็นต้องใช้พวกเขา เป็นเพียงสิ่งประดิษฐ์เกี่ยวกับวิธีการคำนวณ FFT ของคุณ

  3. ความถี่ของสมการ fft-bin คือ (bin_id * freq / 2) / (N / 2) โดยที่ความถี่คือความถี่ตัวอย่างของคุณ (aka 32 Hz และ N คือขนาดของ FFT ของคุณ) ในกรณีของคุณสิ่งนี้จะลดลงเหลือ 1 เฮิรตซ์ต่อถัง ถังขยะ N / 2 ถึง N แสดงถึงความถี่เชิงลบ (ฉันรู้แนวคิดแปลก ๆ ) สำหรับกรณีของคุณพวกเขาไม่มีข้อมูลสำคัญใด ๆ เนื่องจากเป็นเพียงภาพสะท้อนของความถี่ N / 2 แรก

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

หมายเหตุ: คุณอาจต้องการอ่านด้วยว่า autocorrelation คืออะไรและจะใช้เพื่อค้นหาความถี่พื้นฐานของสัญญาณได้อย่างไร ฉันมีความรู้สึกว่านี่คือสิ่งที่คุณต้องการจริงๆ


1
ขอบคุณ. เกี่ยวกับ 1: ฉันเห็นหน้า Matlab นี้ซึ่งแสดงสเปกตรัมความถี่ ( mathworks.com/help/techdoc/ref/fft.html ) ในหน้านั้นเป็นพล็อตที่มีชื่อว่า "Single-Sided Amplitude Spectrum of y (t)" นั่นคือการพล็อตขนาดของความถี่ตามที่คุณแนะนำ sqrt (จริง ^ 2 + img ^ 2) หรือไม่? เกี่ยวกับ 3: ฉันยังไม่ได้รับผลลัพธ์ 2Hz ต่อ bin ในกรณีของฉัน N = 32 และ freq = 32 ใช่ไหม? ดังนั้นจึงมี N / 2 = 32/2 = 16 bins และความถี่สูงสุด (Nyquist) คือ freq / 2 = 32/2 = 16 Hz ส่งผลให้ 16 Hz ต่อ 16 bins ให้ 1 Hz ต่อ bin?
stackoverflowuser2010

1
ใช่พล็อตแสดงขนาดของสเปกตรัม - | Y (f) | แถบค่าสัมบูรณ์หมายถึงขนาด ความกว้างของถัง = อัตราตัวอย่าง / ขนาด FFT อัตราตัวอย่างของคุณคือ 32 hz ขนาด FFT ของคุณคือ 32 ใช่คุณพูดถูกเกี่ยวกับความกว้างของถังขยะ!
Matt Montag

แก้ไขความถี่ของถังขยะ
André Chalella

1
คำตอบที่ดีขอบคุณ! ขอโทษที่ฉันไปงานปาร์ตี้ช้าไปหน่อย แต่บางทีคุณอาจตอบฉันได้ว่าขนาดของความถี่ (ตามที่คุณกล่าวไว้ในข้อ 1) เป็นหน่วยใดโดยทั่วไป? ในกรณีของฉันสัญญาณของค่าจากมาตรความเร่ง (คือ m / s ^ 2) ฉันคิดไม่ออก
Markus

น่าหลงไหล! แถบความถี่การแสดงภาพเพลงของฉันทั้งหมดฉายจากซ้ายไปขวา คำตอบ # 2 อธิบายสิ่งนี้ !! บ้า!!
Ryan S

11

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


ฉันรู้สึกซาบซึ้งที่เวลาผ่านไปนานพอสมควรกับคำตอบนี้ .. อย่างไรก็ตามคุณสามารถอธิบายได้อย่างละเอียดว่าคุณหมายถึงสิ่งประดิษฐ์ประเภทใด?
MattHusz

1
@MattHusz: คำทั่วไปสำหรับที่มาของสิ่งประดิษฐ์เหล่านี้คือ "การรั่วไหลของสเปกตรัม" - ฉันได้เพิ่มลิงก์ไปยังคำตอบแล้วซึ่งอธิบายถึงเรื่องนี้ วิธีที่ดีที่สุดที่ฉันสามารถอธิบายผลกระทบได้ก็คือคลื่นความถี่ของคุณจะถูก "เลอะ" เนื่องจากหน้าต่างสี่เหลี่ยม
Paul R

6

1) มองหาดัชนีในอาร์เรย์จริงที่มีค่าสูงสุดนอกเหนือจากดัชนีแรก (นั่นคือส่วนประกอบ DC) คุณอาจต้องใช้อัตราการสุ่มตัวอย่างที่สูงกว่า 32 Hz และขนาดหน้าต่างที่ใหญ่ขึ้นเพื่อให้ได้ผลลัพธ์ที่มีความหมายมาก

2) ครึ่งหลังของอาร์เรย์ทั้งสองคือมิเรอร์ของครึ่งแรก ตัวอย่างเช่นโปรดทราบว่าองค์ประกอบสุดท้ายของอาร์เรย์จริง (1.774) นั้นเหมือนกับองค์ประกอบที่สอง (1.774) และองค์ประกอบสุดท้ายของอาร์เรย์จินตภาพ (1.474) เป็นค่าลบขององค์ประกอบที่สอง

3) ความถี่สูงสุดที่คุณสามารถรับได้ในอัตราตัวอย่าง 32 Hz คือ 16 Hz ( ขีด จำกัด ของ Nyquist ) ดังนั้นแต่ละขั้นตอนคือ 2 Hz ตามที่ระบุไว้ก่อนหน้านี้โปรดจำไว้ว่าองค์ประกอบแรกคือ 0 Hz (เช่น DC offset)

4) แน่นอนว่าแอมพลิจูดติดลบนั้นสมเหตุสมผล หมายความว่าสัญญาณ "พลิก" - FFT มาตรฐานจะขึ้นอยู่กับโคไซน์ซึ่งโดยปกติจะมีค่า = 1 ที่ t = 0 ดังนั้นสัญญาณที่มีค่า = -1 ในเวลา = 0 จะมีแอมพลิจูดเป็นลบ .


ขอบคุณสำหรับการตอบกลับ. (1) คุณหมายความว่าฉันสามารถละเว้นอาร์เรย์จินตภาพ (ไซน์) ได้หรือไม่และถ้าเป็นเช่นนั้นทำไม? ส่วนประกอบไซน์ต้องสำคัญแน่ ๆ ? (2) เหตุใดการมิเรอร์จึงเกิดขึ้น เป็นเพียงผลลัพธ์ของอัลกอริทึม FFT หรือไม่? คนส่วนใหญ่ไม่สนใจครึ่งกระจกหรือไม่? (3) คุณคำนวณสเต็ปของ 2Hz ได้อย่างไร? ฉันเข้าใจขีด จำกัด ของ Nyquist ที่ 16Hz ดังนั้นหากมีองค์ประกอบอาร์เรย์ 16 (ที่ไม่ใช่มิเรอร์) แต่ละองค์ประกอบต้องเป็น 16 Hz / 16 = 1 Hz (4) ในการค้นหาความถี่หลักฉันเพียงแค่ใช้ค่าสัมบูรณ์ของค่าแอมพลิจูดในอาร์เรย์เอาต์พุตหรือไม่?
stackoverflowuser2010

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

@duskwuff ขอบคุณมาก: คุณให้คำตอบสำหรับคำถามที่ฉันจะโพสต์ถ้าฉันไม่พบคำตอบของคุณ: วิธีตีความส่วนที่สองของ FFT ฉันต้องการแก้ไขข้อมูลและดำเนินการผกผันและฉันยังคงได้ผลลัพธ์เพียงครึ่งเดียวเนื่องจากฉันแก้ไขข้อมูลที่ไม่ถูกต้องในส่วนนั้น ขอบคุณอีกครั้ง.
Martin

(3) ค่าของ step = 2Hz ยังคงมีความหมายสำหรับฉันจนถึงตอนนี้ เรามีถังขยะ 16 ถังแสดงด้วยอาร์เรย์ของความยาว = 16 เราจำเป็นต้องอธิบายความถี่ทั้งหมดตั้งแต่ 0Hz ถึง 16Hz ฉันคิดว่าถังขยะทุกชิ้นอธิบายถึงส่วนหนึ่งของช่วงนั้นใช่หรือไม่
krafter

@krafter ฉันคิดว่ามันลดลงครึ่งหนึ่งเพราะคุณไม่สามารถอนุมานความถี่จากค่าเดียวได้ (เนื่องจากไม่มีการทำซ้ำ)
JVE999

5

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

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