API 4.4.1-2022-10-19-2c4045e59
For MATLAB, Python, Java, and C++ users
exampleEMGTracking_answers.py

This is an example that uses the MocoInverse tool and EMG data to create an EMG-driven simulation of walking.

1
2import opensim as osim
3import exampleEMGTracking_helpers as helpers
4import os
5import numpy as np
6
7
10
11# Part 1a: Load a 19 degree-of-freedom model with 18 lower-limb,
12# sagittal-plane muscles and a torque-actuated torso. This includes a set of
13# ground reaction forces applied to the model via ExternalLoads, which is
14# necessary for the muscle redundancy problem. See the function definition
15# at the bottom of this file to see how the model is loaded and constructed.
16model = helpers.getWalkingModel()
17
18# Part 1b: Create the MocoInverse tool and set the Model.
19inverse = osim.MocoInverse()
20inverse.setModel(model)
21
22# Part 1c: Create a TableProcessor using the coordinates file from inverse
23# kinematics.
24coordinates = osim.TableProcessor('coordinates.mot')
25coordinates.append(osim.TabOpLowPassFilter(6))
26coordinates.append(osim.TabOpUseAbsoluteStateNames())
27
28# Part 1d: Set the kinematics reference for MocoInverse using the
29# TableProcessor we just created.
30inverse.setKinematics(coordinates)
31inverse.set_kinematics_allow_extra_columns(True)
32
33# Part 1e: Provide the solver settings: initial and final time, the mesh
34# interval, and the constraint and convergence tolerances.
35inverse.set_initial_time(0.83)
36inverse.set_final_time(2.0)
37inverse.set_mesh_interval(0.04)
38inverse.set_constraint_tolerance(1e-3)
39inverse.set_convergence_tolerance(1e-3)
40
41if not os.path.isfile('effortSolution.sto'):
42 # Part 1f: Solve the problem!
43 inverseSolution = inverse.solve()
44 solution = inverseSolution.getMocoSolution()
45 solution.write('effortSolution.sto')
46
47
52emgReference = osim.TimeSeriesTable('emg.sto')
53helpers.compareSolutionToEMG(emgReference, 'effortSolution.sto')
54
55
58
59# Part 3a: Call initialize() to get access to the MocoStudy contained within
60# the MocoInverse instance. This will allow us to make additional
61# modifications to the problem not provided by MocoInverse.
62study = inverse.initialize()
63problem = study.updProblem()
64
65# Part 3b: Create a MocoControlTrackingGoal, set its weight, and provide
66# the EMG data as the tracking reference. We also need to specify the
67# reference labels for the four muscles whose EMG we will track.
68tracking = osim.MocoControlTrackingGoal('emg_tracking')
69tracking.setWeight(5)
70tracking.setReference(osim.TableProcessor(emgReference))
71tracking.setReferenceLabel('/forceset/gasmed_l', 'gastrocnemius')
72tracking.setReferenceLabel('/forceset/tibant_l', 'tibialis_anterior')
73tracking.setReferenceLabel('/forceset/bfsh_l', 'biceps_femoris')
74tracking.setReferenceLabel('/forceset/glmax2_l', 'gluteus')
75
76# Part 3c: The EMG signals in the tracking are all normalized to have
77# a maximum value of 1, but the magnitudes of the excitations from the
78# effort minimization solution suggest that these signals should be
79# rescaled. Use addScaleFactor() to add a MocoParameter to the problem that
80# will scale the reference data for the muscles in the tracking cost.
81tracking.addScaleFactor('gastroc_factor', '/forceset/gasmed_l', [0.01, 1.0])
82tracking.addScaleFactor('tibant_factor', '/forceset/tibant_l', [0.01, 1.0])
83tracking.addScaleFactor('bifem_factor', '/forceset/bfsh_l', [0.01, 1.0])
84tracking.addScaleFactor('gluteus_factor', '/forceset/glmax2_l', [0.01, 1.0])
85
86# Part 3d: Add the tracking goal to the problem.
87problem.addGoal(tracking)
88
89# Part 3e: Update the MocoCasADiSolver with the updated MocoProblem using
90# resetProblem().
91solver = osim.MocoCasADiSolver.safeDownCast(study.updSolver())
92solver.resetProblem(problem)
93
94# Part 3f: Tell MocoCasADiSolver that the MocoParameters we added to the
95# problem via addScaleFactor() above do not require initSystem() calls on
96# the model. This provides a large speed-up.
97solver.set_parameters_require_initsystem(False)
98
99if not os.path.isfile('trackingSolution.sto'):
100 # Part 3g: Solve the problem!
101 solution = study.solve()
102 solution.write('trackingSolution.sto')
103
104# Part 3h: Get the values of the optimized scale factors.
105trackingSolution = osim.MocoTrajectory('trackingSolution.sto')
106gastroc_factor = trackingSolution.getParameter('gastroc_factor')
107tibant_factor = trackingSolution.getParameter('tibant_factor')
108bifem_factor = trackingSolution.getParameter('bifem_factor')
109gluteus_factor = trackingSolution.getParameter('gluteus_factor')
110
111
113print('\nOptimized scale factor values:')
114print('------------------------------')
115print('gastrocnemius = ' + str(gastroc_factor))
116print('tibialis anterior = ' + str(tibant_factor))
117print('biceps femoris short head = ' + str(bifem_factor))
118print('gluteus = ' + str(gluteus_factor))
119
120# Part 4b: Re-scale the reference data using the optimized scale factors.
121gastroc = emgReference.updDependentColumn('gastrocnemius')
122tibant = emgReference.updDependentColumn('tibialis_anterior')
123bifem = emgReference.updDependentColumn('biceps_femoris')
124gluteus = emgReference.updDependentColumn('gluteus')
125for t in np.arange(emgReference.getNumRows()):
126 t = int(t) # Convert to Python built-in int type for indexing
127 gastroc[t] = gastroc_factor * gastroc[t]
128 tibant[t] = tibant_factor * tibant[t]
129 bifem[t] = bifem_factor * bifem[t]
130 gluteus[t] = gluteus_factor * gluteus[t]
131
132# Part 4c: Generate the plots. Compare results to the effort minimization
133# solution.
134helpers.compareSolutionToEMG(emgReference, 'effortSolution.sto',
135 'trackingSolution.sto')