Matlab에서 Butterworth 필터 설계 및 온라인 Verilog HDL 코드 생성기의 정수로 필터 [ab] 계수 얻기


15

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

4
이와 같은 고차 IIR 필터는 보통 2 차 섹션을 사용하여 구현 됩니다 . 여러 2 차 단계를 계단식으로 연결하여 원하는 필터를 얻을 수 있습니다 (원하는 순서가 홀수 인 경우 단일 1 차 단계 사용). 일반적으로 고차 필터를 직접 구현하는 것보다 더 강력한 구현입니다.
Jason R

3
@JasonR이 제안한 것을 수행하지 않으면 단어 크기가 매우 커집니다. 이와 같은 필터는 기본 IIR 구조로 구현할 때 단 정밀도 부동 소수점에 실패 할 수 있으므로 SOS가 필요합니다.
Christopher Felton

@JasonR : 이것을 제안 해 주셔서 감사합니다. 위의 답변으로 업데이트했습니다.
Nicholas Kinar

@ChristopherFelton : 이것을 강화하는 데 도움을 주셔서 감사합니다.
Nicholas Kinar

예. 새 SOS 매트릭스를 사용하면 사이트에서 3 개의 필터를 만들 수 있습니다. 또는 여기에서 내 코드를 사용할 수 있습니다 . 웹 사이트와 동일하게 작동합니다. SOS 매트릭스를 제외하고 스크립트를 기꺼이 업데이트하겠습니다.
Christopher Felton

답변:


5

논의 된 바와 같이, 고차 필터를 계단식 2 차 필터로 나누는 섹션의 합계를 사용하는 것이 가장 좋습니다. 업데이트 된 질문에는 SOS 매트릭스가 있습니다. 사용 이 코드예를 여기 파이썬 객체하는 개별 섹션을 생성 할 수 있습니다.

MATLAB에서

save SOS

파이썬에서

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

고정 소수점에 대한 추가 정보는 여기 에서 찾을 수 있습니다


통찰력있는 모든 링크와 Python 코드에 대해 대단히 감사합니다. 귀하의 답변 (및 여기에 게시 된 다른 답변)이 많은 사람들에게 좋은 참고 자료가되기를 바랍니다. 여기에 모든 답변을 허용 된 답변으로 표시 할 수 있기를 바랍니다.
Nicholas Kinar

1
문제가 있으면 알려 주시면 작동하지 않으면 코드를 업데이트 / 수정하겠습니다. SOS 매트릭스를 직접 수용하도록 수정합니다 (상대적으로 doh).
Christopher Felton

1
귀하의 예에서 내 버전을 구현하려고했습니다. 내 시스템에서는 "from numpy import zeros"를 사용하고 loatmat를 loadmat ()로 변경해야했습니다. Matlab ( mathworks.com/help/toolbox/signal/ref/ss2sos.html )에서 제공 한 SOS 매트릭스 가 예상 한 것과 같은 형식입니까? SOS 매트릭스에 액세스하려고 할 때 다음과 같은 오류가 발생합니다. 인터프리터가 "b [ii] = SOS [0 : 3, ii]"줄에 도달하면 "TypeError : unhashable type"
Nicholas Kinar

1
SOS.mat 파일의 형식에 따라 다릅니다. >>> print (matfile)을 사용하면로드 된 .mat 파일의 키가 표시됩니다. scipy.io.loadmat는 항상 사전 (BOMK)으로로드됩니다.
Christopher Felton

1
예, 맞습니다. 0의 출력은 1 등의 입력입니다. 단어 너비에 약간의 생각을 넣어야합니다. 기본값은 2 비트 24 비트 분수 (0 정수, 23 분수, 1 부호)입니다. 나는 당신이 원래 더 작은 단어 너비를 사용하고 싶었다고 생각합니다.
Christopher Felton

10

'프랙 셔널 비트'는 숫자의 소수 부분 (예 : 3.75의 .75)을 나타 내기 위해 전용으로 사용하는 버스의 비트 수입니다.

4 비트 너비의 디지털 버스를 가지고 있다고 가정 해보십시오. 어떤 숫자가 1001나타 납니까? 양의 정수 (2 ^ 3 + 2 ^ 0 = 8 + 1 = 9)로 취급하면 '9'를 의미 할 수 있습니다. 또는 2의 보수 표기법에서 -7을 의미 할 수 있습니다 : (-2 ^ 3 + 2 ^ 0 = -8 + 1 = -7).

소수가있는 숫자, 즉 '실제'숫자는 어떻습니까? 실수는 하드웨어에서 "고정 소수점"또는 "부동 소수점"으로 표시 될 수 있습니다. 이러한 필터 생성기는 고정 소수점을 사용하는 것처럼 보입니다.

4 비트 버스 ( 1001)로 돌아갑니다 . 우리가 얻을 수 있도록 바이너리 포인트를 소개하자 1.001. 이것이 의미하는 것은 이제 정수를 만들기 위해 포인트의 RHS에서 비트를 사용하고 분수를 만들기 위해 LHS에서 비트를 사용하고 있다는 것입니다. 디지털 버스로 설정된 숫자 1.001는 1.125입니다 ( 1* 2 ^ 0 + 0* 2 ^ -1 + 0* 2 ^ -2 + 1* 2 ^ -3 = 1 + 0.125 = 1.125). 이 경우 버스의 4 비트 중 3을 사용하여 숫자의 소수 부분을 나타냅니다. 또는 3 개의 분수 비트가 있습니다.

따라서 위와 같은 실수 목록이 있다면 이제 몇 개의 소수 비트를 나타낼 것인지 결정해야합니다. 그리고 여기에 절충점이 있습니다 : 더 많은 소수 비트를 사용할수록 원하는 수를 더 가깝게 나타낼 수 있지만 회로가 더 커야합니다. 또한 사용하는 소수 비트 수가 적을수록 필터의 실제 주파수 응답이 처음에 설계 한 주파수 응답에서 벗어나게됩니다!

설상가상으로, 무한 임펄스 응답 (IIR) 필터를 구축하려고합니다. 소수 및 정수 비트가 충분하지 않으면 실제로 불안정해질 수 있습니다!


이 통찰력있는 답변을 제공해 주셔서 감사합니다. 위의 작은 b 계수를 사용하여 코드 생성기를 실행하려고했지만 여전히 오류가 발생합니다. 발전기를 올바르게 작동시키기 위해 할 수있는 일을 제안 해 주시겠습니까? 위의 답변을 업데이트하여 내가 한 일을 보여 드리겠습니다.

10

그래서 Marty는 비트 문제를 잘 처리했습니다. 필터 자체에서 계수가 잘못 된 계수에 대해 MATLAB에서 경고 또는 불만을 받고 있다고 생각하십니까? scipy에서 matlab이 아닌 필터를 플롯하면 매우 유사합니다.

응답

통과 대역에서 100dB 감소한 것입니다! 따라서 더 작은 차수 필터를 원하면 구현에 도움이 될 것입니다. 6 차 필터에 도달하면 잘못된 계수에 대한 불만이 중단됩니다. 주문을 줄여도 여전히 요구 사항을 충족하는지 확인하십시오.


이것을 제안 해 주셔서 감사합니다! 나는 6 차 필터가 잘 작동한다고 생각합니다. matlab의 fvtool을 사용하면 응용 프로그램에 응답이 좋다고 생각합니다. 위의 답변을 업데이트했습니다. 그러나 Verilog HDL 코드 생성기 ( spiral.net/hardware/filter.html )에 여전히 문제가 있습니다 . 다른 형식의 [b, a]를 원할 수도 있습니다. 또한 SciPy 사용시 +1입니다.
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.