Determining Muscle Forces From MOCO Solution

OpenSim Moco is a software toolkit to solve optimal control problems with musculoskeletal models defined in OpenSim using the direct collocation method.
POST REPLY
User avatar
Brodie Klosowski
Posts: 6
Joined: Sun Sep 10, 2023 8:00 pm

Determining Muscle Forces From MOCO Solution

Post by Brodie Klosowski » Sun Sep 29, 2024 11:24 pm

Hello,

I am trying to make sense of the outputted muscle forces from a tracking simulation I have run. As an example I will use the left soleus muscle.

My main question is, what does the value of /forceset/soleus_l represent? Is it the percentage of the maximum possible muscle force for that muscle or is it the actual force value in Newtons? I would imagine it would be the percentage of the maximum muscle force due to its magnitude and similarity to the activation but would like confirmation before continuing. Also I do not believe it is an issue with my simulation as I checked a solution provided in the Moco examples and it showed a similar trend. Image for reference:
Capture.PNG
Capture.PNG (34.8 KiB) Viewed 687 times
Cheers in Advance

User avatar
Pasha van Bijlert
Posts: 226
Joined: Sun May 10, 2020 3:15 am

Re: Determining Muscle Forces From MOCO Solution

Post by Pasha van Bijlert » Mon Sep 30, 2024 11:26 am

Hi Brodie,

Moco automatically adds a controller to each muscle when you run an optimization. It computes the control inputs (i.e., muscle excitation signals) or whatever problem you've defined. These are normalized (so between 0 &1, or perhaps bounded between 0.00001 & 1 or similar). Control input (or muscle excitations) result a change in muscle activation (or muscle active state) via 1st order dynamics. You can actually see this in your graph - the muscle's activation basically follows the excitatory input, but is slightly delayed and slightly smoother. Activate state is also bounded between 0 - 1. You can think of these both as percentages.

A Hill-type muscle's force depends on active state, length, and contraction velocity. What you're after is the output "normalized tendon force" (since force in the tendon should be equal to force in the muscle fiber, if the muscle is equilibriated). This will also be bounded between 0 - 1, where 1 represents maximal isometric force (F_max) in Newtons. So you need to plot each muscle's normalized tendon force multiplied by its F_max.

Cheers,
Pasha

User avatar
Brodie Klosowski
Posts: 6
Joined: Sun Sep 10, 2023 8:00 pm

Re: Determining Muscle Forces From MOCO Solution

Post by Brodie Klosowski » Thu Oct 03, 2024 12:43 am

Hi Pasha,

Thanks for the reply.

How would I go about finding the normalised tendon force? Would I need to change something in my simulation code in order for it to be included in the output?

Cheers in advance,
Brodie

User avatar
Ross Miller
Posts: 375
Joined: Tue Sep 22, 2009 2:02 pm

Re: Determining Muscle Forces From MOCO Solution

Post by Ross Miller » Fri Oct 04, 2024 3:15 am

Hi Brodie,

The solution matrix/file from a Moco solution (.sto file) includes the time-varying values of the model's states and controls. If the normalized_tendon_force variables Pasha mentioned are not in your simulation's solution, it probably means your model has rigid tendons, which means the tendon forces are not state variables (the forces are uniquely determined by muscle activations and joint kinematics).

There is surely a post-hoc analysis (e.g. "MuscleAnalysis" class, I would guess) that can compute the various fiber/tendon forces, but for those forces to be state variables in the solution, the tendons need to be set as non-rigid.

Hope this helps!
Ross

User avatar
Brodie Klosowski
Posts: 6
Joined: Sun Sep 10, 2023 8:00 pm

Re: Determining Muscle Forces From MOCO Solution

Post by Brodie Klosowski » Sun Oct 06, 2024 7:28 pm

Hello,

Wouldn't using this muscle analysis tool defeat the purpose of trying to find the muscle forces from the tracking simulation? Or am I misunderstanding this.

It just seems odd that almost every example simulation code I have seen uses the operator "ModOpIgnoreTendonCompliance" when doing this supposedly removes the ability to get the muscle forces from the simulation output.

Cheers

User avatar
Nicholas Bianco
Posts: 1041
Joined: Thu Oct 04, 2012 8:09 pm

Re: Determining Muscle Forces From MOCO Solution

Post by Nicholas Bianco » Mon Oct 07, 2024 12:57 pm

Hi Brodie,

You can use MocoStudy::analyze() to compute muscle forces from a MocoSolution. You need to provide the second argument "outputPaths", which is a list of paths to Outputs in the model for which you want to compute values. You can find the list of Muscle Outputs here. The Output path format is as follows: "/path/to/my_component|output_name".

Best,
Nick

User avatar
Brodie Klosowski
Posts: 6
Joined: Sun Sep 10, 2023 8:00 pm

Re: Determining Muscle Forces From MOCO Solution

Post by Brodie Klosowski » Mon Oct 07, 2024 10:17 pm

Hi Nicholas,

Thank you for that, this is what I am looking for I believe. Is there any chance you could please provide some formatting assistance for me?

I am using MATLAB for this project and I cannot find an example of how to use "MocoStudy::analyze()". I Have tried multiple set ups but whenever I try to use "analyze" MATLAB thinks I am trying to use the analyze function from the radio frequency (RF) toolbox which makes me think I am formatting it wrong. For refference, the code I have tried is:

clc; clear all; close all;

% Import Libraries
import org.opensim.modeling.*;

% Set up moco trajectory from Moco Solution .sto output
tracking_solution = 'gait_solution_single_stride.sto';
traj = MocoTrajectory(tracking_solution);

% Create Moco Study and problem
study = MocoStudy();
study.setName('muscle_force_collection');
problem = study.updProblem();

% Create and assign model processor to problem
modelProcessor = ModelProcessor('subject_walk_onlyNecessaryMarkers.osim');
problem.setModelProcessor(modelProcessor);

% Use study.analyze to find tendon forces
muscle_force = study.analyze(traj, '/forceset/vaslat_r/tendon_force');

%% Attempt at getting all tendon forces
all_muscle_forces = problem.analyze(traj, '.*tendon_force');

I have checked that my MATLAB path is to OpenSim yet I still get this error:

Capture2.PNG
Capture2.PNG (4.39 KiB) Viewed 444 times

Would greatly appreciate some help on this and thank you in advance.
Brodie

User avatar
Nicholas Bianco
Posts: 1041
Joined: Thu Oct 04, 2012 8:09 pm

Re: Determining Muscle Forces From MOCO Solution

Post by Nicholas Bianco » Wed Oct 09, 2024 8:56 pm

Hi Brodie,

The correct format in Matlab would be as follows:

Code: Select all

study = MocoStudy();
% your study configuration here
solution = study.solve();

outputPaths = StdVectorString();
outputPaths.add('/forceset/vaslat_r|tendon_force');
outputs = study.analyze(solution, outputPaths);
The "outputPaths" argument takes a vector or paths; here we need StdVectorString(), our Matlab interface's version of the C++ std::vector<std::string> type. Also note the use of the vertical bar character in the output path.

Best,
Nick

User avatar
Brodie Klosowski
Posts: 6
Joined: Sun Sep 10, 2023 8:00 pm

Re: Determining Muscle Forces From MOCO Solution

Post by Brodie Klosowski » Thu Oct 10, 2024 2:33 am

Hi Nicholas,

Thank you again. Just to clarify, do I need to change my original simulation (with all the set up, bounds, etc) to a MocoStudy instead of a MocoTrack and run it again in order to get these outputs? Or can I just set up a simple moco study (similar to what I did above) and use the solution I already have?

Cheers,
Brodie

User avatar
Nicholas Bianco
Posts: 1041
Joined: Thu Oct 04, 2012 8:09 pm

Re: Determining Muscle Forces From MOCO Solution

Post by Nicholas Bianco » Thu Oct 10, 2024 10:25 am

Hi Brodie,

MocoTrack is just a tool for configuring a MocoStudy for tracking optimization problems. You can access the internally configured MocoStudy using "initialize":

Code: Select all

track = MocoTrack();
% your tracking problem configuration

study = track.initialize();
solution = study.solve();

outputPaths = StdVectorString();
outputPaths.add('/forceset/vaslat_r|tendon_force');
outputs = study.analyze(solution, outputPaths);
Best,
Nick

POST REPLY