I guess it is not that hard, but I have been stuck on that one for a while.
I have a joint that can rotate both direction. A sensor gives me the angle of the joint in the range -pi and +pi.
I would like to convert it in the range -infinity and +infinity. Meaning that if for example the joint rotate clockwise forever, the angle would start at 0 and then increase to infinity. In matlab, the unwrap function does that very well:
newAngle = unwrap([previousAngle newAngle]);
previousAngle = newAngle;
Note: it is assumed the angle does not make big jump, nothing superior to PI for sure.
Note: I really looked hard before asking ...
Thanks !
Q = unwrap( P ) unwraps the radian phase angles in a vector P . Whenever the jump between consecutive angles is greater than or equal to π radians, unwrap shifts the angles by adding multiples of ±2π until the jump is less than π. If P is a matrix, unwrap operates columnwise.
Phase unwrap or unwrap is a process often used to reconstruct a signal's original phase. Unwrap algorithms add appropriate multiples of 2π to each phase input to restore original phase values, as illustrated in the diagram. For more information on the unwrap algorithm used by this block, see Unwrap Method.
Description. theta = angle( z ) returns the phase angle in the interval [-π,π] for each element of a complex array z . The angles in theta are such that z = abs(z). *exp(i*theta) .
// wrap to [-pi,pi]
inline double angle_norm(double x)
{
x = fmod(x + M_PI, M_2PI);
if (x < 0)
x += M_2PI;
return x - M_PI;
}
double phase_unwrap(double prev, double now)
{
return prev + angle_norm(now - prev);
}
This works.
After some work, came up with this. Seems to be working fine.
//Normalize to [-180,180):
inline double constrainAngle(double x){
x = fmod(x + M_PI,M_2PI);
if (x < 0)
x += M_2PI;
return x - M_PI;
}
// convert to [-360,360]
inline double angleConv(double angle){
return fmod(constrainAngle(angle),M_2PI);
}
inline double angleDiff(double a,double b){
double dif = fmod(b - a + M_PI,M_2PI);
if (dif < 0)
dif += M_2PI;
return dif - M_PI;
}
inline double unwrap(double previousAngle,double newAngle){
return previousAngle - angleDiff(newAngle,angleConv(previousAngle));
}
I used code from this post: Dealing with Angle Wrap in c++ code
The following function does the job, assuming the absolute difference between the input angles is less than 2*pi:
float unwrap(float previous_angle, float new_angle) {
float d = new_angle - previous_angle;
d = d > M_PI ? d - 2 * M_PI : (d < -M_PI ? d + 2 * M_PI : d);
return previous_angle + d;
}
If you need to unwrap an array, you can use this routine:
void unwrap_array(float *in, float *out, int len) {
out[0] = in[0];
for (int i = 1; i < len; i++) {
float d = in[i] - in[i-1];
d = d > M_PI ? d - 2 * M_PI : (d < -M_PI ? d + 2 * M_PI : d);
out[i] = out[i-1] + d;
}
}
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