Как использовать функцию sin с фиксированной точкой в ​​Vivado HLS

Я вычисляю точку пересечения двух линий, заданных в полярной системе координат:

typedef ap_fixed<16,3,AP_RND> t_lines_angle;
typedef ap_fixed<16,14,AP_RND> t_lines_rho;

bool get_intersection(
        hls::Polar_< t_lines_angle, t_lines_rho>* lineOne,
        hls::Polar_< t_lines_angle, t_lines_rho>* lineTwo,
        Point* point)
{
    float angleL1 = lineOne->angle.to_float();
    float angleL2 = lineTwo->angle.to_float();
    t_lines_angle rhoL1 = lineOne->rho.to_float();
    t_lines_angle rhoL2 = lineTwo->rho.to_float();
    t_lines_angle ct1=cosf(angleL1);
    t_lines_angle st1=sinf(angleL1);
    t_lines_angle ct2=cosf(angleL2);
    t_lines_angle st2=sinf(angleL2);
    t_lines_angle d=ct1*st2-st1*ct2;

    // we make sure that the lines intersect
    // which means that parallel lines are not possible
    point->X = (int)((st2*rhoL1-st1*rhoL2)/d);
    point->Y = (int)((-ct2*rhoL1+ct1*rhoL2)/d);

    return true;
}

После синтеза для нашей FPGA я увидел, что 4 реализации синуса с плавающей запятой (и cos) занимают 4800 LUT на каждую реализацию, что в сумме составляет 19000 LUT для этих 4 функций. Я хочу уменьшить количество LUT, используя синус с фиксированной точкой. Я уже нашел реализацию CORDIC, но я не знаю, как его использовать. Вход функции - целое число, но у меня есть тип данных ap_fixed. Как я могу сопоставить это ap_fixed с целым числом? и как я могу сопоставить свою фиксированную точку 3.13 с требуемой фиксированной точкой 2.14?


person Jens    schedule 05.12.2017    source источник


Ответы (2)


С помощью одного из моих коллег я нашел довольно простое решение, которое не требует каких-либо написанных вручную реализаций или манипуляций с данными с фиксированной точкой:

используйте функции #include "hls_math.h" и hls::sinf() и hls::cosf().

Важно сказать, что вход функций должен быть ap_fixed<32, I>, где I <= 32. Выходные данные функций могут быть назначены различным типам, например, ap_fixed<16, I>

Пример:

void CalculateSomeTrig(ap_fixed<16,5>* angle, ap_fixed<16,5>* output)
{
    ap_fixed<32,5> functionInput = *angle;
    *output = hls::sinf(functionInput);
}

Потребление LUT:

В моем случае потребление LUT сократилось до 400 LUT на каждую реализацию функции.

person Jens    schedule 07.12.2017

Вы можете использовать битовую нарезку, чтобы получить дробную и целую части переменной ap_fixed, а затем манипулировать ими, чтобы получить новый ap_fixed. Возможно что-то вроде:

constexpr int max(int a, int b) { return a > b ? a : b; }

template <int W2, int I2, int W1, int I1>
ap_fixed<W2, I2> convert(ap_fixed<W1, I1> f)
{
    // Read fraction part as integer:
    ap_fixed<max(W2, W1) + 1, max(I2, I1) + 1> result = f(W1 - I1 - 1, 0);
    // Shift by the original number of bits in the fraction part
    result >>= W1 - I1;
    // Add the integer part
    result += f(W1 - 1, W1 - I1);
    return result;
}

Я плохо тестировал этот код, так что отнеситесь к нему с недоверием.

person haggai_e    schedule 07.12.2017