методы вычисления фиксированной точки atan2 на FPGA

12

Мне нужны вычисления atan2(x,y)на ПЛИС с непрерывным потоком данных ввода / вывода. Мне удалось реализовать это с использованием развернутых конвейерных ядер CORDIC, но для получения необходимой точности мне пришлось выполнить 32 итерации. Это привело к тому, что довольно большое количество LUT было посвящено этой единственной задаче. Я попытался изменить поток для использования частично развернутых ядер CORDIC, но затем мне потребовалась умноженная тактовая частота для выполнения повторяющихся циклов, при этом поддерживая непрерывный поток ввода / вывода. С этим я не смог уложиться в сроки.

Так что теперь я обращаюсь к альтернативным способам вычислений atan2(x,y).

Я думал об использовании таблиц поиска блочной ОЗУ с интерполяцией, но, поскольку есть две переменные, мне потребуются 2 измерения таблиц поиска, и это очень ресурсоемко с точки зрения использования блочной памяти.

Затем я подумал об использовании того факта, который atan2(x,y)связан atan(x/y)с корректировкой квадранта. Проблема заключается в том, что x/yтребуется истинное деление, поскольку yоно не является постоянным, а деления на ПЛИС очень ресурсоемки.

Существуют ли более новые способы реализации atan2(x,y)на ПЛИС, которые позволили бы снизить использование LUT, но при этом обеспечить хорошую точность?

user2913869
источник
2
Какова ваша тактовая частота обработки и ваша скорость ввода данных?
Джим Клэй,
Какая точность вам нужна? Я также предполагаю, что вы используете вычисления с фиксированной запятой. Какую битовую глубину вы используете? Полиномиальное приближение (или LUT) с корректировкой по квадранту является распространенным методом реализации atan2. Не уверен, что вы можете обойтись без разделения, хотя.
Джейсон Р
Входная тактовая частота составляет 150 МГц, скорость входных данных - 150 мс / с. В основном я получаю новый вход каждый такт. Задержка - это хорошо, но я также должен вывести на выходе 150 мс / с.
user2913869
Мои симуляции показывают, что я могу жить с 1 * 10 ^ -9. Не уверен, что абсолютные минимальные биты с фиксированной точкой, но я имитировал с форматом с фиксированной точкой
Q10.32
Эта статья объясняет реализацию с фиксированной запятой atan2. Вам все равно понадобится разделение.
Мэтт Л.

Ответы:

20

Вы можете использовать логарифмы, чтобы избавиться от деления. Для (x,y) в первом квадранте:

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

Atan (2 ^ г)

Рисунок 1. Участок atan(2z)

Вам потребуется приблизить atan(2z) в диапазоне 30<z<30 чтобы получить требуемую точность 1E-9. Вы можете воспользоваться симметрией atan(2z)=π2atan(2z)или, альтернативно, убедитесь, что(x,y)находится в известном октанте. Для приблизительногоlog2(a):

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

b можно рассчитать путем нахождения местоположения старшего значащего ненулевого бита. c может быть рассчитан по сдвигу битов. Вам нужно будет приблизитьlog2(c) в диапазоне1c<2 .

log2 (с)

Рисунок 2. Участок log2(c)

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

Ошибка приближения atan (2 ^ z)

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

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

Для дальнейшего использования вот неуклюжий скрипт Python, который я использовал для вычисления ошибок аппроксимации:

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,

где - вторая производная от а - локальный максимум абсолютной ошибки. С учетом вышеизложенного мы получаем приближения: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)

В этой статье, вероятно, представлен очень похожий алгоритм: Р. Гутьеррес, В. Торрес и Дж. Вальс, « FPGA-реализация atan (Y / X), основанная на логарифмическом преобразовании и методах, основанных на LUT », Journal of Systems Architecture , vol. , 56, 2010. В аннотации говорится, что их реализация превосходит предыдущие алгоритмы на основе CORDIC по скорости и алгоритмы на основе LUT по размеру занимаемой площади.

Олли Нимитало
источник
3
Мы с Мэтью Гамбреллом разработали звуковую микросхему Yamaha YM3812 1985 года (с помощью микроскопа) и нашли в ней аналогичные таблицы только для чтения / записи в ПЗУ. Yamaha использовала дополнительный прием, чтобы заменить каждую вторую запись в каждой таблице на разницу с предыдущей записью. Для гладких функций для разности требуется меньше битов и площади чипа, чем для функции. У них уже был сумматор на чипе, который они могли использовать, чтобы добавить разницу к предыдущей записи.
Олли Нимитало
3
Большое спасибо! Я люблю эти виды подвигов математических свойств. Я определенно разработаю несколько симов MATLAB для этого, и если все будет хорошо, перейдем к HDL. Я сообщу о своих сбережениях LUT, когда все будет сделано.
user2913869
Я использовал ваше описание в качестве руководства, и я рад, что я сократил LUT почти на 60%. У меня действительно была необходимость уменьшить BRAM, поэтому я понял, что могу получить непротиворечивую максимальную ошибку в своей таблице ATAN, выполнив неравномерную выборку: у меня было несколько LUT BRAM (все то же количество битов адреса), чем ближе к ноль, тем быстрее выборка. Я выбрал диапазон таблиц для степеней 2, чтобы я мог легко определить, в каком диапазоне я находился, и выполнять автоматическую индексацию таблиц с помощью битовых манипуляций. Я также применил атан-симметрию, поэтому сохранил только половину сигнала.
user2913869
Кроме того, я мог пропустить некоторые ваши правки, но мне удалось реализовать 2 ^ z, разделив его на 2 ^ {if} = 2 ^ i * 2 ^ {0.f}, где i - целочисленная часть, а f - дробная часть. 2 ^ i прост, всего лишь битовая манипуляция, а 2 ^ {0.f} имеет ограниченный диапазон, поэтому он хорошо подходит для LUT с интерполяцией. Я также обработал отрицательный случай: 2 ^ {- if} = 2 ^ {- i} * 1 / (2 ^ {0.f}. Итак, еще одна таблица для 1/2 ^ {0.f}. Мой следующий шаг может быть, применить мощность 2-х диапазонов / неравномерной выборки к логическим LUT (log2 (y)), так как кажется, что это будет идеальная форма сигнала кандидата для такого рода вещей. Приветствия!
user2913869
1
Я просто пропустил этот шаг. Я собираюсь попробовать это сейчас. Должно спасти меня еще больше LUT и еще больше BRAM
user2913869