Memahami keluaran FFT


88

Saya butuh bantuan untuk memahami output dari komputasi DFT / FFT.

Saya seorang insinyur perangkat lunak berpengalaman dan perlu menafsirkan beberapa bacaan akselerometer ponsel cerdas, seperti menemukan frekuensi utama. Sayangnya, saya tidur sepanjang sebagian besar kelas EE kuliah saya lima belas tahun yang lalu, tetapi saya telah membaca tentang DFT dan FFT selama beberapa hari terakhir (tampaknya sedikit berhasil).

Tolong, tidak ada tanggapan "ambil kelas EE". Saya sebenarnya berencana melakukan itu jika majikan saya akan membayar saya. :)

Jadi inilah masalah saya:

Saya telah menangkap sinyal pada 32 Hz. Berikut adalah sampel 1 detik dari 32 poin, yang telah saya buat grafiknya di Excel.

masukkan deskripsi gambar di sini

Saya kemudian mendapat beberapa kode FFT yang ditulis di Java dari Columbia University (setelah mengikuti saran dalam posting di " FFT handal dan cepat di Java ").

Output dari program ini adalah sebagai berikut. Saya yakin ini menjalankan FFT di tempat, jadi ini menggunakan kembali buffer yang sama untuk input dan output.

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  ]

Jadi, pada titik ini, saya tidak bisa membuat head atau tail output. Saya memahami konsep DFT, seperti bagian sebenarnya adalah amplitudo gelombang kosinus komponen dan bagian imajinernya adalah amplitudo gelombang sinus komponen. Saya juga dapat mengikuti diagram ini dari buku hebat " The Scientist and Engineer's Guide to Digital Signal Processing ": masukkan deskripsi gambar di sini

Jadi pertanyaan spesifik saya adalah:

  1. Dari keluaran FFT, bagaimana cara menemukan "frekuensi yang paling sering terjadi"? Ini adalah bagian dari analisis saya terhadap data akselerometer saya. Haruskah saya membaca array nyata (cosinus) atau imajiner (sinus)?

  2. Saya memiliki input 32-poin dalam domain waktu. Bukankah seharusnya keluaran dari FFT berupa larik 16 elemen untuk real dan larik 16 elemen untuk imajiner? Mengapa program ini memberi saya keluaran larik nyata dan imajiner, keduanya berukuran 32?

  3. Terkait dengan pertanyaan sebelumnya, bagaimana cara mengurai indeks dalam larik keluaran? Mengingat input saya dari 32 sampel yang diambil sampelnya pada 32 Hz, pemahaman saya adalah bahwa output array 16-elemen harus memiliki indeksnya tersebar secara seragam hingga 1/2 tingkat pengambilan sampel (dari 32 Hz), jadi saya benar dalam memahami bahwa setiap elemen dari array mewakili (32 Hz * 1/2) / 16 = 1 Hz?

  4. Mengapa keluaran FFT memiliki nilai negatif? Saya pikir nilai mewakili amplitudo dari sinusoid. Sebagai contoh, keluaran dari Real [3] = -1.075 berarti amplitudo -1.075 untuk gelombang kosinus frekuensi 3. Apakah benar? Bagaimana amplitudo bisa negatif?


Apa yang ingin Anda hitung dari pembacaan akselerometer: kecepatan, jarak? Suara pembacaan akselerometer mengikuti distribusi Gaussian dan saya tidak dapat melihat seberapa pas gelombang sinus akan memperbaikinya.
Ali

2
tag java harus dihapus karena lebih umum daripada bahasa tertentu
user3791372

Melihat sumber Universitas Columbia, itu tidak efisien sama sekali. Ini adalah implementasi Cooley-Tucky yang polos dan tidak dioptimalkan dengan tabel pencarian kupu-kupu, dan bit-reversal dilakukan secara manual alih-alih menggunakan fungsi perpustakaan yang ada
Mark Jeronimus

@ MarkJeronimus: Dapatkah Anda merekomendasikan implementasi FFT yang efisien di Java? Jika saya ingat dengan benar, alasan saya menggunakan kode Universitas Columbia adalah karena perpustakaan FFTW terlalu rumit untuk dijalankan pada smartphone Android.
stackoverflowuser2010

Saya menemukan beberapa implementasi 'dioptimalkan' yang tersebar, tetapi pada dasarnya mereka adalah satu algoritme per ukuran N, jadi jika Anda memerlukan berbagai ukuran, Anda memerlukan semua rutinitas tersebut. Dalam praktiknya saya terutama menggunakan Intel Integrated Performance Primitives (ya, dari Java, melalui JNA), tetapi itu tidak gratis. Di rumah saya pada dasarnya menggunakan algoritme yang sama dengan yang Anda tautkan, tetapi ditulis dari awal pada tahun 2005 menggunakan buku teks. Ini hanya FFT (Fast Fourier Transform), tidak ada yang begitu 'Cepat' tentang itu untuk membenarkan nama 'Fast FFT'.
Mark Jeronimus

Jawaban:


86
  1. Anda tidak boleh mencari bagian nyata atau imajinatif dari bilangan kompleks (yang merupakan larik nyata dan imajiner Anda). Sebagai gantinya Anda ingin mencari besaran frekuensi yang didefinisikan sebagai akar persegi (real * real + imag * imag). Angka ini akan selalu positif. Sekarang yang harus Anda cari adalah nilai maksimum (abaikan entri pertama dalam array Anda. Itu adalah offset DC Anda dan tidak membawa informasi yang bergantung pada frekuensi).

  2. Anda mendapatkan 32 keluaran nyata dan 32 hasil imajiner karena Anda menggunakan FFT kompleks hingga kompleks. Ingatlah bahwa Anda telah mengubah 32 sampel Anda menjadi 64 nilai (atau 32 nilai kompleks) dengan memperluasnya tanpa bagian imajiner. Ini menghasilkan keluaran FFT simetris di mana hasil frekuensi muncul dua kali. Setelah siap digunakan dalam output 0 hingga N / 2, dan setelah dicerminkan dalam output N / 2 ke N. Dalam kasus Anda, yang paling mudah adalah mengabaikan output N / 2 ke N. Anda tidak membutuhkannya, mereka hanya artefak tentang bagaimana Anda menghitung FFT Anda.

  3. Persamaan frekuensi ke fft-bin adalah (bin_id * freq / 2) / (N / 2) di mana freq adalah frekuensi sampel Anda (alias 32 Hz, dan N adalah ukuran FFT Anda). Dalam kasus Anda, ini disederhanakan menjadi 1 Hz per bin. Tempat sampah N / 2 ke N mewakili frekuensi negatif (konsep aneh, saya tahu). Untuk kasus Anda, mereka tidak mengandung informasi penting karena mereka hanyalah cermin dari frekuensi N / 2 pertama.

  4. Bagian nyata dan imajiner Anda dari setiap nampan membentuk bilangan kompleks. Tidak apa-apa jika bagian nyata dan imajiner negatif sedangkan besaran frekuensinya sendiri positif (lihat jawaban saya untuk pertanyaan 1). Saya menyarankan agar Anda membaca tentang bilangan kompleks. Menjelaskan bagaimana mereka bekerja (dan mengapa mereka berguna) melebihi apa yang mungkin untuk dijelaskan dalam satu pertanyaan stackoverflow.

Catatan: Anda mungkin juga ingin membaca apa itu autokorelasi, dan bagaimana hal itu digunakan untuk mencari frekuensi fundamental sebuah sinyal. Saya merasa inilah yang sebenarnya Anda inginkan.


1
Terima kasih. Mengenai 1: Saya melihat halaman Matlab ini yang menunjukkan spektrum frekuensi ( mathworks.com/help/techdoc/ref/fft.html ). Pada halaman itu adalah plot dengan judul "Spektrum Amplitudo Satu Sisi y (t)". Apakah itu menggambarkan besarnya frekuensi seperti yang Anda sarankan, sqrt (real ^ 2 + img ^ 2)? Mengenai 3: Saya masih belum mendapatkan hasil 2Hz per bin. Dalam kasus saya, N = 32 dan freq = 32, bukan? Jadi ada N / 2 = 32/2 = 16 bin, dan frekuensi tertinggi (Nyquist) adalah freq / 2 = 32/2 = 16 Hz, menghasilkan 16 Hz per 16 bin, menghasilkan 1 Hz per bin?
stackoverflowuser2010

1
Ya, plot tersebut menunjukkan besarnya spektrum - | Y (f) |. Batang nilai absolut berarti besaran. Lebar wadah = laju sampel / ukuran FFT. Rasio sampel Anda adalah 32 hz, ukuran FFT Anda adalah 32. Ya, Anda benar tentang lebar wadah!
Matt Montag

Memperbaiki frekuensi bin.
André Chalella

1
Jawaban bagus, terima kasih! Mohon maaf saya agak telat ke pesta, tapi mungkin anda bisa menjawab berapa besaran frekuensi (seperti yang anda sebutkan di poin 1) secara umum? Dalam kasus saya, pada sinyal nilai dari akselerometer (adalah m / s ^ 2). Saya tidak bisa memahaminya.
Markus

Menarik! Bilah frekuensi visualisasi musik saya semuanya keluar dengan cermin dari kiri ke kanan; jawaban # 2 menjelaskan ini !! Gila!!
Ryan S

11

Anda sudah memiliki beberapa jawaban yang bagus, tetapi saya hanya akan menambahkan bahwa Anda benar-benar perlu menerapkan fungsi jendela ke data domain waktu Anda sebelum FFT, jika tidak, Anda akan mendapatkan artefak buruk dalam spektrum Anda, karena kebocoran spektral .


Saya menghargai bahwa cukup banyak waktu telah berlalu sejak jawaban ini .. Namun, bisakah Anda menguraikan jenis artefak yang Anda maksud?
MattHusz

1
@MattHusz: istilah umum untuk asal mula artefak ini adalah "kebocoran spektral" - Saya telah menambahkan tautan ke jawaban sekarang yang menjelaskan hal ini. Cara terbaik untuk menjelaskan efeknya adalah bahwa spektrum Anda akan "tercoreng" karena jendela persegi panjang implisit.
Paul R

6

1) Cari indeks dalam larik nyata dengan nilai tertinggi, selain yang pertama (itu adalah komponen DC). Anda mungkin membutuhkan sample rate yang jauh lebih tinggi dari 32 Hz, dan ukuran window yang lebih besar, untuk mendapatkan hasil yang berarti.

2) Paruh kedua dari kedua larik adalah cermin dari paruh pertama. Misalnya, perhatikan bahwa elemen terakhir dari larik nyata (1.774) sama dengan elemen kedua (1.774), dan elemen terakhir dari larik imajiner (1.474) adalah negatif dari elemen kedua.

3) Frekuensi maksimum yang dapat Anda ambil pada laju sampel 32 Hz adalah 16 Hz ( batas Nyquist ), jadi setiap langkah adalah 2 Hz. Seperti disebutkan sebelumnya, ingat bahwa elemen pertama adalah 0 Hz (yaitu, offset DC).

4) Tentu, amplitudo negatif sangat masuk akal. Ini hanya berarti bahwa sinyal "dibalik" - FFT standar didasarkan pada kosinus, yang biasanya bernilai = 1 pada t = 0, sehingga sinyal yang memiliki nilai = -1 pada waktu = 0 akan memiliki amplitudo negatif .


Terima kasih balasannya. (1) Apakah maksud Anda saya dapat mengabaikan larik imajiner (sinus), dan jika demikian, mengapa? Tentunya komponen sinus pasti penting? (2) Mengapa pencerminan ini terjadi? Apakah ini hanya hasil dari algoritma FFT? Apakah kebanyakan orang mengabaikan setengah cermin? (3) Bagaimana Anda menghitung langkah 2Hz? Saya memahami batas Nyquist 16Hz, jadi jika ada 16 elemen array (non-mirrored), setiap elemen harus masing-masing 16 Hz / 16 = 1 Hz? (4) Untuk menemukan frekuensi utama, apakah saya hanya mengambil nilai absolut dari nilai amplitudo dalam larik keluaran?
stackoverflowuser2010

Anda tidak boleh mencari nilai tertinggi dalam array sebenarnya, dan Anda tidak dapat mengabaikan array sinus / I. Sebaliknya, Anda menginginkan besarnya vektor kompleks komposit. Pencerminan terjadi karena setengah input (larik I) semuanya nol, sehingga hasilnya memiliki setengah derajat kebebasan. Anda dapat mengabaikannya jika data Anda benar-benar nyata.
hotpaw2

@duskwuff Terima kasih banyak: Anda memberikan jawaban untuk pertanyaan yang akan saya posting, jika saya tidak menemukan jawaban Anda: bagaimana menafsirkan bagian KEDUA dari FFT. Saya ingin memodifikasi data dan melakukan pembalikan dan saya terus mendapatkan hanya setengah hasil, karena saya memodifikasi data yang salah di bagian itu. Terima kasih lagi.
Martin

(3), nilai langkah = 2Hz tetap implisit bagi saya sejauh ini. Kami memiliki 16 bin, diwakili oleh array panjang = 16. Kita perlu mendeskripsikan semua frekuensi dari 0Hz hingga 16Hz. Saya berasumsi setiap tempat sampah menggambarkan bagian dari kisaran itu, bukan?
krafter

@krafter Saya pikir itu dibelah dua karena Anda tidak dapat menyimpulkan frekuensi dari satu nilai (karena tidak ada pengulangan).
JVE999

5

Perhatikan bahwa "frekuensi yang paling sering terjadi" dapat terpecah menjadi beberapa kotak FFT, bahkan dengan fungsi jendela. Jadi, Anda mungkin harus menggunakan jendela yang lebih panjang, banyak jendela, atau interpolasi untuk memperkirakan frekuensi puncak spektrum dengan lebih baik.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.