Tôi đã thiết kế bộ lọc Butterworth thông thấp rất đơn giản bằng Matlab. Đoạn mã sau đây cho thấy những gì tôi đã làm.
fs = 2.1e6;
flow = 44 * 1000;
fNorm = flow / (fs / 2);
[b,a] = butter(10, fNorm, 'low');
Trong [b, a] được lưu trữ các hệ số bộ lọc. Tôi muốn lấy [b, a] làm số nguyên để tôi có thể sử dụng trình tạo mã HDL trực tuyến để tạo mã trong Verilog.
Các giá trị Matlab [b, a] dường như quá nhỏ để sử dụng với trình tạo mã trực tuyến (tập lệnh Perl phía máy chủ từ chối tạo mã với các hệ số) và tôi tự hỏi liệu có thể lấy được [b, a] ở dạng có thể được sử dụng làm đầu vào thích hợp.
Các hệ số mà tôi nhận được trong Matlab là:
1.0000
-9.1585
37.7780
-92.4225
148.5066
-163.7596
125.5009
-66.0030
22.7969
-4.6694
0.4307
Các hệ số b mà tôi nhận được trong Matlab là:
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
Sử dụng trình tạo trực tuyến, tôi muốn thiết kế bộ lọc với dạng băng thông 12 bit và dạng lọc I hoặc II. Tôi không biết ý nghĩa của "bit phân đoạn" ở liên kết trên.
Chạy trình tạo mã (http://www.spirus.net/hardware/filter.html) với các hệ số [b, a] được liệt kê ở trên, với các bit phân số được đặt ở 20 và độ rộng bit là 12, tôi nhận được lỗi chạy sau :
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.
Làm thế nào tôi có thể thay đổi thiết kế của mình để lỗi này không xảy ra?
CẬP NHẬT: Sử dụng Matlab để tạo bộ lọc Butterworth bậc 6, tôi nhận được các hệ số sau:
Cho một:
1.0000
-5.4914
12.5848
-15.4051
10.6225
-3.9118
0.6010
cho b:
0.0064e-005
0.0382e-005
0.0954e-005
0.1272e-005
0.0954e-005
0.0382e-005
0.0064e-005
Chạy trình tạo mã trực tuyến (http://www.spirus.net/hardware/filter.html), bây giờ tôi nhận được lỗi sau (với các bit phân số là 8 và độ rộng bit là 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.
Có lẽ các hệ số b quá nhỏ hoặc có lẽ trình tạo mã (http://www.spirus.net/hardware/filter.html) muốn [b, a] ở định dạng khác?
CẬP NHẬT:
Có lẽ điều tôi cần làm là chia tỷ lệ các hệ số [b, a] theo số bit phân số để thu được các hệ số dưới dạng số nguyên.
a .* 2^12
b .* 2^12
Tuy nhiên, tôi vẫn nghĩ rằng các hệ số b là cực kỳ nhỏ. Tôi làm gì sai ở đây?
Có lẽ một loại bộ lọc (hoặc phương pháp thiết kế bộ lọc) sẽ phù hợp hơn? Bất cứ ai có thể đưa ra một đề nghị?
CẬP NHẬT: Theo đề xuất của Jason R và Christopher Felton trong các bình luận bên dưới, bộ lọc SOS sẽ phù hợp hơn. Bây giờ tôi đã viết một số mã Matlab để có được bộ lọc SOS.
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);
Ma trận SOS mà tôi nhận được là:
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
Có thể vẫn sử dụng công cụ tạo mã Verilog (http://www.spirus.net/hardware/filter.html) để triển khai bộ lọc SOS này hay tôi chỉ nên viết Verilog bằng tay? Là một tài liệu tham khảo tốt có sẵn?
Tôi sẽ tự hỏi nếu một bộ lọc FIR sẽ tốt hơn để sử dụng trong tình huống này.
XEM THÊM: Bộ lọc IIR đệ quy có thể được thực hiện bằng toán học số nguyên bằng cách biểu thị các hệ số dưới dạng phân số. (Xem sách xử lý tín hiệu DSP tuyệt vời của Smith để biết thêm chi tiết: http://www.dspguide.com/ch19/5.htm )
Chương trình Matlab sau đây chuyển đổi các hệ số bộ lọc Butterworth thành các phần phân đoạn bằng cách sử dụng hàm Matlab rat (). Sau đó, như đã đề cập trong các nhận xét, phần thứ tự thứ hai có thể được sử dụng để triển khai số lượng bộ lọc (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);