How can I generate the sequence of Kvalues for CORDIC?

70 Views Asked by At

I am trying to implement CORDIC in C. I have to generate the constant values that the algorithm uses. The first list of arctangent values was straightforward but I am having trouble with the second list of 'Kvalues.'

% Kvalues = cumprod(1./sqrt(1 + 1j*2.^(-(0:23))))
Kvalues = [ ...
   0.70710678118655   0.63245553203368   0.61357199107790   0.60883391251775 ...
   0.60764825625617   0.60735177014130   0.60727764409353   0.60725911229889 ...
   0.60725447933256   0.60725332108988   0.60725303152913   0.60725295913894 ...
   0.60725294104140   0.60725293651701   0.60725293538591   0.60725293510314 ...
   0.60725293503245   0.60725293501477   0.60725293501035   0.60725293500925 ...
   0.60725293500897   0.60725293500890   0.60725293500889   0.60725293500888 ];

However I am not very familiar with this notation and I am having a hard time making sense of this and producing a simple formula that would produce the same results. I do not want to just paste these values into my CORDIC implementation because I would like to generate them myself with the appropriate amount of precision.

Here is what I came up with based on what I could understand but this does not produce the correct results:

float prev = 1;
for (int i = 0; i < PRECISION; i++)
    printf("%f\n", prev = prev/sqrt(1+pow(2, -i)));

I am expecting the same values I saw in the list from Wikipedia:

0.707106
0.632455
0.613571
0.608833
0.607648
0.607351

But with my formula they converge to 0.457942... instead of 0.607252...:

0.707107
0.577350
0.516398
0.486864
0.472328
0.465116

What is the correct formula in C to generate PRECISION 'Kvalues' for CORDIC?

2

There are 2 best solutions below

0
Craig Estey On BEST ANSWER

I tried a number of variations [not shown] by doing a websearch on CORDIC and looking at various pages.

From here: https://nonagon.org/ExLibris/cordic-c-javascript I got the formula:

prev = prev / sqrt(1 + (1.0 / pow(2, 2.0 * i)))

Ultimately, for your code, it was change:

pow(2, -i)

Into:

pow(2, -2.0 * i)

Here is the modified code that works:

#include <stdio.h>
#include <math.h>

#define PRECISION   6

#define CALL(_fnc) \
    do { \
        printf("\n" #_fnc "\n"); \
        _fnc(); \
    } while (0)

void
orig(void)
{
    double prev = 1.0;

    for (int i = 0; i < PRECISION; i++)
        printf("%f\n", prev = prev / sqrt(1 + pow(2, -i)));
}

void
fix1(void)
{
    float prev = 1;

    for (int i = 0; i < PRECISION; i++)
        printf("%f\n",prev = prev / sqrt(1 + pow(2, -2.0 * i)));
}

int
main(void)
{

    CALL(orig);
    CALL(fix1);

    return 0;
}

Here is the program output:


orig
0.707107
0.577350
0.516398
0.486864
0.472328
0.465116

fix1
0.707107
0.632456
0.613572
0.608834
0.607648
0.607352

I recommend using double instead of float and increasing the precision of the printf format (e.g. %.14f):

#include <stdio.h>
#include <math.h>

#define PRECISION   6

#define CALL(_fnc) \
    do { \
        printf("\n" #_fnc "\n"); \
        _fnc(); \
    } while (0)

void
orig(void)
{
    double prev = 1.0;

    for (int i = 0; i < PRECISION; i++)
        printf("%.14f\n", prev = prev / sqrt(1 + pow(2, -i)));
}

void
fix1(void)
{
    double prev = 1;

    for (int i = 0; i < PRECISION; i++)
        printf("%.14f\n",prev = prev / sqrt(1 + pow(2, -2.0 * i)));
}

int
main(void)
{

    CALL(orig);
    CALL(fix1);

    return 0;
}

Here is the enhanced output:


orig
0.70710678118655
0.57735026918963
0.51639777949432
0.48686449556015
0.47232793895472
0.46511640189705

fix1
0.70710678118655
0.63245553203368
0.61357199107790
0.60883391251775
0.60764825625617
0.60735177014130
1
CPlus On

It turns out that formula was using using the imaginary unit 1j and complex numbers to obtain the length of the vector. Another way is to simply use the Pythagorean theorem directly, which would drop the 1j part and square the 2.^(-(0:23)) term instead.

Doubling the base of the pow() achieves this effect:

float prev = 1;
for (int i = 0; i < PRECISION; i++)
    printf("%f\n", prev = prev/sqrt(1+pow(/* 2 */ 4, -i)));

Output:

0.707107
0.632456
0.613572
0.608834
0.607648
0.607352
...