Matlab을 사용하여 매우 간단한 저역 통과 버터 워스 필터를 설계했습니다. 다음 코드 스 니펫은 내가 한 일을 보여줍니다.
fs = 2.1e6;
flow = 44 * 1000;
fNorm = flow / (fs / 2);
[b,a] = butter(10, fNorm, 'low');
[b, a]에는 필터 계수가 저장됩니다. 온라인 HDL 코드 생성기 를 사용하여 Verilog에서 코드를 생성 할 수 있도록 [b, a]를 정수로 얻고 싶습니다 .
Matlab [b, a] 값이 온라인 코드 생성기와 함께 사용하기에는 너무 작은 것 같습니다 (서버 측 Perl 스크립트가 계수를 사용하여 코드 생성을 거부 함). [b, a] 올바른 입력으로 사용할 수있는 형태로 제공됩니다.
Matlab에서 얻는 계수는 다음과 같습니다.
1.0000
-9.1585
37.7780
-92.4225
148.5066
-163.7596
125.5009
-66.0030
22.7969
-4.6694
0.4307
Matlab에서 얻는 b 계수는 다음과 같습니다.
1.0167e-012
1.0167e-011
4.5752e-011
1.2201e-010
2.1351e-010
2.5621e-010
2.1351e-010
1.2201e-010
4.5752e-011
1.0167e-011
1.0167e-012
온라인 생성기를 사용하여 12 비트 비트 폭 및 I 또는 II 필터 형식의 필터를 설계하고 싶습니다. 위 링크에서 "분수 비트"가 무엇을 의미하는지 모르겠습니다.
위에 나열된 [b, a] 계수를 사용하여 코드 생성기 (http://www.spiral.net/hardware/filter.html)를 실행하면 분수 비트가 20으로 설정되고 비트 폭이 12로 설정되어 다음과 같은 실행 오류가 발생합니다. :
Integer A constants: 1048576 -9603383 39613104 -96912015 155720456 -171714386 131597231 -69209161 23904282 -4896220 451621
Integer B constants: 0 0 0 0 0 0 0 0 0 0 0
Error: constants wider than 26 bits are not allowed, offending constant = -69209161, effective bitwidth = 7 mantissa + 20 fractional = 27 total.
An error has occurred - please revise the input parameters.
이 오류가 발생하지 않도록 디자인을 어떻게 변경할 수 있습니까?
업데이트 : Matlab을 사용하여 6 차 Butterworth 필터를 생성하면 다음 계수를 얻습니다.
의 경우 :
1.0000
-5.4914
12.5848
-15.4051
10.6225
-3.9118
0.6010
b의 경우 :
0.0064e-005
0.0382e-005
0.0954e-005
0.1272e-005
0.0954e-005
0.0382e-005
0.0064e-005
온라인 코드 생성기 (http://www.spiral.net/hardware/filter.html)를 실행하면 이제 다음과 같은 오류가 발생합니다 (8의 소수 비트와 20의 비트 폭).
./iirGen.pl -A 256 '-1405' '3221' '-3943' '2719' '-1001' '153' -B '0' '0' '0' '0' '0' '0' '0' -moduleName acm_filter -fractionalBits 8 -bitWidth 20 -inData inData -inReg -outReg -outData outData -clk clk -reset reset -reset_edge negedge -filterForm 1 -debug -outFile ../outputs/filter_1330617505.v 2>&1
At least 1 non-zero-valued constant is required. Please check the inputs and try again.
아마도 b 계수가 너무 작거나 코드 생성기 (http://www.spiral.net/hardware/filter.html)가 [b, a]를 다른 형식으로 원하십니까?
최신 정보:
아마도 내가해야 할 일은 계수를 정수로 얻기 위해 [b, a] 계수를 소수 비트 수만큼 스케일링하는 것입니다.
a .* 2^12
b .* 2^12
그러나 나는 여전히 b 계수가 매우 작다고 생각합니다. 내가 여기서 뭘 잘못하고 있니?
다른 유형의 필터 (또는 필터 설계 방법)가 더 적합할까요? 누구든지 제안을 할 수 있습니까?
업데이트 : 아래 의견에서 Jason R과 Christopher Felton이 제안한 것처럼 SOS 필터가 더 적합합니다. SOS 필터를 얻기 위해 Matlab 코드를 작성했습니다.
fs = 2.1e6;
flow = 44 * 1000;
fNorm = flow / (fs / 2);
[A,B,C,D] = butter(10, fNorm, 'low');
[sos,g] = ss2sos(A,B,C,D);
내가 얻는 SOS 매트릭스는 다음과 같습니다.
1.0000 3.4724 3.1253 1.0000 -1.7551 0.7705
1.0000 2.5057 1.9919 1.0000 -1.7751 0.7906
1.0000 1.6873 1.0267 1.0000 -1.8143 0.8301
1.0000 1.2550 0.5137 1.0000 -1.8712 0.8875
1.0000 1.0795 0.3046 1.0000 -1.9428 0.9598
Verilog 코드 생성 도구 (http://www.spiral.net/hardware/filter.html)를 사용하여이 SOS 필터를 구현할 수 있습니까? 아니면 Verilog를 직접 작성해야합니까? 좋은 참고 자료가 있습니까?
이 상황에서 FIR 필터를 사용하는 것이 더 좋은지 궁금합니다.
또한 : 계수를 분수로 표현하여 정수 수학을 사용하여 재귀 IIR 필터를 구현할 수 있습니다. (자세한 내용은 Smith의 뛰어난 DSP 신호 처리 책을 참조하십시오 : http://www.dspguide.com/ch19/5.htm )
다음 Matlab 프로그램은 Matlab rat () 함수를 사용하여 버터 워스 필터 계수를 분수 부분으로 변환합니다. 그런 다음 주석에서 언급 한 것처럼 2 차 섹션을 사용하여 필터를 수치 적으로 구현할 수 있습니다 (http://en.wikipedia.org/wiki/Digital_biquad_filter).
% variables
% variables
fs = 2.1e6; % sampling frequency
flow = 44 * 1000; % lowpass filter
% pre-calculations
fNorm = flow / (fs / 2); % normalized freq for lowpass filter
% uncomment this to look at the coefficients in fvtool
% compute [b,a] coefficients
% [b,a] = butter(7, fNorm, 'low');
% fvtool(b,a)
% compute SOS coefficients (7th order filter)
[z,p,k] = butter(7, fNorm, 'low');
% NOTE that we might have to scale things to make sure
% that everything works out well (see zp2sos help for 'up' and 'inf' options)
sos = zp2sos(z,p,k, 'up', 'inf');
[n,d] = rat(sos);
sos_check = n ./ d; % this should be the same as SOS matrix
% by here, n is the numerator and d is the denominator coefficients
% as an example, write the the coefficients into a C code header file
% for prototyping the implementation
% write the numerator and denominator matices into a file
[rownum, colnum] = size(n); % d should be the same
sections = rownum; % the number of sections is the same as the number of rows
fid = fopen('IIR_coeff.h', 'w');
fprintf(fid, '#ifndef IIR_COEFF_H\n');
fprintf(fid, '#define IIR_COEFF_H\n\n\n');
for i = 1:rownum
for j = 1:colnum
if(j <= 3) % b coefficients
bn = ['b' num2str(j-1) num2str(i) 'n' ' = ' num2str(n(i,j))];
bd = ['b' num2str(j-1) num2str(i) 'd' ' = ' num2str(d(i,j))];
fprintf(fid, 'const int32_t %s;\n', bn);
fprintf(fid, 'const int32_t %s;\n', bd);
end
if(j >= 5) % a coefficients
if(j == 5)
colstr = '1';
end
if(j == 6)
colstr = '2';
end
an = ['a' colstr num2str(i) 'n' ' = ' num2str(n(i,j))];
ad = ['a' colstr num2str(i) 'd' ' = ' num2str(d(i,j))];
fprintf(fid, 'const int32_t %s;\n', an);
fprintf(fid, 'const int32_t %s;\n', ad);
end
end
end
% write the end of the file
fprintf(fid, '\n\n\n#endif');
fclose(fid);