FPGA에서 고정 소수점 atan2를 계산하는 방법


12

atan2(x,y)지속적인 입 / 출력 데이터 스트림을 사용하여 FPGA 에서 컴퓨팅해야 합니다. 롤링되지 않은 파이프 라인 된 CORDIC 커널을 사용하여 구현했지만 필요한 정확도를 얻으려면 32 번의 반복을 수행해야했습니다. 이로 인해 많은 양의 LUT가이 하나의 작업에 전념하게되었습니다. 부분적으로 롤링되지 않은 CORDIC 커널을 사용하도록 흐름을 변경하려고 시도했지만 계속적인 입력 / 출력 흐름을 유지하면서 반복 루프를 실행하기 위해 곱해진 클럭 주파수가 필요했습니다. 이것으로 타이밍을 맞출 수 없었습니다.

그래서 지금은 다른 컴퓨팅 방법을 찾고 atan2(x,y)있습니다.

보간과 함께 블록 RAM 조회 테이블을 사용하는 것에 대해 생각했지만 2 개의 변수가 있으므로 2 차원의 조회 테이블이 필요하며 이는 블록 RAM 사용 측면에서 리소스를 많이 사용합니다.

그런 다음 사분면 조정과 atan2(x,y)관련된 사실을 사용하는 것에 대해 생각했습니다 atan(x/y). 이것에 대한 문제 는 상수가 아니기 x/y때문에 진정한 분할 이 필요하며 yFPGA의 분할은 매우 자원 집약적이라는 것입니다.

atan2(x,y)낮은 LUT 사용을 초래하지만 여전히 우수한 정확도를 제공하는 FPGA 에 구현할 수있는 더 새로운 방법이 있습니까?


2
처리 클럭 속도와 입력 데이터 속도는 무엇입니까?
Jim Clay

필요한 정확도는 무엇입니까? 나는 또한 고정 소수점 계산을 사용한다고 가정합니다. 어떤 비트 심도를 사용하고 있습니까? 사분면 조정을 사용한 다항식 근사 (또는 LUT)는 구현하는 일반적인 방법 atan2입니다. 그러나 부서없이 갈 수 있는지 확실하지 않습니다.
Jason R

입력 클럭은 150MHz이고 입력 데이터 속도는 150MSamps / sec입니다. 기본적으로 클럭 사이클마다 새로운 입력을 얻습니다. 대기 시간은 좋지만 초당 150MSamps로 출력해야합니다.
user2913869

내 시뮬레이션은 약 1 * 10 ^ -9로 살 수 있음을 보여줍니다. 절대 최소 고정 소수점 비트는 확실하지 않지만 Q10.32 고정 소수점 형식으로 시뮬레이션했습니다.
user2913869

이 기사에서는 의 고정 소수점 구현에 대해 설명합니다 atan2. 그래도 여전히 부서가 필요합니다.
Matt L.

답변:


20

로그를 사용하여 나누기를 제거 할 수 있습니다. 옵션 (x,y) 제 사분면 :

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

아탄 (2 ^ z)

도 1의 플롯 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

아탄 (2 ^ z) 근사치의 오차

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

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

나중에 참조 할 수 있도록 근사 오류를 계산하는 데 사용 된 이상한 파이썬 스크립트는 다음과 같습니다.

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,

여기서 는 의 2 차 미분 이고 는 절대 오차의 극대값입니다. 위와 같이 근사값을 얻습니다.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).

함수가 오목하고 샘플이 함수와 일치하기 때문에 오류는 항상 한 방향입니다. 샘플링 간격마다 한 번씩 에러의 부호가 번갈아 바뀌면 로컬 최대 절대 오차가 절반으로 줄어들 수 있습니다. 선형 보간을 사용하면 다음을 통해 각 테이블을 사전 필터링하여 최적의 결과에 근접 할 수 있습니다.

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

프리 필터 및 엔드 컨디셔닝 유무에 따른 근사 오차

그림 4. 프리 필터 유무에 따라 그리고 최종 컨디셔닝 유무에 관계없이 11 개 샘플에서 의 근사 오차 . 최종 컨디셔닝없이 프리 필터는 테이블 바로 바깥에서 기능 값에 액세스 할 수 있습니다.log2(a)

이 문서는 아마 매우 유사한 알고리즘을 제공한다 : R. 레즈, V. 토레스 및 J. 발스 '를 ATAN의 FPGA - 구현 (Y / X), 대수 변환 및 LUT 기반의 기술에 기초하여, " 시스템 아키텍처 저널 , 권 . 초록은 그들의 구현이 이전의 CORDIC 기반 알고리즘 속도보다 빠르며 LUT 기반 알고리즘은 풋 프린트 크기보다 뛰어납니다.


3
Matthew Gambrell과 저는 1985 년 Yamaha YM3812 사운드 칩 (현미경 검사)을 리버스 엔지니어링했으며 비슷한 log / exp 읽기 전용 메모리 (ROM) 테이블을 찾았습니다. Yamaha는 각 테이블의 두 번째 항목을 이전 항목과의 차이로 대체하는 추가 트릭을 사용했습니다. 부드러운 기능을 위해 차이는 기능보다 적은 비트와 칩 면적을 나타냅니다. 그들은 이미 칩에 가산기를 가지고 있었기 때문에 이전 항목에 차이를 더할 수있었습니다.
Olli Niemitalo

3
대단히 감사합니다! 나는 이런 종류의 수학적 속성을 좋아합니다. 나는 이것에 대한 MATLAB 시뮬레이션을 확실히 개발할 것이며 모든 것이 잘 보인다면 HDL로 넘어가십시오. 모든 것이 끝나면 LUT 절감액을 다시보고 할 것입니다.
user2913869

나는 당신의 설명을 가이드로 사용했으며 LUT에 의해 거의 60 % 줄어든 것을 기쁘게 생각합니다. 나는 BRAM을 줄일 필요가 있었으므로 불균일 샘플링을 수행하여 ATAN 테이블에서 일관된 최대 오류를 얻을 수 있다고 생각했습니다. 0은 샘플링 속도가 빠릅니다. 나는 테이블 범위를 2의 거듭 제곱으로 선택했기 때문에 내가 속한 범위를 쉽게 감지하고 비트 조작을 통해 자동 테이블 인덱싱을 수행 할 수 있습니다. 나는 atan 대칭도 적용하여 파형의 절반 만 저장했습니다.
user2913869

또한 편집 내용 중 일부를 놓쳤을 수도 있지만 2 ^ z를 2 ^ {if} = 2 ^ i * 2 ^ {0.f}로 나누면 2 ^ z를 구현할 수 있습니다. 여기서 i는 정수 부분이고 f는 소수 부분. 2 ^ i는 단순하고 비트 조작이 간단하며 2 ^ {0.f}의 범위는 제한되어 있으므로 보간을 통해 LUT에 적합합니다. 또한 2 ^ {-if} = 2 ^ {-i} * 1 / (2 ^ {0.f}이므로 1 / 2 ^ {0.f}에 대한 테이블이 하나 더 있습니다. 다음 단계 log2 (y) LUT에 2 개의 레인 징 / 비 균일 샘플링의 파워를 적용하는 것이 될 수 있습니다. 그것이 그런 종류의 완벽한 후보 파형 인 것처럼 보입니다.
user2913869

1
롤 yu 나는 그 단계를 완전히 놓쳤다. 나는 지금 그것을 시도 할 것입니다. 더 많은 LUT와 더 많은 BRAM을 절약해야합니다.
user2913869
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.