Skip to main content

How JMP Works

This document attempts to describe a mid-level view of the Joint Model Personalization Tool. More in-depth insights into the tool can be gleaned from the source code.

High Level Overview (As a List)

The Joint Model Personalization Tool does the following:

  • Parses JMP XML settings file (xml settings file examples here)
  • Locates all joint parameters, body scaling, and marker motion to be optimized during the run
  • Finds the markers attached to each body adjacent to the joints/bodies of interest and removes all other markers
  • Uses MATLAB's lsqnonlin() to find the set of design variables that minimizes the total distance error between experimental and virtual markers.
  • Upon convergence, the final model is produced and printed to the output file name provided in the XML settings file.

Parsing the Settings File

The JMP XML settings file contains a few important elements:

  • <input_model_file> - this is the relative or absolute path of the model file to be used
  • <output_model_file> - this is the relative or absolute path of the output model file from JMP. If you don't know what to name it, appending _jmp is never a bad bet.
  • <allowable_error> - this is how accurate the optimizer should be and should be in the same units as the marker data. A value of 0.01 for marker data in meters means: "I'm ok with 1cm of error for marker matching".

JMP Tasks

Joint Model Personalization allows for tasks to be strung together so that the user can pass in multiple marker files, each with their own parameters to be optimized, each in a row.

JMP Tasks are equivalent to taking the output of one JMP run and passing it into the next JMP run, but is provided as a convenience. The most common use of multiple tasks is optimizing a single joint from an isolated joint trial prior to optimizing the model from a gait trial. Some joint parameters are optimized in an isolated joint trial, but because they are not effectively described by a gait trial, they are turned off for the gait task.

Important elements in JMPTask include:

  • <index> - tasks are completed in ascending numerical order
  • <marker_file_name> - the path to the trc file used for that task
  • <time_range> - this element is a space-separated pair of start and end values for the marker data (just like in the IK settings file).
  • <JMPJointSet> & <JMPBodySet> - these two sets describe how joints and bodies can be optimized by JMP. Multiple <JMPJoint> and <JMPBody> elements can be contained in each respective set.

JMP Joints

The specific joint parameters to be optimized are described by the<JMPJoint> element. For the separate <parent_frame_transformation> and <child_frame_transformation>, both the <translation> and <orientation> elements accept a space-separated list of boolean values for the X, Y, and Z axes, respectively.

Additionally, the name attribute of the <JMPJoint name="hip_r"> indicates which joint is selected.

JMP Bodies

<JMPBody> elements are similar to <JMPJoint> elements, but contain only two elements:

  • <scale_body> - takes a single boolean value
  • <move_markers> - a space-separated list of boolean values for allowing the markers to move in the direction of the local X, Y, Z axes of the parent body's coordinate system.

Additional Parsing Notes

Modifications to Model Can Occur in Any Order

The joint and body parameters selected in the XML file will be parsed and turned in model-adjusting functions that accept a model and a value. These values will be applied to the model in sequential order based on parsing. It is assumed that these functions are not temporally important, in other words, the order in which they are applied to the model does not matter.

Minimal Marker Set

Along those same lines, any marker that is more than one body beyond the joint or body of interest (probably) has no effect on the results of the optimization. For example, if the femur is to be scaled, markers not on the tibia, femur, or pelvis have no affect on the optimal marker scaling and only act to dilute the optimization by adding additional cost terms. As a result, those markers are removed.

Adding Additional Markers

In some instances, markers from further segments are needed, such as when scaling the tibia. The hindfoot is not included because the child body of the tibia is the talus. The hindfoot markers can be included by adding the <JMPBody name="calcn_r> element with all values set to false. This should increase the number of function calls per iteration, indicating the hindfoot markers are included.

Optimization

JMP uses lsqnonlin() as top-level optimizer. A number of optimizer values can be adjusted from the optional JMP XML settings file elements (at the bottom in the example XML).

Inside the Cost Function

Firstly, the model is adjusted according to the values provided by the optimizer. Next, the marker file is loaded and the OpenSim InverseKinematicsSolver is set up for the given marker subset. Each frame of the marker file is stepped through and the marker distance error for each marker is recorded.

lsqnonlin() accepts a vector of cost terms that are squared and summed. Before that, the values in the vector are normalized by the number of frames, number of markers, and the allowable error.

Saving the Model

lsqnonlin(), upon convergence, returns a vector of values for the optimal result for each function parameter. These values are applied to each parameter just as they were applied within the cost term and the new model is saved to the output file.

Viewing Results

Analysis functions are provided to view the before and after marker error over time. An example of how to view the results of JMP is provided in the nmsm-examples under the JointModelPersonalization directory.