I'm trying to implement an atan2-like function to map two input sinusoidal signals of arbitrary relative phase shift to a single output signal that linearly goes from 0
to 2π
. atan2
normally assumes two signals with a 90 deg phase shift.
y0(x) = sin(x)
and y1 = sin(x + phase)
, where phase
is a fixed non-zero value, how can I implement a way to return x
modulo 2π
?atan2
returns the angle of a 2d vector. Your code does not handle such scaling properly. But no worries, it's actually very easy to reduce your problem to an atan2
that would handle everything nicely.
Notice that calculating sin(x)
and sin(x + phase)
is the same as projecting a point (cos(x), sin(x))
onto the axes (0, 1)
and (sin(phase), cos(phase))
. This is the same as taking dot products with those axes, or transforming the coordinate system from the standard orthogonal basis into the skewed one. This suggests a simple solution: inverse the transformation to get the coordinates in the orthogonal basis and then use atan2
.
Here's a code that does that:
double super_atan2(double x0, double x1, double a0, double a1) {
double det = sin(a0 - a1);
double u = (x1*sin(a0) - x0*sin(a1))/det;
double v = (x0*cos(a1) - x1*cos(a0))/det;
return atan2(v, u);
}
double duper_atan2(double y0, double y1, double phase) {
const double tau = 6.28318530717958647692; // https://tauday.com/
return super_atan2(y0, y1, tau/4, tau/4 - phase);
}
super_atan2
gets the angles of the two projection axes, duper_atan2
solves the problem exactly as you stated.
Also notice that the calculation of det
is not strictly necessary. It is possible to replace it by fmod
and copysign
(we still need the correct sign of u
and v
).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With