2025-01-09 7:19 AM - edited 2025-01-09 7:26 AM
2025-02-25 7:27 PM
Nothing ? Was my exposé too long ? :confounded_face:
Well, having no response at all, and the CORDIC phase calculations still returning gibberish
I had to implement the CORDIC atan2 on the sensor side ( hosted by a measly CH32V003, but it manages to push out samples at 25Ksps, so I'm not complaining -yet- )
Here's the function code, for those interested : its crude, unoptimized, but gets the job done :
/** @brief Returns the angle of a cartesian coordinate relative to zero, expressed in the range [-1.0; 1.0]
* @PAram y,x Q15 signed numbers representing the sine and cosine components of the angle to be returned. */
*/
int16_t cordic_atan2_q15(int16_t y, int16_t x)
{
// Handle special cases where x or y is zero
if (x == 0 && y == 0) {
return 0;
}
if (x == 0) {
return (y > 0) ? 16384 : -16384; // π/2 or -π/2 in scaled Q15
}
if (y == 0) {
return (x > 0) ? 0 : 32767; // 0 or π (clamped to 32767)
}
// Determine the quadrant and take absolute values of x and y
int quadrant;
int16_t abs_x = abs(x);
int16_t abs_y = abs(y);
if (x > 0 && y > 0) {
quadrant = 0;
} else if (x < 0 && y > 0) {
quadrant = 1;
} else if (x < 0 && y < 0) {
quadrant = 2;
} else {
quadrant = 3;
}
// CORDIC algorithm in vectoring mode
int32_t x32 = (int32_t)abs_x;
int32_t y32 = (int32_t)abs_y;
int32_t z = 0;
// Precomputed atan_table in scaled Q15 (atan(2^-i)/π * 32768), rounded to nearest integer
static const int16_t atan_table[] = { 8192, 4836, 2555, 1297, 650, 326, 163, 81, 41, 20, 10, 5, 3, 1 };
const int num_iterations = sizeof(atan_table) / sizeof(atan_table[0]);
for (int i = 0; i < num_iterations; ++i) {
int32_t x_shifted = x32 >> i;
int32_t y_shifted = y32 >> i;
if (y32 >= 0) {
x32 += y_shifted;
y32 -= x_shifted;
z += atan_table[i];
} else {
x32 -= y_shifted;
y32 += x_shifted;
z -= atan_table[i];
}
}
// Adjust the angle based on the original quadrant
int32_t adjusted_angle;
switch (quadrant) {
case 0:
adjusted_angle = z;
break;
case 1:
adjusted_angle = 32768L - z;
break;
case 2:
adjusted_angle = z - 32768L;
break;
case 3:
adjusted_angle = -z;
break;
default:
adjusted_angle = 0;
break;
}
// Clamp the result to the valid Q15 range [-32768, 32767]
if (adjusted_angle > 32767) {
adjusted_angle = 32767;
} else if (adjusted_angle < -32768) {
adjusted_angle = -32768;
}
return (int16_t)adjusted_angle;
}
Hope it helps. Never got the CORDIC coprocessor to work correctly anyway. :sad_but_relieved_face: