FPGA üzerinde sabit nokta atan2 hesaplama yöntemleri


12

atan2(x,y)Sürekli giriş / çıkış veri akışına sahip bir FPGA üzerinde hesaplama yapmaya ihtiyacım var . Açılmamış, boru hatlı CORDIC çekirdekleri kullanarak uygulamayı başardım, ancak ihtiyacım olan doğruluğu elde etmek için 32 yineleme yapmak zorunda kaldım. Bu, oldukça büyük miktarda LUT'un bu tek göreve adanmasına yol açtı. Kısmen açılmamış CORDIC çekirdeklerini kullanmak için akışı değiştirmeyi denedim, ancak daha sonra sürekli bir giriş / çıkış akışını korurken tekrarlanan döngüler gerçekleştirmek için çarpılmış bir saat frekansına ihtiyacım vardı. Bununla zamanlamayı karşılayamadım.

Şimdi alternatif bilgi işlem yollarına ulaşıyorum atan2(x,y).

İnterpolasyon ile blok-RAM arama tablolarını kullanmayı düşündüm, ancak 2 değişken olduğundan arama tablolarının 2 boyutuna ihtiyacım olacaktı ve bu blok-RAM kullanımı açısından çok kaynak yoğun.

Daha sonra kadran ayarlamasıyla atan2(x,y)ilgili gerçeği kullanmayı düşündüm atan(x/y). Buradaki sorun, sabit olmadığı için x/ygerçek bir bölünmeye ihtiyaç duyması yve FPGA'larda bölünmeler çok kaynak yoğun.

atan2(x,y)Bir FPGA üzerinde uygulamanın , daha düşük LUT kullanımına neden olacak, ancak yine de iyi bir doğruluk sağlayan daha yeni yolları var mı?


2
İşlem saat hızınız ve giriş veri hızınız nedir?
Jim Clay

İstediğiniz doğruluk nedir? Ayrıca sabit nokta hesaplaması kullandığınızı varsayıyorum. Hangi bit derinliğini kullanıyorsunuz? Çeyrek ayarlamalı bir polinom yaklaşımı (veya LUT) uygulanması yaygın bir yöntemdir atan2. Yine de bir bölüm olmadan geçip geçemeyeceğinizden emin değilim.
Jason R

Giriş saati 150MHz, giriş veri hızı 150 MSamps / sn'dir. Temelde her saat döngüsünde yeni bir girdi alıyorum. Gecikme süresi iyi, ama 150 MSamps / sn de bir çıkış üretmeliyim.
user2913869

Simülasyonlarım yaklaşık 1 * 10 ^ -9 ile yaşayabileceğimi gösteriyor. Mutlak minimum sabit nokta bitlerinden emin değilim, ancak Q10.32 sabit nokta biçimiyle simüle ediyorum
user2913869

Bu makalede , sabit nokta uygulaması açıklanmaktadır atan2. Yine de bir bölüme ihtiyacınız olacak.
Matt L.

Yanıtlar:


20

Bölme işleminden kurtulmak için logaritma kullanabilirsiniz. İçin (x,y) birinci kadran:

z=log2(y)log2(x)atan2(y,x)=atan(y/x)=atan(2z)

atan (2 ^ z)

Şekil 1. atan(2z)

Sen yaklaşık gerekir atan(2z) aralığında 30<z<30 1E-9'un sizin gerekli doğruluğu almak için. Atanmış simetriden yararlanabilirsiniz ( 2 - z ) = πatan(2z)=π2atan(2z)veya alternatif olarak(x,y)nin bilinen bir oktantta olduğundan emin olun. log2(a)yaklaşmak için:

b=floor(log2(a))c=a2blog2(a)=b+log2(c)

b , en anlamlı sıfır olmayan bitin yerini bularak hesaplanabilir. c , bir bit kaydırma ile hesaplanabilir. 1 c < 2 aralığındalog2(c) ye yaklaşmanız gerekir.1c<2

log 2 (c) '

Şekil 2. Log 2 ( c ) ' nin log2(c)

Doğruluk gereksinimleriniz için, doğrusal enterpolasyon ve düzgün örnekleme için, 0 < z < 30 için 214+1=16385log2(c) örnekleri ve 30×212+1=122881atan(2z) örnekleri yeterli olmalıdır. İkinci tablo oldukça büyük. Bununla birlikte, enterpolasyondan kaynaklanan hata büyük ölçüde z'ye bağlıdır :0<z<30z

Atanma hatası (2 ^ z) yaklaşımı

Şekil 3. atan(2z) farklı aralıklarını yaklaşım büyük mutlak hata z birim aralığı başına örneklerin farklı sayıda (8192 32) için (yatay eksen) z . 0z<1 (atlanmış) için en büyük mutlak hata, floor(log2(z))=0 biraz daha azdır ( log 2 ( z ) ) = 0 .

atan(2z) Tablo tekabül için birden çok subtables yarık olabilir 0z<1 ve farklı floor(log2(z)) ile z1 hesaplamak kolaydır. Tablo uzunlukları, Şekil 3'te gösterildiği gibi seçilebilir. İç-alt indeks, basit bir bit dizisi manipülasyonu ile hesaplanabilir. Senin doğruluk gereksinimleri için atan(2z) Eğer aralığını uzatmak eğer subtables 29217 numunelerin toplam sahip olacak z için 0z<32basitlik için z < 32 .

Daha sonra başvurmak için, yaklaşık hataları hesaplamak için kullandığım hantal Python betiği:

from numpy import *
from math import *
N = 10
M = 20
x = array(range(N + 1))/double(N) + 1
y = empty(N + 1, double)
for i in range(N + 1):
    y[i] = log(x[i], 2)

maxErr = 0
for i in range(N):
    for j in range(M):
        a = y[i] + (y[i + 1] - y[i])*j/M
        if N*M < 1000: 
            print str((i*M + j)/double(N*M) + 1) + ' ' + str(a)
        b = log((i*M + j)/double(N*M) + 1, 2)
        err = abs(a - b)
        if err > maxErr:
            maxErr = err

print maxErr

y2 = empty(N + 1, double)
for i in range(1, N):
    y2[i] = -1.0/16.0*y[i-1] + 9.0/8.0*y[i] - 1.0/16.0*y[i+1]


y2[0] = -1.0/16.0*log(-1.0/N + 1, 2) + 9.0/8.0*y[0] - 1.0/16.0*y[1]
y2[N] = -1.0/16.0*y[N-1] + 9.0/8.0*y[N] - 1.0/16.0*log((N+1.0)/N + 1, 2)

maxErr = 0
for i in range(N):
    for j in range(M):
        a = y2[i] + (y2[i + 1] - y2[i])*j/M
        b = log((i*M + j)/double(N*M) + 1, 2)
        if N*M < 1000: 
            print a
        err = abs(a - b)
        if err > maxErr:
            maxErr = err

print maxErr

y2[0] = 15.0/16.0*y[0] + 1.0/8.0*y[1] - 1.0/16.0*y[2]
y2[N] = -1.0/16.0*y[N - 2] + 1.0/8.0*y[N - 1] + 15.0/16.0*y[N]

maxErr = 0
for i in range(N):
    for j in range(M):
        a = y2[i] + (y2[i + 1] - y2[i])*j/M
        b = log((i*M + j)/double(N*M) + 1, 2)
        if N*M < 1000: 
            print str(a) + ' ' + str(b)
        err = abs(a - b)
        if err > maxErr:
            maxErr = err

print maxErr

P = 32
NN = 13
M = 8
for k in range(NN):
    N = 2**k
    x = array(range(N*P + 1))/double(N)
    y = empty((N*P + 1, NN), double)
    maxErr = zeros(P)
    for i in range(N*P + 1):
        y[i] = atan(2**x[i])

    for i in range(N*P):
        for j in range(M):
            a = y[i] + (y[i + 1] - y[i])*j/M
            b = atan(2**((i*M + j)/double(N*M)))
            err = abs(a - b)
            if (i*M + j > 0 and err > maxErr[int(i/N)]):
                maxErr[int(i/N)] = err

    print N
    for i in range(P):
        print str(i) + " " + str(maxErr[i])    

Bir fonksiyon yaklaşan yerel maksimum hata f(x) lineer interpolasyon ile f ( x ) numunelerinden f ( x ) , ara örnekleme ile homojen numune alınan Δ X ile analitik olarak yaklaşık olarak hesaplanabilir:f^(x)f(x)Δx

f^(x)f(x)(Δx)2limΔx0f(x)+f(x+Δx)2f(x+Δx2)(Δx)2=(Δx)2f(x)8,

burada , in ikinci türevidir ve , mutlak hatanın yerel maksimumundadır. Yukarıdakilerle yaklaşık değerleri elde ederiz:f(x)f(x)x

atan^(2z)atan(2z)(Δz)22z(14z)ln(2)28(4z+1)2,log2^(a)log2(a)(Δa)28a2ln(2).

İşlevler içbükey ve örnekler işlevle eşleştiğinden, hata her zaman bir yöndedir. Hatanın işareti her örnekleme aralığında bir kez ileri geri değişmek için yapılırsa, yerel maksimum mutlak hata yarıya indirilebilir. Doğrusal enterpolasyon ile, her tablonun önceden filtrelenmesiyle optimum sonuçlara yakın olarak elde edilebilir:

y[k]={b0x[k]+b1x[k+1]+b2x[k+2]if k=0,c1x[k1]+c0x[k]+c1x[k+1]if 0<k<N,b2x[k2]+b1x[k1]+b0x[k]if k=N,

burada ve orijinaldir ve filtrelenmiş tablo hem hem de ağırlıkları . Uç koşullandırma (yukarıdaki denklemdeki ilk ve son satır), tablonun dışındaki fonksiyon örneklerine kıyasla tablonun uçlarındaki hatayı azaltır, çünkü ilk ve son örneğin enterpolasyondan kaynaklanan hatayı azaltmak için ayarlanması gerekmez ve masanın hemen dışındaki bir örnek arasında. Farklı örnekleme aralıklarına sahip alt tablolar ayrı olarak önceden filtrelenmelidir. ağırlıklarının değerleri, üs arttırmak için sırayla en aza bulunduxy0kNc0=98,c1=116,b0=1516,b1=18,b2=116c0,c1N yaklaşık hatanın maksimum mutlak değeri:

(Δx)NlimΔx0(c1f(xΔx)+c0f(x)+c1f(x+Δx))(1a)+(c1f(x)+c0f(x+Δx)+c1f(x+2Δx))af(x+aΔx)(Δx)N={(c0+2c11)f(x)if N=0,|c1=1c020if N=1,1+aa2c02(Δx)2f(x)if N=2,|c0=98

örnekler arası enterpolasyon pozisyonları için , içbükey veya dışbükey fonksiyon (örneğin ). Çözülen bu ağırlıklar ile, uç koşullandırma ağırlıklarının maksimum mutlak değerini en aza indirerek bulundu:0a<1f(x)f(x)=exb0,b1,b2

(Δx)NlimΔx0(b0f(x)+b1f(x+Δx)+b2f(x+2Δx))(1a)+(c1f(x)+c0f(x+Δx)+c1f(x+2Δx))af(x+aΔx)(Δx)N={(b0+b1+b21+a(1b0b1b2))f(x)if N=0,|b2=1b0b1(a1)(2b0+b12)Δxf(x)if N=1,|b1=22b0(12a2+(2316b0)a+b01)(Δx)2f(x)if N=2,|b0=1516

için . Yaklaşık ön filtrenin kullanılması yaklaşıklık hatasını yarıya indirir ve tabloların tam optimizasyonundan daha kolaydır.0a<1

Ön filtre ve son koşullama ile ve olmadan yaklaşık hata

Şekil 4. 11 numuneden 'nın ön ve filtresiz ve son şartlandırmasız ve sonlandırmasız yaklaşım hatası . Uç koşullandırma olmadan ön filtre, tablonun hemen dışındaki işlevin değerlerine erişebilir.log2(a)

Bu makale muhtemelen çok benzer bir algoritma sunmaktadır: R. Gutierrez, V. Torres ve J. Valls, “ atanan (Y / X) logaritmik dönüşüm ve LUT tabanlı tekniklere dayalı FPGA uygulaması,Journal of Systems Architecture , cilt . Özet, uygulamalarının hızda önceki CORDIC tabanlı algoritmaları ve ayak izi boyutunda LUT tabanlı algoritmaları geçtiğini söylüyor.


3
Matthew Gambrell ve ben 1985 Yamaha YM3812 ses yongasını (mikroskopi ile) tersine değiştirdik ve içinde benzer log / exp salt okunur bellek (ROM) tablolarını bulduk. Yamaha, her bir tablodaki her ikinci girişi bir önceki girişe göre bir farkla değiştirmek için ek bir hile kullanmıştı. Düzgün işlevler için fark, işlevden daha az bit ve yonga alanı temsil eder. Çip üzerinde, önceki girişe fark eklemek için kullanabildikleri bir toplayıcı zaten vardı.
Olli Niemitalo

3
Çok teşekkür ederim! Matematiksel özelliklerin bu tür istismarlarını seviyorum. Kesinlikle bunun bazı MATLAB sim'lerini geliştireceğim ve her şey iyi görünüyorsa HDL'ye geçin. Her şey bittiğinde AÜSS tasarruflarımı rapor edeceğim.
user2913869

Açıklamanızı bir rehber olarak kullandım ve LUT'lar tarafından neredeyse% 60 oranında azaldığım için mutluyum. BRAM'ları azaltmaya ihtiyacım vardı, bu yüzden tek tip olmayan örnekleme yaparak ATAN masamda tutarlı bir maksimum hata elde edebileceğimi anladım: sıfır, örnekleme ne kadar hızlı olursa. Tablo aralıklarını 2'nin gücü olarak seçtim, böylece hangi aralıkta olduğumu kolayca tespit edebilir ve bit manipülasyonu ile otomatik tablo indeksleme yapabilirim. Ayrıca atanmış simetri uyguladım, bu yüzden dalga formunun sadece yarısını sakladım.
user2913869

Ayrıca, bazı düzenlemelerinizi kaçırmış olabilirim, ancak 2 ^ z'yi 2 ^ {if} = 2 ^ i * 2 ^ {0.f} 'ye böldüm, burada i tamsayı bölümü ve f fraksiyonel kısım. 2 ^ i basit, sadece bit manipülasyonu ve 2 ^ {0.f} sınırlı bir aralığa sahipti, bu yüzden enterpolasyon ile LUT'a iyi ödünç verdi. Olumsuz durumu da ele aldım: 2 ^ {- if} = 2 ^ {- i} * 1 / (2 ^ {0.f}. 1/2 ^ {0.f} için bir tablo daha. . bunun şey Cheers bu tür için mükemmel bir aday dalga olacak gibi görünüyor gibi log 2 (y) olan versiyonlarını 2 arasında değişen / düzgün olmayan örnekleme gücünü uygulamak olabilir!
user2913869

1
Lol yup o adımı tamamen kaçırdım. Bunu şimdi deneyeceğim. Beni daha da fazla LUT ve daha fazla BRAM kurtaracak
user2913869
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.