#ifndef SEMQ_PHASE_ATAN2_H
#define SEMQ_PHASE_ATAN2_H
#include <math.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
#define SEMQ_PI 3.141592653589793238462643383279502884
#define SEMQ_PI_HALF 1.570796326794896619231321691639751442
#define SEMQ_PHASE_C1 0.9947660466480732
#define SEMQ_PHASE_C3 (-0.28543420102605926)
#define SEMQ_PHASE_C5 0.07606631777543432
static inline double semq_phase_atan_poly_unit(double t) {
const double t2 = t * t;
double r = SEMQ_PHASE_C5;
r = fma(r, t2, SEMQ_PHASE_C3);
r = fma(r, t2, SEMQ_PHASE_C1);
return r * t;
}
static inline double semq_phase_atan2_ref(float yf, float xf) {
const double y = (double)yf;
const double x = (double)xf;
const double ax = (x < 0.0) ? -x : x;
const double ay = (y < 0.0) ? -y : y;
if (ax == 0.0 && ay == 0.0) {
return 0.0;
}
double theta;
if (ax >= ay) {
theta = semq_phase_atan_poly_unit(ay / ax);
} else {
theta = SEMQ_PI_HALF - semq_phase_atan_poly_unit(ax / ay);
}
if (x < 0.0) {
theta = SEMQ_PI - theta;
}
if (y < 0.0) {
theta = -theta;
}
return theta;
}
static inline uint8_t semq_phase_sector(float yf, float xf, uint32_t n_bins) {
const double theta = semq_phase_atan2_ref(yf, xf);
const double scale = (double)n_bins / (2.0 * SEMQ_PI);
double raw = (theta + SEMQ_PI) * scale;
if (raw < 0.0) {
raw = 0.0;
}
int64_t s = (int64_t)raw;
if (s >= (int64_t)n_bins) {
s = (int64_t)n_bins - 1;
}
return (uint8_t)s;
}
#ifdef __cplusplus
}
#endif
#endif