Halo semuanya! Artikel ini akan fokus pada satu bagian penting dari pemrosesan sinyal digital - penyaringan sinyal jendela, khususnya pada FPGA. Artikel ini akan menunjukkan cara mendesain jendela klasik dengan panjang standar dan jendela "panjang" dari sampel 64K hingga 16M +. Bahasa pengembangan utama adalah VHDL, basis elemen adalah kristal Xilinx FPGA terbaru dari keluarga terbaru: ini adalah Ultrascale, Ultrascale +, 7-series. Artikel ini akan mendemonstrasikan implementasi CORDIC - kernel dasar untuk mengonfigurasi fungsi jendela dalam durasi berapa pun, serta fungsi jendela dasar. Artikel ini menjelaskan metode desain menggunakan bahasa tingkat tinggi C / C ++ di Vivado HLS. Seperti biasa, di akhir artikel Anda akan menemukan tautan ke kode sumber proyek.
KDPV: skema khas transmisi sinyal melalui node DSP untuk tugas analisis spektrum.

Pendahuluan
Dari kursus "Digital Signal Processing" banyak orang tahu bahwa untuk bentuk gelombang sinusoidal yang tak terbatas dalam waktu, spektrumnya adalah fungsi delta pada frekuensi sinyal. Dalam praktiknya, spektrum sinyal harmonik terbatas waktu nyata setara dengan fungsi
~ sin (x) / x , dan lebar lobus utama tergantung pada durasi interval analisis sinyal
T. Batas waktu tidak lebih dari mengalikan sinyal dengan amplop persegi panjang. Diketahui dari kursus DSP bahwa penggandaan sinyal dalam domain waktu adalah konvolusi dari spektrum mereka dalam domain frekuensi (dan sebaliknya), oleh karena itu, spektrum amplop persegi panjang terbatas dari sinyal harmonik setara dengan ~ sinc (x). Ini juga disebabkan oleh fakta bahwa kita tidak dapat mengintegrasikan sinyal selama interval waktu yang tidak terbatas, dan transformasi Fourier dalam bentuk diskrit, diekspresikan melalui jumlah terbatas, dibatasi oleh jumlah sampel. Sebagai aturan, panjang FFT di perangkat pemrosesan digital FPGA modern membutuhkan nilai
NFFT dari 8 hingga beberapa juta poin. Dengan kata lain, spektrum sinyal input dihitung pada interval
T , yang dalam banyak kasus sama dengan
NFFT . Dengan membatasi sinyal ke interval
T , kami memaksakan "jendela" persegi panjang dengan durasi sampel
T. Oleh karena itu, spektrum yang dihasilkan adalah spektrum dari sinyal harmonik berlipat ganda dan amplop persegi panjang. Dalam tugas-tugas DSP, jendela berbagai bentuk telah ditemukan untuk waktu yang lama, yang, ketika ditumpangkan pada sinyal dalam domain waktu, dapat meningkatkan karakteristik spektralnya. Sejumlah besar berbagai jendela terutama disebabkan oleh salah satu fitur utama dari setiap hamparan jendela. Fitur ini dinyatakan dalam hubungan antara tingkat lobus samping dan lebar lobus sentral. Pola yang terkenal: semakin kuat penekanan lobus samping, semakin luas lobus utama, dan sebaliknya.
Salah satu aplikasi fungsi jendela: deteksi sinyal lemah dengan latar belakang sinyal yang lebih kuat dengan menekan level lobus samping. Fungsi jendela utama dalam tugas DSP adalah segitiga, sinusoidal, Lanczos, Hann, Hamming, Blackman, Harris, jendela Blackman-Harris, jendela flat-top, Natall, Gauss, jendela Kaiser, dan banyak lainnya. Sebagian besar dari mereka diekspresikan melalui seri terbatas dengan menjumlahkan sinyal harmonik dengan bobot tertentu. Windows bentuk kompleks dihitung dengan mengambil eksponen (jendela Gaussian) atau fungsi Bessel yang dimodifikasi (jendela Kaiser), dan tidak akan dipertimbangkan dalam artikel ini. Anda dapat membaca lebih lanjut tentang fungsi jendela dalam literatur, yang secara tradisional akan saya berikan di akhir artikel.
Gambar berikut ini menunjukkan fungsi jendela yang khas dan karakteristik spektralnya yang dibangun menggunakan alat Matlab CAD.

Implementasi
Di awal artikel, saya memasukkan KDPV, yang secara umum menunjukkan diagram struktural dari penggandaan data input dengan fungsi jendela. Jelas, cara termudah untuk menerapkan penyimpanan fungsi jendela di FPGA adalah menulisnya ke memori (blok
RAMB atau didistribusikan
Terdistribusi - tidak masalah banyak), dan kemudian mengambil data secara siklikal ketika sampel input sinyal tiba. Sebagai aturan, dalam FPGA modern, jumlah memori internal memungkinkan penyimpanan fungsi jendela dengan ukuran yang relatif kecil, yang kemudian dikalikan dengan sinyal input yang masuk. Secara kecil maksud saya fungsi jendela hingga 64 ribu sampel.
Tetapi bagaimana jika fungsi jendela terlalu panjang? Misalnya, bacaan 1M. Sangat mudah untuk menghitung bahwa untuk fungsi jendela seperti itu yang disajikan dalam kisi bit 32-bit, NRAMB = 1024 * 1024 * 32/32768 = 1024 blok sel-sel memori dari RAMB36K tipe FPGA Xilinx kristal diperlukan. Dan untuk sampel 16 juta? 16 ribu sel memori! Tidak satu pun FPGA modern yang memiliki begitu banyak memori. Bagi banyak FPGA, ini terlalu banyak, dan dalam kasus lain itu adalah penggunaan sumber daya FPGA yang sia-sia (dan, tentu saja, uang pelanggan).
Dalam hal ini, Anda perlu menemukan metode untuk menghasilkan sampel fungsi jendela langsung ke FPGA on the fly, tanpa menulis koefisien dari perangkat jarak jauh ke memori blok. Untungnya, hal-hal dasar telah lama ditemukan untuk kita. Menggunakan algoritma seperti
CORDIC (metode
digit-per-digit ), dimungkinkan untuk merancang banyak fungsi jendela yang rumusnya dinyatakan dalam sinyal harmonik (Blackman-Harris, Hann, Hamming, Nattal, dll.)
CORDIC
CORDIC adalah metode berulang yang sederhana dan nyaman untuk menghitung rotasi sistem koordinat, yang memungkinkan Anda menghitung fungsi kompleks dengan melakukan penambahan primitif dan operasi shift. Dengan menggunakan algoritma CORDIC, seseorang dapat menghitung nilai sinyal harmonik sin (x), cos (x), menemukan fase - atan (x) dan atan2 (x, y), fungsi trigonometri hiperbolik, memutar vektor, mengekstrak akar angka, dll.
Pada awalnya saya ingin mengambil kernel CORDIC yang sudah jadi dan mengurangi jumlah pekerjaan, tetapi saya tidak menyukai kernel Xilinx. Setelah mempelajari repositori di github, saya menyadari bahwa semua kernel yang disajikan tidak cocok untuk sejumlah alasan (kurang terdokumentasi dan tidak dapat dibaca, tidak universal, dibuat untuk tugas atau basis elemen tertentu,
ditulis dalam Verilog , dll.). Kemudian saya meminta kawan
lazifo untuk melakukan pekerjaan ini untuk saya. Tentu saja, ia mengatasinya, karena implementasi CORDIC adalah salah satu tugas paling sederhana di bidang DSP. Tetapi karena saya tidak sabar, bersamaan dengan pekerjaannya, saya menulis
sepeda saya
dengan inti parametrized saya
sendiri . Fitur utama adalah kedalaman bit yang dapat dikonfigurasi dari sinyal output
DATA_WIDTH dan fase input normal
PHASE_WIDTH dari -1 hingga 1, dan ketepatan perhitungan
PRECISION . Inti CORDIC dijalankan sesuai dengan sirkuit paralel pipa - pada setiap siklus jam, inti siap melakukan perhitungan dan menerima sampel input. Kernel menghabiskan N siklus untuk menghitung sampel keluaran, yang jumlahnya tergantung pada kapasitas sampel keluaran (semakin banyak kapasitas, semakin banyak iterasi untuk menghitung nilai output). Semua perhitungan terjadi secara paralel. Dengan demikian, CORDIC adalah inti dasar untuk membuat fungsi jendela.
Fungsi jendela
Dalam kerangka artikel ini, saya menyadari hanya fungsi-fungsi jendela yang diekspresikan melalui sinyal harmonik (Hann, Hamming, Blackman-Harris dari berbagai pesanan, dll.). Apa yang dibutuhkan untuk ini? Secara umum, rumus untuk membangun jendela terlihat seperti serangkaian panjang yang terbatas.

Seperangkat koefisien tertentu
a k dan anggota seri menentukan nama jendela. Yang paling populer dan sering digunakan adalah jendela Blackman-Harris: dari urutan berbeda (dari 3 hingga 11). Berikut ini adalah tabel koefisien untuk Blackman-Harris windows:

Pada prinsipnya, rangkaian jendela Blackman-Harris dapat diterapkan di banyak masalah analisis spektral, dan tidak perlu mencoba menggunakan jendela kompleks seperti Gauss atau Kaiser. Jendela nattal atau flat-top hanyalah tipe jendela dengan bobot berbeda, tetapi prinsip dasarnya sama dengan Blackman-Harris. Diketahui bahwa semakin banyak anggota seri, semakin kuat penekanan tingkat lobus samping (bergantung pada pilihan yang masuk akal dari kedalaman bit dari fungsi jendela). Berdasarkan tugas tersebut, pengembang tinggal memilih jenis windows yang digunakan.
Implementasi FPGA - pendekatan tradisional
Semua kernel fungsi jendela dirancang menggunakan pendekatan klasik untuk menggambarkan sirkuit digital dalam FPGA dan ditulis dalam bahasa VHDL. Di bawah ini adalah daftar komponen yang dibuat:
- bh_win_7term - Blackman-Harris 7 order, jendela dengan penindasan maksimum perancah samping.
- bh_win_5term - Blackman-Harris 5 order, termasuk jendela dengan atasan datar.
- bh_win_4term - Blackman-Harris 4 pesanan, termasuk jendela Nattal dan Blackman-Nattal.
- bh_win_3term - Blackman-Harris 3 pesanan,
- hamming_win - Jendela Hamming dan Hann.
Kode sumber untuk komponen jendela Blackman-Harris adalah 3 kali lipat:
entity bh_win_3term is generic ( TD : time:=0.5ns;
Dalam beberapa kasus, saya menggunakan perpustakaan
UNISIM untuk menanamkan
simpul DSP48E1 dan DSP48E2 dalam proyek, yang pada akhirnya memungkinkan
saya untuk meningkatkan kecepatan perhitungan karena pipelining di dalam blok-blok ini, tetapi seperti yang diperlihatkan, lebih cepat dan lebih mudah untuk memberikan kendali bebas dan menulis sesuatu seperti
P = A * B + C dan tentukan arahan berikut dalam kode:
attribute USE_DSP of <signal_name>: signal is "YES";
Ini berfungsi dengan baik dan secara kaku mengatur jenis elemen di mana fungsi matematika diimplementasikan untuk synthesizer.
Vivado hl
Selain itu, saya menerapkan semua inti menggunakan alat
HLS Vivado . Saya akan mencantumkan
keuntungan utama
dari Vivado HLS: kecepatan tinggi desain (
waktu-ke-pasar ) dalam bahasa tingkat tinggi C atau C ++, pemodelan cepat node yang dikembangkan karena kurangnya konsep frekuensi clock, konfigurasi solusi yang fleksibel (dalam hal sumber daya dan kinerja) dengan memperkenalkan pragma dan arahan dalam proyek, serta ambang masuk yang rendah untuk pengembang dalam bahasa tingkat tinggi. Kerugian utama adalah biaya suboptimal sumber daya FPGA dibandingkan dengan pendekatan klasik. Juga, tidak mungkin untuk mencapai kecepatan yang disediakan oleh metode RTL klasik lama (VHDL, Verilog, SV). Ya,
kelemahan terbesar adalah menari dengan rebana, tetapi ini adalah karakteristik semua CAD dari Xilinx. (Catatan: dalam debugger Vivado HLS dan dalam model C ++ yang sebenarnya, seringkali diperoleh hasil yang berbeda, karena Vivado HLS bekerja dengan bengkok menggunakan keuntungan dari
presisi yang sewenang -
wenang ).
Gambar berikut menunjukkan log kernel CORDIC yang disintesis di Vivado HLS. Ini cukup informatif dan menampilkan banyak informasi berguna: jumlah sumber daya yang digunakan, antarmuka pengguna kernel, loop dan propertinya, keterlambatan dalam komputasi, interval untuk menghitung nilai output (penting ketika merancang rangkaian serial dan paralel):

Anda juga dapat melihat cara menghitung data dalam berbagai komponen (fungsi). Dapat dilihat bahwa pada fase nol, data fase dibaca, dan pada langkah 7 dan 8, hasil dari simpul CORDIC ditampilkan.

Hasil dari Vivado HLS: kernel RTL yang disintesis dibuat dari kode C. Log menunjukkan bahwa dalam analisis waktu, kernel berhasil melewati semua batasan:

Kelebihan lain dari Vivado HLS adalah untuk memverifikasi hasilnya, dia sendiri membuat testbench dari kode RTL yang disintesis berdasarkan model yang digunakan untuk memeriksa kode C. Ini mungkin tes primitif, tapi saya percaya ini sangat keren dan cukup nyaman untuk membandingkan operasi algoritma di C dan HDL. Di bawah ini adalah tangkapan layar dari Vivado yang menunjukkan simulasi model fungsi kernel dari fungsi jendela yang diperoleh oleh Vivado HLS:

Jadi, untuk semua fungsi jendela, hasil yang sama diperoleh, terlepas dari metode desain - dalam VHDL atau dalam C ++. Namun, dalam kasus pertama, frekuensi operasi yang lebih besar dan jumlah sumber daya yang lebih kecil tercapai, dan dalam kasus kedua, kecepatan desain maksimum tercapai. Kedua pendekatan memiliki hak untuk hidup.
Saya secara khusus menghitung berapa banyak waktu yang akan saya habiskan untuk pengembangan menggunakan metode yang berbeda. Saya menerapkan proyek C ++ di Vivado HLS ~ 12 kali lebih cepat daripada di VHDL.
Perbandingan pendekatan
Bandingkan kode sumber untuk HDL dan C ++ untuk inti CORDIC. Algoritma, seperti yang dikatakan sebelumnya, didasarkan pada operasi penjumlahan, pengurangan, dan pergeseran. Pada VHDL, terlihat seperti ini: ada tiga vektor data - satu bertanggung jawab untuk rotasi sudut, dan dua lainnya menentukan panjang vektor sepanjang sumbu X dan Y, yang setara dengan sin dan cos (lihat gambar dari wiki):

Dengan secara iteratif menghitung nilai Z, nilai-nilai X dan Y dihitung secara paralel. Proses siklus mencari nilai-nilai output pada HDL:
constant ROM_LUT : rom_array := ( x"400000000000", x"25C80A3B3BE6", x"13F670B6BDC7", x"0A2223A83BBB", x"05161A861CB1", x"028BAFC2B209", x"0145EC3CB850", x"00A2F8AA23A9", x"00517CA68DA2", x"0028BE5D7661", x"00145F300123", x"000A2F982950", x"000517CC19C0", x"00028BE60D83", x"000145F306D6", x"0000A2F9836D", x"0000517CC1B7", x"000028BE60DC", x"0000145F306E", x"00000A2F9837", x"00000517CC1B", x"0000028BE60E", x"00000145F307", x"000000A2F983", x"000000517CC2", x"00000028BE61", x"000000145F30", x"0000000A2F98", x"0000000517CC", x"000000028BE6", x"0000000145F3", x"00000000A2FA", x"00000000517D", x"0000000028BE", x"00000000145F", x"000000000A30", x"000000000518", x"00000000028C", x"000000000146", x"0000000000A3", x"000000000051", x"000000000029", x"000000000014", x"00000000000A", x"000000000005", x"000000000003", x"000000000001", x"000000000000" ); pr_crd: process(clk, reset) begin if (reset = '1') then
Di C ++, di Vivado HLS, kode terlihat hampir sama, tetapi catatan beberapa kali lebih pendek:
Rupanya, siklus yang sama dengan shift dan penambahan digunakan. Namun, secara default, semua loop di Vivado HLS "diciutkan" dan dieksekusi secara berurutan, sebagaimana dimaksudkan untuk bahasa C ++. Pengenalan
pragma HLS UNROLL atau
HLS PIPELINE mengubah serial ke komputasi paralel. Ini mengarah pada peningkatan sumber daya FPGA, namun, ini memungkinkan Anda untuk menghitung dan mengirimkan nilai baru ke inti pada setiap siklus clock.
Hasil sintesis proyek dalam VHDL dan C ++ disajikan pada gambar di bawah ini. Seperti yang Anda lihat, secara logis, perbedaannya adalah dua kali lebih mendukung pendekatan tradisional. Untuk sumber daya FPGA lainnya, perbedaannya tidak signifikan. Saya tidak masuk jauh ke dalam mengoptimalkan proyek di C ++, tetapi jelas dengan menetapkan berbagai arahan atau sebagian mengubah kode, jumlah sumber daya yang digunakan dapat dikurangi. Dalam kedua kasus, timing dikonvergensi untuk frekuensi inti yang diberikan ~ 350 MHz.

Fitur Implementasi
Karena perhitungan dilakukan dalam format titik tetap, fungsi jendela memiliki sejumlah fitur yang harus diperhitungkan ketika merancang sistem DSP pada FPGA. Sebagai contoh, semakin besar kedalaman bit dari data fungsi jendela, semakin baik akurasi overlay jendela. Di sisi lain, dengan kedalaman bit yang tidak cukup dari fungsi jendela, distorsi akan dimasukkan ke dalam bentuk gelombang yang dihasilkan, yang akan mempengaruhi kualitas karakteristik spektral. Misalnya, fungsi jendela harus memiliki setidaknya 20 bit ketika dikalikan dengan sinyal dengan durasi 2 ^ 20 = 1M sampel.
Kesimpulan
Artikel ini menunjukkan satu cara untuk merancang fungsi jendela tanpa menggunakan memori eksternal atau memori blok FPGA. Metode menggunakan sumber daya logis eksklusif FPGA (dan dalam beberapa kasus blok DSP) diberikan. Dengan menggunakan algoritma CORDIC, dimungkinkan untuk mendapatkan fungsi-fungsi jendela dari setiap kedalaman bit (dengan alasan), dengan panjang dan urutan berapa pun, dan oleh karena itu memiliki seperangkat karakteristik spektral dari jendela tersebut.
Sebagai bagian dari salah satu studi, saya berhasil mendapatkan kernel fungsi Blackman-Harris yang berfungsi secara stabil dari 5 dan 7 orde besarnya pada sampel 1M pada frekuensi ~ 375 MHz, dan juga membuat generator koefisien putar untuk FFT berdasarkan CORDIC pada frekuensi ~ 400 MHz. FPGA Crystal Digunakan: Kintex Ultrascale + (xcku11p-ffva1156-2-e).
Tautan ke
proyek github di sini . Proyek ini berisi model matematika di Matlab, kode sumber untuk fungsi jendela dan CORDIC di VHDL, serta model fungsi jendela yang terdaftar di C ++ untuk Vivado HLS.
Artikel yang Berguna
Saya juga menyarankan buku yang sangat populer tentang DSP -
Ayficher E., pemrosesan sinyal Jervis B. Digital. Pendekatan praktisTerima kasih atas perhatian anda!