opensim-org / opensim-core

SimTK OpenSim C++ libraries and command-line applications, and Java/Python wrapping.
https://opensim.stanford.edu
Apache License 2.0
796 stars 319 forks source link

JRA vs. ID #3426

Open mrrezaie opened 1 year ago

mrrezaie commented 1 year ago

Hello,

I think something is wrong with jointReaction tool and perhaps there is a bug here. In Rajagopal model, I removed all muscles, added a strong coordinate actuator for every free degree of freedom, ran SO tool (in this case, the output was exactly the same as ID tool) and in JRA tool, I chose to express intersegmental forces/moments of child body in joint child frame.

Firstly, since the knee flexion in this model occurs around X axis (the red one), I would expect to see "_mx" the same as ID, but the negated "_mz" partially matches it. image Moment_old This shows that the output of JRA is not expressed in the knee child frame.

Instead of using the jointReaction tool, I tested the internal functions (OpenSim API in Python) and rather than joint.getChildFrame().findBaseFrame() I used joint.get_frames(1) as the child physical frame. https://github.com/opensim-org/opensim-core/blob/68b37e1d2b327cdb7629f910d614ce45193d7272/OpenSim/Analyses/JointReaction.cpp#L326 Surprisingly, now the "_mx" and ID (in the knee joint) are in a same direction as expected. Also, the ankle moment in both ID and "_mz" are perfectly matched (please compare it with the above graph). Moment_new

Secondly, in any configurations/settings/setups, the intersegmental moments of knee and hip joints do not exactly match the output of inverse dynamics. What is wrong with that?

I'm looking forward to hearing from you. Mohammadreza

nickbianco commented 1 year ago

Hi @mrrezaie. Thank you for the report (and the very nice plots). Starting to take a look into this.

I think joint.get_frames(1) would return the same frame as &joint.getChildFrame() and not &joint.getChildFrame().findBaseFrame(). It would good to compare results from &joint.getChildFrame() too.

I think the main difference here is that ID reports moments for coordinates, where as JRA reports moments about frames. If the definition of a coordinate is relative to a frame, but slightly different from that frame (i.e., due to offsets or orientation differences), then you might observe different results between the two methods. Therefore, it would be helpful to understand clearly how these coordinates are defined relative to the associated frames.

mrrezaie commented 1 year ago

Hi @nickbianco. Thanks for your response. You are right, the output of joint.getChildFrame() is exactly the same as joint.get_frames(1).

Based on the above graphs and the below note from the documentation (OpenSim::Frame), I think joint.getChildFrame().findBaseFrame() is indeed the child body frame, not the joint's child frame. This proves why the negated "_mz" was the same as ID output for knee in the first graph.

Advanced: A Frame's Base Frame and Transform A base Frame is the most ancestral Frame (itself, its parent, grandparent, great-grandparent, etc, down the family tree) whose angular velocity is identical to this Frame.That is they belong to the same rigid spatial entity. For example, anatomical frames may be used to identify points of interest (muscle attachments) and joint connections on a body in a convenient way, but their movement is dictated by the body. That body, in this case, would be a base frame for any of the anatomical frames attached to the body including frames subsequently attached to the anatomical frames and so on. __

ID reports moments for coordinates, where as JRA reports moments about frames. If the definition of a coordinate is relative to a frame, but slightly different from that frame (i.e., due to offsets or orientation differences), then you might observe different results between the two methods.

I think I understand what you mean by "offsets or orientation differences" between coordinates and frame, please correct me: In each joint, the translation/rotation functions for coordinates (in SpatialTransform) make such differences. For instance, the parametrized rotational/translational coordinates in the walker_knee (the Rajagopal model):

https://user-images.githubusercontent.com/38867713/226145342-6813010d-77de-45b9-8fc5-42d1288e68c7.mp4

In the hip joint, however, there are none of these functions and I would expect to get identical moments for the coordinates, joint's child frame and the femur body frame, because all of them are in a same position/orientation. But as you saw the graphs, they were not identical.

[Also, both ID and SO were ran with same filtering (20Hz) and there was none for JRA.]

Thanks again.