Tôi chưa làm việc với các bộ lọc IIR, nhưng nếu bạn chỉ cần tính toán phương trình đã cho
y[n] = y[n-1]*b1 + x[n]
một lần trên mỗi chu kỳ CPU, bạn có thể sử dụng pipelining.
Trong một chu kỳ, bạn thực hiện phép nhân và trong một chu kỳ, bạn cần thực hiện phép tính tổng cho từng mẫu đầu vào. Điều đó có nghĩa là FPGA của bạn phải có khả năng thực hiện phép nhân trong một chu kỳ khi được chạy ở tốc độ mẫu đã cho! Sau đó, bạn sẽ chỉ cần thực hiện phép nhân của mẫu hiện tại VÀ tổng kết quả của phép nhân mẫu cuối cùng song song. Điều này sẽ gây ra độ trễ xử lý liên tục trong 2 chu kỳ.
Ok, chúng ta hãy xem công thức và thiết kế một đường ống dẫn:
y[n] = y[n-1]*b1 + x[n]
Mã đường ống của bạn có thể trông như thế này:
output <= last_output_times_b1 + last_input
last_output_times_b1 <= output * b1;
last_input <= input
Lưu ý rằng cả ba lệnh cần được thực thi song song và "đầu ra" trong dòng thứ hai do đó sử dụng đầu ra từ chu kỳ xung nhịp cuối cùng!
Tôi đã không làm việc nhiều với Verilog, vì vậy cú pháp của mã này rất có thể sai (ví dụ: thiếu độ rộng bit của tín hiệu đầu vào / đầu ra; cú pháp thực thi để nhân). Tuy nhiên, bạn nên có ý tưởng:
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: Có thể một số lập trình viên Verilog có kinh nghiệm có thể chỉnh sửa mã này và xóa nhận xét này và nhận xét phía trên mã sau đó. Cảm ơn!
PPS: Trong trường hợp hệ số "b1" của bạn là hằng số cố định, bạn có thể tối ưu hóa thiết kế bằng cách triển khai một hệ số nhân đặc biệt chỉ mất một đầu vào vô hướng và chỉ tính "lần b1".
Trả lời: "Thật không may, điều này thực sự tương đương với y [n] = y [n-2] * b1 + x [n]. Điều này là do giai đoạn đường ống phụ." như nhận xét cho phiên bản cũ của câu trả lời
Vâng, điều đó thực sự phù hợp với phiên bản cũ (INCORRECT !!!) sau đây:
always @ (posedge clk or posedge reset)
if (reset) begin
t <= 0;
end else begin
y <= t + x;
t <= mult(y, b);
end
Tôi hy vọng đã sửa lỗi này ngay bây giờ bằng cách trì hoãn các giá trị đầu vào, trong một thanh ghi thứ hai:
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
Để đảm bảo nó hoạt động chính xác trong lần này, hãy xem điều gì xảy ra ở một vài chu kỳ đầu tiên. Lưu ý rằng 2 chu kỳ đầu tiên tạo ra nhiều hơn hoặc ít hơn (xác định) rác, vì không có giá trị đầu ra trước đó (ví dụ: y [-1] == ??) có sẵn. Thanh ghi y được khởi tạo bằng 0, tương đương với giả sử y [-1] == 0.
Chu kỳ đầu tiên (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
Chu kỳ thứ hai (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]
Chu kỳ thứ ba (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]
Chu kỳ thứ tư (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]
Chúng ta có thể thấy, bắt đầu với hình trụ n = 2, chúng ta có được đầu ra sau:
y[2]=y[0]*b+x[1]
y[3]=y[1]*b+x[2]
tương đương với
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
Như đã đề cập ở trên, chúng tôi giới thiệu độ trễ bổ sung là l = 1 chu kỳ. Điều đó có nghĩa là đầu ra của bạn y [n] bị trễ bởi độ trễ l = 1. Điều đó có nghĩa là dữ liệu đầu ra tương đương nhưng bị trì hoãn bởi một "chỉ mục". Để rõ ràng hơn: Dữ liệu đầu ra bị trễ là 2 chu kỳ, vì cần một chu kỳ đồng hồ (bình thường) và thêm 1 chu kỳ (lag l = 1) cho giai đoạn trung gian.
Dưới đây là một bản phác thảo để mô tả đồ họa cách dữ liệu chảy:
PS: Cảm ơn bạn đã xem kỹ mã của tôi. Vì vậy, tôi cũng đã học được điều gì đó! ;-) Hãy cho tôi biết nếu phiên bản này là chính xác hoặc nếu bạn thấy bất kỳ vấn đề nào nữa.