Seperti yang disebutkan orang lain, Anda harus mempertimbangkan filter IIR (respon impuls tak terbatas) daripada filter FIR (respon impuls terbatas) yang Anda gunakan sekarang. Ada lebih dari itu, tetapi pada pandangan pertama filter FIR diimplementasikan sebagai konvolusi eksplisit dan filter IIR dengan persamaan.
Filter IIR tertentu yang sering saya gunakan dalam mikrokontroler adalah filter low pass tiang tunggal. Ini setara dengan digital dari filter analog RC sederhana. Untuk sebagian besar aplikasi, ini akan memiliki karakteristik yang lebih baik daripada filter kotak yang Anda gunakan. Sebagian besar penggunaan filter kotak yang saya temui adalah hasil dari seseorang yang tidak memperhatikan kelas pemrosesan sinyal digital, bukan karena membutuhkan karakteristik khusus mereka. Jika Anda hanya ingin menipiskan frekuensi tinggi yang Anda tahu kebisingan, filter low pass tiang tunggal lebih baik. Cara terbaik untuk mengimplementasikan satu secara digital dalam mikrokontroler biasanya:
FILT <- FILT + FF (BARU - FILT)
FILT adalah bagian dari status persisten. Ini adalah satu-satunya variabel persisten yang Anda perlukan untuk menghitung filter ini. BARU adalah nilai baru bahwa filter sedang diperbarui dengan iterasi ini. FF adalah fraksi filter , yang menyesuaikan "bobot" filter. Lihatlah algoritma ini dan lihat bahwa untuk FF = 0 filternya sangat berat karena outputnya tidak pernah berubah. Untuk FF = 1, benar-benar tidak ada filter sama sekali karena output hanya mengikuti input. Nilai yang berguna ada di antaranya. Pada sistem kecil Anda memilih FF menjadi 1/2 Nsehingga kalikan dengan FF dapat dicapai sebagai pergeseran yang tepat oleh N bit. Sebagai contoh, FF mungkin 1/16 dan kalikan dengan FF oleh karena itu pergeseran kanan 4 bit. Kalau tidak, filter ini hanya perlu satu pengurangan dan satu penambahan, meskipun angkanya biasanya harus lebih luas dari nilai input (lebih lanjut tentang ketepatan numerik di bagian terpisah di bawah).
Saya biasanya mengambil pembacaan A / D secara signifikan lebih cepat daripada yang dibutuhkan dan menerapkan dua filter ini mengalir. Ini setara dengan digital dari dua filter RC secara seri, dan dilemahkan oleh 12 dB / oktaf di atas frekuensi rolloff. Namun, untuk pembacaan A / D biasanya lebih relevan untuk melihat filter dalam domain waktu dengan mempertimbangkan respons langkahnya. Ini memberitahu Anda seberapa cepat sistem Anda akan melihat perubahan ketika hal yang Anda ukur berubah.
Untuk memfasilitasi merancang filter ini (yang hanya berarti memilih FF dan memutuskan berapa banyak dari mereka yang akan mengalir), saya menggunakan FILTBITS program saya. Anda menentukan jumlah bit shift untuk setiap FF dalam rangkaian filter berjenjang, dan menghitung respons langkah dan nilai lainnya. Sebenarnya saya biasanya menjalankan ini melalui skrip pembungkus saya PLOTFILT. Ini menjalankan FILTBITS, yang membuat file CSV, lalu memplot file CSV. Sebagai contoh, berikut adalah hasil dari "PLOTFILT 4 4":
Dua parameter untuk PLOTFILT berarti akan ada dua filter yang diturunkan dari tipe yang dijelaskan di atas. Nilai 4 menunjukkan jumlah bit shift untuk mewujudkan kalikan dengan FF. Oleh karena itu dua nilai FF adalah 1/16 dalam kasus ini.
Jejak merah adalah respons langkah unit, dan merupakan hal utama yang harus dilihat. Misalnya, ini memberi tahu Anda bahwa jika input berubah secara instan, output dari filter gabungan akan menetap hingga 90% dari nilai baru dalam 60 iterasi. Jika Anda peduli 95% waktu penyelesaian maka Anda harus menunggu sekitar 73 iterasi, dan untuk 50% waktu penyelesaian hanya 26 iterasi.
Jejak hijau menunjukkan kepada Anda output dari lonjakan amplitudo penuh. Ini memberi Anda beberapa gagasan tentang penindasan kebisingan acak. Sepertinya tidak ada sampel tunggal akan menyebabkan lebih dari 2,5% perubahan dalam output.
Jejak biru adalah untuk memberikan perasaan subjektif tentang apa yang dilakukan filter ini dengan white noise. Ini bukan tes yang ketat karena tidak ada jaminan apa sebenarnya konten dari nomor acak yang dipilih sebagai input derau untuk menjalankan PLOTFILT ini. Ini hanya untuk memberi Anda perasaan kasar tentang berapa banyak itu akan tergencet dan seberapa halus itu.
PLOTFILT, mungkin FILTBITS, dan banyak hal berguna lainnya, terutama untuk pengembangan firmware PIC tersedia di rilis perangkat lunak PIC Development Tools di halaman unduhan Perangkat Lunak saya .
Menambahkan tentang ketepatan angka
Saya melihat dari komentar dan sekarang jawaban baru bahwa ada minat mendiskusikan jumlah bit yang diperlukan untuk mengimplementasikan filter ini. Perhatikan bahwa kalikan dengan FF akan membuat bit baru Log 2 (FF) di bawah titik biner. Pada sistem kecil, FF biasanya dipilih menjadi 1/2 N sehingga penggandaan ini sebenarnya diwujudkan dengan pergeseran N bit yang tepat.
Oleh karena itu FILT biasanya merupakan integer titik tetap. Perhatikan bahwa ini tidak mengubah matematika apa pun dari sudut pandang prosesor. Misalnya, jika Anda memfilter pembacaan A / D 10 bit dan N = 4 (FF = 1/16), maka Anda memerlukan 4 bit fraksi di bawah bacaan A / D integer 10 bit. Salah satu prosesor yang paling, Anda akan melakukan operasi integer 16 bit karena pembacaan A / D 10 bit. Dalam hal ini, Anda masih dapat melakukan operasi integer 16 bit persis sama, tetapi mulai dengan pembacaan A / D dibiarkan digeser oleh 4 bit. Prosesor tidak tahu bedanya dan tidak perlu. Melakukan perhitungan matematika pada keseluruhan bilangan bulat 16 bit berfungsi baik jika Anda menganggapnya sebagai 12,4 titik tetap atau bilangan bulat 16 bit sejati (titik tetap 16,0).
Secara umum, Anda perlu menambahkan N bit setiap kutub filter jika Anda tidak ingin menambahkan suara karena representasi numerik. Pada contoh di atas, filter kedua dari dua harus memiliki 10 + 4 + 4 = 18 bit untuk tidak kehilangan informasi. Dalam prakteknya pada mesin 8 bit itu berarti Anda akan menggunakan nilai 24 bit. Secara teknis hanya kutub kedua dari dua akan membutuhkan nilai yang lebih luas, tetapi untuk kesederhanaan firmware saya biasanya menggunakan representasi yang sama, dan dengan demikian kode yang sama, untuk semua kutub filter.
Biasanya saya menulis subroutine atau makro untuk melakukan satu operasi tiang filter, kemudian menerapkannya pada setiap kutub. Apakah subrutin atau makro tergantung pada apakah siklus atau memori program lebih penting dalam proyek tertentu. Either way, saya menggunakan beberapa negara awal untuk lulus BARU ke subroutine / makro, yang memperbarui FILT, tetapi juga memuat yang ke dalam negara awal yang sama BARU masuk. Ini membuatnya mudah untuk menerapkan beberapa kutub sejak FILT diperbarui satu kutub BARU dari yang berikutnya. Saat subrutin, ada gunanya memiliki titik penunjuk ke FILT saat masuk, yang diperbarui setelah FILT saat keluar. Dengan cara itu subrutin secara otomatis beroperasi pada filter berturut-turut dalam memori jika dipanggil beberapa kali. Dengan makro Anda tidak perlu pointer karena Anda memasukkan alamat untuk beroperasi pada setiap iterasi.
Contoh Kode
Berikut adalah contoh makro seperti dijelaskan di atas untuk PIC 18:
//////////////////////////////////////////////////// ////////////////////////////////
//
// Filtro FILTER Makro
//
// Perbarui satu kutub filter dengan nilai baru di NEWVAL. NEWVAL diperbarui ke
// mengandung nilai baru yang difilter.
//
// FILT adalah nama variabel status filter. Diasumsikan 24 bit
// lebar dan di bank lokal.
//
// Formula untuk memperbarui filter adalah:
//
// FILT <- FILT + FF (NEWVAL - FILT)
//
// Penggandaan dengan FF dilakukan dengan menggeser bit FILTBITS dengan benar.
//
/ filter makro
/menulis
dbankif lbankadr
movf [arg 1] +0, w; NEWVAL <- NEWVAL - FILT
subwf newval + 0
movf [arg 1] +1, w
subwfb newval + 1
movf [arg 1] +2, w
subwfb newval + 2
/menulis
/ loop n filtbits; sekali untuk setiap bit untuk menggeser NEWVAL ke kanan
rlcf newval + 2, w; menggeser NEWVAL ke kanan sedikit
rrcf newval + 2
rrcf newval + 1
rrcf newval + 0
/ endloop
/menulis
movf newval + 0, w; tambahkan nilai yang dialihkan ke filter dan simpan dalam NEWVAL
addwf [arg 1] +0, w
movwf [arg 1] +0
movwf newval + 0
movf newval +1, w
addwfc [arg 1] +1, w
movwf [arg 1] +1
movwf newval +1
movf newval + 2, w
addwfc [arg 1] +2, w
movwf [arg 1] +2
movwf newval + 2
/ endmac
Dan di sini adalah makro yang serupa untuk PIC 24 atau dsPIC 30 atau 33:
//////////////////////////////////////////////////// ////////////////////////////////
//
// Macro FILTER ffbits
//
// Perbarui keadaan satu filter low pass. Nilai input baru di W1: W0
// dan status filter yang akan diperbarui ditunjukkan oleh W2.
//
// Nilai filter yang diperbarui juga akan dikembalikan dalam W1: W0 dan W2 akan menunjuk
// ke memori pertama melewati status filter. Makro ini karena itu bisa
// dipanggil secara berurutan untuk memperbarui serangkaian filter low pass bertingkat.
//
// Rumus filternya adalah:
//
// FILT <- FILT + FF (BARU - FILT)
//
// di mana kalikan dengan FF dilakukan oleh pergeseran kanan aritmatika
// FFBITS.
//
// PERINGATAN: W3 hancur.
//
/ filter makro
/ var new ffbits integer = [arg 1]; dapatkan jumlah bit yang bergeser
/menulis
/ write "; Lakukan penyaringan low pass satu kutub, shift bits =" ffbits
/menulis " ;"
sub w0, [w2 ++], w0; BARU - FILT -> W1: W0
subb w1, [w2--], w1
lsr w0, # [v ffbits], w0; ubah hasilnya dalam W1: W0 benar
sl w1, # [- 16 ffbits], w3
ior w0, w3, w0
asr w1, # [v ffbits], w1
tambah w0, [w2 ++], w0; tambahkan FILT untuk membuat hasil akhir di W1: W0
addc w1, [w2--], w1
mov w0, [w2 ++]; tulis hasil ke status filter, pointer muka
mov w1, [w2 ++]
/menulis
/ endmac
Kedua contoh ini diimplementasikan sebagai makro menggunakan preprocessor assembler PIC saya , yang lebih mampu daripada salah satu dari fasilitas makro bawaan.