metode komputasi titik tetap atan2 pada FPGA

12

Saya membutuhkan komputasi atan2(x,y)pada FPGA dengan aliran input / output data yang berkelanjutan. Saya berhasil mengimplementasikannya menggunakan kernel CORDIC yang belum di-pipeline, tetapi untuk mendapatkan akurasi yang saya butuhkan, saya harus melakukan 32 iterasi. Hal ini menyebabkan sejumlah besar LUT dikhususkan untuk tugas yang satu ini. Saya mencoba mengubah aliran untuk menggunakan kernel CORDIC yang tidak dikontrol sebagian, tetapi kemudian saya membutuhkan frekuensi clock yang dikalikan untuk mengeksekusi loop berulang sambil tetap mempertahankan aliran input / output yang berkelanjutan. Dengan ini, saya tidak dapat menemukan waktu.

Jadi sekarang saya mencari cara komputasi alternatif atan2(x,y).

Saya berpikir tentang menggunakan tabel look-up blok-RAM dengan interpolasi, tetapi karena ada 2 variabel saya akan membutuhkan 2 dimensi tabel lookup, dan ini sangat sumber daya intensif dalam hal penggunaan block-RAM.

Saya kemudian berpikir untuk menggunakan fakta yang atan2(x,y)terkait atan(x/y)dengan penyesuaian kuadran. Masalahnya adalah ini x/yperlu pembagian yang benar karena ytidak konstan, dan pembagian pada FPGA sangat intensif sumber daya.

Apakah ada cara baru untuk menerapkan atan2(x,y)pada FPGA yang akan menghasilkan penggunaan LUT yang lebih rendah, tetapi masih memberikan akurasi yang baik?

pengguna2913869
sumber
2
Berapa laju jam pemrosesan Anda, dan laju input data Anda?
Jim Clay
Apa akurasi yang Anda butuhkan? Saya berasumsi juga Anda menggunakan perhitungan fixed-point. Apa kedalaman bit yang Anda gunakan? Pendekatan polinomial (atau LUT) dengan penyesuaian kuadran adalah metode yang umum untuk diterapkan atan2. Namun, tidak yakin apakah Anda bisa bertahan tanpa pembagian.
Jason R
Input clock adalah 150MHz, input data rate 150 MSamps / detik. Pada dasarnya saya mendapat input baru setiap siklus clock. Memiliki latensi baik-baik saja, tetapi saya harus menghasilkan output pada 150 MSamps / detik juga.
user2913869
Simulasi saya menunjukkan saya bisa hidup dengan sekitar 1 * 10 ^ -9. Tidak yakin bit titik tetap minimum absolut, tapi saya telah mensimulasikan dengan format titik tetap
Q10.32
Artikel ini menjelaskan implementasi titik tetap dari atan2. Anda masih akan membutuhkan pembagian.
Matt L.

Jawaban:

20

Anda dapat menggunakan logaritma untuk menyingkirkan divisi. Untuk (x,y) di kuadran pertama:

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

atan (2 ^ z)

Gambar 1. Plot atan(2z)

atan(2z)30<z<30atan(2z)=π2atan(2z)(x,y)log2(a)

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

bclog2(c)1c<2

log2 (c)

log2(c)

214+1=16385log2(c)30×212+1=122881atan(2z)0<z<30z

Kesalahan perkiraan atan (2 ^ z)

atan(2z)zz0z<1floor(log2(z))=0

atan(2z)0z<1floor(log2(z))z1atan(2z)z0z<32

Untuk referensi nanti, berikut ini adalah skrip Python kikuk yang saya gunakan untuk menghitung kesalahan aproksimasi:

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])    

f(x)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,

di mana adalah turunan kedua dari dan adalah maksimum lokal dari kesalahan absolut. Dengan yang di atas kita mendapatkan perkiraan: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).

Karena fungsinya cekung dan sampel cocok dengan fungsinya, kesalahan selalu ke satu arah. Kesalahan absolut maksimum lokal dapat dikurangi setengahnya jika tanda kesalahan dibuat bergantian bolak-balik setiap interval pengambilan sampel. Dengan interpolasi linier, hasil yang mendekati optimal dapat dicapai dengan memfilter setiap tabel dengan:

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,

di mana dan adalah asli dan tabel yang difilter mencakup rentang dan bobotnya adalah . Pengkondisian akhir (baris pertama dan terakhir dalam persamaan di atas) mengurangi kesalahan pada ujung tabel dibandingkan dengan menggunakan sampel fungsi di luar tabel, karena sampel pertama dan terakhir tidak perlu disesuaikan untuk mengurangi kesalahan dari interpolasi antara itu dan sampel di luar tabel. Subtabel dengan interval pengambilan sampel yang berbeda harus difilter secara terpisah. Nilai bobot ditemukan dengan meminimalkan secara berurutan untuk meningkatkan eksponenxy0kNc0=98,c1=116,b0=1516,b1=18,b2=116c0,c1N nilai absolut maksimum kesalahan perkiraan:

(Δ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

untuk posisi interpolasi antar sampel , dengan fungsi cekung atau cembung (misalnya ). Dengan bobot tersebut diselesaikan, nilai bobot akhir pengkondisian ditemukan dengan meminimalkan nilai absolut maksimum: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

untuk . Penggunaan prefilter tentang separuh kesalahan aproksimasi dan lebih mudah dilakukan daripada optimasi penuh tabel.0a<1

Kesalahan perkiraan dengan dan tanpa prefilter dan pengkondisian akhir

Gambar 4. Kesalahan perkiraan dari 11 sampel, dengan dan tanpa prefilter dan dengan dan tanpa pengkondisian akhir. Tanpa akhir pengkondisian prefilter memiliki akses ke nilai-nilai fungsi tepat di luar tabel.log2(a)

Artikel ini mungkin menyajikan algoritma yang sangat mirip: R. Gutierrez, V. Torres, dan J. Valls, " FPGA-implementasi atan (Y / X) berdasarkan transformasi logaritmik dan teknik berbasis LUT, " Journal of Systems Architecture , vol . 56, 2010. Abstrak mengatakan implementasi mereka mengalahkan algoritma berbasis CORDIC sebelumnya dalam kecepatan dan algoritma berbasis LUT dalam ukuran jejak.

Olli Niemitalo
sumber
3
Matthew Gambrell dan saya telah merekayasa balik chip suara Yamaha YM3812 1985 (dengan mikroskop) dan menemukan di dalamnya tabel log / exp read only memory (ROM) yang serupa. Yamaha telah menggunakan trik tambahan untuk mengganti setiap entri kedua di setiap tabel dengan perbedaan pada entri sebelumnya. Untuk fungsi yang halus, perbedaan membutuhkan lebih sedikit bit dan area chip untuk mewakili daripada fungsi. Mereka sudah memiliki penambah pada chip yang dapat mereka gunakan untuk menambahkan perbedaan pada entri sebelumnya.
Olli Niemitalo
3
Terima kasih banyak! Saya suka jenis eksploitasi properti matematika ini. Saya pasti akan mengembangkan beberapa MATLAB sims ini, dan jika semuanya terlihat baik, pindah ke HDL. Saya akan melaporkan kembali tabungan LUT saya setelah semuanya selesai.
user2913869
Saya menggunakan deskripsi Anda sebagai panduan dan saya senang tinggal bahwa saya dikurangi dengan LUTs hampir 60%. Saya memang memiliki kebutuhan untuk mengurangi BRAM, jadi saya tahu saya bisa mendapatkan kesalahan maks yang konsisten pada tabel ATAN saya dengan melakukan pengambilan sampel yang tidak seragam: Saya memiliki beberapa LUT BRAM (semua jumlah bit alamat yang sama), semakin dekat ke nol, semakin cepat pengambilan sampel. Saya memilih rentang tabel saya menjadi kekuatan 2 sehingga saya dapat dengan mudah mendeteksi rentang mana saya juga dan melakukan pengindeksan tabel otomatis melalui manipulasi bit. Saya menerapkan atan simetri juga jadi saya hanya menyimpan setengah bentuk gelombang.
user2913869
Juga, saya mungkin telah melewatkan beberapa suntingan Anda, tetapi saya berhasil menerapkan 2 ^ z dengan membaginya menjadi 2 ^ {jika} = 2 ^ i * 2 ^ {0.f}, di mana saya adalah bagian bilangan bulat dan f adalah bagian fraksional. 2 ^ i sederhana, hanya manipulasi bit, dan 2 ^ {0.f} memiliki jangkauan terbatas, jadi ia meminjamkan dirinya dengan baik ke LUT dengan interpolasi. Saya juga menangani kasus negatif: 2 ^ {- if} = 2 ^ {- i} * 1 / (2 ^ {0.f}. Jadi satu tabel lagi untuk 1/2 ^ {0.f}. Langkah saya selanjutnya mungkin untuk menerapkan kekuatan 2 mulai / non-seragam sampling pada log2 (y) LUT, seperti yang tampaknya seperti itu akan menjadi calon gelombang sempurna untuk hal semacam itu Ceria.!
user2913869
1
Lol ya saya benar-benar ketinggalan langkah itu. Saya akan mencobanya sekarang. Harus menyelamatkan saya lebih banyak LUT dan bahkan lebih banyak
BRAM