Cara resample audio menggunakan FFT atau DFT

12

Saya mengambil sampel audio suara dengan terlebih dahulu melakukan FFT, kemudian hanya mengambil bagian dari hasil yang saya butuhkan, dan kemudian melakukan FFT terbalik. Namun, ini hanya berfungsi dengan baik ketika saya menggunakan frekuensi yang sama-sama berkekuatan dua, katakanlah pengambilan sampel dari 32768 hingga 8192. Saya melakukan FFT pada data 32k, membuang 3/4 data teratas dan kemudian melakukan FFT terbalik pada 1/4 yang tersisa.

Namun, setiap kali saya mencoba melakukan ini dengan data yang tidak sesuai dengan benar satu dari dua hal terjadi: Perpustakaan matematika saya (Aforge.Math) menggunakan lemparan yang cocok, karena sampel saya bukan kekuatan dua. Jika saya mencoba untuk mem-zero-pad sampel sehingga mereka menjadi kekuatan berpasangan, itu menjadi omong kosong. Saya juga mencoba menggunakan DFT sebagai gantinya, tetapi akhirnya menjadi sangat lambat (ini harus dilakukan dalam waktu nyata).

Bagaimana saya akan melakukan nol pad data FFT dengan benar, baik pada FFT awal dan FFT terbalik pada akhirnya? Dengan asumsi saya memiliki sampel pada 44.1khz yang perlu mencapai 16khz, saya saat ini mencoba sesuatu seperti ini, sampel berukuran 1000.

  1. Masukkan data input ke 1024 di akhir
  2. Lakukan FFT
  3. Baca 512 item pertama ke dalam array (saya hanya perlu 362 pertama, tetapi perlu ^ 2)
  4. Lakukan FFT terbalik
  5. Baca 362 item pertama ke dalam buffer putar audio

Dari ini, saya mendapatkan sampah pada akhirnya. Melakukan hal yang sama tetapi tanpa harus pad pada langkah 1 dan 3 karena sampel sudah ^ 2, memberikan hasil yang benar.


sumber
9
FFT sebenarnya bukan cara yang tepat untuk melakukan ini. Anda menginginkan bank filter polyphase untuk efisiensi maksimum, tetapi jika Anda hanya ingin menyelesaikan masalah, pertama-tama ganti rugi ke GCD, lalu lowpass, lalu turunkan sampel.
Bjorn Roche
Hai Bjorn: apa itu "GCD"?
SpeedCoder5

Jawaban:

16

Langkah pertama adalah memverifikasi bahwa laju sampel awal dan laju sampel target Anda adalah bilangan rasional . Karena mereka bilangan bulat, mereka secara otomatis bilangan rasional. Jika salah satu dari mereka bukan bilangan rasional, masih mungkin untuk membuat perubahan tingkat sampel, tetapi itu adalah proses yang jauh berbeda dan lebih sulit.

Langkah selanjutnya adalah memfaktorkan dua tingkat sampel. Tingkat sampel awal, dalam hal ini, adalah 44100, yang merupakan faktor . Tingkat sampel target, 16000, faktor ke . Jadi, untuk mengkonversi dari laju sampel awal ke laju target, kami harus memusnahkan dengan dan menginterpolasi dengan .2232527227533272255

Langkah-langkah sebelumnya harus dilakukan, tidak peduli bagaimana Anda ingin menguji ulang data. Sekarang mari kita bicara tentang bagaimana melakukannya dengan FFT. Trik untuk resampling dengan FFT adalah memilih panjang FFT yang membuat semuanya berjalan baik. Itu berarti memilih panjang FFT yang merupakan kelipatan dari laju penipisan (441, dalam hal ini). Sebagai contoh, mari kita pilih panjang FFT 441, meskipun kita bisa memilih 882, atau 1323, atau kelipatan positif lain dari 441.

Untuk memahami cara kerjanya, ada baiknya memvisualisasikannya. Anda mulai dengan sinyal audio yang terlihat, dalam domain frekuensi, sesuatu seperti gambar di bawah ini. Tingkat sampel 44,1 kHz

Ketika Anda selesai dengan pemrosesan Anda ingin menurunkan laju sampel menjadi 16 kHz, tetapi Anda ingin sesedikit mungkin distorsi. Dengan kata lain, Anda hanya ingin menyimpan semuanya dari gambar di atas dari -8 kHz hingga +8 kHz dan membuang yang lainnya. Itu menghasilkan gambar di bawah ini. masukkan deskripsi gambar di sini

Harap dicatat bahwa laju sampel tidak untuk skala, mereka hanya ada untuk menggambarkan konsep.

Keindahan memilih panjang FFT yang merupakan kelipatan dari faktor penipisan adalah bahwa Anda dapat melakukan pengujian ulang hanya dengan menjatuhkan bagian dari hasil FFT, dan kemudian membalikkan FFT apa yang tersisa. Dalam kasus contoh kami, Anda FFT 441 sampel data, yang memberi Anda 441 sampel kompleks dalam domain frekuensi. Kami ingin memusnahkan oleh 441 dan interpolasi oleh 160 ( ), jadi kami menjaga 160 sampel yang mewakili frekuensi dari -8 kHz ke +8 kHz. Kami kemudian membalikkan FFT sampel dan presto itu! Anda memiliki 160 sampel domain waktu yang diambil sampelnya pada 16 kHz.255

Seperti yang Anda duga, ada beberapa masalah potensial. Saya akan membahas masing-masing dan menjelaskan bagaimana Anda dapat mengatasinya.

  1. Apa yang Anda lakukan jika data Anda bukan kelipatan faktor penipisan yang bagus? Anda dapat dengan mudah mengatasinya dengan melapisi bagian akhir data Anda dengan angka nol yang cukup untuk menjadikannya kelipatan faktor penipisan. Data itu diisi sebelum itu FFT.

  2. Meskipun metode yang saya jelaskan sangat sederhana, metode ini juga tidak ideal karena dapat memperkenalkan dering dan artefak jahat lainnya dalam domain waktu. Anda dapat menghindari itu dengan memfilter data domain frekuensi sebelum menjatuhkan data frekuensi tinggi. Anda melakukan ini dengan FFT'ing filter Anda dengan panjang , padding data Anda (sebelum FFT'ing itu) dengan setidaknyall-1nol (harap dicatat bahwa jumlah sampel data dan jumlah sampel padding KEDUA harus menjadi kelipatan positif dari faktor penipisan - Anda dapat meningkatkan panjang padding untuk memenuhi batasan ini), MENCARI data padded, mengalikan domain frekuensi data dan filter, dan kemudian aliasing frekuensi tinggi (> 8 kHz) hasil turun ke frekuensi rendah (<8 kHz) hasil sebelum menjatuhkan hasil frekuensi tinggi. Sayangnya, karena pemfilteran dalam domain frekuensi adalah topik besar dengan caranya sendiri, saya tidak akan dapat membahas lebih detail dalam jawaban ini. Namun, saya akan mengatakan bahwa jika Anda memfilter dan memproses data dalam lebih dari satu chunk, Anda perlu mengimplementasikan Overlap-and-Add atau Overlap-and-Save untuk membuat penyaringan berlanjut.

Saya harap ini membantu.

EDIT: Perbedaan antara jumlah awal sampel domain frekuensi dan jumlah target sampel domain frekuensi harus genap sehingga Anda dapat menghapus jumlah sampel yang sama dari sisi positif hasil sebagai sisi negatif dari hasil. Dalam kasus contoh kami, jumlah awal sampel adalah tingkat penipisan, atau 441, dan jumlah target sampel adalah tingkat interpolasi, atau 160. Perbedaannya adalah 279, yang bahkan tidak genap. Solusinya adalah dengan menggandakan panjang FFT ke 882, yang menyebabkan jumlah target sampel juga menjadi dua kali lipat menjadi 320. Sekarang perbedaannya genap, dan Anda dapat menjatuhkan sampel domain frekuensi yang sesuai tanpa masalah.

Jim Clay
sumber
Sangat bagus. Bagaimana Anda membuat angka-angka bagus dengan cepat, Jim?
Spacey
@Mohammad Saya biasanya menggunakan Powerpoint. Dalam hal ini saya menggunakan Powerpoint versi Libre Office, yang saya percaya disebut "Impress".
Jim Clay
Halo, saya punya pertanyaan tentang poin Anda (2). Apa yang Anda maksud persis di langkah ini: "... dan kemudian aliasing frekuensi tinggi (> 8 kHz) hasil turun ke frekuensi rendah (<8 kHz) hasil sebelum menjatuhkan hasil frekuensi tinggi." Saya mengerti langkah-langkah sebelumnya. Setelah saya melipatgandakan data domain-f saya dengan domain-f filter saya, lalu apa? Juga, apakah metode ini berfungsi jika Anda ingin meng-upample data Anda juga? Terima kasih.
TheGrapeBeyond
@TheGrapeBeyond Ketika Anda alias dalam domain waktu Anda menambahkan semua zona Nyquist bersama-sama. Elemen pertama dari semua zona Nyquist ditambahkan bersama-sama dan menjadi elemen pertama baru dari zona Nyquist pertama. Elemen kedua dari semua zona Nyquist ditambahkan bersama-sama dan menjadi elemen kedua baru dari zona Nyquist pertama, dll.
Jim Clay
Hmm, saya tidak yakin saya mengerti bagaimana Anda melakukan resampling berbasis FFT, karena ketika saya mencobanya di sini saya mendapatkan hasil yang sangat aneh. Saya akan mengajukan pertanyaan tentang itu.
TheGrapeBeyond
3

Sementara jawaban di atas benar-benar lengkap:

Inilah intinya:

  1. untuk mengecilkan sinyal, harus berupa bilangan bulat. Sebelum pengambilan sampel sinyal, Anda perlu memfilter sinyal.
  2. Anda dapat memperoleh downsampling nomor rasional dengan Up-sampling / interpolasi sinyal terlebih dahulu.
  3. Upsampling hanya memasukkan nol dan kemudian MEMASANG sinyal.
  4. sehingga untuk mencapai tingkat sampel 3/4. Upample sinyal dengan memasukkan 4 nol antara setiap sampel sinyal. Terapkan filter. Kemudian FILTER sinyal dan hapus setiap 3 dari setiap 4 sampel sinyal.

Detail tentang ini:

http://www.ws.binghamton.edu/fowler/fowler%20personal%20page/EE523_files/Ch_14_1%20Subband%20Intro%20&%20Multirate%20(PPT).pdf

Juga: kecuali jika benar-benar diperlukan JANGAN komputerkan FFT untuk kemudian menghitung IFFT. Ini merupakan proses yang sangat lambat dan dianggap tidak pantas untuk sebagian besar tugas pemrosesan sinyal. FFT biasanya digunakan untuk menganalisis masalah atau menerapkan pemrosesan sinyal hanya dalam domain frekuensi.

CyberMen
sumber
1

Seperti yang dikatakan Bjorn Roche, menggunakan FFT untuk ini akan sangat tidak efisien. Tapi ini dia dengan cara yang sangat sangat sederhana menggunakan metode filter upample dan downsample dalam domain frekuensi.

1 - Ambil sinyal vektor yang diinginkan dengan panjang N.

2 - Lakukan FFT titik N.

3 - Nol padd FFT dengan 160 * N nol di tengah-tengah vektor FFT.

4 - Lakukan IFFT

5 - Pilih satu dari 441 sampel yang dibuang, 440 lainnya.

Anda akan dibiarkan dengan vektor dengan panjang N * 160/441, itu akan menjadi sinyal Anda.

Seperti yang Anda lihat, Anda melakukan banyak perhitungan sia-sia, karena sebagian besar hasilnya akan dibuang. Tetapi jika Anda memiliki akses ke kode melakukan FFT, Anda sebenarnya bisa sedikit men-tweak sehingga hanya menghitung hasil IFFT yang akan Anda dapatkan dan bukan yang akan Anda buang.

Semoga ini bisa membantu.

tulang
sumber