Computing muscle fiber lengths using the Python API.
Posted: Sun Jan 14, 2018 4:06 pm
Hi all,
I am using OpenSim 4.0 API (Python) in order to calculate muscle length changes given a state trajectory (sequence of coordinate values through a motion file). As a first test, I used the Arm26 model and the motion file within to verify if my results match. The model can be found at '<source>/Models/Arm26/arm26.osim' and the motion file I use can be found at '<source>/Models/Arm26/OutputReference/InverseKinematics/arm26_InverseKinematics.mot'.
1. In order to compute the muscle lengths at each time point in the motion file, I use the Analyze->MuscleAnalysis tool through the OpenSim 3.3 GUI, and solve for equilibrium states which generates a file 'arm26_MuscleAnalysis_FiberLength.sto'. Now, using the following code, I compute the same through the Python API:
Here, I step through each time point, update the coordinate values, assemble the kinematics of the state and use the equilibriateMuscles() routine to find the muscle states. Is this a sensible way to proceed? This gives me almost identical results to the fiber length values obtained through the GUI. However, when I modify the motion file to discard 'r_elbow_flexion' and only keep 'r_shoulder_elev', I notice a clear difference in the computed muscle lengths. But I do not know why this is so!
Figure 1: Muscle analysis through the GUI vs through the API. (Left) When the specified motion file has values for both coordinates: 'r_shoulder_elv' and 'r_elbow_flexion'. Notice that the results obtained through MuscleAnalysis from GUI and through my code overlap almost perfectly (there are two lines, on top of each other)! (Right) The specified motion file only has values for 'r_shoulder_elv'. Notice now that the fiber-length curves are not identical, but only so for one of the muscles. <Sorry for not creating dashed lines for easier comparison (like in Figure 2)> the top blue line with two bumps is obtained through my code above, while the bottom line is obtained through the Analyze tool.
When I repeat this with the Stanford VA UpperLimb model, where I specify values for only 4 coordinates, things are much worse and very different from the results I obtain using the GUI.
2. Apart from this, I also noticed that using the plot tool's motion curves (where one can specify a motion file associated with the model to plot muscle length variations) gives quantitatively different values for the muscle lengths, although the fiber-length vs time curves look qualitatively similar. Why could this be so?
Any help is much appreciated.
Thanks a lot.
I am using OpenSim 4.0 API (Python) in order to calculate muscle length changes given a state trajectory (sequence of coordinate values through a motion file). As a first test, I used the Arm26 model and the motion file within to verify if my results match. The model can be found at '<source>/Models/Arm26/arm26.osim' and the motion file I use can be found at '<source>/Models/Arm26/OutputReference/InverseKinematics/arm26_InverseKinematics.mot'.
1. In order to compute the muscle lengths at each time point in the motion file, I use the Analyze->MuscleAnalysis tool through the OpenSim 3.3 GUI, and solve for equilibrium states which generates a file 'arm26_MuscleAnalysis_FiberLength.sto'. Now, using the following code, I compute the same through the Python API:
Code: Select all
# Load the corresponding opensim model and motion file; initialize.
arm26 = osim.Model("C:/OpenSim 3.3/Models/Arm26/arm26.osim")
motion_filepath = "C:/OpenSim 3.3/Models/Arm26/OutputReference/InverseKinematics/arm26_InverseKinematics.mot"
init_state = arm26.initSystem()
# Declare generalized coordinate values for the trajectory
gen_coordinates = osim.STOFileAdapter.read(motion_filepath) # returns a TimeSeriesTable object
num_timepoints = gen_coordinates.getNumRows()
num_coordinates = gen_coordinates.getNumColumns()
muscle_set = arm26.getMuscles()
num_muscles = muscle_set.getSize()
# Compute muscle lengths at each time point in the motion by updating the state
musclelengths = np.zeros((num_muscles,num_timepoints))
for timepoint in range(num_timepoints):
for i in range(num_coordinates): # I make sure that the order of specifying generalized coordinates is preserved
arm26.getCoordinateSet().get(i).setValue(init_state,
np.radians(gen_coordinates.getDependentColumnAtIndex(i)[timepoint]), False)
arm26.assemble(init_state)
arm26.equilibrateMuscles(init_state)
for muscle_num in range(num_muscles):
muscle = muscle_set.get(muscle_num)
musclelengths[muscle_num, timepoint] = muscle.getFiberLength(init_state)
Figure 1: Muscle analysis through the GUI vs through the API. (Left) When the specified motion file has values for both coordinates: 'r_shoulder_elv' and 'r_elbow_flexion'. Notice that the results obtained through MuscleAnalysis from GUI and through my code overlap almost perfectly (there are two lines, on top of each other)! (Right) The specified motion file only has values for 'r_shoulder_elv'. Notice now that the fiber-length curves are not identical, but only so for one of the muscles. <Sorry for not creating dashed lines for easier comparison (like in Figure 2)> the top blue line with two bumps is obtained through my code above, while the bottom line is obtained through the Analyze tool.
When I repeat this with the Stanford VA UpperLimb model, where I specify values for only 4 coordinates, things are much worse and very different from the results I obtain using the GUI.
2. Apart from this, I also noticed that using the plot tool's motion curves (where one can specify a motion file associated with the model to plot muscle length variations) gives quantitatively different values for the muscle lengths, although the fiber-length vs time curves look qualitatively similar. Why could this be so?
Any help is much appreciated.
Thanks a lot.