1

I am calculating the intersection point of two lines given in the polar coordinate system:

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;
}

After synthesis for our FPGA I saw that the 4 implementations of the float sine (and cos) take 4800 LUTs per implementation, which sums up to 19000 LUTs for these 4 functions. I want to reduce the LUT count by using a fixed point sine. I already found a implementation of CORDIC but I am not sure how to use it. The input of the function is an integer but i have a ap_fixed datatype. How can I map this ap_fixed to integer? and how can I map my 3.13 fixed point to the required 2.14 fixed point?

Jens
  • 2,592
  • 2
  • 21
  • 41

2 Answers2

1

With the help of one of my colleagues I figured out a quite easy solution that does not require any hand written implementations or manipulation of the fixed point data:

use #include "hls_math.h" and the hls::sinf() and hls::cosf() functions.

It is important to say that the input of the functions should be ap_fixed<32, I> where I <= 32. The output of the functions can be assigned to different types e.g., ap_fixed<16, I>

Example:

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

LUT consumption:

In my case the consumption of LUT was reduced to 400 LUTs for each implementation of the function.

Jens
  • 2,592
  • 2
  • 21
  • 41
0

You can use bit-slicing to get the fraction and the integer parts of the ap_fixed variable, and then manipulate them to get the new ap_fixed. Perhaps something like:

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;
}

I haven't tested this code well, so take it with a grain of salt.

haggai_e
  • 4,689
  • 1
  • 24
  • 37