Expressions
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
This command results in *trial1.c3d being active
This command results in *trial2.c3d and *trial3.c3d being active. |
= Boolean Operator equals |
---|
Example: Comparing a model metric with a string
|
< Boolean Operator less than |
---|
Example:
|
<= or =< Boolean Operator less than or equal to |
---|
Example:
|
> Boolean Operator greater than |
---|
Example:
|
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 |
---|
Extracting one "component" of data from signal
|
Using Square Brackets and Boolean Operators |
---|
|
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
|
isNAN(expression) tests values against NAN - If the number is NAN the result is 1, otherwise the result is 0 |
---|
Returns "1" because -999999 is equal to Data Not Found in Visual3D.
Example: Set negative values to NO_DATA If the z-component of the LELB signal is below 0 set the frame to NO_DATA
|
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:
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
This would result in Visual3D interpreting the query
|
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:
The legacy syntax can get complicated if Pipeline_Parameters are used in the signal name because of the order in which equations are parsed.
This gets even more complicate if the folder is also a pipeline parameter. An alternative is the following
} |
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
Using CURRENT_SIGNAL
|
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
Using CURRENT_SIGNAL
} |
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
Compute the length of Two TARGETS (RFT1 and RFT2) in the ORIGINAL folder
Compute a Best_Plane_Fit for multiple signals at each frame of data
} |
If APPLY_AS_SUFFIX_TO_SIGNAL_NAME is false, AND RESULT_NAMES.size() == 1 |
---|
Compute the length of one TARGET (TARGET::ORIGINAL::RFT1)
} |
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) |
---|
Note that all components contain different values
|
- length(x) -- creates the length (magnitude) of a vector
distance(a,b) -- distance between two signals. |
---|
|
add(a,b) -- add two expressions |
---|
|
- 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 |
---|
|
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 |
---|
|
Metric Functions
Metric_Minimum(signal, start_event, end_event) - Minimum within each event_sequence |
---|
|
Metric_Maximum(signal, start_event, end_event) - Maximum within each event_sequence |
---|
|
Metric_Mean(signal, start_event, end_event) - Mean within each event_sequence |
---|
|
Metric_Median(signal, start_event, end_event) - Median within each event_sequence |
---|
|
Metric_StdDev(signal, start_event, end_event) - Standard Deviation within each event_sequence |
---|
|
Metric_RMS(signal, start_event, end_event) - RMS within each event_sequence |
---|
|
Metric_InterQuartile(signal, start_event, end_event) - Inter Quartile Range |
---|
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 |
---|
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. |
---|
|
Metric_Integrate(signal, initial_value, start_event, end_event) - where initial_value, start_event and end_event are optional. |
---|
See Pipeline Command Metric_Integrate
|
Signal Functions
sort(signal, direction (default = 1), component (default = 1)) |
---|
|
Transpose(signal) |
---|
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).
|
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
|
Resolve_Discontinuity(signal, expected magnitude of the discontinuity, event_label, event_instance) |
---|
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:
if the instance is omitted:
if the instance and the event_label are omitted:
|
Indefinite_Integral(signal, initial_value, start_event, end_event) - where initial_value, start_event and end_event are optional. |
---|
See Pipeline Command Indefinite_Integral
|
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.
|
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. |
---|
|
Best_Fit_Circle(signal, start_event_signal, end_event_signal) |
---|
|
Best_Fit_Sphere(signal,start_event_signal,end_event_signal) |
---|
Create 6 TARGETS representing the Vertices
Note that TARGETS are created and the sphere computed has each TARGET on its surface.
|
Simple_Linear_Regression(signal1, signal2, start_event, end_event); - Fit a signal to a line. Y = mX + b. |
---|
|
Intersection Functions
Line_Line_Intersect(line1, line2, line3, line4, tolerance) |
---|
|
Line_Plane_Intersect(line1, line2, plane1, plane2, plane3) |
---|
|
Project_Point_On_Plane(plane, point). |
---|
|
Point_Distance_To_Plane(plane, point). |
---|
|
Point_Distance_To_Line(point_on_vector, vector, point). |
---|
|
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
|
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 |
---|
|
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).
|
COFP(segment) |
---|
Select the center of pressure assigned to the Left Foot segment (default segment name LFT).
|
FREEMOMENT(segment) |
---|
Select the Free Moment assigned to the Left Foot segment (default segment name LFT).
|
Error Messages |
---|
There are several possible error messages related to the Assigned Forces Function.
|
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
|
- 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 |
---|
|
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...) |
---|
|
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...) |
---|
The result is
The result is
The result is
The result is
Note: For STRING_MID the number values are zero based Set_Pipeline_Parameter_From_Expression
The result is
Set_Pipeline_Parameter_From_Expression
The result is
Set_Pipeline_Parameter_From_Expression
The result is
|
Example: Extract text (more...) |
---|
Random Stuff <Subject>Scott</Subject> More Random Stuff
|
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:
- The filtered signal isn't very good at the point of dropout
- The best fit to the tracking marker template changes when the template changes.
The following are different solutions that could be used:
- 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).
- 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.
- 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.
- 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
- if y1(i,3)< y1(i,4)
- 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 ;