เป็นไปได้ไหมที่จะสร้างตัวกรอง IIR ใน FPGA ที่มีสัญญาณนาฬิกาที่ความถี่ตัวอย่าง?


9

คำถามนี้เกี่ยวกับการนำตัวกรอง IIR ไปใช้ใน FPGA ด้วย DSP slices ที่มีเกณฑ์เฉพาะมาก

สมมติว่าคุณกำลังสร้างตัวกรองโดยไม่มีการแตะไปข้างหน้าและแตะย้อนกลับเพียง 1 ครั้งด้วยสมการนี้:

y[n]=y[n1]b1+x[n]

(ดูภาพ)

ยกตัวอย่าง DSP48A1 จาก Xilinx เป็นตัวอย่าง - ชิ้นส่วน IP DSP ที่ยากที่สุดจะคล้ายกัน

ให้บอกว่าคุณมีข้อมูลอะนาล็อกที่เข้ามาที่ 1 ตัวอย่างต่อนาฬิกา ฉันต้องการออกแบบตัวกรอง IIR ที่ทำงานพร้อมกันที่นาฬิกาตัวอย่าง

ปัญหาคือว่าในการรันชิ้น DSP ในอัตราสูงสุดคุณไม่สามารถคูณและเพิ่มในรอบเดียวกันได้ คุณต้องมีการลงทะเบียนไพพ์ไลน์ระหว่างส่วนประกอบเหล่านี้

ดังนั้นถ้าคุณมี 1 ตัวอย่างใหม่ทุก ๆ นาฬิกาคุณจะต้องสร้างเอาต์พุต 1 ตัวต่อนาฬิกา อย่างไรก็ตามคุณจำเป็นต้องมีนาฬิกา 2 เอาท์พุทก่อนหน้าก่อนที่คุณจะสามารถสร้างใหม่ในการออกแบบนี้

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

แต่น่าเสียดายที่ถ้าคุณกำลังสุ่มตัวอย่างด้วยอัตราสัญญาณนาฬิกาสูงสุดของชิ้น DSP ที่ผ่านการปิเปตอย่างเต็มรูปแบบไม่สามารถแก้ปัญหาเหล่านั้นได้ มีวิธีอื่นในการสร้างสิ่งนี้หรือไม่?

(คะแนนโบนัสหากคุณสามารถออกแบบตัวกรอง IIR ที่ทำงานที่ครึ่งหนึ่งของอัตราตัวอย่างโดยใช้จำนวนชิ้น DSP ใด ๆ )

เป้าหมายคือการเรียกใช้ตัวกรองการชดเชยสำหรับ 1 GSPS ADC ใน Xilinx Artix FPGA ชิ้นส่วน DSP ของพวกเขาสามารถทำงานได้มากกว่า 500 MHz เมื่อไปป์ไลน์เต็มที่ หากมีวิธีแก้ปัญหาสำหรับ 1 ตัวอย่างต่อนาฬิกาฉันต้องการลองและปรับขนาดโซลูชันสำหรับ 2 ตัวอย่างต่อนาฬิกา ทั้งหมดนี้ง่ายมากด้วยตัวกรอง FIR

ตัวอย่างตัวกรอง IIR ข้อเสนอแนะเดี่ยว


1
เพื่ออธิบายให้ชัดเจนไม่มีเหตุผลใดที่คุณจะไม่มีเอาต์พุตหนึ่งตัวต่อรอบนาฬิกาด้วยวิธีการไพพ์ไลน์ใช่ไหม คุณกำลังพยายามลดเวลาในการตอบสนองลงเหลือหนึ่งรอบนาฬิกาแทนที่จะเป็นสองรอบใช่ไหม ขึ้นอยู่กับสถานการณ์ของคุณหากคุณใช้จำนวนเต็มสำหรับ b1 คุณสามารถแปลงจำนวนทวีคูณเป็นส่วนเสริมขนาดใหญ่รวมถึง x [n]
Horta

ขวา - เนื่องจากมีหนึ่งอินพุตต่อนาฬิกาจึงต้องมีเอาต์พุตหนึ่งเอาต์พุตต่อนาฬิกา ความหน่วงแฝงไม่ใช่ปัญหา DSP slice มีตัวบวกอินพุต 2 ตัวเท่านั้นและก๊อกมักจะเป็นตัวเลขที่ค่อนข้างใหญ่ดังนั้นคุณจึงไม่สามารถเพิ่ม b1 เท่าในหนึ่งรอบนาฬิกาได้ ขีด จำกัด หลักคือเอาท์พุทต้องย้อนกลับไปใน 1 นาฬิกา แต่มันใช้เวลา 2 นาฬิกาในการผลิต
Marcus10110

1
ฉันคิดว่าคุณยังคงเข้าใจผิดว่าไปป์ไลน์ทำงานอย่างไร ไปป์ไลน์อาจเพิ่มเวลาแฝง แต่อนุญาตให้คุณรับ 1 เอาต์พุตสำหรับแต่ละอินพุตในแต่ละรอบสัญญาณนาฬิกา มันเป็นเพียงแค่ว่าผลที่ได้คือตอนนี้ 2 นาฬิกาหลังจากมากกว่า 1 นาฬิกาในอุดมคติ อินพุตจะเป็นลำดับดังนี้: x [0], x [1], x [2], x [3], x [4] ในขณะที่เอาต์พุตจะอยู่ในช่วงเวลาเดียวกัน y [-2], y [-1], y [0], y [1], y [2] คุณไม่ได้สูญเสียตัวอย่างใด ๆ นอกจากนี้คุณยังอยู่ใน FPGA ดังนั้นหากคุณต้องการทำงานให้สำเร็จมากกว่าที่ท่อ DSP ออกแบบมาให้ใช้ fpga เพื่อแบ่งงานให้เท่ากัน
Horta

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

ฮอร์ต้า - คุณถูกต้องเกี่ยวกับการวางท่อโดยทั่วไป แต่ปัญหาคือแท็บ b1 ในกรณีนี้มีความคิดเห็น - หมายความว่าสเตจในท่อขึ้นอยู่กับเอาต์พุตของค่าก่อนหน้า หากใช้เวลา 2 นาฬิกาเสมอในการสร้างเอาต์พุตถัดไปจากเอาต์พุตก่อนหน้านี้จะไม่มีวิธีสร้าง 1 เอาต์พุตต่อนาฬิกาไม่ว่าคุณจะเพิ่มเวลาแฝงเท่าใด jbarlow - คุณถูกต้อง DSP slice มีตัวเลือกการหลอม 1 รอบ อย่างไรก็ตามมันไม่สามารถรันเร็วพอในกรณีนี้ โดยการเพิ่มการลงทะเบียน M (ดูแผ่นข้อมูล) คุณสามารถเข้าถึง 500 MHz อย่างไรก็ตามคุณไม่สามารถคูณและเพิ่มใน clk เดียวกันได้
Marcus10110

คำตอบ:


3

ฉันยังไม่ได้ทำงานกับตัวกรอง IIR แต่ถ้าคุณต้องการคำนวณสมการที่กำหนด

y[n] = y[n-1]*b1 + x[n]

หนึ่งครั้งต่อรอบ CPU คุณสามารถใช้ pipelining

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

เอาล่ะมาดูสูตรและออกแบบท่อ:

y[n] = y[n-1]*b1 + x[n]

รหัสท่อของคุณอาจมีลักษณะเช่นนี้:

output <= last_output_times_b1 + last_input
last_output_times_b1 <= output * b1;
last_input <= input

โปรดทราบว่าทั้งสามคำสั่งจะต้องดำเนินการแบบขนานและ "เอาต์พุต" ในบรรทัดที่สองจึงใช้เอาต์พุตจากวงจรนาฬิกาล่าสุด!

ฉันไม่ได้ทำงานอะไรมากกับ Verilog ดังนั้นไวยากรณ์ของรหัสนี้อาจผิดพลาดมากที่สุด (เช่นไม่มีสัญญาณความกว้างบิตของสัญญาณอินพุต / เอาต์พุต; ไวยากรณ์การประมวลผลสำหรับการคูณ) อย่างไรก็ตามคุณควรได้รับความคิด:

module IIRFilter( clk, reset, x, b, y );
  input clk, reset, x, b;
  output y;

  reg y, t, t2;
  wire clk, reset, x, b;

  always @ (posedge clk or posedge reset)
  if (reset) begin
    y <= 0;
    t <= 0;
    t2 <= 0;
  end else begin
    y <= t + t2;
    t <= mult(y, b);
    t2 <= x
  end

endmodule

PS: บางทีโปรแกรมเมอร์ Verilog ที่มีประสบการณ์บางคนสามารถแก้ไขรหัสนี้และลบความคิดเห็นนี้และความคิดเห็นด้านบนรหัสหลังจากนั้น ขอบคุณ!

PPS: ในกรณีที่ปัจจัย "b1" ของคุณเป็นค่าคงที่คงที่คุณอาจสามารถปรับการออกแบบให้เหมาะสมโดยใช้ตัวคูณพิเศษที่รับอินพุตสเกลาร์เดียวเท่านั้นและคำนวณ "คูณ b1" เท่านั้น

การตอบสนองต่อ: "น่าเสียดายจริง ๆ แล้วนี่เทียบเท่ากับ y [n] = y [n-2] * b1 + x [n] นี่เป็นเพราะขั้นตอนการวางท่อเพิ่มเติม" แสดงความคิดเห็นเป็นคำตอบเวอร์ชันเก่า

ใช่แล้วมันเหมาะสำหรับเวอร์ชั่นเก่า (INCORRECT !!!) ต่อไปนี้:

  always @ (posedge clk or posedge reset)
  if (reset) begin
    t <= 0;
  end else begin
    y <= t + x;
    t <= mult(y, b);
  end

ฉันหวังว่าจะแก้ไขข้อผิดพลาดนี้ในขณะนี้โดยการชะลอค่าอินพุตเช่นกันในการลงทะเบียนครั้งที่สอง:

  always @ (posedge clk or posedge reset)
  if (reset) begin
    y <= 0;
    t <= 0;
    t2 <= 0;
  end else begin
    y <= t + t2;
    t <= mult(y, b);
    t2 <= x
  end

เพื่อให้แน่ใจว่าการทำงานอย่างถูกต้องในครั้งนี้ลองมาดูว่าเกิดอะไรขึ้นในสองสามรอบแรก โปรดทราบว่า 2 รอบแรกจะสร้างขยะมากขึ้นหรือน้อยลงเนื่องจากไม่มีค่าเอาต์พุตก่อนหน้า (เช่น y [-1] == ??) register y ถูกเตรียมใช้งานด้วย 0 ซึ่งเทียบเท่ากับ y [-1] == 0

รอบแรก (n = 0):

BEFORE: INPUT (x=x[0], b); REGISTERS (t=0, t2=0, y=0)

y <= t + t2;      == 0
t <= mult(y, b);  == y[-1] * b  = 0
t2 <= x           == x[0]

AFTERWARDS: REGISTERS (t=0, t2=x[0], y=0), OUTPUT: y[0]=0

รอบที่สอง (n = 1):

BEFORE: INPUT (x=x[1], b); REGISTERS (t=0, t2=x[0], y=y[0])

y <= t + t2;      ==     0  +  x[0]
t <= mult(y, b);  ==  y[0]  *  b
t2 <= x           ==  x[1]

AFTERWARDS: REGISTERS (t=y[0]*b, t2=x[1], y=x[0]), OUTPUT: y[1]=x[0]

รอบที่สาม (n = 2):

BEFORE: INPUT (x=x[2], b); REGISTERS (t=y[0]*b, t2=x[1], y=y[1])

y <= t + t2;      ==  y[0]*b +  x[1]
t <= mult(y, b);  ==  y[1]   *  b
t2 <= x           ==  x[2]

AFTERWARDS: REGISTERS (t=y[1]*b, t2=x[2], y=y[0]*b+x[1]), OUTPUT: y[2]=y[0]*b+x[1]

รอบที่สี่ (n = 3):

BEFORE: INPUT (x=x[3], b); REGISTERS (t=y[1]*b, t2=x[2], y=y[2])

y <= t + t2;      ==  y[1]*b +  x[2]
t <= mult(y, b);  ==  y[2]   *  b
t2 <= x           ==  x[3]

AFTERWARDS: REGISTERS (t=y[2]*b, t2=x[3], y=y[1]*b+x[2]), OUTPUT: y[3]=y[1]*b+x[2]

เราสามารถเห็นได้ว่าเริ่มต้นด้วย cylce n = 2 เราได้ผลลัพธ์ต่อไปนี้:

y[2]=y[0]*b+x[1]
y[3]=y[1]*b+x[2]

ซึ่งเทียบเท่ากับ

y[n]=y[n-2]*b + x[n-1]
y[n]=y[n-1-l]*b1 + x[n-l],  where l = 1
y[n+l]=y[n-1]*b1 + x[n],  where l = 1

ดังที่ได้กล่าวมาแล้วเราแนะนำเพิ่มเติมความล่าช้าของ l = 1 รอบ นั่นหมายความว่าเอาต์พุตของคุณ y [n] ล่าช้าโดย lag l = 1 นั่นหมายความว่าข้อมูลที่ส่งออกจะเทียบเท่า แต่ล่าช้าโดย "ดัชนี" หนึ่งรายการ เพื่อให้ชัดเจนยิ่งขึ้น: ข้อมูลขาออกล่าช้าเป็น 2 รอบเนื่องจากจำเป็นต้องใช้วงจรนาฬิกาหนึ่ง (ปกติ) และ 1 นาฬิกาเพิ่มเติม (lag l = 1) จะถูกเพิ่มสำหรับรอบกลาง

นี่คือภาพร่างที่แสดงภาพกราฟิกว่าข้อมูลไหลอย่างไร:

ร่างของการไหลของข้อมูล

PS: ขอบคุณที่มองรหัสของฉันอย่างใกล้ชิด ดังนั้นฉันจึงเรียนรู้บางอย่างเช่นกัน! ;-) แจ้งให้เราทราบหากรุ่นนี้ถูกต้องหรือหากคุณเห็นปัญหาเพิ่มเติม


เยี่ยมมาก! น่าเสียดายที่ y [n] = y [n-2] * b + x [n-1] ไม่ได้มีฟังก์ชั่นเทียบเท่ากับ y [n] = y [n-1] * b + x [n] ที่มีเวลาแฝง รูปแบบของฟังก์ชั่นการถ่ายโอน IIR มีลักษณะดังนี้: y [n] = x [n] * b0 + x [n-1] * b1 - y [n-1] * a1 - y [n-2] * a2 และอื่น ๆ แบบฟอร์มของคุณตั้งค่า b0 และ a1 เป็น 0 และใช้ b1 และ a2 แทน อย่างไรก็ตามการแปลงที่จริงแล้วสร้างตัวกรองที่แตกต่างกันมาก หากมีวิธีคำนวณตัวกรองโดยตั้งค่าตัวหารแรก (a1) เป็นศูนย์แม้ว่าโซลูชันทั้งสองของคุณจะทำงานได้อย่างสมบูรณ์
Marcus10110

คุณต้องเข้าใจปัญหา "การล่าช้าที่แนะนำ" อย่างถูกต้อง ตัวอย่างเช่นตัวกรอง "การประมวลผลสตรีมข้อมูล" ควรส่งต่ออินพุตเมื่อ y [n] = x [n] จะทำงานอย่างถูกต้องหากมันสร้าง y [n] = x [n-1] เป็นเอาต์พุต เอาท์พุทล่าช้าเพียง 1 รอบ (เช่นดัชนีเอาท์พุทถูกชดเชยด้วยค่าคงที่เทียบกับดัชนีอินพุททั้งหมด)! ในตัวอย่างของเรานี้หมายถึงการทำงานของคุณเป็นy[n+l] = y[n-1] * b + x[n]ที่มีค่าคงที่สำหรับความล่าช้าlซึ่งสามารถเขียนใหม่เพื่อy[n] = y[n-1-l] * b + x[n-l]และ L = 1 y[n] = y[n-2] * b + x[n-1]นี้อยู่
SDwarfs

สำหรับตัวกรอง IIR ของคุณที่ซับซ้อนมากขึ้นคุณจะต้องทำเช่นเดียวกัน: =>y[n+l] = x[n] * b0 + x[n-1] * b1 - y[n-1] * a1 - y[n-2] * a2 y[n] = x[n-l]*b0 + x[n-1-l] * b1 - y[n-1-l] * a1 - y[n-2-l]*a2สมมติว่าคุณสามารถทำการคูณทั้งสามแบบขนาน (1. ขั้นตอน / 1 รอบ) และจำเป็นต้องเพิ่มผลิตภัณฑ์เข้าด้วยกันคุณต้องใช้ 2 รอบ (1 รอบ: เพิ่ม / ย่อยสองผลิตภัณฑ์แรก, 1 รอบ: เพิ่ม / ย่อย ผลที่ตามมาจากการเพิ่ม / ย่อยทั้งสอง) คุณจะต้องเพิ่มอีก 2 รอบ ดังนั้น l = (3-1) = 2 ให้คุณy[n]=x[n-2]*b0+x[n-1-2]*b1-y[n-1-2]*a1-y[n-2-2]*a2=>y[n]=x[n-2]*b0+x[n-3]*b1-y[n-3]*a1-y[n-4]*a2
SDwarfs

แน่นอนว่าสิ่งนี้จะทำให้ FPGA ของคุณทำงานได้ในแบบคู่ขนาน: การคูณ 4 ครั้งและการบวก / ลบ 3 ครั้ง หมายความว่าคุณต้องการทรัพยากรสำหรับตัวคูณ 4 และตัวเสริม 3 ตัว
SDwarfs

0

ใช่คุณสามารถนาฬิกาที่ความถี่ตัวอย่าง

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

ให้ไว้: y [n] = y [n-1] * b1 + x [n];

สิ่งนี้สามารถจัดการได้ใน: y [n] = y [n-2] * b1 * b1 + x [n-1] * b1 + x [n]

ในการตรวจสอบว่าเป็นลำดับเดียวกันให้พิจารณาว่าเกิดอะไรขึ้นกับตัวอย่างหลายตัวอย่างแรก x [0], x [1], x [2] ฯลฯ โดยที่ก่อนหน้า x [0] ทั้งหมด x, y ตัวอย่างเป็นศูนย์

สำหรับนิพจน์ต้นฉบับลำดับคือ:

y = x[0],

x[1] +x[0]*b1,

x[2] +x[1]*b1 +x[0]*b1*b1,

x[3] +x[2]*b1 +x[1]*b1*b1 +x[0]*b1*b1*b1, ...

เป็นที่ชัดเจนว่ามีความจำเป็นที่ b1 <1 ไม่เช่นนั้นจะเติบโตโดยไม่มีข้อผูกมัด

ตอนนี้ให้พิจารณานิพจน์ที่จัดการ:

y = x[0],

x[0]*b1 +x[1],

x[0]*b1*b1 +x[1]*b1 +x[2],

x[0]*b1*b1*b1 +x[1]*b1*b1 +x[2]*b1 +x[3], ...

นี่คือลำดับเดียวกัน

โซลูชันฮาร์ดแวร์ในไลบรารีแบบ Xilinx จำเป็นต้องใช้ DSP48E สองตัวในการเรียงซ้อน อ้างถึงรูปภาพ 1-1 ใน UG193 v3.6 สำหรับพอร์ตและลงทะเบียนชื่อด้านล่าง ดึกดำบรรพ์แรกนั้นคูณด้วย b1 และเพิ่มหนึ่งนาฬิกาในภายหลัง วินาทีคือการคูณด้วย b1 * b1 และเพิ่มหนึ่งนาฬิกาในภายหลัง มีเวลาแฝงไปป์ไลน์ 4 นาฬิกาสำหรับตรรกะนี้

- DSP48E # 1

a_port1: = b1; - สัมประสิทธิ์คงที่ตั้งค่า AREG = 1

b_port1: = x; - set attribute BREG = 1

c_port1: = x; - ตั้ง CREG = 1

- ภายในเพื่อ DSP48E # 1

reg_a1 <= a_port1;

reg_b1 <= b_port1;

reg_c1 ​​<= c_port1;

reg_m1 <= reg_a1 * reg_b1;

reg_p1 <= reg_m1 + reg_c1; - เอาต์พุตของ DSP48E อันดับ 1

- จุดสิ้นสุดของ DSP48E # 1

- DSP48E # 2

a_port2: = reg_p2; - ชุดคุณลักษณะ AREG = 0

                -- this means the output of register reg_p2

                -- directly feeds back to the multiplier

b_port2: = b1 * b1; - ค่าคงที่ตั้ง BREG = 1

c_port2: = reg_p1; - ตั้ง CREG = 1

- ภายในเพื่อ DSP48E # 2

reg_b2 <= b_port2;

reg_c2 <= c_port2;

reg_m2 <= a_port2 * reg_b2;

reg_p2 <= reg_m2 + reg_c2;

- จุดสิ้นสุดของ DSP48E # 2

ลำดับที่ reg_p1:

x [0],

x [1] + x [0] * b1

x [2] + x [1] * b1

x [3] + x [2] * b1

เป็นต้น

ลำดับที่ reg_p2 เป็นผลลัพธ์ที่ต้องการ ภายใน DSP48E ตัวที่สอง register reg_m2 มีลำดับ:

x [0] * * * * * * * * b1 b1,

x [1] * b1 * b1 + x [0] * b1 * b1 * b1,

x [2] * b1 * b1 + x [1] * b1 * b1 * b1 + x [0] * b1 * b1 * b1 * b1 *

มีความสง่างามของผลลัพธ์นี้ เห็นได้ชัดว่า DSP48E ไม่ได้คูณและเพิ่มในนาฬิกาเดียวกัน แต่นั่นคือสิ่งที่ต้องการความแตกต่างของสมการ สมการความแตกต่างที่ถูกควบคุมช่วยให้เราสามารถทนต่อการลงทะเบียน M และ P ใน DSP48E และนาฬิกาด้วยความเร็วสูงสุด

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.