movement
movement copied to clipboard
Computing a (smooth) angular head velocity over time
Is your feature request related to a problem? Please describe. Right now to compute this one would: compute the polar angle of (user-defined) head vector, and then take the derivative.
But the output is probably noisy, we would need to think a bit more how this would be improved
- slerp maybe? - SM interested in trying
- Adam mentions scipy circular stats
- opendirection may be useful
I forgot, I also used to use: https://github.com/circstat/pycircstat
With #376 (this is my revival of #315, but still in draft), this can become a two step process:
from movement.kinematics import compute_heading_angle, compute_angle_time_derivative
head_angle = compute_heading_angle(ds.position, left_keypoint="left_ear", right_keypoint="right_ear")
angular_head_velocity = compute_angle_time_derivative(head_angle)
#376 just adds the first of these two functions. The envisioned 2nd function (not necessarily named as in the above example) should be added as a solution to this issue. That function should also provide some options for smoothing the derivative (see comments above).
See also @kiradust's excellent notes on circular statistics here.
As far as I can tell, scipy's directional stats submodule implements the "intrinsic" circular mean and variance (see Kira's notes for the difference between "extrinsic" and "intrinsic" circular means).
As far as I can tell, scipy's directional stats submodule implements the "intrinsic" circular mean and variance (see Kira's notes for the difference between "extrinsic" and "intrinsic" circular means).
Correction, after looking into scipy's source code, both me and Kira agree that they are actually computing the "extrinsic" mean.
Hi @niksirbi I have some suggestions for the compute_angle_time_derivative function, there are two ways to approach the smoothing problem: either by smoothing the angle time series first and then differentiating, or by computing the raw angular velocity.
delta_theta = (angles[t+1] - angles[t] + π) % (2π) - π.
For each pair of consecutive angles, compute the smallest angular difference to avoid wrap-around issues. This ensures the difference lies between -π and π, representing the shortest path on the circle. Then, divide by the time step dt to get velocity in radians per second.
I am curious about using the extrinsic mean here as it could introduce bias or edge cases when smoothing head angles, especially near the ±π boundary? If needed, I’d be happy to look into whether implementing an intrinsic mean (or supporting both) would make sense use case. Also, in the direction of compute_angle_time_derivative, I can help draft or test the smoothing logic with both mean types to see which works best under noisy conditions. let me know if there is any way I can provide value here. Thanks