Numune frekansında saatlenmiş bir FPGA'da IIR filtresi oluşturmak mümkün müdür?


9

Bu soru, DSP dilimleri olan bir FPGA'da çok spesifik kriterlere sahip bir IIR filtresi uygulamakla ilgilidir.

Diyelim ki ileriye dokunmamayan ve sadece 1 geri vuruşlu bir filtre yapıyorsunuz, bu denklemle:

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

(resme bakın)

Örnek olarak DSP48A1 dilimini Xilinx'ten alın - çoğu sert IP DSP dilimi benzerdir.

Diyelim ki saatte 1 örnekte gelen analog veriler var. Örnek saatte senkronize çalışan bir IIR filtresi tasarlamak istiyorum.

Sorun, DSP dilimini maksimum hızda çalıştırmak için, aynı döngüde çarpılamaz VE ekleyemezsiniz. Bu bileşenler arasında bir boru hattı kaydınızın olması gerekir.

Yani, her saatte 1 yeni numuneniz varsa, saat başına 1 çıkış üretmeniz gerekecektir. Ancak, bu tasarımda yeni bir tane üretebilmeniz için önceki çıkış 2 saatlerine ihtiyacınız var.

Açık çözüm, verileri çift saat hızında işlemek veya boru hattı kaydını devre dışı bırakmak, böylece aynı döngüye çarpıp ekleyebilirsiniz.

Ne yazık ki, tamamen pipeline edilmiş DSP diliminin maksimum saat hızında örneklediğinizi varsayarsak, bu çözümlerin hiçbiri mümkün değildir. Bunu inşa etmenin başka bir yolu var mı?

(İstediğiniz sayıda DSP dilimi kullanarak örnekleme oranının yarısında çalışan bir IIR filtresi tasarlayabiliyorsanız bonus puanlar)

Amaç, bir Xilinx Artix FPGA'da 1 GSPS ADC için bir telafi filtresi çalıştırmak olacaktır. DSP dilimleri tamamen boru hattına bağlandığında 500 MHz'in biraz üzerinde çalışabilir. Saatte 1 numune için bir çözüm varsa, saatte 2 numune için çözümü ölçeklendirmeyi denemek istiyorum. Bir FIR filtresi ile bunların hepsi çok kolaydır.

tek geri besleme IIR filtre örneği


1
Açıklığa kavuşturmak için, boru hattı yöntemiyle saat döngüsü başına bir çıktınızın olmamasının bir nedeni yok, değil mi? Gecikmeyi iki yerine bir saat döngüsüne indirmeye çalışıyorsunuz, değil mi? Durumunuza bağlı olarak, b1 için bir tamsayı kullanıyorsanız, çarpımı x [n] dahil dev bir eklentiye dönüştürebilirsiniz.
horta

sağ - saat başına bir giriş olduğundan, saat başına bir çıkış olması gerekir. gecikme de bir sorun değil. DSP dilimi yalnızca 2 giriş toplayıcıya sahiptir ve musluklar genellikle oldukça büyük sayılardır, bu nedenle 1 saat döngüsünde b1 kez ekleyemezsiniz. ana sınır, çıkışın 1 saat içinde geri beslenmesi gerektiğidir, ancak üretmek için 2 saat gerekir.
Marcus10110

1
Bence hala bir boru hattının nasıl çalıştığını yanlış anlıyorsunuz. Bir boru hattı potansiyel olarak gecikmeyi artırır, ancak her saat döngüsünde her giriş için 1 çıkış almanızı sağlar. Sadece sonuç, ideal 1 saat sonra değil, şimdi 2 saat sonra. Giriş şu şekilde sıralanır: x [0], x [1], x [2], x [3], x [4], çıkış aynı zaman aralığında y [-2], y olur [-1] y [0] y [1] y [2]. Hiç örnek kaybetmiyorsunuz. Ayrıca, bir FPGA kullanıyorsunuz, bu nedenle DSP boru hatlarının tasarlandığından daha fazla iş yapmak istiyorsanız, iş yükünü paralelleştirmek için fpga'yı kullanın.
horta

DSP, bir döngüde sigortalı bir çarpma birikimi yapabilir. Bir DSP diliminin çıktısının tek bir döngüde geri besleme ile kendi girişine bağlanıp bağlanamayacağı belli değil.
jbarlow

horta - genel olarak boru hatlarıyla ilgili haklısınız, ancak sorun, bu durumda b1 sekmesinin geribildirime sahip olması - yani boru hattındaki bir aşamanın önceki değerin çıktısına bağlı olması. önceki çıktıdan bir sonraki çıktıyı üretmek için her zaman 2 saat gerekiyorsa, ne kadar gecikme eklediğinize bakılmaksızın saat başına 1 çıktı üretmenin bir yolu yoktur. jbarlow - haklısınız, DSP diliminin 1 döngü sigortalı seçeneği var. Ancak bu durumda yeterince hızlı çalışamaz. M kaydını ekleyerek (veri sayfasına bakın) 500 MHz'e erişebilirsiniz, ancak o zaman aynı clk ile çarpıp ekleyemezsiniz.
Marcus10110

Yanıtlar:


3

Henüz IIR filtreleri ile çalışmadım, ancak sadece verilen denklemi hesaplamanız gerekiyorsa

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

CPU döngüsü başına bir kez boru hattını kullanabilirsiniz.

Bir döngüde çarpma işlemini ve bir döngüde her girdi örneği için toplamı yapmanız gerekir. Bu, FPGA'nızın verilen örnek hızında saatlendiğinde çarpımı bir döngüde yapabilmesi gerektiği anlamına gelir! O zaman sadece geçerli örneğin çarpımını VE son örneğin çarpım sonucunun toplamını paralel olarak yapmanız gerekir. Bu, 2 döngüden oluşan sabit bir işleme gecikmesine neden olacaktır.

Tamam, formüle bir göz atalım ve bir boru hattı tasarlayalım:

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

Boru hattı kodunuz şöyle görünebilir:

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

Her üç komutun da paralel yürütülmesi gerektiğini ve bu nedenle ikinci satırdaki "çıktı" nın son saat döngüsünün çıktısını kullandığını unutmayın!

Verilog ile fazla çalışmadım, bu yüzden bu kodun sözdizimi büyük olasılıkla yanlıştır (örneğin, giriş / çıkış sinyallerinin bit genişliği eksik; çarpma için yürütme sözdizimi). Ancak şu fikri edinmelisiniz:

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

Not: Belki bazı deneyimli Verilog programcısı bu kodu düzenleyebilir ve daha sonra bu yorumu ve kodun üstündeki yorumu kaldırabilir. Teşekkürler!

PPS: "b1" çarpanınızın sabit bir sabit olması durumunda, yalnızca bir skaler girdi alan ve yalnızca "b1 çarpı" değerini hesaplayan özel bir çarpan uygulayarak tasarımı optimize edebilirsiniz.

Yanıt: "Ne yazık ki, bu aslında y [n] = y [n-2] * b1 + x [n] ile eşdeğerdir. Bunun nedeni fazladan boru hattı aşamasıdır." cevabın eski versiyonuna yorum olarak

Evet, bu aslında aşağıdaki eski (INCORRECT !!!) sürüm için doğruydu:

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

Umarım şimdi ikinci bir kayıtta da giriş değerlerini geciktirerek bu hatayı düzelttim:

  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

Bu sefer düzgün çalıştığından emin olmak için ilk birkaç döngüde neler olduğuna bakalım. Önceki çıktı değerlerinin (ör. Y [-1] == ??) mevcut olmadığından, ilk 2 döngünün az çok (tanımlanmış) çöp ürettiğine dikkat edin. Y kaydı, y [-1] == 0 varsayılmasına eşdeğer olan 0 ile başlatılır.

Birinci Düzey (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

İkinci Düzey (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]

Üçüncü Çevrim (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]

Dördüncü Döngü (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]

Gördüğümüz gibi, n = 2 silindirinden başlayarak aşağıdaki çıktıyı elde ediyoruz:

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

eşdeğer

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

Yukarıda belirtildiği gibi ek bir l = 1 devir gecikmesi sunuyoruz. Bu, y [n] çıkışınızın l = 1 gecikmesi ile geciktiği anlamına gelir. Bu, çıktı verilerinin eşdeğer olduğu ancak bir "indeks" tarafından geciktiği anlamına gelir. Daha açık olmak gerekirse: Bir (normal) saat çevrimi gerektiğinden ve ara aşama için 1 ek (gecikme l = 1) saat çevrimi eklendiğinden, çıkış verileri 2 döngü gecikmelidir.

Verilerin nasıl aktığını grafik olarak gösteren bir çizim:

veri akışı taslağını

Not: Koduma yakından baktığınız için teşekkür ederim. Ben de bir şey öğrendim! ;-) Bu sürümün doğru olup olmadığını veya daha fazla sorun görürseniz bana bildirin.


İyi iş! Ne yazık ki, y [n] = y [n-2] * b + x [n-1] aslında işlevsel olarak y [n] = y [n-1] * b + x [n] ile gecikmeli olarak eşdeğer değildir. Bir IIR aktarım fonksiyonunun şekli aslında şuna benzer: y [n] = x [n] * b0 + x [n-1] * b1 - y [n-1] * a1 - y [n-2] * a2 ve bunun gibi. Formunuz b0 ve a1 değerini 0 olarak ayarlar ve bunun yerine b1 ve a2 kullanır. Ancak, bu dönüşüm aslında çok farklı bir filtre üretir. İlk payda (a1) sıfıra ayarlanmış bir filtre hesaplamanın bir yolu olsaydı, her iki çözümünüz de mükemmel çalışır.
Marcus10110

Peki, "tanıtılan gecikme" sorununu doğru bir şekilde anlamalısınız. Örneğin, bir "veri akışı işleme" filtresi yalnızca y [n] = x [n] çıktı olarak y [n] = x [n-1] üretirse girişini yönlendirmelidir. Çıkış sadece 1 döngü geciktirilir (örneğin, çıkış endeksi tüm giriş indekslerine göre sabit bir değer ile dengelenir)! Örneğimizde bu, fonksiyonunuzun y[n+l] = y[n-1] * b + x[n]gecikme için sabit bir değere lsahip olduğu y[n] = y[n-1-l] * b + x[n-l]ve l = 1 için bu olduğu anlamına gelir y[n] = y[n-2] * b + x[n-1].
SDwarfs

Daha karmaşık IIR filtreniz için aynısını yapmanız gerekir: 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. Üç çarpımı da paralel olarak yapabileceğinizi varsayalım (1. aşama / 1 döngü) ve ürünleri birlikte eklemek için yapmanız gerekir, 2 döngüye ihtiyacınız vardır (1 döngü: ilk iki ürün sonucunu ekleyin / ekleyin, 1 döngü: ekle / sub bu iki ekleme / almanın sonucu), 2 ek döngüye ihtiyacınız olacaktır. Böylece l = (3-1) = 2 size 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

Elbette bunun çalışması için FPGA'nız paralel olarak yapabilmelidir: 4 çarpma ve 3 toplama / çıkarma. Yani 4 çarpan ve 3 toplayıcı için kaynaklara ihtiyacınız var.
SDwarfs

0

Evet, örnek frekansında saat çalıştırabilirsiniz.

Bu sorunun çözümü, istenen ifadeyi korurken boru hattı kayıtlarının eklenebilmesi için orijinal ifadeyi değiştirmektir.

Verilen: y [n] = y [n-1] * b1 + x [n];

bu şu şekilde değiştirilebilir: y [n] = y [n-2] * b1 * b1 + x [n-1] * b1 + x [n].

Bunun aynı sekans olduğunu doğrulamak için, x [0], x [1], x [2] vb. İlk birkaç örneğe ne olduğunu düşünün, burada x [0] 'dan önce tüm x, y örnekleri sıfırdı.

Orijinal ifade için sıra:

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'in gerekli olduğu açıktır, aksi takdirde bu sınırsız büyür.

Şimdi manipüle edilen ifadeyi düşünün:

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], ...

Bu aynı dizidir.

Xilinx kütüphanesi ilkellerindeki bir donanım çözümü, kademeli olarak iki DSP48E'ye ihtiyaç duyacaktır. Aşağıdaki bağlantı noktası ve kayıt adları için UG193 v3.6'daki şekil 1-1'e bakın. İlk ilkel b1 ile çarpılır ve bir saat sonra eklenir; ikincisi b1 * b1 ile çarpılır ve bir saat sonra eklenir. Bu mantık için 4 saatlik bir boru hattı gecikmesi vardır.

- DSP48E # 1

a_port1: = b1; - sabit katsayı, ayarlanmış AREG = 1

b_port1: = x; - BREG = 1 özelliğini ayarla

c_port1: = x; - CREG = 1 ayarını yapın

- DSP48E # 1'e dahili

reg_a1 <= a_port1;

reg_b1 <= b_port1;

reg_c1 ​​<= c_port1;

reg_m1 <= reg_a1 * reg_b1;

reg_p1 <= reg_m1 + reg_c1; - 1. DSP48E çıkışı

- DSP48E # 1'in sonu

- DSP48E # 2

a_port2: = reg_p2; - AREG = 0 özelliğini ayarla

                -- this means the output of register reg_p2

                -- directly feeds back to the multiplier

b_port2: = b1 * b1; - sabit, ayarlanmış BREG = 1

c_port2: = reg_p1; - CREG = 1 ayarını yapın

- DSP48E # 2'ye dahili

reg_b2 <= b_port2;

reg_c2 <= c_port2;

reg_m2 <= a_port2 * reg_b2;

reg_p2 <= reg_m2 + reg_c2;

- DSP48E # 2'nin sonu

Reg_p1'deki sıra:

x [0],

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

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

x [3] + x [2] * b1,

vb.

Reg_p2'deki dizi istenen sonuçtur. 2. DSP48E'nin içinde, reg_m2 kaydı bir sıraya sahiptir:

x [0] * b 1 * 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

Bu sonucun hoş bir zarafeti var. Açıkçası DSP48E aynı saatte çoğalmıyor ve eklenmiyor, ancak fark denkleminin gerektirdiği şey bu. Manipüle edilmiş fark denklemi, DSP48E'deki M ve P kayıtlarını tolere etmemizi ve tam hızda çalışmamızı sağlar.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.