phương pháp tính điểm cố định atan2 trên FPGA


12

Tôi đang cần máy tính atan2(x,y)trên một đồ họa với luồng dữ liệu đầu vào / đầu ra liên tục. Tôi đã quản lý để thực hiện nó bằng các hạt nhân CORDIC không được kiểm soát, nhưng để có được độ chính xác tôi cần, tôi đã phải thực hiện 32 lần lặp. Điều này dẫn đến một lượng LUT khá lớn được dành cho một nhiệm vụ này. Tôi đã thử thay đổi luồng để sử dụng các hạt CORDIC chưa được kiểm soát một phần, nhưng sau đó tôi cần một tần số xung nhịp nhân để thực hiện các vòng lặp lặp lại trong khi vẫn duy trì luồng đầu vào / đầu ra liên tục. Với điều này, tôi không thể đáp ứng thời gian.

Vì vậy, bây giờ tôi đang tiếp cận với các cách khác nhau của máy tính atan2(x,y).

Tôi đã nghĩ về việc sử dụng các bảng tra cứu khối RAM với phép nội suy, nhưng vì có 2 biến nên tôi cần 2 chiều của bảng tra cứu và điều này rất tốn tài nguyên về mặt sử dụng RAM khối.

Sau đó tôi nghĩ về việc sử dụng thực tế có atan2(x,y)liên quan đến atan(x/y)điều chỉnh góc phần tư. Vấn đề với điều này là x/ycần một sự phân chia thực sự vì ykhông phải là một hằng số và các phân chia trên các GPU rất tốn tài nguyên.

Có cách nào mới hơn để thực hiện atan2(x,y)trên một đồ họa có thể dẫn đến việc sử dụng LUT thấp hơn, nhưng vẫn cung cấp độ chính xác tốt không?


2
Tốc độ đồng hồ xử lý của bạn và tốc độ dữ liệu đầu vào của bạn là gì?
Jim Clay

Độ chính xác mà bạn yêu cầu là gì? Tôi giả sử bạn cũng đang sử dụng tính toán điểm cố định. Độ sâu bit nào bạn đang sử dụng? Một xấp xỉ đa thức (hoặc LUT) với điều chỉnh góc phần tư là một phương pháp phổ biến để thực hiện atan2. Không chắc chắn nếu bạn có thể nhận được mà không có một bộ phận, mặc dù.
Jason R

Đồng hồ đầu vào là 150 MHz, tốc độ dữ liệu đầu vào là 150 MSamp / giây. Về cơ bản tôi nhận được một đầu vào mới mỗi chu kỳ đồng hồ. Có độ trễ là tốt, nhưng tôi cũng phải tạo ra một đầu ra ở 150 MSamp / giây.
dùng2913869

Mô phỏng của tôi cho thấy tôi có thể sống với khoảng 1 * 10 ^ -9. Không chắc chắn các bit điểm cố định tối thiểu tuyệt đối, nhưng tôi đã mô phỏng với định dạng điểm cố định
Q10.32

Bài viết này giải thích một triển khai điểm cố định atan2. Bạn vẫn sẽ cần một bộ phận mặc dù.
Matt L.

Câu trả lời:


20

Bạn có thể sử dụng logarit để thoát khỏi sự phân chia. Với (x,y) trong góc phần tư thứ nhất:

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

atan (2 ^ z)

Hình 1. Lô đất của atan(2z)

Bạn sẽ cần xấp xỉ atan(2z) trong phạm vi 30<z<30 để có độ chính xác cần thiết là 1E-9. Bạn có thể tận dụng atan đối xứng ( 2 - z ) = πatan(2z)=π2atan(2z)hoặc thay thế đảm bảo rằng(x,y)nằm trong một quãng tám đã biết. Để tính gần đúnglog2(a):

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

b có thể được tính bằng cách tìm vị trí của bit khác không có ý nghĩa nhất. c có thể được tính bằng một sự thay đổi bit. Bạn sẽ cần xấp xỉlog2(c) trong phạm vi1c<2 .

log2 (c)

Hình 2. Lô của log2(c)

Đối với các yêu cầu chính xác của bạn, nội suy tuyến tính và lấy mẫu thống nhất, 214+1=16385 mẫu của log2(c)30×212+1=122881 mẫu atan(2z) cho 0<z<30 đủ. Bảng sau khá lớn. Với nó, lỗi do nội suy phụ thuộc rất lớn vào z :

Lỗi xấp xỉ atan (2 ^ z)

Hình 3. Lỗi tuyệt đối lớn nhất xấp xỉ atan(2z) cho các phạm vi khác nhau của z (trục hoành) cho các số lượng mẫu khác nhau (32 đến 8192) trên mỗi đơn vị khoảng z . Lỗi tuyệt đối lớn nhất cho 0z<1 (bỏ qua) ít hơn một chút so với floor(log2(z))=0 .

Bảng atan(2z) có thể được chia thành nhiều phụ đề tương ứng với 0z<1 và các floor(log2(z)) khác nhau ( log 2 ( z ) ) với z1 , rất dễ tính toán. Độ dài bảng có thể được chọn theo hướng dẫn trong Hình 3. Chỉ số bên trong có thể được tính bằng thao tác chuỗi bit đơn giản. Đối với yêu cầu độ chính xác của bạn, các phụ đề atan(2z) sẽ có tổng số 29217 mẫu nếu bạn mở rộng phạm vi từ z đến 0z<32 vì đơn giản.

Để tham khảo sau, đây là tập lệnh Python cồng kềnh mà tôi đã sử dụng để tính toán các lỗi gần đúng:

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

Các lỗi tối đa địa phương từ xấp xỉ một hàm f(x) bằng tuyến tính nội suy f ( x ) từ các mẫu của f ( x ) , lấy bằng cách lấy mẫu thống nhất với lấy mẫu khoảng Δ x , có thể xấp xỉ phân tích theo: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,

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

Bởi vì các hàm là lõm và các mẫu khớp với hàm, nên lỗi luôn luôn theo một hướng. Lỗi tuyệt đối tối đa cục bộ có thể giảm đi một nửa nếu dấu hiệu lỗi được thực hiện để thay thế qua lại một lần sau mỗi khoảng thời gian lấy mẫu. Với phép nội suy tuyến tính, gần với kết quả tối ưu có thể đạt được bằng cách lọc trước mỗi bảng bằng cách:

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,

xy0kNc0=98,c1=116,b0=1516,b1=18,b2=116c0,c1N

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

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

0a<1

Lỗi xấp xỉ có và không có tiền lọc và điều hòa cuối

log2(a)

Bài viết này có thể trình bày một thuật toán rất giống nhau: R. Gutierrez, V. Torres, và J. Valls, “ nghệ FPGA thực hiện atan (Y / X) dựa trên sự biến đổi logarit và kỹ thuật LUT-based,Journal of Systems Kiến trúc , vol . 56, 2010. Bản tóm tắt cho biết việc triển khai của họ đánh bại các thuật toán dựa trên CORDIC trước đây về tốc độ và thuật toán dựa trên LUT ở kích thước dấu chân.


3
Matthew Gambrell và tôi đã thiết kế lại chip âm thanh Yamaha YM3812 1985 (bằng kính hiển vi) và tìm thấy trong đó các bảng ghi / chỉ đọc bộ nhớ (ROM) tương tự. Yamaha đã sử dụng một mẹo bổ sung để thay thế mỗi mục nhập thứ hai trong mỗi bảng bằng một sự khác biệt so với mục trước đó. Đối với các chức năng trơn tru, sự khác biệt cần ít bit và diện tích chip hơn so với chức năng. Họ đã có một bộ cộng trên chip mà họ có thể sử dụng để thêm sự khác biệt cho mục trước đó.
Olli Niemitalo 16/2/2016

3
Cảm ơn rât nhiều! Tôi yêu những kiểu khai thác thuộc tính toán học này. Tôi chắc chắn sẽ phát triển một số sim MATLAB về điều này, và nếu tất cả đều ổn, hãy chuyển sang HDL. Tôi sẽ báo cáo lại khoản tiết kiệm LUT của mình khi tất cả đã xong.
dùng2913869

Tôi đã sử dụng mô tả của bạn như một hướng dẫn và tôi rất vui khi biết rằng tôi đã giảm LUT gần 60%. Tôi đã có nhu cầu giảm BRAM, vì vậy tôi nhận ra rằng tôi có thể nhận được một lỗi tối đa nhất quán trên bảng ATAN của mình bằng cách lấy mẫu không đồng nhất: Tôi có nhiều LAM BRAM (tất cả cùng số bit địa chỉ), càng gần không, lấy mẫu càng nhanh. Tôi đã chọn phạm vi bảng của mình là lũy thừa 2 để tôi có thể dễ dàng phát hiện ra phạm vi nào tôi đang ở và thực hiện lập chỉ mục bảng tự động thông qua thao tác bit. Tôi cũng áp dụng tính đối xứng atan vì vậy tôi chỉ lưu trữ một nửa dạng sóng.
dùng2913869

Ngoài ra, tôi có thể đã bỏ lỡ một số chỉnh sửa của bạn, nhưng tôi đã quản lý để thực hiện 2 ^ z bằng cách chia nó thành 2 ^ {if} = 2 ^ i * 2 ^ {0.f}, trong đó i là phần nguyên và f là phần phân số. 2 ^ i rất đơn giản, chỉ cần thao tác bit và 2 ^ {0.f} có phạm vi giới hạn, do đó, nó cho vay chính xác để LUT với phép nội suy. Tôi cũng đã xử lý trường hợp tiêu cực: 2 ^ {- if} = 2 ^ {- i} * 1 / (2 ^ {0.f}. Vì vậy, thêm một bảng cho 1/2 ^ {0.f}. Bước tiếp theo của tôi có thể áp dụng sức mạnh của 2 mẫu / không đồng nhất trên các LUT log2 (y), vì có vẻ như đó sẽ là dạng sóng ứng cử viên hoàn hảo cho loại điều đó. Chúc mừng!
user2913869 19/2/2016

1
Lol yup tôi hoàn toàn bỏ lỡ bước đó. Tôi sẽ thử nó ngay bây giờ. Nên tiết kiệm cho tôi nhiều
LUT
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.