Expressions

From Software Product Documentation
Jump to navigation Jump to search
Language:  English  • français • italiano • português • español 

Many (but not all) edit boxes and pipeline command parameters allow the use of expressions instead of numerical values. Visual3D uses a common expression parser, so the following syntax is common.


Evaluate_Expression Command

The Evaluate_Expression command allows the users to include expressions for defining the processing of the signals.

Evaluate_Expression
/Expression=
!/Signal_Type=
!/Signal_Folder=
!/Signal_Name=
/Result_Type=
/Result_Folder=
/Result_Name=
!/Apply_as_suffix_to_signal_name=FALSE
;

Expression Syntax

This expression syntax is used wherever Visual3D allows an expression.

Mathematical Operators

+ add
- subtract
* multiply
/ divide
^ power -> for example, x^2 = x to the power 2
| logical OR -> the adjective NOT is allowed
&

logical AND-> the adjective NOT is allowed

<> or >< not equals
== equals
>= or => greater than or equal to
     Using the Adjective NOT

NOT can be used with the logical AND and logical OR

Example: Given a workspace containing 3 trials (*trial1.c3d, *trial2.c3d, and *trial3.c3d)

All trials are assigned a TAG labeled WALK

  • trial1.c3d is also assigned a TAG labeled BAD
Select_Active_File
/FILE_NAME=WALK
/QUERY=BAD
;

This command results in *trial1.c3d being active

Select_Active_File
/FILE_NAME=WALK
/QUERY=NOT(BAD)
;

This command results in *trial2.c3d and *trial3.c3d being active.

     = Boolean Operator equals

Example: Comparing a model metric with a string

Consider a model metric that is defined as a string.
Set_Model_Metric
! /CALIBRATION_FILE=
/METRIC_NAME=TEST
/METRIC_VALUE="TTT"
;
Now compare it to the text string "TTT"
Evaluate_Expression
/EXPRESSION=MODEL::METRIC::TEST="TTT"
/RESULT_NAME=SCOTT
/RESULT_TYPE=METRIC
! /RESULT_FOLDER=PROCESSED
;
The text strings should be equal so the resulting signal contains a 1
     < Boolean Operator less than

Example:

Given two signals
TARGET::ORIGINAL::RFT1
TARGET::ORIGINAL::LFT1
Use the Boolean operator < to identify when the Z component of RFT1 is less than the Z component of LFT1
Evaluate_Expression
/EXPRESSION= TARGET::ORIGINAL::RFT1::Z < TARGET::ORIGINAL::LFT1::Z
/RESULT_NAME=RFT1_GREATER
/RESULT_TYPE=DERIVED
/RESULT_FOLDER=PROCESSED
;
The output signal will be 1 when RFT1::Z is less than LFT1::Z and 0 otherwise
     <= or =< Boolean Operator less than or equal to

Example:

Given two signals
TARGET::ORIGINAL::RFT1
TARGET::ORIGINAL::LFT1
Use the Boolean operator <= or the boolean operative =< to identify when the Z component of RFT1 is less than or equal to the Z component of LFT1
Evaluate_Expression
/EXPRESSION= TARGET::ORIGINAL::RFT1::Z <= TARGET::ORIGINAL::LFT1::Z
/RESULT_NAME=RFT1_GREATER
/RESULT_TYPE=DERIVED
/RESULT_FOLDER=PROCESSED
;
The output signal will be 1 when RFT1::Z is less than or equal toLFT1::Z and 0 otherwise
     > Boolean Operator greater than

Example:

Given two signals
TARGET::ORIGINAL::RFT1
TARGET::ORIGINAL::LFT1
Use the Boolean operator > to identify when the Y component of RFT1 is greater than the Y component of LFT1
Evaluate_Expression
/EXPRESSION= TARGET::ORIGINAL::RFT1::Y > TARGET::ORIGINAL::LFT1::Y
/RESULT_NAME=RFT1_GREATER
/RESULT_TYPE=DERIVED
/RESULT_FOLDER=PROCESSED
;
The output signal will be 1 when RFT1::Y is greater than LFT1::Y and 0 otherwise


Note: Visual3D parses the mathematical operators before it parses the signal names. If you have a signal name that contains a mathematical operator (e.g. R-Foot1), Visual3D will probably not be able to parse the equation expression properly.

Brackets

Parenthesis ( and ) are used to contain the parameters in a function
     Square Brackets [ and ] specify frame numbers and components
Square Brackets [ and ] are used at the end of a function call or parenthesis ( ) to specify the frames numbers and components
Example, add two signals and retrieve the component 1 from frame 5
Evaluate_Expression
/Expression= (TARGET::ORIGINAL::RFT1 + TARGET::ORIGINAL::RFT2)[5,1]
/Result_Name=RFT_ADD_X
/Result_Type=DERIVED
/Result_Folder=PROCESSED
;
for example, add two signals and retrieve the component 1 for all frames
Evaluate_Expression
/Expression= (TARGET::ORIGINAL::RFT1 + TARGET::ORIGINAL::RFT2)[-1,1]
/Result_Name=RFT_ADD_X
/Result_Type=DERIVED
/Result_Folder=PROCESSED
;
NOTE a frame of -1 means all frames

Extracting one "component" of data from signal

The following command will result in the DERIVED signal TEST containing the X component values of the TARGET RFT1.
Evaluate_Expression
/EXPRESSION=TARGET::ORIGINAL::RFT1::X
/RESULT_NAME=TEST
/RESULT_TYPE=DERIVED
! /RESULT_FOLDER=PROCESSED
;
     Using Square Brackets and Boolean Operators
In this example, project a collection of markers onto the floor
whenever the z-component of a marker is less than a threshold (e.g. 0.08 in this example)
otherwise set the resulting frame to NO_DATA
Evaluate_Expression
/EXPRESSION=(((CURRENT_SIGNAL[-1,3])<0.08)/((CURRENT_SIGNAL[-1,3])<0.08))*VECTOR(1,1,0)*CURRENT_SIGNAL
/SIGNAL_TYPES=TARGET
/SIGNAL_FOLDER=ORIGINAL
/SIGNAL_NAMES=LFT1+LFT2+LFT3+RFT1+RFT2+RFT3
/RESULT_TYPES=TARGET
/RESULT_FOLDERS=GROUND
! /RESULT_NAME=
/APPLY_AS_SUFFIX_TO_SIGNAL_NAME=TRUE
;

NO_DATA (NAN)

     NAN is a reserved string used to designate "Not a Number".

Visual3D commands refer to NO_DATA or DATA_NOT_FOUND as NAN

For example, the expression 1/0 results in NAN
     isNAN(expression) tests values against NAN - If the number is NAN the result is 1, otherwise the result is 0
[Set_Pipeline_Parameter_From_Expression]
/PARAMETER_NAME= NAN_TEST
/EXPRESSION=ISNAN(1/0)
/AS_INTEGER=TRUE
;
::NAN_TEST = 1
[Set_Pipeline_Parameter_From_Expression]
/PARAMETER_NAME= NAN_TEST
/EXPRESSION=ISNAN(-999999.000000)
/AS_INTEGER=TRUE
;
::NAN_TEST = 1

Returns "1" because -999999 is equal to Data Not Found in Visual3D.

[Set_Pipeline_Parameter_From_Expression]
/PARAMETER_NAME= NAN_TEST
/EXPRESSION=ISNAN(15)
/AS_INTEGER=TRUE
;
::NAN_TEST = 0

Example: Set negative values to NO_DATA

If the z-component of the LELB signal is below 0 set the frame to NO_DATA

Evaluate_Expression
/EXPRESSION=(TARGET::ORIGINAL::LELB::Z>0)/(TARGET::ORIGINAL::LELB::Z>0)*TARGET::ORIGINAL::LELB
/RESULT_NAME=LELB
/RESULT_TYPE=TARGET
/RESULT_FOLDER=PROCESSED
;

Pipeline parameters using + as delimiter

Visual3D's pipeline parameters assume that a + is a delimiter between entries.

If the user wants to use an expression containing a + in a command that allows multiple signals, Visual3D will interpret this plus sign incorrectly.

The workaround is to use a mathematical function add() to express the addition.

add(a,b) -- adds two expressions.

Visual3D Reserved Operators

There are five characters that cause the equation parser considerable trouble. We have introduced reserved pipeline commands that can be used in the place of these characters.

     AMP = &

For example, if the desired pipeline command were as follows:

Select_Active_File
/FILE_NAME=ALL_FILES
/QUERY= TAG1 & TAG2
;

If the tags TAG1 and TAG2 exist then all files that have been assigned both tags will be active.

If, however, we want to use pipeline parameters in place of the text TAG1 and TAG2, we have a problem because there is no way to stop Visual3D from using the & character to concatenate the text. The solution was to introduce a reserved parameter ::AMP.

The following pipeline would result

Set_Pipeline_Parameter

Set_Pipeline_Parameter
/PARAMETER_NAME=A
/PARAMETER_VALUE=TAG1
;
Set_Pipeline_Parameter
/PARAMETER_NAME=B
/PARAMETER_VALUE=TAG2
;
Select_Active_File
/FILE_NAME=ALL_FILES
/QUERY= ::A&::AMP&::B
;

This would result in Visual3D interpreting the query

/QUERY=TAG1 & TAG2
     COLON = :
     SEMICOLON = ;
     PLUS = +
     FSLASH = /

CURRENT_SIGNAL

     Used to refer to a specific signal with a simple syntax

Compute the length of one signal.

The legacy syntax is:

Evaluate_Expression
/EXPRESSION=LENGTH(TARGET::ORIGINAL::RFT1)
/RESULT_TYPES=DERIVED
/RESULT_FOLDERS=PROCESSED
/RESULT_NAME=_LENGTH
/APPLY_AS_SUFFIX_TO_SIGNAL_NAME=TRUE
;

The legacy syntax can get complicated if Pipeline_Parameters are used in the signal name because of the order in which equations are parsed.

! Create a pipeline parameter containing the marker name
Set_Pipeline_Parameter
/PARAMETER_NAME=MARKER
/PARAMETER_VALUE=RFT1
;
Evaluate_Expression
/EXPRESSION=LENGTH(TARGET::ORIGINAL&:&:&::MARKER&)
/RESULT_TYPES=DERIVED
/RESULT_FOLDERS=PROCESSED
/RESULT_NAME=_LENGTH
;

This gets even more complicate if the folder is also a pipeline parameter.

An alternative is the following

Evaluate_Expression
/EXPRESSION=LENGTH(CURRENT_SIGNAL)
/SIGNAL_TYPES=TARGET
/SIGNAL_FOLDER=ORIGINAL
/SIGNAL_NAMES=::MARKER
/RESULT_TYPES=DERIVED
/RESULT_FOLDERS=PROCESSED
/RESULT_NAME=_LENGTH
/APPLY_AS_SUFFIX_TO_SIGNAL_NAME=TRUE
;

}

     Used to allow multiple signals to be specified in an expression

Compute the length of TARGETS RFT1, RFT2, and RFT3 in the ORIGINAL folder

The legacy implementation requires a For_Each statement

For_Each
/Iteration_Parameter_Name= MARKERS
/Items= RFT1+RFT2+RFT3
;
Evaluate_Expression
/EXPRESSION=LENGTH(TARGET::ORIGINAL&:&:&::MARKERS&)
/SIGNAL_TYPES=TARGET
/SIGNAL_FOLDER=ORIGINAL
/SIGNAL_NAMES=
/RESULT_TYPES=DERIVED
/RESULT_FOLDERS=PROCESSED
/RESULT_NAME=::MARKERS
/APPLY_AS_SUFFIX_TO_SIGNAL_NAME=TRUE
;
End_For_Each
/Iteration_Parameter_Name=MARKERS
;

Using CURRENT_SIGNAL

Evaluate_Expression
/EXPRESSION=LENGTH(CURRENT_SIGNAL)
/SIGNAL_TYPES=TARGET
/SIGNAL_FOLDER=ORIGINAL
/SIGNAL_NAMES=RFT1+RFT2+RFT3
/RESULT_TYPES=DERIVED
/RESULT_FOLDERS=PROCESSED
/RESULT_NAME=_LENGTH
/APPLY_AS_SUFFIX_TO_SIGNAL_NAME=TRUE
;


}

     Used to Specifying all signals of a given TYPE

Compute the length of all TARGETS in the ORIGINAL folder

The legacy implementation requires a For_Each command and a command to get the names of all of the TARGETS

Set_Pipeline_Parameter_To_List_Of_Signal_Names
/PARAMETER_NAME=ALL_TARGETS
/SIGNAL_TYPE=TARGET
/SIGNAL_FOLDER=ORIGINAL
;
For_Each
/Iteration_Parameter_Name= MARKERS
/Items= ::ALL_TARGETS
;
Evaluate_Expression
/EXPRESSION=LENGTH(TARGET::ORIGINAL&:&:&::MARKERS&)
/SIGNAL_TYPES=TARGET
/SIGNAL_FOLDER=ORIGINAL
/SIGNAL_NAMES=
/RESULT_TYPES=DERIVED
/RESULT_FOLDERS=PROCESSED
/RESULT_NAME=::MARKERS
/APPLY_AS_SUFFIX_TO_SIGNAL_NAME=TRUE
;
End_For_Each
/Iteration_Parameter_Name=MARKERS
;

Using CURRENT_SIGNAL

Evaluate_Expression
/EXPRESSION=LENGTH(CURRENT_SIGNAL)
/SIGNAL_TYPES=TARGET
/SIGNAL_FOLDER=ORIGINAL
/SIGNAL_NAMES=
/RESULT_TYPES=DERIVED
/RESULT_FOLDERS=PROCESSED
/RESULT_NAME=_LENGTH
/APPLY_AS_SUFFIX_TO_SIGNAL_NAME=TRUE
;

}

APPLY_AS_SUFFIX_TO_SIGNAL_NAME

     If APPLY_AS_SUFFIX_TO_SIGNAL_NAME is true, OR RESULT_NAMES.size() == SIGNAL_NAMES.size()

Compute the length of all TARGETS in the ORIGINAL folder

Evaluate_Expression
/EXPRESSION=LENGTH(CURRENT_SIGNAL)
/SIGNAL_TYPES=TARGET
/SIGNAL_FOLDER=ORIGINAL
/SIGNAL_NAMES=
/RESULT_TYPES=DERIVED
/RESULT_FOLDERS=PROCESSED
/RESULT_NAME=_LENGTH
/APPLY_AS_SUFFIX_TO_SIGNAL_NAME=TRUE
;

Compute the length of Two TARGETS (RFT1 and RFT2) in the ORIGINAL folder

Evaluate_Expression
/EXPRESSION=LENGTH(CURRENT_SIGNAL)
/SIGNAL_TYPES=TARGET
/SIGNAL_FOLDER=ORIGINAL
/SIGNAL_NAMES=RFT1+RFT2
/RESULT_TYPES=DERIVED
/RESULT_FOLDERS=PROCESSED
/RESULT_NAME=_LENGTH
/APPLY_AS_SUFFIX_TO_SIGNAL_NAME=TRUE
;

Compute a Best_Plane_Fit for multiple signals at each frame of data

Evaluate_Expression
/EXPRESSION=Best_Fit_Plane(CURRENT_SIGNAL)
/SIGNAL_TYPES=TARGET
/SIGNAL_FOLDER=ORIGINAL
/SIGNAL_NAMES=LSK_1+LSK_2+LSK_3
/RESULT_TYPES=DERIVED
/RESULT_FOLDERS=PROCESSED
/RESULT_NAME=LSK_PLANE
/APPLY_AS_SUFFIX_TO_SIGNAL_NAME=TRUE
;

}

     If APPLY_AS_SUFFIX_TO_SIGNAL_NAME is false, AND RESULT_NAMES.size() == 1

Compute the length of one TARGET (TARGET::ORIGINAL::RFT1)

Evaluate_Expression
/EXPRESSION=LENGTH(TARGET::ORIGINAL::RFT1)
/RESULT_TYPES=DERIVED
/RESULT_FOLDERS=PROCESSED
/RESULT_NAME=RFT1_LENGTH
;

Functions

Visual3D includes the following functions.

Some of these functions are common mathematical expressions, some are "convenience functions" that we have found useful.

pi() - returns 3.14159265358979323846
int(a) - truncate each component to the nearest integer
round(a) - round each component to the nearest integer
fmod(y,x) - Returns the floating-point remainder of y/x
=> y and x must be one dimensional signals; returns a one dimensional signal
abs(a) - absolute value
sign(a)= sign of the signal ((a<0)=-1, (a>0)=1, (a==0) = 0
sqrt(a) - square root
exp(a) - exponent
log(a) - natural log
log10(a) - log base 10
     rand(lo_value,hi_value,signal) - random number in the range (lo_value,hi_value)
Example : rand() will generate a random number in the range 0 to 1
Set_Pipeline_Parameter_From_Expression
/PARAMETER_NAME=TEST1
/EXPRESSION=RAND()
/AS_INTEGER=FALSE
;
::TEST1 = 0.220525
Example : rand(lo_value,hi_value) will generate a random number in the range lo_value to hi_value
Set_Pipeline_Parameter_From_Expression
/PARAMETER_NAME=TEST2
/EXPRESSION=RAND(2,3)
/AS_INTEGER=FALSE
;
::TEST2 = 2.232995
Example : rand(lo_value,hi_value,signal) will generate a random number in the range lo_value to hi_value with the same number of components and frames as signal.
Set_Pipeline_Parameter_From_Expression
/PARAMETER_NAME=TEST3
/EXPRESSION=RAND(2,3,FRAME_NUMBERS::ORIGINAL::FRAMES)
/AS_INTEGER=FALSE
;
::TEST3 = 2.808424+2.582592+2.346721+2.697052+2.662510+2.861250+2.843808+...(to number of frames)
Example : rand(lo_value,hi_value,signal). If signal is a number, that number of values are returned.
Set_Pipeline_Parameter_From_Expression
/PARAMETER_NAME=TEST4
/EXPRESSION=RAND(2,3,3)
/AS_INTEGER=FALSE
;
::TEST4 = 2.446495 + 2.718410 + 2.201863
Example : Create a TARGET with random values between 0 and 1
Create_Target
/SIGNAL_NAMES=TEST5
! /SIGNAL_DESCRIPTION=
/EXPRESSION=RAND(0,1,TARGET::ORIGINAL::LFT1)
! /INCLUDE_CALFILE=FALSE
;
View the resulting signal in the 3D viewer by turning on the target trail
Example: create a TARGET with random values between 0 and 1.
Create_Target
/SIGNAL_NAMES=TEST6
! /SIGNAL_DESCRIPTION=
/EXPRESSION=VECTOR(RAND(0,1,FRAME_NUMBERS::ORIGINAL::FRAMES),RAND(0,1,FRAME_NUMBERS::ORIGINAL::FRAMES),RAND(0,1,FRAME_NUMBERS::ORIGINAL::FRAMES))
! /INCLUDE_CALFILE=FALSE
;

Note that all components contain different values

Example : Create a TARGET where each frame is on a random location on the surface of a sphere of radius 1
Evaluate_Expression
/EXPRESSION=RAND(-PI(),PI(),FRAME_NUMBERS::ORIGINAL::FRAMES)
/RESULT_TYPES=DERIVED
/RESULT_FOLDERS=RADIUS
/RESULT_NAME=VERTICAL
! /APPLY_AS_SUFFIX_TO_SIGNAL_NAME=FALSE
;
Evaluate_Expression
/EXPRESSION=RAND(0,2*PI(),FRAME_NUMBERS::ORIGINAL::FRAMES)
/RESULT_TYPES=DERIVED
/RESULT_FOLDERS=RADIUS
/RESULT_NAME=HORIZONTAL
! /APPLY_AS_SUFFIX_TO_SIGNAL_NAME=FALSE
;
Create_Target
/SIGNAL_NAMES=SPHERE
! /SIGNAL_DESCRIPTION=
/EXPRESSION=VECTOR(
COS(DERIVED::RADIUS::VERTICAL)*COS(DERIVED::RADIUS::HORIZONTAL),
-COS(DERIVED::RADIUS::VERTICAL)*SIN(DERIVED::RADIUS::HORIZONTAL),
SIN(DERIVED::RADIUS::VERTICAL))
! /INCLUDE_CALFILE=FALSE
;
length(x) -- creates the length (magnitude) of a vector
     distance(a,b) -- distance between two signals.
Example
Evaluate_Expression
/Expression= distance(LANDMARK::ORIGINAL::RIGHT_HIP , TARGET::ORIGINAL::LHIP)
/Result_Name=PROX_THIGH_RADIUS
! /Result_Type=DERIVED
! /Result_Folder=PROCESSED
;
     add(a,b) -- add two expressions
Visual3D's pipeline parameters assume that a + is a delimiter between entries.
If the user wants to use an expression containing a + in a command that allows multiple signals, Visual3D will interpret this plus sign incorrectly.
The workaround is to use a mathematical function add() to express the addition.
Example. Adding two signals could be accomplished equally well by the following two commands.
Evaluate_Expression
/Expression= LANDMARK::ORIGINAL::RIGHT_HIP + TARGET::ORIGINAL::LHIP
/Result_Name=TEST1
! /Result_Type=DERIVED
! /Result_Folder=PROCESSED
;
Evaluate_Expression
/Expression= add(LANDMARK::ORIGINAL::RIGHT_HIP , TARGET::ORIGINAL::LHIP)
/Result_Name=TEST2
! /Result_Type=DERIVED
! /Result_Folder=PROCESSED
;
dot (a, b) -- creates the dot product of a and b
cross (a, b) -- creates the cross product of a and b
NOTE: Often you will want to do dot (a, b)/ length (b), or cross (a, b) / length (b)
First_Derivative(a) -- creates the first derivative of the signal
Second_Derivative(a) -- creates the second derivative of the signal


     Frame_Count(a) -- return the number of frames in the signal
Example. Extract the last 3 frames of data from a metric signal
Create a test metric signal
Metric_Explicit
! /RESULT_METRIC_FOLDER=PROCESSED
/RESULT_METRIC_NAME=AA
/METRIC_VALUE=LIST(1,2,3,4)
;
Create a new signal from the last 3 frames of this metric sigal
Evaluate_Expression
/EXPRESSION=SNIP(METRIC::PROCESSED::AA,FRAME_COUNT(METRIC::PROCESSED::AA)-2,FRAME_COUNT(METRIC::PROCESSED::AA))
! /SIGNAL_TYPES=
! /SIGNAL_FOLDER=ORIGINAL
! /SIGNAL_NAMES=
/RESULT_TYPES=METRIC
/RESULT_FOLDERS=PROCESSED
/RESULT_NAME=AB
! /APPLY_AS_SUFFIX_TO_SIGNAL_NAME=FALSE
;
Note that in this case this is equivalent to:
Evaluate_Expression
/EXPRESSION=SNIP(METRIC::PROCESSED::AA,2,4)
! /SIGNAL_TYPES=
! /SIGNAL_FOLDER=ORIGINAL
! /SIGNAL_NAMES=
/RESULT_TYPES=METRIC
/RESULT_FOLDERS=PROCESSED
/RESULT_NAME=AB
! /APPLY_AS_SUFFIX_TO_SIGNAL_NAME=FALSE
;

Using Pipeline Parameters in an Expression

The syntax for using a pipeline parameter as part of an expression is a bit unusual and takes an understanding of how Visual3D parses parameters and pre-processes commands.

The ampersand & is used in pipeline commands to concatenate strings together, and thus is a separator for the parser to find the pieces that need to be parsed separately.

For example, to use a pipeline parameter LP_FREQ:

/EXPRESSION=2*pi()*&::LP_FREQ

The ampersand tells the parser to take the 2*pi()* and the ::LP_FREQ separately through the pre-parser. The first part is just taken as is since it doesn't have a prefix of ::. The value after the & does have a :: prefix, so it is substituted with the pipeline parameter.

If you have more complex expressions, you might need to surround each pipeline parameter with an ampersand

&::LP_FREQ&*&::MULTIPLIER&-&::CONSTANT which may evaluate to something like: 60*1.4-90.0 once all the pipeline parameters are substituted.

The general rule is to surround the pipeline parameter with ampersands.

Expressions in Model Metrics

Model metrics have a simpler syntax. The Signal Type and Signal Folder need not be specified because there is only one version of a signal.

     Creating a Landmark at the center of a ball
Given 6 markers placed on the surface of a round ball
BALL1, BALL2, BALL3, BALL4, BALL5, BALL6
Create a model metric at the center of a best fit sphere to the ball.
Metric Name= BALL
Metric Expression = Best_Fit_Sphere(List(BALL1, BALL2, BALL3, BALL4, BALL5, BALL6))
The resulting metric will have 3 values separated by a comma (e.g. the 3 components of the center)
As an example a center value of (0.5, 0.6, 0.7) would appear as
0.5,0.6,0.7
Create a landmark using this metric data

Note the syntax for the offsets
BALL[1,1]
The syntax may seem a little strange, but [1,1] refers to the first element of the first frame

Metric Functions

     Metric_Minimum(signal, start_event, end_event) - Minimum within each event_sequence
Metric_Minimum(target::processed::rft1)
returns the Minimum value across all frames
Metric_Minimum(target::processed::rft1, event_label::original::rhs)
returns the Minimum value at the event rhs
Metric_Minimum(target::processed::rft1, event_label::original::rhs, event_label::original::rto)
returns the Minimum value between the events rhs and rto
     Metric_Maximum(signal, start_event, end_event) - Maximum within each event_sequence
Metric_Maximum(target::processed::rft1)
returns the maximum value across all frames
Metric_Maximum(target::processed::rft1, event_label::original::rhs)
returns the maximum value at the event rhs
Metric_Maximum(target::processed::rft1, event_label::original::rhs, event_label::original::rto)
returns the maximum value between the events rhs and rto
     Metric_Mean(signal, start_event, end_event) - Mean within each event_sequence
Metric_Mean(target::processed::rft1)
returns the Mean value across all frames
Metric_Mean(target::processed::rft1, event_label::original::rhs)
returns the Mean value at the event rhs
Metric_Mean(target::processed::rft1, event_label::original::rhs, event_label::original::rto)
returns the Mean value between the events rhs and rto
     Metric_Median(signal, start_event, end_event) - Median within each event_sequence
Metric_Median(target::processed::rft1)
returns the Median value across all frames
Metric_Median(target::processed::rft1, event_label::original::rhs)
returns the Median value at the event rhs
Metric_Median(target::processed::rft1, event_label::original::rhs, event_label::original::rto)
returns the Median value between the events rhs and rto
     Metric_StdDev(signal, start_event, end_event) - Standard Deviation within each event_sequence
Metric_StdDev(target::processed::rft1)
returns the Standard Deviation value across all frames
Metric_StdDev(target::processed::rft1, event_label::original::rhs)
returns the Standard Deviation value at the event rhs
Metric_StdDev(target::processed::rft1, event_label::original::rhs, event_label::original::rto)
returns the Standard Deviation value between the events rhs and rto
     Metric_RMS(signal, start_event, end_event) - RMS within each event_sequence
Metric_RMS(target::processed::rft1)
returns the RMS value across all frames
Metric_RMS(target::processed::rft1, event_label::original::rhs)
returns the RMS value at the event rhs
Metric_RMS(target::processed::rft1, event_label::original::rhs, event_label::original::rto)
returns the RMS value between the events rhs and rto
     Metric_InterQuartile(signal, start_event, end_event) - Inter Quartile Range
Interquartile Definition
Example:
Metric_InterQuartile(target::processed::rft1, event_label::original::rhs, event_label::original::rto)

The resulting signal as 3 components, and interquartile for each of the 3 components of RFT1

     Cross_Correlation(signal1, signal2, Wrap, Max_Delay) - Cross Correlation between two signals
Cross_Correlation(signal1, signal2, Wrap, Max_Delay)

The parameters are consistent with the Cross_Correlation Pipeline Command

     Metric_Sum(signal, start_event, end_event) - where start_event and end_event are optional.
Example;
Metric_Sum(target::processed::rft1)
Metric_Sum(target::processed::rft1, event_label::original::rhs)
Metric_Sum(target::processed::rft1, event_label::sequence::rcycle)
Metric_Sum(target::processed::rft1, event_label::original::rhs, event_label::original::rto)
Note that the event label requires the full signal path. i.e. event_label::original::rhs not just rhs
     Metric_Integrate(signal, initial_value, start_event, end_event) - where initial_value, start_event and end_event are optional.

See Pipeline Command Metric_Integrate

Example;
Metric_Integrate(target::processed::rft1)
Metric_Integrate(target::processed::rft1, event_label::original::rhs)
Metric_Integrate(target::processed::rft1, event_label::original::rhs, event_label::original::rto)
Note that the event label requires the full signal path. i.e. event_label::original::rhs not just rhs

Signal Functions

     sort(signal, direction (default = 1), component (default = 1))
sort(target::original::rft1) sort descending by all components independently
sort(target::original::rft1, 1.0) sort ascending by all components independently
sort(target::original::rft1, -1.0) sort descending by all components independently
sort(target::original::rft1, 1.0, Component) sort ascending, by component, other frames sorted by component sort
sort(target::original::rft1, -1.0, Component) sort descending, by component, other frames sorted by component sort
     Transpose(signal)
Transpose(signal) // Swaps frames and components of a signal
This transposes a signal. Useful when you have an array of signals, and you create a metric for each and append as components. You can turn the components into a list of metrics by frames (like we are used to using in Visual3D).

Example of it's use, creates a list of metrics of the mean of the z component of the target rft1 from RTO to RHS. (note, the spline didn't have to be done here, but it is here just to show it's use).

Evaluate_Expression
/EXPRESSION=transpose( mean( append_as_components ( spline ( snip (target::original::rft1::z, event_label::original::rto, event_label::original::rhs), 101) )))
! /SIGNAL_TYPES=
! /SIGNAL_FOLDER=ORIGINAL
! /SIGNAL_NAMES=
! /RESULT_TYPES=DERIVED
! /RESULT_FOLDERS=PROCESSED
/RESULT_NAME=test
! /APPLY_AS_SUFFIX_TO_SIGNAL_NAME=FALSE
;
     interpolate(signal, gap, fit, order)
:for example, interpolate a signal across a maximum gap of 10 frames, fitting 3 frames before and after the gap using a third order polynomial
INTERPOLATE(TARGET::PROCESSED::RSK3,10,3,3)
     Resolve_Discontinuity(signal, expected magnitude of the discontinuity, event_label, event_instance)
Joint angles often exhibit discontinuities because of limitations of resolving a joint angle as an Euler Sequence. This command resolves the discontinuity by add/subtracting an offset at the point the discontinuity occurs.
For example,
Resolve_Discontinuity(link_model_based::original::rshoulder_angle, range, event_label::original::rhs, instance)
Resolve_Discontinuity(link_model_based::original::rshoulder_angle, range, event_label::original::rhs) // starts from first instance
Resolve_Discontinuity(link_model_based::original::rshoulder_angle, range) // starts from first valid frame,
Note that the event label requires the full signal path. i.e. event_label::original::rhs not just rhs
One of the interesting consequences of this decision is that the command is actually looking for an array of "frame times" so you could actually use a number or a metric signal or an expression.

Example, a figure skater spinning has a rotation angle that continues to increase; a double jump may cover 720 degrees.

Euler angles, however, can only be resolved into a range of 360 degrees because anything beyond that is actually the same physical angle as an angle within this range.

In the case of the figure skater, the axial angle may begin at 90 degrees relative to the laboratory and increase to 180 degrees at which it suddenly becomes -180 degrees and then continues up to 180 degrees at which it suddenly becomes -180 degrees.

This is a natural consequence of the way Euler angles are parsed from the Rotation Matrix.

Visual3D includes a "convenience function" for removing this discontinuity, by adding/subtracting an offset at the point the discontinuity occurs.

The typical calling syntax is:

Resolve_Discontinuity(signal, range, event_label, instance)
The range represents the range of motion of the signal. In the figure skating example above, the range is 360 degrees.
The value of the signal at the specified instance of the event_label is assumed to be "in the range"
Visual3D then looks for a large discontinuity in the signal and adds the range.

if the instance is omitted:

Resolve_Discontinuity(signal, range, event_label)
The first instance of the event is used.

if the instance and the event_label are omitted:

Resolve_Discontinuity(signal, range)
the first valid frame is used


Example: the angle of a golf club to the anterior direction of the golfer (LINK_MODEL_BASED::ORIGINAL::CLUB_ANGLE).

The has a discontinuity as the signal goes beyond the range possible for computing the Cardan Sequence.
The following expression adds 360 at the point of discontinuity
At the Event_Label TAKEAWAY the club angle is assumed to be "within the range", which means that this value will persist in the output signal.
The command is looking for the time of the event, so it is important to use the full signal name EVENT_LABEL::ORIGINAL::TAKEAWAY
At a discontinuity 360 degrees is either added or subtracted from the value depending on the direction of the discontinuity.
Evaluate_Expression
/EXPRESSION=RESOLVE_DISCONTINUITY(LINK_MODEL_BASED::ORIGINAL::CLUB_ANGLE,360,EVENT_LABEL::ORIGINAL::TAKEAWAY)
/RESULT_NAME=CLUB_ANGLE
/RESULT_TYPE=LINK_MODEL_BASED
/RESULT_FOLDER=PROCESSED
;
     Indefinite_Integral(signal, initial_value, start_event, end_event) - where initial_value, start_event and end_event are optional.

See Pipeline Command Indefinite_Integral

Example;
Indefinite_Integral(target::processed::rft1)
Indefinite_Integral(target::processed::rft1, vector(0.0, 0.0, 1.0))
Indefinite_Integral(target::processed::rft1, vector(0.0, 0.0, 1.0), event_label::original::rhs)
Indefinite_Integral(target::processed::rft1, vector(0.0, 0.0, 1.0), event_label::original::rhs, event_label::original::rto)
Note that the event label requires the full signal path. i.e. event_label::original::rhs not just rhs
     Point_Relative_To_3Points(Point1, Vertex1, Vertex2, Vertex3)

Compute the location of Point1 relative to a coordinate system defined by Vertex1, Vertex2, and Vertex3

Consider the hypothetical situation.

There are two sets of motion trials, tagged condition1 and condition2
there are two static files (e.g. two models)
in one model (assigned to condition1) the anatomical landmarks are attached.
in the other model, the same anatomical landmarks did not exist.
Selecting condition1 to be active, makes model1 active
Select_Active_File
/FILE_NAME=CONDITION1
! /QUERY=
;
! determine the offsets of marker RLKNEE relative to the three markers RTH1, RTH2, and RTH3
! and save as a pipeline parameter
Set_Pipeline_Parameter_From_Expression
/PARAMETER_NAME=TEST
/EXPRESSION=Median(Point_Relative_To_3Points(MODEL::TARGET::RLKNEE, MODEL::TARGET::RTH2, MODEL::TARGET::RTH3, MODEL::TARGET::RTH4))
/AS_INTEGER=FALSE
;
! making condition2 active will make model2 active.
Select_Active_File
/FILE_NAME=CONDITION2
! /QUERY=
;
! now create a landmark for RLKNEE in the second model
Add_Landmark
/LANDMARK_NAME=RLKNEE
! /CALIBRATION_FILE=
! /USER_GENERATED=TRUE
! /USE_PERCENTAGE=FALSE
! /CALIBRATION_ONLY=FALSE
/USE_TARGETS=TRUE
! /SEGMENT_NAME=
/TARGET_TYPES=TARGET+TARGET+TARGET
/TARGET_NAMES=RTH2+RTH3+RTH4
! /MCS_ML=0.0
! /MCS_AP=0.0
! /MCS_AXIAL=0.0
/LANDMARK_LOCATION=::TEST
! /REFERENCE_LOCATION_TYPE=
! /REFERENCE_LOCATION_NAME=
! /USE_REFERENCE_LOCATION=FALSE
;

Least Squares Fitting of Data

     Best_Fit_Plane(signal, start_event_signal, end_event_signal) - Find a plane that fits the path of a point from a start event to an end event.
[The resulting plane is defined by 4 components]
Example: Compute a Best_Plane_Fit for one signal across a range of frames
Evaluate_Expression
/EXPRESSION=Best_Fit_Plane(CURRENT_SIGNAL,EVENT_LABEL::ORIGINAL::START,EVENT_LABEL::ORIGINAL::END)
/SIGNAL_TYPES=TARGET
/SIGNAL_FOLDER=ORIGINAL
/SIGNAL_NAMES=LSK_1
/RESULT_TYPES=METRIC
/RESULT_FOLDERS=PROCESSED
/RESULT_NAME=LSK1_PLANE
/APPLY_AS_SUFFIX_TO_SIGNAL_NAME=TRUE
;
Example: Compute a Best_Plane_Fit for multiple signals at each frame of data
Evaluate_Expression
/EXPRESSION=Best_Fit_Plane(CURRENT_SIGNAL)
/SIGNAL_TYPES=TARGET
/SIGNAL_FOLDER=ORIGINAL
/SIGNAL_NAMES=LSK_1+LSK_2+LSK_3
/RESULT_TYPES=DERIVED
/RESULT_FOLDERS=PROCESSED
/RESULT_NAME=LSK_PLANE
/APPLY_AS_SUFFIX_TO_SIGNAL_NAME=TRUE
;
     Best_Fit_Circle(signal, start_event_signal, end_event_signal)
Fit a 2D circle to the path of a signal.
The algorithm computes a best fit plane to the data, rotates this plane into a principal plane, computes the center and radius, the rotates these values back into the original plane.
The result is 4 components; the X,Y,Z location of the origin and the radius.
     Best_Fit_Sphere(signal,start_event_signal,end_event_signal)
Example : Fit a sphere to 6 points on a DIAMOND

Create 6 TARGETS representing the Vertices

Create_Target
/SIGNAL_NAMES=V1
! /SIGNAL_DESCRIPTION=
/EXPRESSION=VECTOR((0.5+0*FRAME_NUMBERS::ORIGINAL::FRAMES),0,0)
! /INCLUDE_CALFILE=FALSE
;
Create_Target
/SIGNAL_NAMES=V2
! /SIGNAL_DESCRIPTION=
/EXPRESSION=VECTOR((-0.5+0*FRAME_NUMBERS::ORIGINAL::FRAMES),0,0)
! /INCLUDE_CALFILE=FALSE
;
Create_Target
/SIGNAL_NAMES=V3
! /SIGNAL_DESCRIPTION=
/EXPRESSION=VECTOR((0,0.5+0*FRAME_NUMBERS::ORIGINAL::FRAMES),0)
! /INCLUDE_CALFILE=FALSE
;
Create_Target
/SIGNAL_NAMES=V4
! /SIGNAL_DESCRIPTION=
/EXPRESSION=VECTOR((0,-0.5+0*FRAME_NUMBERS::ORIGINAL::FRAMES),0)
! /INCLUDE_CALFILE=FALSE
;
Create_Target
/SIGNAL_NAMES=V5
! /SIGNAL_DESCRIPTION=
/EXPRESSION=VECTOR((0,0,0.5+0*FRAME_NUMBERS::ORIGINAL::FRAMES))
! /INCLUDE_CALFILE=FALSE
;
Create_Target
/SIGNAL_NAMES=V6
! /SIGNAL_DESCRIPTION=
/EXPRESSION=VECTOR((0,0,-0.5+0*FRAME_NUMBERS::ORIGINAL::FRAMES))
! /INCLUDE_CALFILE=FALSE
;
Evaluate_Expression
/EXPRESSION=Best_Fit_Sphere(CURRENT_SIGNAL)
/SIGNAL_TYPES=TARGET
/SIGNAL_FOLDER=ORIGINAL
/SIGNAL_NAMES=V1+V2+V3+V4+V5+V6
/RESULT_TYPES=DERIVED
! /RESULT_FOLDERS=PROCESSED
/RESULT_NAME=SPHERE
! /APPLY_AS_SUFFIX_TO_SIGNAL_NAME=FALSE
;

Note that TARGETS are created and the sphere computed has each TARGET on its surface.

Example : Create a TARGET where each frame is on a random location on the surface of a sphere of radius 1
Evaluate_Expression
/EXPRESSION=RAND(-PI(),PI(),FRAME_NUMBERS::ORIGINAL::FRAMES)
/RESULT_TYPES=DERIVED
/RESULT_FOLDERS=RADIUS
/RESULT_NAME=VERTICAL
! /APPLY_AS_SUFFIX_TO_SIGNAL_NAME=FALSE
;
Evaluate_Expression
/EXPRESSION=RAND(0,2*PI(),FRAME_NUMBERS::ORIGINAL::FRAMES)
/RESULT_TYPES=DERIVED
/RESULT_FOLDERS=RADIUS
/RESULT_NAME=HORIZONTAL
! /APPLY_AS_SUFFIX_TO_SIGNAL_NAME=FALSE
;
Create_Target
/SIGNAL_NAMES=SPHERE
! /SIGNAL_DESCRIPTION=
/EXPRESSION=VECTOR(
COS(DERIVED::RADIUS::VERTICAL)*COS(DERIVED::RADIUS::HORIZONTAL),
-COS(DERIVED::RADIUS::VERTICAL)*SIN(DERIVED::RADIUS::HORIZONTAL),
SIN(DERIVED::RADIUS::VERTICAL))
! /INCLUDE_CALFILE=FALSE
;
Evaluate_Expression
/EXPRESSION=Best_Fit_Sphere(CURRENT_SIGNAL)
/SIGNAL_TYPES=TARGET
/SIGNAL_FOLDER=ORIGINAL
/SIGNAL_NAMES=SPHERE
/RESULT_TYPES=DERIVED
! /RESULT_FOLDERS=PROCESSED
/RESULT_NAME=SPHERE
! /APPLY_AS_SUFFIX_TO_SIGNAL_NAME=FALSE
;
     Simple_Linear_Regression(signal1, signal2, start_event, end_event); - Fit a signal to a line. Y = mX + b.
An explanation of the calculation can be found here or [here]
Signal1 and Signal2 are one component signals
Resulting METRIC signal contains 6 components
Slope = m -> Component 1
Intercept = b -> Component 2
Siga = uncertainty in m -> Component 3
Sigb = uncertainty in b -> Component 4
Chi2 = chi square -> Component 5
Q = The R^2 statistic -> Component 6

Intersection Functions

     Line_Line_Intersect(line1, line2, line3, line4, tolerance)
vector1 is defined by vertices line1 and line2
vector2 is defined by vertices line3 and line4
two vectors in 3D space rarely intersect precisely.
tolerance is the maximum distance at the closest point of the two vectors that will be labeled an intersection
the default value of the tolerance=0.01
     Line_Plane_Intersect(line1, line2, plane1, plane2, plane3)
Line1 and line 2 define the vector
Plane1, Plane2, and Plane3 define the plane
Line_Plane_Intersect(line1, line2, plane)
Line1 and line 2 define the vector
Plane defines the plane (for example, a best_fit_plane
     Project_Point_On_Plane(plane, point).
Project a point onto a plane.
[The resulting plane is defined by 4 components]
     Point_Distance_To_Plane(plane, point).
Compute perpendicular distance from a point to a plane.
[The resulting plane is defined by 4 components]
     Point_Distance_To_Line(point_on_vector, vector, point).
Compute perpendicular distance from a point to a line.
     Is_Point_Inside_Polygon(Point1, Vertex1, Vertex2, Vertex3, ...)

Is a Point inside a planar polygon comprised of any number of vertices?

Example: Create a polygon comprising 4 vertices, check to see if a point is inside the Polygon

Metric_Explicit
/RESULT_METRIC_FOLDER=VERTEX
/RESULT_METRIC_NAME=V1
/METRIC_VALUE=VECTOR(0,0,0)
;
Metric_Explicit
/RESULT_METRIC_FOLDER=VERTEX
/RESULT_METRIC_NAME=V2
/METRIC_VALUE=VECTOR(1,0,0)
;
Metric_Explicit
/RESULT_METRIC_FOLDER=VERTEX
/RESULT_METRIC_NAME=V3
/METRIC_VALUE=VECTOR(1,1,0)
;
Metric_Explicit
/RESULT_METRIC_FOLDER=VERTEX
/RESULT_METRIC_NAME=V4
/METRIC_VALUE=VECTOR(0,1,0)
;
Evaluate_Expression
/EXPRESSION=Is_Point_Inside_Polygon(
VECTOR(0.5,0.5,0),
METRIC::VERTEX::V1,
METRIC::VERTEX::V2,
METRIC::VERTEX::V3,
METRIC::VERTEX::V4
)
/SIGNAL_TYPES=
/SIGNAL_FOLDER=
/SIGNAL_NAMES=
/RESULT_TYPES=METRIC
/RESULT_FOLDERS=POLYGON
/RESULT_NAME=TEST_IN
! /APPLY_AS_SUFFIX_TO_SIGNAL_NAME=FALSE
;
Expression Result : 1.000000
Evaluate_Expression
/EXPRESSION=Is_Point_Inside_Polygon(
VECTOR(0.5,0.5,0.5),
METRIC::VERTEX::V1,
METRIC::VERTEX::V2,
METRIC::VERTEX::V3,
METRIC::VERTEX::V4
)
/SIGNAL_TYPES=
/SIGNAL_FOLDER=
/SIGNAL_NAMES=
/RESULT_TYPES=METRIC
/RESULT_FOLDERS=POLYGON
/RESULT_NAME=TEST_IN
! /APPLY_AS_SUFFIX_TO_SIGNAL_NAME=FALSE
;
Expression Result : 0.000000

Snip

Functions for segmenting a signal into a collection of signals within event_sequences

Snip(signal, start_event, end_event)
or
Snip(signal, event_sequence)
Example: Snip(DERIVED::PROCESSED::SIGNAL_NAME, EVENT_LABEL::ORIGINAL::START, EVENT_LABEL::ORIGINAL::END)
This creates a list (array) of signal segments (snips) within each event sequence.

Spline

Spline(signal_list, number_of_points)
This does a spline of a signal (array of snips) to normalize each signal to the same number of points.

Append As...

Append_As_Components(signal_list)
This takes the signal list, and appends each signal into one signal as new components.
Append_As_Frames(signal_list)
This takes a signal list, and appends each signal to the end of the previous signal to create the result with each signal appended to each other as new frames
     Append_As_Frames Example
Open any cmz file with more than 1 file
Select_Active_File
/FILE_NAME=ALL_FILES
! /QUERY=
;
! Create a metric signal with 3 components and 1 frame
Metric_Explicit
/RESULT_METRIC_FOLDER=TEST
/RESULT_METRIC_NAME=SCOTT
/METRIC_VALUE=1+2+3
;
!The following command will concatenate the metric signal from each file
!into a GLOBAL metric signal.
Evaluate_Expression
/EXPRESSION=Append_As_Frames(GLOBAL::METRIC::TEST::SCOTTA,CURRENT_SIGNAL)
/SIGNAL_TYPES=METRIC
/SIGNAL_FOLDER=TEST
/SIGNAL_NAMES=SCOTT
/RESULT_TYPES=METRIC
/RESULT_FOLDERS=TEST
/RESULT_NAME=GLOBAL::SCOTTA
! /APPLY_AS_SUFFIX_TO_SIGNAL_NAME=FALSE
;

Assigned Forces

The model based items GRF_DATA and COP Path are signals stored at the Motion Capture rate.
This is because these signals have the option to be resolved into a Segment Coordinate System and all Segment Coordinate Systems (except the default LAB) are at the motion capture rate.
There are times, however, when it would be useful to get the Force, CofP, and FreeMoment for the force assignment at the analog sample rate.
     FORCE(segment)

Select the force assigned to the Left Foot segment (default segment name LFT).

Evaluate_Expression
/EXPRESSION=FORCE("LFT")
/RESULT_NAME=SCOTT
! /RESULT_TYPE=DERIVED
! /RESULT_FOLDER=PROCESSED
;
     COFP(segment)

Select the center of pressure assigned to the Left Foot segment (default segment name LFT).

Evaluate_Expression
/EXPRESSION=COFP("LFT")
/RESULT_NAME=SCOTT
! /RESULT_TYPE=DERIVED
! /RESULT_FOLDER=PROCESSED
;
     FREEMOMENT(segment)

Select the Free Moment assigned to the Left Foot segment (default segment name LFT).

Evaluate_Expression
/EXPRESSION=FREEMOMENT("LFT")
/RESULT_NAME=SCOTT
! /RESULT_TYPE=DERIVED
! /RESULT_FOLDER=PROCESSED
;
     Error Messages

There are several possible error messages related to the Assigned Forces Function.

Evaluate_Expression
/EXPRESSION=FORCE(JUNK)
/RESULT_TYPE=DERIVED
/RESULT_FOLDER=PROCESSED
/RESULT_NAME=TEST
;
WARNING! No Segment Name was specified. Did you forget the quotes?
In order to ensure that a string containing the segment name is recognized quotes must be used.
Evaluate_Expression
/EXPRESSION=COFP("JUNK")
/RESULT_TYPE=DERIVED
/RESULT_FOLDER=PROCESSED
/RESULT_NAME=TEST
;
INFO! Segment Junk was not found
The segment was not part of the Link Model
Evaluate_Expression
/EXPRESSION=COFP("Right Foot")
/RESULT_TYPE=DERIVED
/RESULT_FOLDER=PROCESSED
/RESULT_NAME=TEST
;
WARNING! Evaluate_Expression requires default segment names. For Right Foot use RFT
Visual3D has a set of default segment names that must be used in expressions, so that the
expressions can be shared between users that have different config files.
Evaluate_Expression
/EXPRESSION=COFP("Right Fore Foot")
/RESULT_TYPE=DERIVED
/RESULT_FOLDER=PROCESSED
/RESULT_NAME=TEST
;
INFO! Segment Right Fore Foot is Kinematic Only, so there is no Force Assignment possible.
Only Kinetic segments can be assigned a force.

Trigonometric functions

Note all trigonometric data are radians (not degrees)

cos(a) - cosine
sin(a) - sine
tan(a) - tangent
ctan(a) - cotangent
atan(a) - arctangent
asin(a) - arcsine
acos(a) - arccosine
atan2(y,x) - arctangent => y and x must be one dimensional signals; return one dimensional signal

Arrays

     Vector(a,b, etc)

creates a vector of the number of components specified

! Create a metric signal with 2 components and one frame
[Metric_Explicit]
! /RESULT_METRIC_FOLDER=PROCESSED
/RESULT_METRIC_NAME=VEC2
/METRIC_VALUE=2+3
;
! Create a vector containing a constant, a two dimensional metric and a 3 dimensional model based signal.
Evaluate_Expression
/EXPRESSION=vector (1, METRIC::PROCESSED::VEC2, LINK_MODEL_BASED::ORIGINAL::RKNEE_ANGLE)
! /SIGNAL_TYPES=
! /SIGNAL_FOLDER=ORIGINAL
! /SIGNAL_NAMES=
! /RESULT_TYPES=DERIVED
! /RESULT_FOLDERS=PROCESSED
/RESULT_NAME=TEST
! /APPLY_AS_SUFFIX_TO_SIGNAL_NAME=FALSE
;
The resulting signal will have the first three columns (one for the constant, one for the vector of 2 components) buffered to the number of frames of RKNEE_ANGLE by replicating the first frame.
list(a,b,etc) -- creates a list (column vector) or the number of rows specified:
unit_vector (a, b, etc) -- creates a unit vector of the number of components specified:

Specifying a Data Tree signal

Signals should be placed into the expression in the form:

SIGNAL_TYPE::SIGNAL_FOLDER::SIGNAL_NAME

To define a specific element of a signal (e.g. the X Component)

SIGNAL_TYPE::SIGNAL_FOLDER::SIGNAL_NAME::X

To define a specific frame of a data of signal (e.g. Frame 2)

SIGNAL_TYPE::SIGNAL_FOLDER::SIGNAL_NAME[2]

Data stored in the GLOBAL Workspace should be expressed as follows:

GLOBAL::SIGNAL_TYPE::SIGNAL_FOLDER::SIGNAL_NAME

NOTE: Global signals can be accessed regardless of the ACTIVE FILES.

     Examples for Specifying a Data Tree Signal
TARGET::ORIGINAL::RFT1 = Signal RFT1 in the TARGET type and ORIGINAL folder
ANALOG::PROCESSED::FX1 = Signal FX1 in the ANALOG type and PROCESSED folder
PARAMETER::ANALOG::RATE= Parameter RATE in the ANALOG group of the C3D PARAMETERS

Specifying a TAG

TAGS can be expressed as follows:

TAG::TAG_NAME

C3D Parameters can be expressed as follows:

PARAMETER::GROUP::PARAMETER_NAME

Specifying an item from a model

The following Model data is available.

MODEL::METRIC::NAME
MODEL::SEGMENT::segname::LENGTH
MODEL::SEGMENT::segname::DEPTH
MODEL::SEGMENT::segname::CENTER_OF_MASS
MODEL::SEGMENT::segname::IXX
MODEL::SEGMENT::segname::IYY
MODEL::SEGMENT::segname::IZZ
MODEL::SEGMENT::segname::MASS
MODEL::SEGMENT::segname::PROXIMAL_RADIUS
MODEL::SEGMENT::segname::DISTAL_RADIUS
MODEL::SEGMENT::segname::ORIGIN

To refer to a marker

MODEL::TARGET::MARKER_NAME

If you want to refer to a specific component of a signal

MODEL::TARGET::MARKER_NAME::X

To refer to a landmark

MODEL::LANDMARK::LANDMARK_NAME

To refer to a force. NOTE This will be available in version 5.0

MODEL::FORCE::FP1

The following command will create a global signal containing the average value of the signal FORCE::FP1 over the range of frames specified for the model (e.g. if a range is not specified, all frames will be used).

The command is executed once for each active file, so the resulting signal will continually be overwritten and the last file processed will correspond to the resulting signal.

Evaluate_Expression
/EXPRESSION=MODEL::FORCE::FP1
/RESULT_NAME=GLOBAL::SCOTT
/RESULT_TYPE=DERIVED
! /RESULT_FOLDER=PROCESSED
;

If you edit commands in the text editor, which is the only way to use evaluate_expression at the moment, you need to use the 3 letter acronyms for the names.

[Default (Internal) Segment Names]

Specifying String Data

Quotes are to be used around string data in an expression to differentiate it from variable names. ie; subject_name="John Smith". Parameters in the pipeline that are strings, are not quoted (i.e.; EXPRESSION is a string, but you don't need quotes around it). Within EXPRESSION, our expression parser parses the variables, data and operators out of the expression. Data can be doubles or strings. If it is a string, Visual3D has no way to recognize the difference between a string and a variable name reference, except to quote the string data.

For example, there is a problem with the following evaluate_expression:

Evaluate_Expression
/EXPRESSION=(::HandChoice="LEFT")
/RESULT_NAME=TEST_4
! /RESULT_TYPE=DERIVED
! /RESULT_FOLDER=PROCESSED
;

This uses a pipeline parameter in the middle of a string parameter (the EXPRESSION). Global parameters cannot be evaluated in the middle of a string, so to recognize that a pipeline parameter, you need to concatenate it into the expression as follows:

Evaluate_Expression
/EXPRESSION=(&::HandChoice&="LEFT")
/RESULT_NAME=TEST_4
! /RESULT_TYPE=DERIVED
! /RESULT_FOLDER=PROCESSED
;

Currently, the operators are only parsed as a single character, so the use of "/=" (not equals) cannot be used yet. You can do NOT(item1=item2) in order to process a not equals currently, but this will change shortly to allow "/=", "!=" cannot be used because the "!" is our start comment character for the pipeline commands.

Modifying String Data

STRING_TO_UPPER(string)
STRING_TO_LOWER(string)
Converting To_Upper and To_Lower String Data (more...)
Set_Pipeline_Parameter_From_Expression
/PARAMETER_NAME=TEST
/EXPRESSION=STRING_TO_LOWER("XXXXXX")
/AS_INTEGER=FALSE
;
Set_Pipeline_Parameter_From_Expression
/PARAMETER_NAME=TEST
/EXPRESSION=STRING_TO_UPPER("yyyyyyy")
/AS_INTEGER=FALSE
;
Select_Active_File
/FILE_NAME=GLOBAL
! /QUERY=
;
Create_Text_Data
/SIGNAL_FOLDER=SCOTT
/SIGNAL_NAMES=NAME
/TEXT_DATA=Hello World
! /TEXT_FILE_NAME=
! /PROMPT_ON_EMPTY=TRUE
;
Evaluate_Expression
/EXPRESSION=STRING_TO_UPPER(TEXT_DATA::SCOTT::NAME)
! /SIGNAL_TYPES=
! /SIGNAL_FOLDER=ORIGINAL
! /SIGNAL_NAMES=
/RESULT_TYPES=TEXT_DATA
/RESULT_FOLDERS=SCOTT
/RESULT_NAME=SCOTT_UPPER
! /APPLY_AS_SUFFIX_TO_SIGNAL_NAME=FALSE
;
Evaluate_Expression
/EXPRESSION=STRING_TO_LOWER(TEXT_DATA::SCOTT::NAME)
! /SIGNAL_TYPES=
! /SIGNAL_FOLDER=ORIGINAL
/SIGNAL_NAMES=
/RESULT_TYPES=TEXT_DATA
/RESULT_FOLDERS=SCOTT
/RESULT_NAME=SCOTT_LOWER
! /APPLY_AS_SUFFIX_TO_SIGNAL_NAME=FALSE
;

Parsing String Data

Given a pipeline parameter that is a string. For internal reasons, the string cannot be a number, or it will be interpreted as a number.

There are 3 commands that extract a portion of a string.

STRING_LEFT(string,index)
STRING_RIGHT(string,index)
STRING_MID(string,index1,index2)
STRING_LENGTH(string)
STRING_FIND(string, substring, start)

NOTE: When referencing strings, the string should be surrounded by quotes. This identifies to Visual3D that you are referencing a string, and not a file name etc.

Parsing String Data (more...)
Set_Pipeline_Parameter_From_Expression
/PARAMETER_NAME=TEST_STRING
/EXPRESSION="A123456789"
/AS_INTEGER=FALSE
;

The result is

::TEST_STRING = A123456789


Set_Pipeline_Parameter_From_Expression
/PARAMETER_NAME=TEST_LEFT
/EXPRESSION=STRING_LEFT("&::TEST_STRING&",3)
/AS_INTEGER=FALSE
;

The result is

::TEST_LEFT = A12
Set_Pipeline_Parameter_From_Expression
/PARAMETER_NAME=TEST_RIGHT
/EXPRESSION=STRING_RIGHT("&::TEST_STRING&",3)
/AS_INTEGER=FALSE
;

The result is

::TEST_RIGHT = 789
Set_Pipeline_Parameter_From_Expression
/PARAMETER_NAME=TEST_MID
/EXPRESSION=STRING_MID("&::TEST_STRING&",3,3)
/AS_INTEGER=FALSE
;

The result is

::TEST_MID = 345

Note: For STRING_MID the number values are zero based

Set_Pipeline_Parameter_From_Expression

/PARAMETER_NAME=TEST_LENGTH
/EXPRESSION=STRING_LENGTH("&::TEST_STRING&")
/AS_INTEGER=TRUE
;

The result is

::TEST_LENGTH = 10

Set_Pipeline_Parameter_From_Expression

/PARAMETER_NAME=TEST_INDEX
/EXPRESSION=STRING_FIND("&::TEST_STRING&",234,0)
/AS_INTEGER=TRUE
;

The result is

::TEST_INDEX = 2

Set_Pipeline_Parameter_From_Expression

/PARAMETER_NAME=TEST_INDEX
/EXPRESSION=STRING_FIND("&::TEST_STRING&",234,5)
/AS_INTEGER=TRUE
;

The result is

::TEST_INDEX = -1


Example: Extract text (more...)
Given the following Text_Data loaded from a file store in a signal TEXT_DATA::SCOTT:TEST

Random Stuff <Subject>Scott</Subject> More Random Stuff

Extract the name of the subject.
Set_Pipeline_Parameter_From_Expression
/PARAMETER_NAME=F1
/EXPRESSION=9+STRING_FIND(TEXT_DATA::SCOTT::TEST, "<Subject>", 0)
/AS_INTEGER=TRUE
;
Set_Pipeline_Parameter_From_Expression
/PARAMETER_NAME=F2
/EXPRESSION=STRING_FIND(TEXT_DATA::SCOTT::TEST, "</Subject>", 0)-&::F1
/AS_INTEGER=TRUE
;
Set_Pipeline_Parameter_From_Expression
/PARAMETER_NAME=SUBJECT
/EXPRESSION=String_Mid(TEXT_DATA::SCOTT::TEST,&::F1&,&::F2&)
/AS_INTEGER=FALSE
;
The resulting pipeline parameter contains "Scott"

Examples

Example: Create signal using another signal component

Extract the z-component of a target.

Evaluate_Expression
/Expression= TARGET::ORIGINAL::RFT1::Z
/Result_Name=RFT1_Z
/Result_Type=DERIVED
/Result_Folder=PROCESSED
;

Example: Add two ANALOG signals

Evaluate_Expression
/Expression= ANALOG::ORIGINAL::EMG1 + ANALOG::ORIGINAL::EMG2
/Result_Name=EMG_ADD
! /Result_Type=DERIVED
! /Result_Folder=PROCESSED
;

Example: Divide the components of a signal

Evaluate_Expression
/Expression= FORCE::ORIGINAL::FP1::Y/FORCE::ORIGINAL::FP1::X
/Result_Name=FP1Y_X
! /Result_Type=DERIVED
! /Result_Folder=PROCESSED
;

Example: Create a vector between two locations

A Vector is created by subtracting one location from another.

Evaluate_Expression
/Expression= LINK_MODEL_BASED::ORIGINAL::RT_COP-LINK_MODEL_BASED::ORIGINAL::COM
/Result_Name=R
/Result_Type=DERIVED
/Result_Folder=PROCESSED
;

Example: Average several TARGET signals

Evaluate_Expression
/Expression= (TARGET::ORIGINAL::TARG1 + TARGET::ORIGINAL::TARG2 + TARGET::ORIGINAL::TARG3) / 3
/Result_Name=TARG_AVG
! /Result_Type=DERIVED
! /Result_Folder=PROCESSED
;

Example: Distance between a TARGET and a LANDMARK

Evaluate_Expression
/Expression= distance(LANDMARK::ORIGINAL::RIGHT_HIP , TARGET::ORIGINAL::LHIP)
/Result_Name=PROX_THIGH_RADIUS
! /Result_Type=DERIVED
! /Result_Folder=PROCESSED
;

Example: Perpendicular distance - LANDMARK to VECTOR

Compute the perpendicular distance from the Knee joint center
LANDMARK::ORIGINAL::RT_KNEE
To a vector between the Hip Joint Center and Ankle Joint Center
LANDMARK::ORIGINAL::RIGHT_HIP
LANDMARK::ORIGINAL::RT_ANKLE


! create a unit_vector from the hip joint landmark (RIGHT_HIP) to the ankle joint landmark (RT_ANKLE)
Evaluate_Expression
/EXPRESSION=(LANDMARK::ORIGINAL::RIGHT_HIP-LANDMARK::ORIGINAL::RT_ANKLE)/DISTANCE(LANDMARK::ORIGINAL::RIGHT_HIP,LANDMARK::ORIGINAL::RT_ANKLE)
/RESULT_NAME=UNIT_VECTOR_HIP_ANKLE
/RESULT_TYPE=DERIVED
/RESULT_FOLDER=MIKULICZ
;
! create a vector from the hip joint landmark (RIGHT_HIP) to the knee joint landmark (RT_KNEE)
Evaluate_Expression
/EXPRESSION=LANDMARK::ORIGINAL::RIGHT_HIP-LANDMARK::ORIGINAL::RT_KNEE
/RESULT_NAME=VECTOR_HIP_KNEE
/RESULT_TYPE=DERIVED
/RESULT_FOLDER=MIKULICZ
;
! compute the perpendicular distance from the RT_KNEE to the vector from the HIP to the ANKLE
Evaluate_Expression
/EXPRESSION=LENGTH(CROSS(DERIVED::MIKULICZ::UNIT_VECTOR_HIP_ANKLE,DERIVED::MIKULICZ::VECTOR_HIP_KNEE))
/RESULT_NAME=PERPENDICULAR_DISTANCE
/RESULT_TYPE=DERIVED
/RESULT_FOLDER=MIKULICZ
;

Example: Get the actual start time of the C3D file

Visual3D always treats the first frame of data in the C3D file as Frame 1. If the original c3d file was truncated, so that the first frame is not 1, Visual3D retains that information and stores it in the Visual3D Parameter Group. If a user wants to compute the actual start time for the file, the following command can be used.

Evaluate_Expression
/EXPRESSION=(PARAMETER::VISUAL3D::ORIGINAL_FIRST_FRAME-1)/PARAMETER::POINT::RATE
/RESULT_NAME=START_TIME
/RESULT_TYPE=METRIC
/RESULT_FOLDER=PROCESSED
;

Example: Copying a signal

Evaluate_Expression
/Expression= ANALOG::ORIGINAL::EMG1
/Result_Name=EMG1_COPY
/Result_Type=ANALOG
/Result_Folder=PROCESSED
;

Note that the Result_Folder cannot be ORIGINAL because we frown on artificially labelling a signal as ORIGINAL. If ORIGINAL is specified, the data is automatically stored in the PROCESSED folder

Example: Copy a signal to the Global Workspace

In order to pass data between files, it is necessary to use the Global Workspace which is common to all files in the Workspace.

Evaluate_Expression
/EXPRESSION=METRIC::ORIGINAL::RTH1_MEAN
/RESULT_NAME=GLOBAL::RTH1_MEAN
/RESULT_TYPE=METRIC
/RESULT_FOLDER=PROCESSED
;

Example: Copy a signal to a different signal type

Evaluate_Expression
/Expression= ANALOG::ORIGINAL::EMG1
/Result_Name=EMG1_COPY
/Result_Type=DERIVED
/Result_Folder=PROCESSED
;

Note: the PROCESSED signal is at the sampling rate of the Analog signal.

Example: Subtracting Two Metrics

Subtract two metric signals.

Evaluate_Expression
/EXPRESSION=METRIC::PROCESSED::EMG1_MAX - METRIC::PROCESSED::EMG1_MIN
/RESULT_NAME=EMG1_RANGE
/RESULT_TYPE=METRIC
/RESULT_FOLDER=PROCESSED
;

Example: Subtract Global Mean Value from Signal

The evaluate_expression command can be used to subtract a global mean value from a signal. In this example, an offset (mean value of the signal) is found for two analog signals from one trial and the offset value is subtracted from the same two analog signals found in other trials.

! -----------------------------------------------
! Select a specific trial and compute mean values
! -----------------------------------------------
! Select OFFSET_TRIAL as active file
Select_Active_File
/FILE_NAME=OFFSET_TRIAL
;

! Compute mean of signals ADC1 and ADC2. The resulting means are named ADC1_Offset and ADC2_offset and
! are located in the METRIC::OFFSET folder
Metric_Mean
/RESULT_METRIC_NAME=_Offset
/APPLY_AS_SUFFIX_TO_SIGNAL_NAME=TRUE
/RESULT_METRIC_FOLDER=OFFSET
/SIGNAL_TYPES=ANALOG
/SIGNAL_NAMES=ADC1+ADC2
/SIGNAL_FOLDER=ORIGINAL
! /SIGNAL_COMPONENTS=ALL_COMPONENTS
/EVENT_SEQUENCE=
/EXCLUDE_EVENTS=
! /GENERATE_MEAN_AND_STDDEV=TRUE
! /APPEND_TO_EXISTING_VALUES=FALSE
;

! -----------------------------------------------
! Select remaining trials and subtract mean value
! ----------------------------------------------- 

! Select OTHER_TRIALS as the active files
Select_Active_File
/FILE_NAME=OTHER_TRIALS
;

! Loop for each signal
For_Each
/ITERATION_PARAMETER_NAME=INDEX
/ITEMS=ADC1+ADC2
;

! Subtract Global Mean Value from Signal
Evaluate_Expression
/EXPRESSION=ANALOG::ORIGINAL&:&:&::INDEX& - GLOBAL::METRIC::OFFSET&:&:&::INDEX&_Offset_MEAN
/RESULT_NAME=::INDEX
/RESULT_TYPE=ANALOG
/RESULT_FOLDER=PROCESSED
;

End_For_Each
/ITERATION_PARAMETER_NAME=INDEX
;

Example: Create a vector

Evaluate_Expression
/EXPRESSION=vector(0.4, 1.2)
/RESULT_NAME=VECTOR
/RESULT_TYPE=DERIVED
/RESULT_FOLDER=PROCESSED
;
Evaluate_Expression
/EXPRESSION=vector(target::processed::rft1::x, target::processed::lft1::y, target::processed::rpv4::z)
/RESULT_NAME=VECTOR
/RESULT_TYPE=DERIVED
/RESULT_FOLDER=PROCESSED
;

Example: Set 2 components of a vector to zero

set the x and z components of a vector to zero

Evaluate_Expression
/EXPRESSION=vector(0*target::processed::rft1::x, target::processed::rft1::y, 0*target::processed::rft1::z)
/RESULT_NAME=Y_VEC
/RESULT_TYPE=DERIVED
/RESULT_FOLDER=PROCESSED
;

Example: Compute the magnitude of a vector

Evaluate_Expression
/EXPRESSION=length(FORCE::ORIGINAL::FP1)
/RESULT_NAME=VECTOR
/RESULT_TYPE=DERIVED
/RESULT_FOLDER=PROCESSED
;

Example: Create a 2x2 matrix

Evaluate_Expression
/EXPRESSION=vector(list(11,21),list(12,22))
/RESULT_NAME=2x2
/RESULT_TYPE=DERIVED
/RESULT_FOLDER=PROCESSED
;

The output of this command will be:

Frame   X           Y
1       11.0000     12.0000
2       21.0000     22.0000

Example: Create a 1 Hz Sine wave

Create the signal at the POINT rate.

Evaluate_Expression
/EXPRESSION=SIN(2*PI()*FRAME_NUMBERS::ORIGINAL::TIME)
/RESULT_NAME=SIN_WAVE
/RESULT_TYPE=DERIVED
/RESULT_FOLDER=PROCESSED
;

Create the signal at the ANALOG rate.

Evaluate_Expression
/EXPRESSION=SIN(2*PI()*FRAME_NUMBERS::ORIGINAL::ANALOGTIME)
/RESULT_NAME=SIN_WAVE
/RESULT_TYPE=DERIVED
/RESULT_FOLDER=PROCESSED
;

Example: Compute the cross product of two vectors

Evaluate_Expression
/EXPRESSION=CROSS(TARGET::PROCESSED::VEC1,TARGET::PROCESSED::VEC)
/RESULT_NAME=ANGLE_RAD
/RESULT_TYPE=DERIVED
/RESULT_FOLDER=PROCESSED
;


Example: Compute the angle between two unit vectors

Evaluate_Expression
/EXPRESSION=ACOS(DOT(TARGET::PROCESSED::UNIT1,TARGET::PROCESSED::UNIT2))
/RESULT_NAME=ANGLE_RAD
/RESULT_TYPE=DERIVED
/RESULT_FOLDER=PROCESSED
;

The resulting values will be expressed in Radians.

The equivalent command that will have the result expressed in Degrees is:

Evaluate_Expression
/EXPRESSION=ACOS(DOT(TARGET::PROCESSED::UNIT1,TARGET::PROCESSED::UNIT2))*180/PI()
/RESULT_NAME=ANGLE_DEG
/RESULT_TYPE=DERIVED
/RESULT_FOLDER=PROCESSED
;

Example Integrate a Signal between Events

Integrate a force signal (FORCE::ORIGINAL::FP1) between event labels (START & END) with an initial value of zero

Evaluate_Expression
/EXPRESSION= Integrate(FORCE::ORIGINAL::FP1,VECTOR(0,0,0),EVENT_LABEL::ORIGINAL::START,EVENT_LABEL::ORIGINAL::END)
/RESULT_NAME=IMPULSE
/RESULT_TYPE=DERIVED
/RESULT_FOLDER=PROCESSED
;

Example: Create a binary signal

Based on a threshold signal, make the new signal 1 when the value is greater than a threshold and 0 otherwise.

Evaluate_Expression
/EXPRESSION= ANALOG::ORIGINAL::CHANNEL1 > 1
/RESULT_NAME=CHANNEL1_BINARY
/RESULT_TYPE=DERIVED
/RESULT_FOLDER=PROCESSED
;


Example: Signal 1 greater than Signal 2

Given two signals
TARGET::ORIGINAL::RFT1
TARGET::ORIGINAL::LFT1
Use the Boolean operator > to identify when the Z component of RFT1 is greater than the Z component of LFT1
Evaluate_Expression
/EXPRESSION= TARGET::ORIGINAL::RFT1::Z > TARGET::ORIGINAL::LFT1::Z
/RESULT_NAME=RFT1_GREATER
/RESULT_TYPE=DERIVED
/RESULT_FOLDER=PROCESSED
;
The output signal will be 1 when RFT1::Z is greater than LFT1::Z and 0 otherwise

Example: Set negative values to zero

Set all of the negative values of a signal to 0.0.

Evaluate_Expression
/EXPRESSION=(FORCE::ORIGINAL::FP1::Y>0)*FORCE::ORIGINAL::FP1::Y
/RESULT_NAME=SCOTT_POS
/RESULT_TYPE=DERIVED
/RESULT_FOLDER=PROCESSED
;
This expression uses the Boolean operator > to identify when the Y component of FP1 is greater than 0

Similarly, you can set the positive values to zero

Evaluate_Expression
/EXPRESSION=(FORCE::ORIGINAL::FP1::Y<0)*FORCE::ORIGINAL::FP1::Y
/RESULT_NAME=SCOTT_NEG
/RESULT_TYPE=DERIVED
/RESULT_FOLDER=PROCESSED
;

Example: Set negative values to NO_DATA

If the z-component of the LELB signal is below 0 set the frame to NO_DATA

Evaluate_Expression
/EXPRESSION=(TARGET::ORIGINAL::LELB::Z>0)/(TARGET::ORIGINAL::LELB::Z>0)*TARGET::ORIGINAL::LELB
/RESULT_NAME=LELB
/RESULT_TYPE=TARGET
/RESULT_FOLDER=PROCESSED
;

Example: If one tracking marker is no_data, make all tracking markers no_data

When tracking markers drop out or go missing through out a trial, there is often an artifact in the segment pose.

This artifact is related to two issues:

  1. The filtered signal isn't very good at the point of dropout
  2. The best fit to the tracking marker template changes when the template changes.

The following are different solutions that could be used:

  1. Solution One: Remove all signal processing until the very end. In other words filter the LINK_MODEL_BASED signals, but don't filter the TARGET or ANALOG signals. This option is consistent with Ton van den Bogert's recommendation that all signals be filtered with the same filter characteristics (see attached).
  2. Solution Two: Filter the data, and apply a median filter to the LINK_MODEL_BASED signals. This removes artifacts but we aren't sure if this is appropriate.
  3. Solution Three: This solution isn't available in Visual3D yet, but we are exploring the possibility of filtering the rotation matrix (e.g. after the pose is computed). I like this option, but it may be a while before it is implemented.
  4. Solution Four: Require that all tracking markers on a segment exist or the pose won't be computed.

An example of Solution Four is below:

  • Given thigh targets RTH1, RTH2, RTH3, RTH4
  • If one of the targets is NO_DATA, you want all targets to be NO_DATA.
  • Use a boolean operator on the target residual.
    • The target residual is specified using the component "R" - if you are using an older version of Visual3D, try using component "4" instead in the example below.
Evaluate_Expression
/EXPRESSION=TARGET::ORIGINAL::RTH2 /
   (
     (TARGET::ORIGINAL::RTH1::R>=0) & 
     (TARGET::ORIGINAL::RTH2::R>=0) & 
     (TARGET::ORIGINAL::RTH3::R>=0) & 
     (TARGET::ORIGINAL::RTH4::R>=0)
   )
/RESULT_NAME=RTH2
/RESULT_TYPE=TARGET
/RESULT_FOLDER=PROCESSED
;

Example: Conditional Statement

Implement a conditional expression like the following:

for i=1:nframe
if y1(i,3)< y1(i,4)
data(i)= y1(i,3)/y1(i,4);
else
data(i)= y1(i,4)/y1(i,3);
end
end

Assume the signal y1 is a target TARGET::ORIGINAL::RFT1 and the components of interest are Y and Z.

The expressions (Y <Z and Y >= Z) evaluate to "0" or "1" depending on if they are True or False, and then you multiply by the value you want to use if the expression is true in this case Y/Z or Z/Y. Then you add the 2 expressions together, and you get only the expression that evaluated true!

Evaluate_Expression
/EXPRESSION=(TARGET::ORIGINAL::RFT1::Y < TARGET::ORIGINAL::RFT1::Z)*(TARGET::ORIGINAL::RFT1::Y/TARGET::ORIGINAL::RFT1::Z
 +(TARGET::ORIGINAL::RFT1::Y >= TARGET::ORIGINAL::RFT1::Z)*(TARGET::ORIGINAL::RFT1::Z/TARGET::ORIGINAL::RFT1::Y) 
/RESULT_NAME=SCOTT
/RESULT_TYPE=DERIVED
/RESULT_FOLDER=PROCESSED
;

Example: Rank Order a Set of Metrics

Given a set of metric signals containing one component.

METRIC::GROUP1::TIME
METRIC::GROUP2::TIME
METRIC::GROUP3::TIME
METRIC::GROUP4::TIME

The result of the following command will be the RANK of the metric (METRIC::GROUP1::TIME) amongst the cohort.

Evaluate_Expression
/EXPRESSION= 1 + (METRIC::GROUP1::TIME > METRIC::GROUP2::TIME) + (METRIC::GROUP1::TIME > METRIC::GROUP3::TIME) + (METRIC::GROUP1::TIME > METRIC::GROUP4::TIME)
/RESULT_NAME=RANK_GROUP1
/RESULT_TYPE=METRIC
/RESULT_FOLDER=GROUP1
;

Example: Extracting one "component" of data from signal

The following command will result in the DERIVED signal TEST containing the X component values of the TARGET RFT1.

Evaluate_Expression
/EXPRESSION=TARGET::ORIGINAL::RFT1::X
/RESULT_NAME=TEST
/RESULT_TYPE=DERIVED
! /RESULT_FOLDER=PROCESSED
;

Example: Extracting one frame of data from a signal

The following command will result in the METRIC signal TEST containing the values of the TARGET RFT1 from Frame 3.

Evaluate_Expression
/EXPRESSION=TARGET::ORIGINAL::RFT1[3]
/RESULT_NAME=TEST
/RESULT_TYPE=METRIC
! /RESULT_FOLDER=PROCESSED
;

This can be useful in the following situation.

A signal exists that contains the mean and standard deviation of a signal over a gait cycle

(e.g. created using Global_Normalized_Signal_Mean; this creates a P2D signal in the Global Workspace)

A mean signal is time normalized (by default to 101 frames). If you want one specific value of this signal, you cannot use an Event Label to specify the frame of data because Event Labels have no meaning for a signal that does not have a time base (e.g. a data rate). However, you can take advantage of the fact that you know exactly how many frames of data are in the signal. If you want the value at 25% of the range, you can simply do the following:

Evaluate_Expression
/EXPRESSION=GLOBAL::P2D::ORIGINAL::TESTX[25]
/RESULT_NAME=TEST
/RESULT_TYPE=METRIC
! /RESULT_FOLDER=PROCESSED
;

Example: Value of signal at an analog frame

Assume that you have an analog signal and the frame that you are looking for is based on a threshold crossing which usually doesn't occur at a point frame rate but occurs at the analog frame rate. Thus, you cannot use events since they are in reference to the point frame rate and not the analog frame rate.

Assume that you want the value of another analog signal at that analog_frame. The GRF is at the analog rate, and I am assuming the COM-COP is computed from the analog signals, so it too is at analog rate.

! Step 1 Create an event at frame 1
Event_Explicit
/EVENT_NAME=START
/FRAME=1
! /TIME=
;

! Step 2 Create a metric with the threshold value
! Presumably you have some method for computing this
! but in this example, I just set the metric
Metric_Explicit
/RESULT_METRIC_NAME=THRESH
! /RESULT_METRIC_FOLDER=PROCESSED
/METRIC_VALUE=-10
;
! Step 3 is to create a binary signal FZ2_BIN that is based on the analog signal (in this case FZ2).
! Any analog frame that is greater than the metric value THRESH is set to 1 all other frames are set to 0
Evaluate_Expression
/EXPRESSION=ANALOG::ORIGINAL::FZ2>METRIC::PROCESSED::THRESH
/RESULT_NAME=FZ2_BIN
/RESULT_TYPE=ANALOG
/RESULT_FOLDER=BINARY
;

! Step 4 - Create an END frame that is after the threshold crossing but before the next time the
! binary signal becomes 1. This will be at the POINT rate.
Event_Onset
/SIGNAL_TYPES=ANALOG
/SIGNAL_NAMES=FZ2_BIN
/SIGNAL_FOLDER=BINARY
/EVENT_NAME=END
! /SELECT_X=TRUE
! /SELECT_Y=FALSE
! /SELECT_Z=FALSE
/THRESHOLD=1
! /THRESHOLD_INSTANCE=0
! /BASELINE=0
! /FRAME_WINDOW=8
! /ASCENDING=FALSE
! /DESCENDING=FALSE
/START_AT_EVENT=START
! /END_AT_EVENT=
;

! Step 5 - Now sum the binary signal from START to END
! The resulting number is the analog frame number
Metric_Sum
/RESULT_METRIC_NAME=ANALOG_FRAME
! /APPLY_AS_SUFFIX_TO_SIGNAL_NAME=FALSE
! /RESULT_METRIC_FOLDER=PROCESSED
/SIGNAL_TYPES=ANALOG
/SIGNAL_NAMES=FZ2_BIN
/SIGNAL_FOLDER=BINARY
! /SIGNAL_COMPONENTS=ALL_COMPONENTS
/EVENT_SEQUENCE=START+END
/EXCLUDE_EVENTS=
/GENERATE_MEAN_AND_STDDEV=FALSE
! /APPEND_TO_EXISTING_VALUES=FALSE
;

! Step 6 - This is kind of a goofy step, but we need to create a pipeline
! parameter to hold the metric value analog frame
Set_Pipeline_Parameter_To_Data_Value
/PARAMETER_NAME=ANALOG_FRAME
/SIGNAL_TYPES=METRIC
/SIGNAL_NAMES=ANALOG_FRAME
/SIGNAL_FOLDER=PROCESSED
! /SIGNAL_COMPONENTS=ALL_COMPONENTS
;

! Step 7 - Now you can get the value of an analog signal at the analog frame
Evaluate_Expression
/EXPRESSION=FORCE::ORIGINAL::FP1[&::ANALOG_FRAME&]
/RESULT_NAME=FORCE
/RESULT_TYPE=METRIC
! /RESULT_FOLDER=PROCESSED
;

Example: Create a SINE wave

The following command creates a sine wave of frequency 1 Hz

Evaluate_Expression
/EXPRESSION=sin(2*PI()*1*(FRAME_NUMBERS::ORIGINAL::TIME-1))
/RESULT_NAME=SIN1
/RESULT_TYPE=DERIVED
/RESULT_FOLDER=SINEWAVES
;

This command takes advantage of the FRAME_NUMBERS data type, which stores FRAMES and TIME.

This data type is hidden in all versions of Visual3D prior to version 4.1

If the frequency was stored as a METRIC signal (e.g. METRIC::PROCESSED::FREQ), you could use the following:

Evaluate_Expression
/EXPRESSION=sin(2*PI()*METRIC::PROCESSED::FREQ*(FRAME_NUMBERS::ORIGINAL::TIME-1))
/RESULT_NAME=SIN1
/RESULT_TYPE=DERIVED
/RESULT_FOLDER=SINEWAVES
;

Representing the equation R= (Y - M*X - B)^2

Consider a DERIVED signal named TEST that is stored in the processed folder and has 2 or more component (X, Y, ....).

X => DERIVED::PROCESSED::TEST::X
Y => DERIVED::PROCESSED::TEST::Y


Consider M and B to be two Metric signals with one component

M => METRIC::PROCESSED::M
B => METRIC::PROCESSED::B


The expression is represented as:

Evaluate_Expression
/EXPRESSION=(DERIVED::PROCESSED::TEST::Y-METRIC::PROCESSED::M*DERIVED::PROCESSED::TEST::X-METRIC::PROCESSED::B)^2
/RESULT_NAME=RESULT
/RESULT_TYPE=DERIVED
/RESULT_FOLDER=PROCESSED
;

The resulting signal is named RESULT and stored in the PROCESSED folder

Using a pipeline parameter as part of a signal definition

The syntax is a little funky when it comes to using pipeline parameters in the middle of a signal definition because of the order in which equations are parsed.

The following subtracts two signals.

Evaluate_Expression
/EXPRESSION=ANALOG::FILTERED&:&:&::INDEX&:&:&X&-METRIC::PROCESSED&:&:&::INDEX&_zero
/RESULT_NAME=::INDEX
/RESULT_TYPE=ANALOG
/RESULT_FOLDER=OFFSET
;

Example: Comparing a model metric with a string

Consider a model metric that is defined as a string.

Set_Model_Metric
! /CALIBRATION_FILE=
/METRIC_NAME=TEST
/METRIC_VALUE="TTT"
;

Now compare it to the text string "TTT"

Evaluate_Expression
/EXPRESSION=MODEL::METRIC::TEST="TTT"
/RESULT_NAME=SCOTT
/RESULT_TYPE=METRIC
! /RESULT_FOLDER=PROCESSED
;

The text strings should be equal so the resulting signal contains a 1

Example: Exporting a model metric

Model metrics cannot be exported directly. You can, however, copy the model metric to a regular metric signal that can be exported. It is probably safest to create the new metric signal as a global metric because it isn't associated with any particular movement trial. For example the commands below will export the length of the right thigh segment.

! Copy the model metric RTH::LENGTH to the GLOBAL metric folder
Evaluate_Expression
/EXPRESSION=MODEL::SEGMENT::RTH::LENGTH
/RESULT_NAME=GLOBAL::RTH_LENGTH
/RESULT_TYPE=METRIC
/RESULT_FOLDER=EXPORT
;

! Make the global workspace active
Select_Active_File
/FILE_NAME=GLOBAL
;

! Export the signal
! Prompt for the exported filename
Export_Data_To_Ascii_File
! /FILE_NAME=
/SIGNAL_TYPES=METRIC
/SIGNAL_NAMES=RTH_LENGTH
/SIGNAL_FOLDER=EXPORT
;

Example Store a Model Metric in the Data Tree

Model metrics are stored with the model, but the data can be moved to each C3D file (stored in the data tree). This example will multiply the model metrics for mass and height to use for normalizing a signal. The resulting metric is called MASS_X_HEIGHT and will be stored in the METRIC::MODEL folder

Evaluate_Expression
/EXPRESSION=MODEL::METRIC::MASS*MODEL::METRIC::HEIGHT
/RESULT_NAME=MASS_X_HEIGHT
/RESULT_TYPE=METRIC
/RESULT_FOLDER=MODEL
;

Example: Quasi Case Statement

Given a group of unilaterally affected subjects. The Left side calculations could be the "affected” side and the right side could be the "normal” side, but for other subjects the opposite would be true. The data should be collected as "affected" or "normal" rather than "left" or "right" export them as a group.

In the commands below, wo parameters specify the letter of primary side (SIDE_LETTER) and the letter of opposite side (OPP_SIDE_LETTER). The script then uses these parameters to compute the Arm angle relative to the trunk for the two sides. The final command uses Evaluate_Expression to check to see which is the primary side and compute the arms angle of the primary side using Evaluate Expression's string comparison conditional statement. If ("&::SIDE_LETTER&" = "R") is TRUE, then the value will be 1, if not the value will be zero. If ("&::SIDE_LETTER&" = "L") is TRUE, then the value will be 1, if not the value will be zero. In the example commands below, the primary side will be the "right side" and therefore the primary side will be the right arm angle. You can change this by defining "L" as the SIDE_LETTER and "R" as the OPP_SIDE_LETTER in the first two commands.

! Define Side Parameters
Set_Pipeline_Parameter
/PARAMETER_NAME=SIDE_LETTER
/PARAMETER_VALUE=R
;

Set_Pipeline_Parameter
/PARAMETER_NAME=OPP_SIDE_LETTER
/PARAMETER_VALUE=L
;

!Calculate IN MODEL BASED joint angle - ArmAngle for side
Compute_Model_Based_Data
/RESULT_NAME=::SIDE_LETTER&ArmAngle
/FUNCTION=JOINT_ANGLE
/SEGMENT=::SIDE_LETTER&AR
/REFERENCE_SEGMENT=RTA
/RESOLUTION_COORDINATE_SYSTEM=
! /USE_CARDAN_SEQUENCE=FALSE
! /NORMALIZATION=FALSE
! NORMALIZATION_METHOD=
 /NORMALIZATION_METRIC=
 /NEGATEX=FALSE
! /NEGATEY=FALSE
/NEGATEZ=TRUE
/AXIS1=z
!/AXIS2=Y
 /AXIS3=Z
;

! Calculate IN MODEL BASED joint angle - ArmAngle for opposite side

Compute_Model_Based_Data
/RESULT_NAME=::OPP_SIDE_LETTER&ArmAngle
/FUNCTION=JOINT_ANGLE
/SEGMENT=::OPP_SIDE_LETTER&AR
/REFERENCE_SEGMENT=RTA
/RESOLUTION_COORDINATE_SYSTEM=
! /USE_CARDAN_SEQUENCE=FALSE
! /NORMALIZATION=FALSE
! NORMALIZATION_METHOD=
 /NORMALIZATION_METRIC=
 /NEGATEX=FALSE
! /NEGATEY=FALSE
/NEGATEZ=TRUE
/AXIS1=z
!AXIS2=Y
/AXIS3=Z
;

! Handle sidedness
Evaluate_Expression
/EXPRESSION=LINK_MODEL_BASED::ORIGINAL::RArmAngle*("&::SIDE_LETTER&" = "R") +  LINK_MODEL_BASED::ORIGINAL::LArmAngle*("&::SIDE_LETTER&" = "L")
/RESULT_NAME=PrimaryArmAngle
/RESULT_TYPE=DERIVED
/RESULT_FOLDER=PROCESSED
;

Example: At Event

Get the event times for the label ONSET and place them in the metric folder

Evaluate Expression
/EXPRESSION=EVENT_LABEL::ORIGINAL::ONSET
/RESULT_NAME=ONSETS
/RESULT_TYPE=METRIC
/RESULT_FOLDER=PROCESSED
;
Retrieved from ""