Thiết kế bộ lọc Butterworth trong Matlab và lấy các hệ số của bộ lọc [ab] làm số nguyên cho trình tạo mã VerL HDL trực tuyến


15

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);

4
Các bộ lọc IIR bậc cao như thế này thường được triển khai bằng các phần thứ hai ; bạn có được bộ lọc bạn muốn bằng cách xếp tầng nhiều giai đoạn thứ hai (với một giai đoạn đơn hàng đầu tiên nếu thứ tự mong muốn là số lẻ). Nó thường là một triển khai mạnh mẽ hơn so với thực hiện trực tiếp bộ lọc bậc cao.
Jason R

3
Nếu bạn không làm những gì @JasonR gợi ý, bạn sẽ có kích thước từ rất lớn. Các bộ lọc như thế này có thể thất bại điểm nổi chính xác duy nhất khi được triển khai với cấu trúc IIR cơ bản, bạn cần có SOS.
Christopher Felton

@JasonR: Cảm ơn bạn đã gợi ý điều này. Tôi đã cập nhật bằng câu trả lời ở trên.
Nicholas Kinar

@ChristopherFelton: Cảm ơn bạn đã giúp củng cố điều này.
Nicholas Kinar

Có với ma trận SOS mới của bạn, bạn có thể tạo 3 bộ lọc từ trang web. Hoặc bạn có thể sử dụng mã của tôi ở đây . Nó sẽ hoạt động giống như trang web. Tôi sẵn sàng cập nhật tập lệnh ngoại trừ ma trận SOS.
Christopher Felton

Câu trả lời:


5

Như đã thảo luận, tốt nhất là sử dụng tổng các phần, đó là phá vỡ bộ lọc bậc cao thành bộ lọc bậc 2 xếp tầng. Câu hỏi cập nhật có ma trận SOS. Sử dụng mã này và một ví dụ ở đây , đối tượng Python có thể được sử dụng để tạo các phần riêng lẻ.

Trong matlab

save SOS

Trong Python

import shutil
import numpy
from scipy.io import loadmat
from siir import SIIR

matfile = loadmat('SOS.mat')  
SOS = matfile['SOS']
b = numpy.zeros((3,3))
a = numpy.zeros((3,3))
section = [None for ii in range(3)]
for ii in xrange(3):
    b[ii] = SOS[ii,0:3]
    a[ii] = SOS[ii,3:6]

    section[ii] = SIIR(b=b[ii], a=a[ii], W=(24,0))
    section[ii].Convert()  # Create the Verilog for the section
    shutil.copyfile('siir_hdl.v', 'iir_sos_section%d.v'%(ii))

Thông tin bổ sung về điểm cố định có thể được tìm thấy ở đây


Cảm ơn bạn rất nhiều vì tất cả các liên kết sâu sắc và mã Python; Tôi hy vọng rằng câu trả lời của bạn (và các câu trả lời khác được đăng ở đây) đóng vai trò là tài liệu tham khảo tốt cho nhiều người khác. Tôi ước rằng tôi có thể đánh dấu tất cả các câu trả lời ở đây là câu trả lời được chấp nhận.
Nicholas Kinar

1
Nếu bạn có bất kỳ vấn đề nào hãy cho tôi biết và tôi sẽ cập nhật / sửa mã nếu nó không hoạt động với bạn. Tôi sẽ sửa đổi nó (tương đối sớm, doh) để trực tiếp chấp nhận ma trận SOS.
Christopher Felton

1
Tôi đã cố gắng thực hiện phiên bản của riêng tôi từ ví dụ của bạn. Trên hệ thống của tôi, tôi đã phải sử dụng "từ số không nhập numpy" và thay đổi loatmat thành loadmat (). Là ma trận SOS được đưa ra bởi Matlab ( mathworks.com/help/toolbox/signal/ref/ss2sos.html ) có cùng định dạng như mong đợi không? Tôi nhận được lỗi sau khi thử truy cập ma trận SOS: "TypeError: loại không thể xóa được" khi trình thông dịch đạt đến dòng "b [ii] = SOS [0: 3, ii]"
Nicholas Kinar

1
Điều đó phụ thuộc vào định dạng của tệp SOS.mat. Nếu bạn chỉ cần >>> in (matfile), nó sẽ hiển thị cho bạn các khóa trong tệp .mat đã tải. Scipy.io.loadmat luôn tải dưới dạng từ điển (BOMK).
Christopher Felton

1
Vâng, đó là chính xác, đầu ra của 0 là đầu vào 1 và vv. Một chút suy nghĩ cần phải được đưa vào chiều rộng từ. Mặc định là hai sử dụng phân số 24 bit (0 số nguyên, 23 phân số, 1 dấu). Tôi tin rằng ban đầu bạn muốn sử dụng chiều rộng từ nhỏ hơn.
Christopher Felton

10

'Các bit phân đoạn' là số bit trong một bus mà bạn dành riêng để biểu thị phần phân số của một số (ví dụ: 0,75 trong 3,75).

Giả sử bạn có một bus kỹ thuật số rộng 4 bit, số nào 1001thể hiện? Nó có thể có nghĩa là '9' nếu bạn coi nó là số nguyên dương (2 ^ 3 + 2 ^ 0 = 8 + 1 = 9). Hoặc nó có thể có nghĩa là -7 trong ký hiệu bổ sung của hai: (-2 ^ 3 + 2 ^ 0 = -8 + 1 = -7).

Còn những con số có một số phân số trong đó, tức là số 'thực' thì sao? Số thực có thể được biểu diễn trong phần cứng dưới dạng "điểm cố định" hoặc "điểm nổi". Có vẻ như những bộ tạo bộ lọc sử dụng điểm cố định.

Quay lại xe buýt 4 bit của chúng tôi ( 1001). Hãy giới thiệu một điểm nhị phân để chúng ta có được 1.001. Điều này có nghĩa là bây giờ đã sử dụng các bit trên RHS của điểm để xây dựng các số nguyên và các bit trên LHS để xây dựng một phân số. Số được biểu thị bằng một bus kỹ thuật số được đặt thành 1.001là 1.125 ( 1* 2 ^ 0 + 0* 2 ^ -1 + 0* 2 ^ -2 +1 * 2 ^ -3 = 1 + 0.125 = 1.125). Trong trường hợp này, trong số 4 bit trong bus, chúng tôi đang sử dụng 3 trong số chúng để biểu thị phần phân số của một số. Hoặc, chúng ta có 3 bit phân đoạn.

Vì vậy, nếu bạn có một danh sách các số thực như bạn có ở trên, bây giờ bạn phải quyết định có bao nhiêu bit phân số mà bạn muốn đại diện cho chúng. Và đây là sự đánh đổi: bạn sử dụng càng nhiều bit phân đoạn, bạn càng có thể biểu thị số bạn muốn càng gần, nhưng mạch của bạn sẽ càng lớn. Và hơn thế nữa, số bit phân đoạn bạn sử dụng càng ít, đáp ứng tần số thực của bộ lọc sẽ càng lệch so với tốc độ bạn thiết kế khi bắt đầu!

Và để làm cho vấn đề tồi tệ hơn, bạn đang tìm cách xây dựng bộ lọc Phản hồi xung vô hạn (IIR). Chúng thực sự có thể không ổn định nếu bạn không có đủ các bit phân số và số nguyên!


Cảm ơn đã cung cấp câu trả lời sâu sắc này. Tôi đã cố chạy trình tạo mã bằng các hệ số b nhỏ ở trên và tôi vẫn nhận được một số lỗi. Bạn có thể đề xuất một cái gì đó mà tôi có thể làm để chạy máy phát điện đúng cách không? Tôi sẽ cập nhật câu trả lời ở trên để hiển thị những gì tôi đã làm.

10

Vì vậy, Marty đã chăm sóc tốt các câu hỏi bit. Trên chính bộ lọc, tôi nghĩ rằng bạn có thể nhận được cảnh báo hoặc khiếu nại từ matlab về các hệ số có tỷ lệ kém? Khi tôi vẽ bộ lọc, từ scipy không phải MATLAB nhưng nó có thể rất giống nhau.

Phản ứng

Đó là 100 dB xuống ở băng thông! Vì vậy, bạn có thể muốn đảm bảo rằng bạn muốn một bộ lọc đơn hàng nhỏ hơn, điều này sẽ giúp bạn thực hiện bằng mọi cách. Khi tôi nhận được bộ lọc thứ 6, tôi sẽ ngừng nhận được khiếu nại về các hệ số xấu. Có thể thử giảm thứ tự và xem nếu nó vẫn đáp ứng yêu cầu của bạn.


Cảm ơn đã gợi ý điều này! Tôi nghĩ rằng bộ lọc thứ 6 cũng sẽ hoạt động tốt. Sử dụng fvtool của matlab, tôi nghĩ rằng phản hồi là tốt cho ứng dụng của tôi. Bây giờ tôi đã cập nhật phản hồi của tôi ở trên. Tuy nhiên, vẫn có điều gì đó không ổn với trình tạo mã VerL HDL ( xoắn ốc.net/hardware/filter.html ). Có lẽ nó muốn [b, a] ở định dạng khác. Ngoài ra, +1 cho việc sử dụng SciPy.
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.