การออกแบบตัวกรอง Butterworth ใน Matlab และการรับสัมประสิทธิ์ตัวกรอง [ab] สัมประสิทธิ์เป็นจำนวนเต็มสำหรับเครื่องสร้างรหัส Verilog HDL ออนไลน์


15

ฉันได้ออกแบบตัวกรอง Butterworth โลว์พาสง่าย ๆ โดยใช้ Matlab ข้อมูลโค้ดต่อไปนี้แสดงให้เห็นถึงสิ่งที่ฉันได้ทำไปแล้ว

fs = 2.1e6;
flow = 44 * 1000;
fNorm =  flow / (fs / 2);
[b,a] = butter(10, fNorm, 'low');

ใน [b, a] ถูกจัดเก็บค่าสัมประสิทธิ์ตัวกรอง ฉันต้องการได้รับ [b, a] เป็นจำนวนเต็มเพื่อให้ฉันสามารถใช้เครื่องสร้างรหัสHDL ออนไลน์เพื่อสร้างรหัสใน Verilog

ค่า 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

สัมประสิทธิ์ b ที่ฉันได้ใน Matlab คือ:

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 ฉันไม่รู้ว่า "เศษส่วน" มีความหมายอย่างไรที่ลิงค์ด้านบน

เรียกใช้ตัวสร้างโค้ด (http://www.spiral.net/hardware/filter.html) ด้วยค่าสัมประสิทธิ์ [b, a] ข้างต้นด้วยเศษบิตที่ตั้งไว้ที่ 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. 

ฉันจะเปลี่ยนการออกแบบเพื่อไม่ให้เกิดข้อผิดพลาดนี้ได้อย่างไร

UPDATE: การใช้ Matlab เพื่อสร้างตัวกรอง Butterworth ลำดับที่ 6 ฉันได้รับค่าสัมประสิทธิ์ดังต่อไปนี้:

สำหรับ:

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-coefficients นั้นเล็กเกินไปหรือบางทีตัวสร้างโค้ด (http://www.spiral.net/hardware/filter.html) ต้องการ [b, a] ในรูปแบบอื่นหรือไม่?

UPDATE:

บางทีสิ่งที่ฉันต้องทำคือปรับสเกลสัมประสิทธิ์ [b, a] ด้วยจำนวนของเศษส่วนเศษส่วนเพื่อให้ได้สัมประสิทธิ์เป็นจำนวนเต็ม

a .* 2^12
b .* 2^12

อย่างไรก็ตามฉันยังคิดว่าสัมประสิทธิ์ b มีขนาดเล็กมาก ฉันทำอะไรผิดที่นี่

บางทีตัวกรองประเภทอื่น (หรือวิธีการออกแบบตัวกรอง) จะเหมาะสมกว่าหรือไม่ ใครช่วยแนะนำได้บ้าง

อัพเดท: ตามคำแนะนำของ Jason R และ Christopher Felton ในความคิดเห็นด้านล่างตัวกรองสัญญาณขอความช่วยเหลือจะเหมาะสมกว่า ตอนนี้ฉันได้เขียนโค้ด 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 จะดีกว่าที่จะใช้ในสถานการณ์นี้หรือไม่

MOREOVER:ตัวกรอง IIR แบบเรียกซ้ำสามารถใช้งานได้โดยใช้เลขจำนวนเต็มโดยแสดงค่าสัมประสิทธิ์เป็นเศษส่วน (ดูสมุดประมวลผลสัญญาณ DSP ที่ยอดเยี่ยมของ Smith สำหรับรายละเอียดเพิ่มเติม: http://www.dspguide.com/ch19/5.htm )

โปรแกรม Matlab ต่อไปนี้แปลงค่าสัมประสิทธิ์บัตเตอร์เวิร์ ธ เป็นส่วนที่เป็นเศษส่วนโดยใช้ฟังก์ชัน Matlab rat () จากนั้นตามที่กล่าวไว้ในความคิดเห็นส่วนลำดับที่สองสามารถใช้ในการใช้ตัวกรองเป็นตัวเลข (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 เช่นนี้มักจะดำเนินการโดยใช้ส่วนที่สองการสั่งซื้อ ; คุณได้รับตัวกรองที่คุณต้องการโดยการเรียงลำดับขั้นตอนที่สองหลาย ๆ ลำดับ (ด้วยลำดับขั้นตอนเดียวลำดับแรกหากคำสั่งที่ต้องการเป็นเลขคี่) โดยทั่วไปแล้วจะเป็นการใช้งานที่มีประสิทธิภาพมากกว่าการใช้ตัวกรองลำดับสูงกว่าโดยตรง
Jason R

3
หากคุณไม่ทำตามที่ @JasonR แนะนำคุณจะมีขนาดคำที่ใหญ่มาก ตัวกรองเช่นนี้อาจล้มเหลวจุดลอยตัวที่มีความแม่นยำเดียวเมื่อใช้งานกับโครงสร้าง IIR พื้นฐานคุณต้องมี SOS
Christopher Felton

@ JasonR: ขอบคุณสำหรับการแนะนำสิ่งนี้ ฉันได้อัปเดตโดยคำตอบข้างต้น
Nicholas Kinar

@ChristopherFelton: ขอบคุณที่ช่วยเสริมกำลังนี้
Nicholas Kinar

ใช่ด้วยเมทริกซ์ SOS ใหม่ของคุณคุณสามารถสร้างตัวกรอง 3 ตัวจากเว็บไซต์ หรือคุณสามารถใช้รหัสของฉันที่นี่ มันจะทำงานเช่นเดียวกับเว็บไซต์ ฉันยินดีที่จะอัปเดตสคริปต์เป็นยกเว้นเมทริกซ์ SOS
Christopher Felton

คำตอบ:


5

ตามที่กล่าวไว้จะเป็นการดีที่สุดที่จะใช้ผลรวมของส่วนซึ่งจะแบ่งตัวกรองคำสั่งซื้อที่สูงกว่าออกเป็นตัวกรองลำดับที่สองที่เรียงซ้อน คำถามที่อัพเดตมีเมทริกซ์ SOS การใช้รหัสนี้และตัวอย่างที่นี่วัตถุ Python สามารถใช้เพื่อสร้างแต่ละส่วน

ใน 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
หากคุณมีปัญหาใด ๆ แจ้งให้เราทราบและฉันจะอัปเดต / แก้ไขรหัสหากมันไม่ได้ผลสำหรับคุณ ฉันจะแก้ไขมัน (ค่อนข้างเร็ว ๆ นี้ doh) เพื่อยอมรับเมทริกซ์ SOS โดยตรง
Christopher Felton

1
ฉันพยายามใช้เวอร์ชันของฉันเองจากตัวอย่างของคุณ ในระบบของฉันฉันต้องใช้ "จากศูนย์นำเข้าที่ไม่มีเลข" และเปลี่ยน loatmat เป็น loadmat () Matlab SOS ได้รับจาก Matlab ( mathworks.com/help/toolbox/signal/ref/ss2sos.html ) ในรูปแบบเดียวกับที่คาดไว้หรือไม่ ฉันได้รับข้อผิดพลาดต่อไปนี้เมื่อพยายามเข้าถึงเมทริกซ์ SOS: "TypeError: unhashable type" เมื่อล่ามมาถึงบรรทัด "b [ii] = SOS [0: 3, ii]"
Nicholas Kinar

1
ขึ้นอยู่กับรูปแบบของไฟล์ SOS.mat หากคุณเพียงพิมพ์ >>> (matfile) มันจะแสดงปุ่มต่าง ๆ ในไฟล์. mat ที่โหลดไว้ scipy.io.loadmat โหลดเป็นพจนานุกรม (BOMK) เสมอ
Christopher Felton

1
ใช่ถูกต้องเอาต์พุตของ 0 คืออินพุตถึง 1 และต่อไป ความคิดเล็กน้อยจะต้องใส่ในความกว้างของคำ ค่าเริ่มต้นคือสองใช้ 24 บิตเศษส่วน (0 จำนวนเต็ม, 23 เศษส่วน, 1 เครื่องหมาย) ฉันเชื่อว่าคุณต้องการใช้ความกว้างของคำที่เล็กลง
Christopher Felton

10

'เศษส่วนบิต' คือจำนวนบิตในรถบัสที่คุณทุ่มเทเพื่อเป็นตัวแทนเศษส่วนของตัวเลข (เช่น. 75 ใน 3.75)

สมมติว่าคุณมีดิจิตอลบัสความกว้าง 4 บิตตัวเลขจะ1001เป็นตัวแทนอะไร มันอาจหมายถึง '9' ถ้าคุณคิดว่ามันเป็นจำนวนเต็มบวก (2 ^ 3 + 2 ^ 0 = 8 + 1 = 9) หรืออาจหมายถึง -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 บิตเศษส่วน

ดังนั้นหากคุณมีรายการของจำนวนจริงเหมือนที่คุณมีข้างต้นตอนนี้คุณต้องตัดสินใจว่าคุณต้องการที่จะเป็นตัวแทนเศษส่วน และนี่คือการแลกเปลี่ยน: ยิ่งคุณใช้เศษส่วนน้อยเท่าไหร่คุณยิ่งแสดงจำนวนที่คุณต้องการได้มากเท่านั้น แต่ยิ่งวงจรของคุณใหญ่ขึ้นเท่าไหร่ ยิ่งไปกว่านั้นเศษส่วนที่คุณใช้น้อยกว่ายิ่งการตอบสนองความถี่ที่แท้จริงของตัวกรองจะเบี่ยงเบนจากที่คุณออกแบบไว้ตอนเริ่มต้น!

และเพื่อให้เรื่องแย่ลงคุณต้องการสร้างตัวกรอง Infinite Impulse Response (IIR) สิ่งเหล่านี้อาจไม่เสถียรหากคุณไม่มีเศษส่วนและจำนวนเต็ม!


ขอบคุณที่ให้คำตอบที่ลึกซึ้งนี้ ฉันพยายามเรียกใช้ตัวสร้างโค้ดโดยใช้สัมประสิทธิ์ b ขนาดเล็กด้านบนและฉันยังคงได้รับข้อผิดพลาด คุณช่วยแนะนำบางอย่างที่ฉันสามารถทำได้เพื่อเรียกใช้ตัวกำเนิดอย่างถูกต้องหรือไม่? ฉันจะอัปเดตคำตอบข้างต้นเพื่อแสดงสิ่งที่ฉันทำ

10

ดังนั้นมาร์ตี้ดูแลคำถามอย่างดี สำหรับตัวกรองเองฉันคิดว่าคุณน่าจะได้รับคำเตือนหรือคำร้องเรียนจาก MATLAB เกี่ยวกับค่าสัมประสิทธิ์ที่มีขนาดไม่ดี? เมื่อฉันพล็อตตัวกรองจาก scipy ไม่ใช่ matlab แต่ก็น่าจะคล้ายกันมาก

คำตอบ

อันไหนที่ 100 เดซิเบลที่ passband! ดังนั้นคุณอาจต้องการตรวจสอบให้แน่ใจว่าคุณต้องการตัวกรองคำสั่งซื้อขนาดเล็กซึ่งจะช่วยให้คุณสามารถใช้งานได้ เมื่อฉันไปถึงตัวกรองลำดับที่ 6 ฉันหยุดรับข้อร้องเรียนเกี่ยวกับสัมประสิทธิ์ที่ไม่ดี อาจลองลดคำสั่งซื้อและดูว่ายังมีคุณสมบัติตรงตามความต้องการของคุณหรือไม่


ขอบคุณที่แนะนำสิ่งนี้! ฉันคิดว่าตัวกรองลำดับที่ 6 ก็ใช้ได้เช่นกัน ด้วยการใช้ fvtool ของ matlab ฉันคิดว่าการตอบสนองดีต่อแอปพลิเคชันของฉัน ฉันได้อัปเดตคำตอบของฉันด้านบนแล้ว อย่างไรก็ตามมีบางสิ่งที่เกิดขึ้นกับตัวสร้างโค้ด Verilog HDL ( spiral.net/hardware/filter.html ) บางทีมันอาจต้องการ [b, a] ในรูปแบบอื่น นอกจากนี้ +1 สำหรับการใช้งาน SciPy
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.