Processing Mocap Data
This documentation is WIP:
Nimble is focused on human motion and biomechanics analysis. We include many utilities that will be familiar to biomechanics practitioners: loading C3D files, loading multiple OpenSim formats, and the algorithms that power AddBiomechanics.
To load C3D files, check out:
- class nimblephysics.biomechanics.C3DLoader
- static debugToGUI(file: nimblephysics_libs._nimblephysics.biomechanics.C3D, server: nimblephysics_libs._nimblephysics.server.GUIWebsocketServer) None
- static fixupMarkerFlips(c3d: nimblephysics_libs._nimblephysics.biomechanics.C3D) List[List[Tuple[str, str]]]
- static loadC3D(uri: str) nimblephysics_libs._nimblephysics.biomechanics.C3D
To run some heuristics to clean up the C3D data, you can use:
- class nimblephysics.biomechanics.MarkerFixer
- static generateDataErrorsReport(immutableMarkerObservations: List[Dict[str, numpy.ndarray[numpy.float64[3, 1]]]], dt: float, dropProlongedStillness: bool = False, rippleReduce: bool = True, rippleReduceUseSparse: bool = True, rippleReduceUseIterativeSolver: bool = True, rippleReduceSolverIterations: int = 100000.0) nimblephysics_libs._nimblephysics.biomechanics.MarkersErrorReport
This will return you an object with a field markerObservationsAttemptedFixed
- class nimblephysics.biomechanics.MarkersErrorReport
- property droppedMarkerWarnings
- getMarkerMapOnTimestep(self: nimblephysics_libs._nimblephysics.biomechanics.MarkersErrorReport, t: int) Dict[str, numpy.ndarray[numpy.float64[3, 1]]]
- getMarkerNamesOnTimestep(self: nimblephysics_libs._nimblephysics.biomechanics.MarkersErrorReport, t: int) List[str]
- getMarkerPositionOnTimestep(self: nimblephysics_libs._nimblephysics.biomechanics.MarkersErrorReport, t: int, marker: str) numpy.ndarray[numpy.float64[3, 1]]
- getNumTimesteps(self: nimblephysics_libs._nimblephysics.biomechanics.MarkersErrorReport) int
- property info
- property markerObservationsAttemptedFixed
- property markersRenamedFromTo
- property warnings
For OpenSim files, check out:
- nimblephysics.biomechanics.OpenSimParser
alias of <module ‘nimblephysics_libs._nimblephysics.biomechanics.OpenSimParser’>
This class is the basis of the kinematic fit (just bone scaling, marker offsets, and IK, no dynamics) for AddBiomechanics.
- class nimblephysics.biomechanics.MarkerFitter
- addZeroConstraint(self: nimblephysics_libs._nimblephysics.biomechanics.MarkerFitter, name: str, loss: Callable[[nimblephysics_libs._nimblephysics.biomechanics.MarkerFitterState], float]) None
- autorotateC3D(self: nimblephysics_libs._nimblephysics.biomechanics.MarkerFitter, c3d: nimblephysics_libs._nimblephysics.biomechanics.C3D) None
- checkForEnoughMarkers(self: nimblephysics_libs._nimblephysics.biomechanics.MarkerFitter, markerObservations: List[Dict[str, numpy.ndarray[numpy.float64[3, 1]]]]) bool
- checkForFlippedMarkers(self: nimblephysics_libs._nimblephysics.biomechanics.MarkerFitter, markerObservations: List[Dict[str, numpy.ndarray[numpy.float64[3, 1]]]], init: nimblephysics_libs._nimblephysics.biomechanics.MarkerInitialization, report: nimblephysics_libs._nimblephysics.biomechanics.MarkersErrorReport) bool
- debugTrajectoryAndMarkersToGUI(self: nimblephysics_libs._nimblephysics.biomechanics.MarkerFitter, server: nimblephysics_libs._nimblephysics.server.GUIWebsocketServer, init: nimblephysics_libs._nimblephysics.biomechanics.MarkerInitialization, markerObservations: List[Dict[str, numpy.ndarray[numpy.float64[3, 1]]]], forcePlates: List[nimblephysics_libs._nimblephysics.biomechanics.ForcePlate] = None, goldOsim: nimblephysics_libs._nimblephysics.biomechanics.OpenSimFile = None, goldPoses: numpy.ndarray[numpy.float64[m, n]] = array([], shape=(0, 0), dtype=float64)) None
- findJointCenters(self: nimblephysics_libs._nimblephysics.biomechanics.MarkerFitter, initializations: nimblephysics_libs._nimblephysics.biomechanics.MarkerInitialization, newClip: List[bool], markerObservations: List[Dict[str, numpy.ndarray[numpy.float64[3, 1]]]]) None
- fineTuneWithIMU(self: nimblephysics_libs._nimblephysics.biomechanics.MarkerFitter, accObservations: List[Dict[str, numpy.ndarray[numpy.float64[3, 1]]]], gyroObservations: List[Dict[str, numpy.ndarray[numpy.float64[3, 1]]]], markerObservations: List[Dict[str, numpy.ndarray[numpy.float64[3, 1]]]], newClip: List[bool], init: nimblephysics_libs._nimblephysics.biomechanics.MarkerInitialization, dt: float, weightAccs: float = 1.0, weightGyros: float = 1.0, weightMarkers: float = 100.0, regularizePoses: float = 1.0, useIPOPT: bool = True, iterations: int = 300, lbfgsMemory: int = 100) nimblephysics_libs._nimblephysics.biomechanics.MarkerInitialization
- generateDataErrorsReport(self: nimblephysics_libs._nimblephysics.biomechanics.MarkerFitter, markerObservations: List[Dict[str, numpy.ndarray[numpy.float64[3, 1]]]], dt: float, rippleReduce: bool = True, rippleReduceUseSparse: bool = True, rippleReduceUseIterativeSolver: bool = True, rippleReduceSolverIterations: int = 100000.0) nimblephysics_libs._nimblephysics.biomechanics.MarkersErrorReport
- getIMUFineTuneProblem(self: nimblephysics_libs._nimblephysics.biomechanics.MarkerFitter, accObservations: List[Dict[str, numpy.ndarray[numpy.float64[3, 1]]]], gyroObservations: List[Dict[str, numpy.ndarray[numpy.float64[3, 1]]]], markerObservations: List[Dict[str, numpy.ndarray[numpy.float64[3, 1]]]], init: nimblephysics_libs._nimblephysics.biomechanics.MarkerInitialization, dt: float, start: int, end: int) nimblephysics_libs._nimblephysics.biomechanics.IMUFineTuneProblem
- getImuList(self: nimblephysics_libs._nimblephysics.biomechanics.MarkerFitter) List[Tuple[nimblephysics_libs._nimblephysics.dynamics.BodyNode, nimblephysics_libs._nimblephysics.math.Isometry3]]
- getImuMap(self: nimblephysics_libs._nimblephysics.biomechanics.MarkerFitter) Dict[str, Tuple[nimblephysics_libs._nimblephysics.dynamics.BodyNode, nimblephysics_libs._nimblephysics.math.Isometry3]]
- getImuNames(self: nimblephysics_libs._nimblephysics.biomechanics.MarkerFitter) List[str]
- getInitialization(self: nimblephysics_libs._nimblephysics.biomechanics.MarkerFitter, markerObservations: List[Dict[str, numpy.ndarray[numpy.float64[3, 1]]]], newClip: List[bool], params: nimblephysics_libs._nimblephysics.biomechanics.InitialMarkerFitParams = InitialMarkerFitParams(numBlocks=12)) nimblephysics_libs._nimblephysics.biomechanics.MarkerInitialization
- getMarkerIsTracking(self: nimblephysics_libs._nimblephysics.biomechanics.MarkerFitter, marker: str) bool
- static getMarkerLossGradientWrtJoints(skeleton: nimblephysics_libs._nimblephysics.dynamics.Skeleton, markers: List[Tuple[nimblephysics_libs._nimblephysics.dynamics.BodyNode, numpy.ndarray[numpy.float64[3, 1]]]], lossGradWrtMarkerError: numpy.ndarray[numpy.float64[m, 1]]) numpy.ndarray[numpy.float64[m, 1]]
- getNumMarkers(self: nimblephysics_libs._nimblephysics.biomechanics.MarkerFitter) int
- measureAccelerometerRMS(self: nimblephysics_libs._nimblephysics.biomechanics.MarkerFitter, accObservations: List[Dict[str, numpy.ndarray[numpy.float64[3, 1]]]], newClip: List[bool], init: nimblephysics_libs._nimblephysics.biomechanics.MarkerInitialization, dt: float) float
- measureGyroRMS(self: nimblephysics_libs._nimblephysics.biomechanics.MarkerFitter, gyroObservations: List[Dict[str, numpy.ndarray[numpy.float64[3, 1]]]], newClip: List[bool], init: nimblephysics_libs._nimblephysics.biomechanics.MarkerInitialization, dt: float) float
- optimizeBilevel(self: nimblephysics_libs._nimblephysics.biomechanics.MarkerFitter, markerObservations: List[Dict[str, numpy.ndarray[numpy.float64[3, 1]]]], initialization: nimblephysics_libs._nimblephysics.biomechanics.MarkerInitialization, numSamples: int, applyInnerProblemGradientConstraints: bool = True) nimblephysics_libs._nimblephysics.biomechanics.BilevelFitResult
- static pickSubset(markerObservations: List[Dict[str, numpy.ndarray[numpy.float64[3, 1]]]], subsetSize: int) List[Dict[str, numpy.ndarray[numpy.float64[3, 1]]]]
- removeZeroConstraint(self: nimblephysics_libs._nimblephysics.biomechanics.MarkerFitter, name: str) None
- rotateIMUs(self: nimblephysics_libs._nimblephysics.biomechanics.MarkerFitter, accObservations: List[Dict[str, numpy.ndarray[numpy.float64[3, 1]]]], gyroObservations: List[Dict[str, numpy.ndarray[numpy.float64[3, 1]]]], newClip: List[bool], init: nimblephysics_libs._nimblephysics.biomechanics.MarkerInitialization, dt: float) None
- runKinematicsPipeline(self: nimblephysics_libs._nimblephysics.biomechanics.MarkerFitter, markerObservations: List[Dict[str, numpy.ndarray[numpy.float64[3, 1]]]], newClip: List[bool], params: nimblephysics_libs._nimblephysics.biomechanics.InitialMarkerFitParams, numSamples: int = 20, skipFinalIK: bool = False) nimblephysics_libs._nimblephysics.biomechanics.MarkerInitialization
- runMultiTrialKinematicsPipeline(self: nimblephysics_libs._nimblephysics.biomechanics.MarkerFitter, markerTrials: List[List[Dict[str, numpy.ndarray[numpy.float64[3, 1]]]]], params: nimblephysics_libs._nimblephysics.biomechanics.InitialMarkerFitParams, numSamples: int = 50) List[nimblephysics_libs._nimblephysics.biomechanics.MarkerInitialization]
- runPrescaledPipeline(self: nimblephysics_libs._nimblephysics.biomechanics.MarkerFitter, markerObservations: List[Dict[str, numpy.ndarray[numpy.float64[3, 1]]]], params: nimblephysics_libs._nimblephysics.biomechanics.InitialMarkerFitParams) nimblephysics_libs._nimblephysics.biomechanics.MarkerInitialization
- saveTrajectoryAndMarkersToGUI(self: nimblephysics_libs._nimblephysics.biomechanics.MarkerFitter, path: str, init: nimblephysics_libs._nimblephysics.biomechanics.MarkerInitialization, markerObservations: List[Dict[str, numpy.ndarray[numpy.float64[3, 1]]]], accObservations: List[Dict[str, numpy.ndarray[numpy.float64[3, 1]]]], gyroObservations: List[Dict[str, numpy.ndarray[numpy.float64[3, 1]]]], frameRate: int, forcePlates: List[nimblephysics_libs._nimblephysics.biomechanics.ForcePlate] = None, goldOsim: nimblephysics_libs._nimblephysics.biomechanics.OpenSimFile = None, goldPoses: numpy.ndarray[numpy.float64[m, n]] = array([], shape=(0, 0), dtype=float64)) None
- setAnatomicalMarkerDefaultWeight(self: nimblephysics_libs._nimblephysics.biomechanics.MarkerFitter, weight: float) None
- setAnthropometricPrior(self: nimblephysics_libs._nimblephysics.biomechanics.MarkerFitter, prior: nimblephysics_libs._nimblephysics.biomechanics.Anthropometrics, weight: float = 0.001) None
- setCustomLossAndGrad(self: nimblephysics_libs._nimblephysics.biomechanics.MarkerFitter, loss: Callable[[nimblephysics_libs._nimblephysics.biomechanics.MarkerFitterState], float]) None
- setDebugJointVariability(self: nimblephysics_libs._nimblephysics.biomechanics.MarkerFitter, debug: bool) None
- setDebugLoss(self: nimblephysics_libs._nimblephysics.biomechanics.MarkerFitter, debug: bool) None
- setExplicitHeightPrior(self: nimblephysics_libs._nimblephysics.biomechanics.MarkerFitter, prior: float, weight: float = 1000.0) None
- setIgnoreJointLimits(self: nimblephysics_libs._nimblephysics.biomechanics.MarkerFitter, ignore: bool) None
- setImuMap(self: nimblephysics_libs._nimblephysics.biomechanics.MarkerFitter, imuMap: Dict[str, Tuple[nimblephysics_libs._nimblephysics.dynamics.BodyNode, nimblephysics_libs._nimblephysics.math.Isometry3]]) None
- setInitialIKMaxRestarts(self: nimblephysics_libs._nimblephysics.biomechanics.MarkerFitter, starts: int) None
- setInitialIKSatisfactoryLoss(self: nimblephysics_libs._nimblephysics.biomechanics.MarkerFitter, loss: float) None
- setIterationLimit(self: nimblephysics_libs._nimblephysics.biomechanics.MarkerFitter, iters: int) None
- setJointAxisFitSGDIterations(self: nimblephysics_libs._nimblephysics.biomechanics.MarkerFitter, iters: int) None
- setJointForceFieldSoftness(self: nimblephysics_libs._nimblephysics.biomechanics.MarkerFitter, softness: float) None
Larger values will increase the softness of the threshold penalty. Smaller values, as they approach zero, will have an almost perfectly vertical penality for going below the threshold distance. That would be hard to optimize, so don’t make it too small.
- setJointForceFieldThresholdDistance(self: nimblephysics_libs._nimblephysics.biomechanics.MarkerFitter, minDistance: float) None
This sets the minimum distance joints have to be apart in order to get zero “force field” loss. Any joints closer than this (in world space) will incur a penalty.
- setJointSphereFitSGDIterations(self: nimblephysics_libs._nimblephysics.biomechanics.MarkerFitter, iters: int) None
- setMarkerIsTracking(self: nimblephysics_libs._nimblephysics.biomechanics.MarkerFitter, marker: str, isTracking: bool = True) None
- setMaxAxisWeight(self: nimblephysics_libs._nimblephysics.biomechanics.MarkerFitter, weight: float) None
- setMaxJointWeight(self: nimblephysics_libs._nimblephysics.biomechanics.MarkerFitter, weight: float) None
- setMaxMarkerOffset(self: nimblephysics_libs._nimblephysics.biomechanics.MarkerFitter, offset: float) None
- setMinAxisFitScore(self: nimblephysics_libs._nimblephysics.biomechanics.MarkerFitter, score: float) None
- setMinJointVarianceCutoff(self: nimblephysics_libs._nimblephysics.biomechanics.MarkerFitter, cutoff: float) None
- setMinSphereFitScore(self: nimblephysics_libs._nimblephysics.biomechanics.MarkerFitter, score: float) None
- setParallelIKWarps(self: nimblephysics_libs._nimblephysics.biomechanics.MarkerFitter, parallelWarps: bool) None
- If True, this processes “single threaded” IK tasks 32 timesteps at a time
(a “warp”), in parallel, using the first timestep of the warp as the initialization for the whole warp. Defaults to False.
- setPostprocessAnatomicalMarkerOffsets(self: nimblephysics_libs._nimblephysics.biomechanics.MarkerFitter, postprocess: bool) None
If we set this to true, then after the main optimization completes we will do a final step to “center” the error of the anatomical markers. This minimizes marker RMSE, but does NOT respect the weights about how far markers should be allowed to move.
- setPostprocessTrackingMarkerOffsets(self: nimblephysics_libs._nimblephysics.biomechanics.MarkerFitter, postprocess: bool) None
If we set this to true, then after the main optimization completes we will do a final step to “center” the error of the tracking markers. This minimizes marker RMSE, but does NOT respect the weights about how far markers should be allowed to move.
- setRegularizeAllBodyScales(self: nimblephysics_libs._nimblephysics.biomechanics.MarkerFitter, weight: float) None
- setRegularizeAnatomicalMarkerOffsets(self: nimblephysics_libs._nimblephysics.biomechanics.MarkerFitter, weight: float) None
- setRegularizeIndividualBodyScales(self: nimblephysics_libs._nimblephysics.biomechanics.MarkerFitter, weight: float) None
- setRegularizeJointBounds(self: nimblephysics_libs._nimblephysics.biomechanics.MarkerFitter, weight: float) None
- setRegularizeJointWithVirtualSpring(self: nimblephysics_libs._nimblephysics.biomechanics.MarkerFitter, jointName: str, weight: float) None
- setRegularizePelvisJointsWithVirtualSpring(self: nimblephysics_libs._nimblephysics.biomechanics.MarkerFitter, weight: float) None
- setRegularizeTrackingMarkerOffsets(self: nimblephysics_libs._nimblephysics.biomechanics.MarkerFitter, weight: float) None
- setStaticTrial(self: nimblephysics_libs._nimblephysics.biomechanics.MarkerFitter, markerObservationsMapAtStaticPose: Dict[str, numpy.ndarray[numpy.float64[3, 1]]], staticPose: numpy.ndarray[numpy.float64[m, 1]]) None
- setStaticTrialWeight(self: nimblephysics_libs._nimblephysics.biomechanics.MarkerFitter, weight: float) None
- setTrackingMarkerDefaultWeight(self: nimblephysics_libs._nimblephysics.biomechanics.MarkerFitter, weight: float) None
- setTrackingMarkers(self: nimblephysics_libs._nimblephysics.biomechanics.MarkerFitter, trackingMarkerNames: List[str]) None
- setTriadsToTracking(self: nimblephysics_libs._nimblephysics.biomechanics.MarkerFitter) None
- writeCSVData(self: nimblephysics_libs._nimblephysics.biomechanics.MarkerFitter, path: str, init: nimblephysics_libs._nimblephysics.biomechanics.MarkerInitialization, rmsMarkerErrors: List[float], maxMarkerErrors: List[float], timestamps: List[float]) None