Ainda não trabalhei com filtros IIR, mas se você precisar apenas calcular a equação fornecida
y[n] = y[n-1]*b1 + x[n]
uma vez por ciclo de CPU, você pode usar pipelining.
Em um ciclo, você faz a multiplicação e, em um ciclo, precisa fazer a soma para cada amostra de entrada. Isso significa que seu FPGA deve ser capaz de fazer a multiplicação em um ciclo quando cronometrado na taxa de amostragem especificada! Então você só precisará fazer a multiplicação da amostra atual E o somatório do resultado da multiplicação da última amostra em paralelo. Isso causa um atraso de processamento constante de 2 ciclos.
Ok, vamos dar uma olhada na fórmula e criar um pipeline:
y[n] = y[n-1]*b1 + x[n]
O código do seu pipeline pode ficar assim:
output <= last_output_times_b1 + last_input
last_output_times_b1 <= output * b1;
last_input <= input
Observe que todos os três comandos precisam ser executados em paralelo e que a "saída" na segunda linha usa a saída do último ciclo do relógio!
Como não trabalhei muito com o Verilog, a sintaxe desse código pode estar errada (por exemplo, falta de largura de bit dos sinais de entrada / saída; sintaxe de execução para multiplicação). No entanto, você deve ter a ideia:
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: Talvez algum programador experiente da Verilog possa editar esse código e remover esse comentário e o comentário acima do código posteriormente. Obrigado!
PPS: Caso seu fator "b1" seja uma constante fixa, você poderá otimizar o design implementando um multiplicador especial que apenas recebe uma entrada escalar e calcula apenas "tempos b1".
Resposta a: "Infelizmente, isso é realmente equivalente a y [n] = y [n-2] * b1 + x [n]. Isso ocorre devido ao estágio extra do pipeline." como comentário para a versão antiga da resposta
Sim, isso foi realmente adequado para a seguinte versão antiga (INCORRETA !!!):
always @ (posedge clk or posedge reset)
if (reset) begin
t <= 0;
end else begin
y <= t + x;
t <= mult(y, b);
end
Espero corrigir esse bug agora, atrasando os valores de entrada também em um segundo registro:
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
Para garantir que funcione corretamente dessa vez, vejamos o que acontece nos primeiros ciclos. Observe que os 2 primeiros ciclos produzem mais ou menos lixo (definido), pois nenhum valor de saída anterior (por exemplo, y [-1] == ??) está disponível. O registro y é inicializado com 0, o que equivale a assumir que y [-1] == 0.
Primeiro ciclo (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
Segundo ciclo (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]
Terceiro ciclo (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]
Quarto ciclo (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]
Podemos ver que, começando com cylce n = 2, obtemos a seguinte saída:
y[2]=y[0]*b+x[1]
y[3]=y[1]*b+x[2]
que é equivalente a
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
Como mencionado acima, introduzimos um atraso adicional de l = 1 ciclos. Isso significa que sua saída y [n] está atrasada por lag l = 1. Isso significa que os dados de saída são equivalentes, mas estão atrasados em um "índice". Para ser mais claro: os dados de saída atrasados são 2 ciclos, pois é necessário um ciclo de relógio (normal) e 1 ciclo de relógio adicional (atraso l = 1) é adicionado para o estágio intermediário.
Aqui está um esboço para representar graficamente como os dados fluem:
PS: Obrigado por dar uma olhada no meu código. Então eu aprendi algo também! ;-) Deixe-me saber se esta versão está correta ou se você encontrar mais problemas.