2011/04/17

FIR LPF及びHPFの係数を求めるプログラム

前回のFIR LPF(ローパスフィルタ)に加えて、HPF(ハイパスフィルタ)にも対応させてみた。ちゃんとした資料もない中、適当に作っているので問題があるかもしれない。LPFの改造でHPFは実現できるので手軽に作れるかなと思ったら甘かった。少々苦労したが、まぁ結果はそれなりに出たかな。
LPFはタップ数が少ない方向で作れるが、HPFはサンプリング周波数に応じてかなりのタップ数を要求してくる。タップ数が少ないと全くHPFにならないこともあるので注意。またタップ数が増えるとデジタルフィルタの高速化を検討しないとだめだと思った。

120111 機能追加
窓関数を選べるようにした。Rectangular Windowは窓がないのと同じ状態。


FIR LPF/HPF
Low-Pass Filter
High-Pass Filter
Tap N (odd number)
Sampling Frequency Hz
Cutoff Frequency Hz
Rectangular Window
Hamming Window
Hanning Window

Coefficient n

Audacityで周波数スペクトル表示
タップ数による違いがどうでるか確認してみた。
ホワイトノイズにHPFをかけてみた。
サンプリング周波数は44100Hz。
150Hz以下をカット。

201タップ


501タップ


1001タップ

201タップでは効きが弱くHPFとしては不十分。501タップはそれなりの効き方をしている。さすがに1001タップもあると理想的な形になってくる。まじめに処理するとなると1000タップ以上は欲しくなる。


さらに低いカットオフ周波数で多めのタップ数で試す
HPF
カットオフ周波数80Hz
8001タップ

これだけのタップを使うとかなりの精度になることが分かった。でも処理に時間がかかるので、デジタルフィルタの効率化をしないとダメだわ。

スクリプト 110727
今までHTMLソースを見れば分かると思って記載しなかったのだけど、そうでもないようなので改めて置いておきます。下記をコピーしてhtmlファイルにして、ブラウザで実行すれば動きます。

Java版はこちらのページ

<HTML>
<HEAD>
<TITLE>FIR LPF/HPF</TITLE>
<script type="text/javascript">
<!--
function calcF(){
var tapn = document.formFIRfilter2.elements[2].value;
var sFreq= document.formFIRfilter2.elements[3].value;
var cFreq = document.formFIRfilter2.elements[4].value;
var tapn2 =((tapn-1)/2)+1;
var omega = (cFreq)/(sFreq/2);
var omega2 = Math.PI*omega;
var omega3 =1-(((cFreq)/(sFreq))*2);
var omega4 = Math.PI*omega3;
var tapArray = new Array(tapn2);
var coeff = 0;
var windowF = 0;
var windowType = 0;
var coeffWin;
var coeffWin2;
if(document.formFIRfilter2.radioWindow[0].checked){
windowType = 0;
}else if(document.formFIRfilter2.radioWindow[1].checked){
windowType = 1;
}else{
windowType = 2;
}
if(document.formFIRfilter2.radiofilter[0].checked){
for(i=1; i<tapn2; i++){
coeff = 1/(Math.PI*i)*Math.sin(i*omega2);
switch(windowType){
case 0:
 windowF = 1;
 break;
case 1:
 windowF = 0.54+0.46*Math.cos((i*Math.PI)/(tapn2-1));
 break;
case 2:
 windowF = 0.5+0.5*Math.cos((i*Math.PI)/(tapn2-1));
 break;
}
coeffWin = coeff*windowF;
tapArray[i] = coeffWin;
}
tapArray[0] = 1-omega3;
}else{
for(i=1; i<tapn2; i++){
coeff = (1/(Math.PI*i))*Math.sin(i*omega4);

switch(windowType){
case 0:
 windowF = 1;
 break;
case 1:
 windowF = 0.54+0.46*Math.cos((i*Math.PI)/(tapn2-1));
 break;
case 2:
 windowF = 0.5+0.5*Math.cos((i*Math.PI)/(tapn2-1));
 break;
}
coeffWin = coeff*windowF;
coeffWin2 = coeffWin*Math.pow(-1,i);
tapArray[i] = coeffWin2;
}
tapArray[0] = omega3;
}
var listArray ="";
for(i=tapArray.length-1; i>=0; i--){
listArray = listArray + tapArray[i] + ",\n";//+cFreqR+ ",\n";
}
for(i=1; i<tapArray.length; i++){
listArray = listArray + tapArray[i] + ",\n";
}
document.formFIRfilter2.coefficient.value=listArray;
}
//-->
</script>
</HEAD>
<BODY>
<b>FIR LPF/HPF</b><br>
hamming window<br>
<form name="formFIRfilter2">
<input type="radio" name="radiofilter" value="lpf">Low-Pass Filter<br>
<input type="radio" name="radiofilter" value="hpf"checked>High-Pass Filter<br>
Tap n <input type="text" size="3"value="21"><br>
Sampling Frequency <input type="text" size="3"value="44100"> Hz<br>
Cutoff Frequency <input type="text" size="3"value="4050"> Hz<br>
<input type="radio" name="radioWindow" value="0">Rectangular Window<br>
<input type="radio" name="radioWindow" value="1"checked>Hamming Window<br>
<input type="radio" name="radioWindow" value="2">Hanning Window<br>
<input type="button" value="calculate" onClick="calcF()"><br>
Coefficient n<br>
<textarea name="coefficient"id="translationarea" 
cols="26" rows="24" readonly="readonly"></textarea><br>
</BODY>
</HTML>


sound programming 目次はこちら