Simbody
3.3
|
This AssemblyCondition specifies a correspondence between stations on mobilized bodies ("markers") and fixed ground-frame locations ("observations"). More...
#include <Assembler.h>
Public Member Functions | |
SimTK_DEFINE_UNIQUE_LOCAL_INDEX_TYPE (Markers, MarkerIx) | |
Define the MarkerIx type which is just a uniquely-typed int. More... | |
SimTK_DEFINE_UNIQUE_LOCAL_INDEX_TYPE (Markers, ObservationIx) | |
Define the ObservationIx type which is just a uniquely-typed int. More... | |
Construction and setup | |
These methods are used as an extended construction phase for Markers objects, defining the markers and observations that will be used in the subsequent tracking steps. | |
Markers () | |
The default constructor creates an empty Markers AssemblyCondition object that should be filled in with calls to addMarker() and optionally defineObservationOrder(). More... | |
MarkerIx | addMarker (const String &name, MobilizedBodyIndex bodyB, const Vec3 &markerInB, Real weight=1) |
Define a new marker attached to a particular MobilizedBody. More... | |
MarkerIx | addMarker (MobilizedBodyIndex bodyB, const Vec3 &markerInB, Real weight=1) |
Define an unnamed marker. More... | |
void | defineObservationOrder (const Array_< MarkerIx > &observationOrder) |
Define the meaning of the observation data by giving the MarkerIx associated with each observation. More... | |
void | defineObservationOrder (const Array_< String > &observationOrder) |
Define the meaning of the observations by giving the marker name corresponding to each observation, as a SimTK::Array_<String>. More... | |
void | defineObservationOrder (const std::vector< String > &observationOrder) |
Define observation order using an std::vector of SimTK::String. More... | |
void | defineObservationOrder (const Array_< std::string > &observationOrder) |
Define observation order using an Array_ of std::string. More... | |
void | defineObservationOrder (const std::vector< std::string > &observationOrder) |
Define observation order using an std::vector of std::string. More... | |
void | defineObservationOrder (int n, const char *const observationOrder[]) |
Define observation order using a C array of const char* names. More... | |
Retrieve setup information | |
These methods are used to query information associated with the construction and setup of this Markers object. This information does not normally change during a marker-tracking study, although marker weights may be changed by some inverse kinematics methods. | |
int | getNumMarkers () const |
Return a count n of the number of currently-defined markers. More... | |
const String & | getMarkerName (MarkerIx ix) |
Return the unique marker name assigned to the marker whose index is provided. More... | |
const MarkerIx | getMarkerIx (const String &name) |
Return the marker index associated with the given marker name. More... | |
Real | getMarkerWeight (MarkerIx mx) |
Get the weight currently in use for the specified marker; this can be changed dynamically via changeMarkerWeight(). More... | |
MobilizedBodyIndex | getMarkerBody (MarkerIx mx) const |
Get the MobilizedBodyIndex of the body associated with this marker. More... | |
const Vec3 & | getMarkerStation (MarkerIx mx) const |
Get the station (fixed location in its body frame) of the given marker. More... | |
int | getNumObservations () const |
Return the number of observations that were defined via the last call to defineObservationOrder(). More... | |
ObservationIx | getObservationIxForMarker (MarkerIx mx) const |
Return the ObservationIx of the observation that is currently associated with the given marker, or an invalid index if the marker doesn't have any corresponding observation (in which case it is being ignored). More... | |
bool | hasObservation (MarkerIx mx) const |
Return true if the supplied marker is currently associated with an observation. More... | |
MarkerIx | getMarkerIxForObservation (ObservationIx ox) const |
Return the MarkerIx of the marker that is associated with the given observation, or an invalid index if the observation doesn't correspond to any marker (in which case it is being ignored). More... | |
bool | hasMarker (ObservationIx ox) const |
Return true if the supplied observation is currently associated with a marker. More... | |
const Array_< MarkerIx > & | getMarkersOnBody (MobilizedBodyIndex mbx) |
The Markers assembly condition organizes the markers by body after initialization; call this to get the list of markers on any particular body. More... | |
Execution methods | |
These methods can be called between tracking steps to make step-to-step changes without reinitialization, and to access the current values of step-to-step data including the resulting marker errors. | |
void | moveOneObservation (ObservationIx ox, const Vec3 &observation) |
Move a single marker's observed location without moving any of the others. More... | |
void | moveAllObservations (const Array_< Vec3 > &observations) |
Set the observed marker locations for a new observation frame. More... | |
void | changeMarkerWeight (MarkerIx mx, Real weight) |
Change the weight associated with a particular marker. More... | |
const Vec3 & | getObservation (ObservationIx ox) const |
Return the current value of the location for this observation. More... | |
const Array_< Vec3, ObservationIx > & | getAllObservations () const |
Return the current values of all the observed locations. More... | |
Vec3 | findCurrentMarkerLocation (MarkerIx mx) const |
Using the current value of the internal state, calculate the ground frame location of a particular marker. More... | |
Real | findCurrentMarkerError (MarkerIx mx) const |
Using the current value of the internal state, calculate the distance between the given marker's current location and its corresponding observed location (unweighted). More... | |
Real | findCurrentMarkerErrorSquared (MarkerIx mx) const |
Using the current value of the internal state, calculate the (unweighted) square of the distance between the given marker's current location and its corresponding observed location (the squared distance is less expensive to compute than the distance). More... | |
AssemblyCondition virtuals | |
These methods are the implementations of the AssemblyCondition virtuals. | |
int | calcErrors (const State &state, Vector &err) const |
Calculate the amount by which this assembly condition is violated by the q values in the given state, with one scalar error per assembly equation returned in err. More... | |
int | calcErrorJacobian (const State &state, Matrix &jacobian) const |
Override to supply an analytic Jacobian for the assembly errors returned by calcErrors(). More... | |
int | getNumErrors (const State &state) const |
Override to supply an efficient method for determining how many errors will be returned by calcErrors(). More... | |
int | calcGoal (const State &state, Real &goal) const |
Calculate the current contribution (>= 0) of this assembly condition to the goal value that is being minimized. More... | |
int | calcGoalGradient (const State &state, Vector &grad) const |
Override to supply an analytic gradient for this assembly condition's goal. More... | |
int | initializeCondition () const |
This is called whenever the Assembler is initialized in case this assembly condition wants to do some internal work before getting started. More... | |
void | uninitializeCondition () const |
This is called whenever the containing Assembler is uninitialized in case this assembly condition has some cleanup to do. More... | |
Public Member Functions inherited from SimTK::AssemblyCondition | |
AssemblyCondition (const String &name) | |
Base class constructor just takes the assembly condition name and saves it. More... | |
virtual | ~AssemblyCondition () |
Destructor is virtual for use by derived classes. More... | |
const char * | getName () const |
Return the name assigned to this AssemblyCondition on construction. More... | |
bool | isInAssembler () const |
Test whether this AssemblyCondition has already been adopted by an Assembler. More... | |
const Assembler & | getAssembler () const |
Return the Assembler that has adopted this AssemblyCondition. More... | |
AssemblyConditionIndex | getAssemblyConditionIndex () const |
Return the AssemblyConditionIndex of this concrete AssemblyCondition within the Assembler that has adopted it. More... | |
Additional Inherited Members | |
Protected Member Functions inherited from SimTK::AssemblyCondition | |
int | getNumFreeQs () const |
Ask the assembler how many free q's there are; only valid after initialization but does not invoke initialization. More... | |
QIndex | getQIndexOfFreeQ (Assembler::FreeQIndex fx) const |
Ask the assembler where to find the actual q in the State that corresponds to a given free q; only valid after initialization but does not invoke initialization. More... | |
Assembler::FreeQIndex | getFreeQIndexOfQ (QIndex qx) const |
Ask the assembler where to find the free q (if any) that corresponds to a given q in the State; only valid after initialization but does not invoke initialization. More... | |
const MultibodySystem & | getMultibodySystem () const |
Ask the assembler for the MultibodySystem with which it is associated. More... | |
const SimbodyMatterSubsystem & | getMatterSubsystem () const |
Ask the assembler for the MultibodySystem with which it is associated and extract the SimbodyMatterSubsystem contained therein. More... | |
void | initializeAssembler () const |
Call this method before doing anything that logically requires the Assembler, or at least this AssemblyCondition, to have been initialized. More... | |
void | uninitializeAssembler () const |
Call this when modifying any parameter of the concrete AssemblyCondition that would require reinitialization of the Assembler or the AssemblyCondition. More... | |
This AssemblyCondition specifies a correspondence between stations on mobilized bodies ("markers") and fixed ground-frame locations ("observations").
The idea is to adjust the q's so that each marker is located close to its corresponding observation. This is normally used as a goal since we don't expect a perfect fit, but you can use these as a set of assembly error conditions if there are enough degrees of freedom to achieve a near-perfect solution.
Markers are defined one at a time and assigned sequential marker index values of type Markers::MarkerIx. They may optionally be given unique, case-sensitive names, and we will keep a map from name to MarkerIx. A default name will be assigned if none is given. A weight is assigned to every marker, with default weight=1. We do not expect that all the markers will be used; markers with weights of zero will not be included in the study, nor will markers for which no observation is given.
Once specified, the marker definitions do not change during a series of inverse kinematic (tracking) steps. The observations, on the other hand, are expected to come from a time series of experimental measurements of marker locations and will be different at every step. They typically come from a file organized by "frame", meaning an observation time and a set of observed locations, one per marker, corresponding to that time. During initial setup, the number of observations per frame and their correspondence to the defined markers is specified. They can be in any order, may skip some markers, and may include data for markers that are not defined. However, once initialized each frame must supply the same information in the same order. Data for an unobserved marker can be provided as NaN in which case it will be ignored in that frame. The frame time is supplied to the track() method which initiates assembly for a frame.
Observation-marker correspondence maps a ObservationIx to a unique MarkerIx. By default, we'll expect to get an observation for each marker and that the observation order and the marker order are the same, i.e. ObservationIx==MarkerIx for every marker. However, you can instead define observation/marker correspondence yourself, (after all markers have been defined), via one of the defineObservationOrder() methods. This is done by supplying an array of MarkerIx values, or an array of Marker names, with the array elements ordered by ObservationIx. Any invalid marker index or unrecognized marker name means we will ignore values provide for that observation; similarly, any markers whose index or name is not specified at all will be ignored.
|
inline |
The default constructor creates an empty Markers AssemblyCondition object that should be filled in with calls to addMarker() and optionally defineObservationOrder().
SimTK::Markers::SimTK_DEFINE_UNIQUE_LOCAL_INDEX_TYPE | ( | Markers | , |
MarkerIx | |||
) |
Define the MarkerIx type which is just a uniquely-typed int.
SimTK::Markers::SimTK_DEFINE_UNIQUE_LOCAL_INDEX_TYPE | ( | Markers | , |
ObservationIx | |||
) |
Define the ObservationIx type which is just a uniquely-typed int.
|
inline |
Define a new marker attached to a particular MobilizedBody.
Note that a marker will be ignored unless an observation is provided for it.
[in] | name | A unique name to be used to identify this marker. If the name is empty or blank, a default name will be supplied. |
[in] | bodyB | The MobilizedBody to which this marker is fixed. Markers on Ground are allowed but will be ignored. |
[in] | markerInB | This is the position vector of the marker in bodyB's local frame, also known as the marker's "station" on bodyB. |
[in] | weight | An optional weight for use in defining the objective function, which combines errors in this marker's position with errors in other markers' positions. If the weight is zero this marker is ignored. |
|
inline |
Define an unnamed marker.
A default name will be assigned; that name will be "_UNNAMED_XX" where XX is the MarkerIx assigned to that marker (don't use names of that form yourself).
|
inline |
Define the meaning of the observation data by giving the MarkerIx associated with each observation.
The length of the array of marker indices defines the expected number of observations to be provided for each observation frame. Any marker index that is supplied with an invalid value means that the corresponding observation will be present in the supplied data but should be ignored.
[in] | observationOrder | This is an array of marker index values, one per observation, that defines both the number of expected observations and the marker corresponding to each observation. Markers can be in any order; an invalid marker index means that observation will be provided but should be ignored; markers whose indices are never listed are ignored. If observationOrder is supplied as a zero-length array, then we'll assume there are as many observations as markers and that their indices match. |
Define the meaning of the observations by giving the marker name corresponding to each observation, as a SimTK::Array_<String>.
The length of the array of marker indices defines the expected number of observations. Any marker name that is unrecognized or empty means that the corresponding observation will be present in the supplied data but should be ignored.
|
inline |
Define observation order using an std::vector of SimTK::String.
|
inline |
Define observation order using an Array_ of std::string.
|
inline |
Define observation order using an std::vector of std::string.
|
inline |
Define observation order using a C array of const char* names.
|
inline |
Return a count n of the number of currently-defined markers.
Valid marker index values (of type Markers::MarkerIx) are 0..n-1.
|
inline |
Return the unique marker name assigned to the marker whose index is provided.
If the marker was defined without a name, this will return the default name that was assigned to it.
|
inline |
Return the marker index associated with the given marker name.
If the name is not recognized the returned index will be invalid (test with index.isValid()).
|
inline |
Get the weight currently in use for the specified marker; this can be changed dynamically via changeMarkerWeight().
|
inline |
Get the MobilizedBodyIndex of the body associated with this marker.
|
inline |
Get the station (fixed location in its body frame) of the given marker.
|
inline |
Return the number of observations that were defined via the last call to defineObservationOrder().
These are not necessarily all being used. If defineObservationOrder() was never called, we'll expect the same number of observations as markers although that won't be set up until the Assembler has been initialized.
|
inline |
Return the ObservationIx of the observation that is currently associated with the given marker, or an invalid index if the marker doesn't have any corresponding observation (in which case it is being ignored).
An exception will be thrown if the given MarkerIx is not in the range 0..getNumMarkers()-1.
|
inline |
Return true if the supplied marker is currently associated with an observation.
|
inline |
Return the MarkerIx of the marker that is associated with the given observation, or an invalid index if the observation doesn't correspond to any marker (in which case it is being ignored).
An exception will be thrown if the given ObservationIx is not in the range 0..getNumObservations()-1.
|
inline |
Return true if the supplied observation is currently associated with a marker.
|
inline |
|
inline |
Move a single marker's observed location without moving any of the others.
If the value contains a NaN, this marker/observation pair will be ignored the next time the assembly goal cost function is calculated.
Set the observed marker locations for a new observation frame.
These are the locations to which we will next attempt to move all the corresponding markers. Note that not all observations necessarily have corresponding markers defined; locations of those markers must still be provided here but they will be ignored. The length of the allObservations array must be the same as the number of defined observations; you can obtain that using getNumObservations(). Any observations that contain a NaN will be ignored; that marker/observation pair will not be used in the next calculation of the assembly goal cost function.
|
inline |
Change the weight associated with a particular marker.
If this is just a quantitative change (e.g., weight was 0.3 now it is 0.4) then this does not require any reinitialization and will affect the goal calculation next time it is done. If the weight changes to or from zero (a qualitative change) then this will uninitialize the Assembler and all the internal data structures will be changed to remove or add this marker from the list of active markers. If you want to temporarily ignore a marker without reinitializing, you can set its corresponding observation to NaN in which case it will simply be skipped when the goal value is calculated.
|
inline |
Return the current value of the location for this observation.
This is where we will try to move the corresponding marker if there is one. The result might be NaN if there is no current value for this observation; you can check using Vec3's isFinite() method.
Return the current values of all the observed locations.
This is where we will try to move the corresponding markers, for those observations that have corresponding markers defined. Some of the values may be NaN if there is currently no corresponding observation. Note that these are indexed by ObservationIx; use getObservationIxForMarker() to map a MarkerIx to its corresponding ObservationIx.
Vec3 SimTK::Markers::findCurrentMarkerLocation | ( | MarkerIx | mx | ) | const |
Using the current value of the internal state, calculate the ground frame location of a particular marker.
The difference between this location and the corresponding observation is the current error for this marker.
|
inline |
Using the current value of the internal state, calculate the distance between the given marker's current location and its corresponding observed location (unweighted).
If the marker is not associated with an observation, or if the observed location is missing (indicated by a NaN value), then the error is reported as zero.
|
inline |
Using the current value of the internal state, calculate the (unweighted) square of the distance between the given marker's current location and its corresponding observed location (the squared distance is less expensive to compute than the distance).
If the marker is not associated with an observation, or if the observed location is missing (indicated by a NaN value), then the error is reported as zero.
Calculate the amount by which this assembly condition is violated by the q values in the given state, with one scalar error per assembly equation returned in err.
The functional return should be zero if successful; negative values are reserved with -1 meaning "not implemented"; return a positive value if your implementation is unable to evaluate the error at the current state. If this method is not implemented then you must implement calcGoal() and this assembly condition may only be used as a goal, not a requirement.
Reimplemented from SimTK::AssemblyCondition.
Override to supply an analytic Jacobian for the assembly errors returned by calcErrors().
The returned Jacobian must be nErr X nFreeQs; that is, if there is only one assembly error equation the returned matrix is a single row (that's the transpose of the gradient). The functional return should be zero if this succeeds; negative values are reserved with the default implementation returning -1 which indicates that the Jacobian must be calculated numerically using the calcErrors() method. Return a positive value if your implementation is unable to evaluate the Jacobian at the current state.
Reimplemented from SimTK::AssemblyCondition.
|
virtual |
Override to supply an efficient method for determining how many errors will be returned by calcErrors().
Otherwise the default implementation determines this by making a call to calcErrors() and returning the size of the returned error vector. The functional return should be zero if this succeeds; negative values are reserved; return a positive value if your implementation of this method can't determine the number of errors with the given state (unlikely!).
Reimplemented from SimTK::AssemblyCondition.
|
virtual |
Calculate the current contribution (>= 0) of this assembly condition to the goal value that is being minimized.
If this isn't overridden we'll generate it by combining the m errors returned by calcErrors() in a mean sum of squares: goal = err^2/m.
Reimplemented from SimTK::AssemblyCondition.
Override to supply an analytic gradient for this assembly condition's goal.
The returned gradient must be nFreeQ X 1; that is, it is a column vector giving the partial derivative of the goal with respect to each of the free q's in order. The functional return should be zero if this succeeds. The default implementation return -1 which indicates that the gradient must be calculated numerically using the calcGoal() method.
Reimplemented from SimTK::AssemblyCondition.
|
virtual |
This is called whenever the Assembler is initialized in case this assembly condition wants to do some internal work before getting started.
None of the other virtual methods will be called until this one has been, except possibly the destructor. The set of free q's and the internal State are valid at this point and can be retrieved from the Assembler stored in the base class.
Reimplemented from SimTK::AssemblyCondition.
|
virtual |
This is called whenever the containing Assembler is uninitialized in case this assembly condition has some cleanup to do.
Reimplemented from SimTK::AssemblyCondition.