User Tools

Site Tools


visual3d:documentation:pipeline:expressions:signal_functions

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
visual3d:documentation:pipeline:expressions:signal_functions [2024/08/30 21:34] – [Data_Exists] wikisysopvisual3d:documentation:pipeline:expressions:signal_functions [2024/11/15 19:27] (current) – [Point_Tracked_By_3Points] wikisysop
Line 28: Line 28:
  
 **add(a,b)** -- add two expressions **add(a,b)** -- add two expressions
-Visual3D's pipeline parameters assume that a + is a delimiter between entries.+ 
 +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. 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. 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. Example. Adding two signals could be accomplished equally well by the following two commands.
 +
 +<code>
 Evaluate_Expression Evaluate_Expression
 /Expression= LANDMARK::ORIGINAL::RIGHT_HIP + TARGET::ORIGINAL::LHIP /Expression= LANDMARK::ORIGINAL::RIGHT_HIP + TARGET::ORIGINAL::LHIP
Line 37: Line 41:
 ! /Result_Type=DERIVED ! /Result_Type=DERIVED
 ! /Result_Folder=PROCESSED ! /Result_Folder=PROCESSED
-**;**+; 
 Evaluate_Expression Evaluate_Expression
 /Expression= add(LANDMARK::ORIGINAL::RIGHT_HIP , TARGET::ORIGINAL::LHIP) /Expression= add(LANDMARK::ORIGINAL::RIGHT_HIP , TARGET::ORIGINAL::LHIP)
Line 43: Line 48:
 ! /Result_Type=DERIVED ! /Result_Type=DERIVED
 ! /Result_Folder=PROCESSED ! /Result_Folder=PROCESSED
-**;**+; 
 +</code>
 ==== Sort ==== ==== Sort ====
  
 **sort(signal, direction (default = 1), component (default = 1))** **sort(signal, direction (default = 1), component (default = 1))**
  
 +<code>
 sort(target::original::rft1) sort descending by all components independently 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 ascending by all components independently
Line 53: Line 60:
 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 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 sort(target::original::rft1, -1.0, Component) sort descending, by component, other frames sorted by component sort
 +</code>
 ==== Transpose ==== ==== Transpose ====
  
Line 60: Line 68:
 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). 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**+<code> 
 +Evaluate_Expression
 /EXPRESSION=transpose( mean( append_as_components ( spline ( snip (target::original::rft1::z, event_label::original::rto, event_label::original::rhs), 101) ))) /EXPRESSION=transpose( mean( append_as_components ( spline ( snip (target::original::rft1::z, event_label::original::rto, event_label::original::rhs), 101) )))
 ! /SIGNAL_TYPES= ! /SIGNAL_TYPES=
Line 69: Line 78:
 /RESULT_NAME=test /RESULT_NAME=test
 ! /APPLY_AS_SUFFIX_TO_SIGNAL_NAME=FALSE ! /APPLY_AS_SUFFIX_TO_SIGNAL_NAME=FALSE
-**;**+; 
 +</code>
 ==== First_Derivative ==== ==== First_Derivative ====
 +[[visual3d:documentation:pipeline:signal_commands:second_derivative#first_derivative]]
 ==== Second_Derivative ==== ==== Second_Derivative ====
 +[[visual3d:documentation:pipeline:signal_commands:second_derivative#second_derivative]]
 ==== Interpolate ==== ==== Interpolate ====
  
Line 89: Line 99:
 For example, For example,
  
 +<code>
 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, 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, event_label::original::rhs) %%//%% starts from first instance
 Resolve_Discontinuity(link_model_based::original::rshoulder_angle, range) %%//%% starts from first valid frame, Resolve_Discontinuity(link_model_based::original::rshoulder_angle, range) %%//%% starts from first valid frame,
 +</code>
 +
 **Note that the event label requires the full signal path. i.e. event_label::original::rhs not just rhs** **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. 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. Example, a figure skater spinning has a rotation angle that continues to increase; a double jump may cover 720 degrees.
Line 107: Line 121:
  
 Resolve_Discontinuity(signal, range, event_label, instance) 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 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" The value of the signal at the specified instance of the event_label is assumed to be "in the range"
Line 113: Line 128:
  
 Resolve_Discontinuity(signal, range, event_label) Resolve_Discontinuity(signal, range, event_label)
 +
 The first instance of the event is used. The first instance of the event is used.
 if the instance and the event_label are omitted: if the instance and the event_label are omitted:
  
 Resolve_Discontinuity(signal, range) Resolve_Discontinuity(signal, range)
 +
 the first valid frame is used 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). 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 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 +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. +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 +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. +At a discontinuity 360 degrees is either added or subtracted from the value depending on the direction of the discontinuity.\\ 
-**Evaluate_Expression**+ 
 +<code> 
 +Evaluate_Expression
 /EXPRESSION=RESOLVE_DISCONTINUITY(LINK_MODEL_BASED::ORIGINAL::CLUB_ANGLE,360,EVENT_LABEL::ORIGINAL::TAKEAWAY) /EXPRESSION=RESOLVE_DISCONTINUITY(LINK_MODEL_BASED::ORIGINAL::CLUB_ANGLE,360,EVENT_LABEL::ORIGINAL::TAKEAWAY)
 /RESULT_NAME=CLUB_ANGLE /RESULT_NAME=CLUB_ANGLE
 /RESULT_TYPE=LINK_MODEL_BASED /RESULT_TYPE=LINK_MODEL_BASED
 /RESULT_FOLDER=PROCESSED /RESULT_FOLDER=PROCESSED
-**;**+; 
 +</code>
 ==== Indefinite Integral ==== ==== Indefinite Integral ====
  
Line 138: Line 158:
 [[Visual3D:Documentation:Pipeline:Signal_Commands:Indefinite_Integral|See Pipeline Command Indefinite_Integral]] [[Visual3D:Documentation:Pipeline:Signal_Commands:Indefinite_Integral|See Pipeline Command Indefinite_Integral]]
  
 +<code>
 Example; Example;
 Indefinite_Integral(target::processed::rft1) Indefinite_Integral(target::processed::rft1)
Line 143: Line 164:
 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)
 Indefinite_Integral(target::processed::rft1, vector(0.0, 0.0, 1.0), event_label::original::rhs, event_label::original::rto) Indefinite_Integral(target::processed::rft1, vector(0.0, 0.0, 1.0), event_label::original::rhs, event_label::original::rto)
 +</code>
 +
 +**Note that the event label requires the full signal path. i.e. event_label::original::rhs not just rhs**
 +
 +==== Cumulative_Sum ====
 +
 +**Cumulative_Sum(signal, initial_value, start_event, end_event)** - where initial_value, start_event and end_event are optional.
 +
 +<code>
 +Example;
 +Cumulative_Sum(target::processed::rft1)
 +Cumulative_Sum(target::processed::rft1, vector(0.0, 0.0, 1.0))
 +Cumulative_Sum(target::processed::rft1, vector(0.0, 0.0, 1.0), event_label::original::rhs)
 +Cumulative_Sum(target::processed::rft1, vector(0.0, 0.0, 1.0), event_label::original::rhs, event_label::original::rto)
 +Cumulative_Sum(target::processed::rft1, vector(NAN, NAN, NAN), event_label::original::rhs)
 +</code>
 +
 **Note that the event label requires the full signal path. i.e. event_label::original::rhs not just rhs** **Note that the event label requires the full signal path. i.e. event_label::original::rhs not just rhs**
 ==== Point Relative to 3 Points ==== ==== Point Relative to 3 Points ====
Line 152: Line 190:
 Consider the hypothetical situation. Consider the hypothetical situation.
  
 +<code>
 There are two sets of motion trials, tagged condition1 and condition2 There are two sets of motion trials, tagged condition1 and condition2
 there are two static files (e.g. two models) there are two static files (e.g. two models)
Line 160: Line 199:
 /FILE_NAME=CONDITION1 /FILE_NAME=CONDITION1
 ! /QUERY= ! /QUERY=
-**;**+; 
 ! determine the offsets of marker RLKNEE relative to the three markers RTH1, RTH2, and RTH3 ! determine the offsets of marker RLKNEE relative to the three markers RTH1, RTH2, and RTH3
 ! and save as a pipeline parameter ! and save as a pipeline parameter
-**Set_Pipeline_Parameter_From_Expression**+Set_Pipeline_Parameter_From_Expression
 /PARAMETER_NAME=TEST /PARAMETER_NAME=TEST
 /EXPRESSION=Median(Point_Relative_To_3Points(MODEL::TARGET::RLKNEE, MODEL::TARGET::RTH2, MODEL::TARGET::RTH3, MODEL::TARGET::RTH4)) /EXPRESSION=Median(Point_Relative_To_3Points(MODEL::TARGET::RLKNEE, MODEL::TARGET::RTH2, MODEL::TARGET::RTH3, MODEL::TARGET::RTH4))
Line 169: Line 209:
 **;** **;**
 ! making condition2 active will make model2 active. ! making condition2 active will make model2 active.
-\\ 
  
- +Select_Active_File
-**Select_Active_File**+
 /FILE_NAME=CONDITION2 /FILE_NAME=CONDITION2
 ! /QUERY= ! /QUERY=
-**;**+; 
 ! now create a landmark for RLKNEE in the second model ! now create a landmark for RLKNEE in the second model
-**Add_Landmark**+Add_Landmark
 /LANDMARK_NAME=RLKNEE /LANDMARK_NAME=RLKNEE
 ! /CALIBRATION_FILE= ! /CALIBRATION_FILE=
Line 194: Line 233:
 ! /REFERENCE_LOCATION_NAME= ! /REFERENCE_LOCATION_NAME=
 ! /USE_REFERENCE_LOCATION=FALSE ! /USE_REFERENCE_LOCATION=FALSE
-**;** +
-\\+</code>
  
 +==== Point_Tracked_By_3Points ====
 +
 +**Point_Tracked_By_3Points(Point1, Vertex1, Vertex2, Vertex3)**
 +
 +This function was implemented to used DERIVED signals as tracking markers for a point relative to these tracking markers.
 +
 +In other words, this is mimics a LANDMARK in which a point is tracked by three TARGETS or LANDMARKS in a model.
 +
 +The difference is that a model isn't required.
 +
 +Why would this be useful?\\
 +The c3d format specifies that the lowest sampling rate is the POINT rate (i.e. the marker rate)\\
 +Marker based tracking, however, often has possible sampling rates that are much higher than video rates used by markerless tracking.\\
 +In a situation like baseball batting or golf many users record marker and markerless synchronously and merge the files.\\
 +The markers are used to track the club or bat at a higher sampling rate than the video\\
 +Then the c3d format, and Visual3D's implementation, collide with this objective.\\
 +When merging the two files, Visual3D automatically downsamples the POINT rate to the ROTATION rate.\\
 +To compensate (at least somewhat), Visual3D stores a copy of the POINT data as a DERIVED signal at the original POINT rate\\
 +The data is preserved, but the model and model based items cannot refer to the DERIVED signals\\
 +The workaround is to perform some calculations only on the DERIVED signals independent of any model.\\
 +**As as aside, for some applications, using only the marker data will result in faster processing and smaller cmz files.**\\
 +
 +Example: 
 +locate a point in the model relative to 3 markers\\
 +then track this point in the movement trial
 +
 +<code>
 +Evaluate_Expression
 +/EXPRESSION=Point_Tracked_By_3Points(Point_Relative_To_3Points(MODEL::TARGET::FaceBot, MODEL::TARGET::Shaft4, MODEL::TARGET::Shaft5, MODEL::TARGET::Shaft6),
 + TARGET::ORIGINAL::Shaft4, TARGET::ORIGINAL::Shaft5, TARGET::ORIGINAL::Shaft6)
 +/RESULT_TYPES=DERIVED
 +/RESULT_FOLDERS=CLUBFACE
 +/RESULT_NAME=FaceBot
 +;
 +</code>
  
 ==== Snip ==== ==== Snip ====
Line 218: Line 292:
 === Example === === Example ===
  
-This example demonstrates how the Snip expression can be used to extract the last 3 frames of data from a metric signal.+Example 1 demonstrates how the Snip expression can be used to extract the last 3 frames of data from a metric signal.
  
 <code> <code>
Line 256: Line 330:
 </code> </code>
  
 +Example 2 demonstrates how the Snip expression in conjunction with spline, and several other functions
 +
 +<code>
 +The following pipeline resulted from a support email.\\
 +The request was to compare several different methods for defining the hip and knee angles\\
 +Signals were created by pairwise subtracting one signal from another signal\\
 +Each of the difference signals in several files were parsed into regions defined by an event sequence\\
 +Each region was then time normalized to 101 points\\
 +The RMS for each region was then computed.\\
 +Each file, therefore, contained a number of RMS values\\
 +The RMS signals from each file were then concatenated into a signal GLOBAL signal containing values from all files
 +
 +Select_Active_File
 + /FILE_NAME=ALL_FILES
 +! /QUERY=
 +! /SUBJECT_TAGS=NO_SUBJECT
 +;
 +
 +! difference signals were stored as DERIVED::PROCESSED
 +! Create a pipeline parameter containing a list of the signal names in this folder
 +
 +Set_Pipeline_Parameter_To_List_Of_Signal_Names
 +/PARAMETER_NAME=SIGNALS
 +/SIGNAL_TYPES=DERIVED
 +/SIGNAL_FOLDER=PROCESSED
 +! /SIGNAL_MASK=*
 +;
 +
 +! Use a For_Each command to iteratively act on each signal in the list
 +
 +For_Each
 +/ITERATION_PARAMETER_NAME=INDEX
 +! /ITERATION_PARAMETER_COUNT_NAME=
 + /ITEMS=::SIGNALS
 +;
 +
 +! While it might be possible to provide a solution with a single expression, it would
 +! take some time to modify Visual3D
 +! the following the commands (one for each of x, y, z) do 3 things
 +! isolates the data with the event sequence selected
 +! resamples the data to 101 points using a cubic spline
 +! create a resulting signal that has a column for each event sequence in the file time normalized to 101 frames
 +
 +Evaluate_Expression
 +/EXPRESSION=Append_As_Components(
 +SPLINE(
 +SNIP(CURRENT_SIGNAL, EVENT_LABEL::ORIGINAL::Left Foot Strike, EVENT_LABEL::ORIGINAL::Left Foot Strike),101)
 +)
 +/SIGNAL_TYPES=DERIVED
 +/SIGNAL_FOLDER=PROCESSED
 +/SIGNAL_NAMES=::INDEX
 +/SIGNAL_COMPONENTS=X
 +! /RESULT_TYPES=DERIVED
 +/RESULT_FOLDERS=DIFF
 +/RESULT_NAME=_DIFFX
 +/APPLY_AS_SUFFIX_TO_SIGNAL_NAME=TRUE
 +;
 +
 +Evaluate_Expression
 +/EXPRESSION=Append_As_Components(
 +SPLINE(
 +SNIP(CURRENT_SIGNAL, EVENT_LABEL::ORIGINAL::Left Foot Strike, EVENT_LABEL::ORIGINAL::Left Foot Strike),101)
 +)
 +/SIGNAL_TYPES=DERIVED
 +/SIGNAL_FOLDER=PROCESSED
 +/SIGNAL_NAMES=::INDEX
 +/SIGNAL_COMPONENTS=Y
 +! /RESULT_TYPES=DERIVED
 +/RESULT_FOLDERS=DIFF
 +/RESULT_NAME=_DIFFY
 +/APPLY_AS_SUFFIX_TO_SIGNAL_NAME=TRUE
 +;
 +
 +Evaluate_Expression
 +/EXPRESSION=Append_As_Components(
 +SPLINE(
 +SNIP(CURRENT_SIGNAL, EVENT_LABEL::ORIGINAL::Left Foot Strike, EVENT_LABEL::ORIGINAL::Left Foot Strike),101)
 +)
 +/SIGNAL_TYPES=DERIVED
 +/SIGNAL_FOLDER=PROCESSED
 +/SIGNAL_NAMES=::INDEX
 +/SIGNAL_COMPONENTS=Z
 +! /RESULT_TYPES=DERIVED
 +/RESULT_FOLDERS=DIFF
 +/RESULT_NAME=_DIFFZ
 +/APPLY_AS_SUFFIX_TO_SIGNAL_NAME=TRUE
 +;
 +
 +! the following command consolidates the above information 
 +! the RMS value of each column is computed
 +! the signal is transposed so that each RMS value for each event sequence is on a different line
 +! x,y, and z values for the RMS are then stored in one signal
 +
 +Evaluate_Expression
 +/EXPRESSION=VECTOR(Transpose(Metric_RMS(DERIVED::DIFF:&:&::INDEX&_DIFFX)),Transpose(Metric_RMS(DERIVED::DIFF:&:&::INDEX&_DIFFY)),Transpose(Metric_RMS(DERIVED::DIFF:&:&::INDEX&_DIFFZ)))
 +/SIGNAL_TYPES=
 +/SIGNAL_FOLDER=
 +/SIGNAL_NAMES=
 +! /SIGNAL_COMPONENTS=
 +/RESULT_TYPES=METRIC
 + /RESULT_FOLDERS=RMS
 +/RESULT_NAME=::INDEX&_RMS
 +! /APPLY_AS_SUFFIX_TO_SIGNAL_NAME=FALSE
 +;
 +
 +End_For_Each
 +/ITERATION_PARAMETER_NAME=INDEX
 +;
 +
 +! Create a pipeline containing the names of the metric signals just created
 +
 +Set_Pipeline_Parameter_To_List_Of_Signal_Names
 +/PARAMETER_NAME=SIGNALS
 +/SIGNAL_TYPES=METRIC
 +/SIGNAL_FOLDER=RMS
 +! /SIGNAL_MASK=*
 +;
 +
 +! Concatenate the RMS metric signals into one GLOBAL signal containing all RSM values
 +! across all files
 +! Make the GLOBAL workspace active and you should see the results.
 +
 +For_Each
 +/ITERATION_PARAMETER_NAME=INDEX2
 +! /ITERATION_PARAMETER_COUNT_NAME=
 + /ITEMS=::SIGNALS
 +;
 +
 +Evaluate_Expression
 +/EXPRESSION=Append_As_Frames(GLOBAL::METRIC::RMS:&:&::INDEX2&,CURRENT_SIGNAL)
 +/SIGNAL_TYPES=METRIC
 +/SIGNAL_FOLDER=RMS
 +/SIGNAL_NAMES=::INDEX2
 +! /SIGNAL_COMPONENTS=
 +/RESULT_TYPES=METRIC
 +/RESULT_FOLDERS=RMS
 +/RESULT_NAME=GLOBAL:&:&::INDEX2
 +! /APPLY_AS_SUFFIX_TO_SIGNAL_NAME=FALSE
 +;
 +
 +End_For_Each
 +/ITERATION_PARAMETER_NAME=INDEX2
 +;
 +</code>
 ==== Spline ==== ==== Spline ====
  
Line 268: Line 486:
  
 This takes the signal list, and appends each signal into one signal as new components. This takes the signal list, and appends each signal into one signal as new components.
 +
 **Append_As_Frames(signal_list)** **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 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: **Append_As_Frames** Example:
  
 +<code>
 Open any cmz file with more than 1 file Open any cmz file with more than 1 file
-[[Visual3D:Documentation:Pipeline:File_Commands:Select_Active_File|Select_Active_File]]+Select_Active_File
 /FILE_NAME=ALL_FILES /FILE_NAME=ALL_FILES
 ! /QUERY= ! /QUERY=
 **;** **;**
 +
 ! Create a metric signal with 3 components and 1 frame ! Create a metric signal with 3 components and 1 frame
-[[Visual3D:Documentation:Pipeline:Metric_Commands:Metric_Explicit|Metric_Explicit]]+Metric_Explicit
 /RESULT_METRIC_FOLDER=TEST /RESULT_METRIC_FOLDER=TEST
 /RESULT_METRIC_NAME=SCOTT /RESULT_METRIC_NAME=SCOTT
 /METRIC_VALUE=1+2+3 /METRIC_VALUE=1+2+3
-**;**+; 
 !The following command will concatenate the metric signal from each file !The following command will concatenate the metric signal from each file
 !into a GLOBAL metric signal. !into a GLOBAL metric signal.
Line 296: Line 518:
 /RESULT_NAME=GLOBAL::SCOTTA /RESULT_NAME=GLOBAL::SCOTTA
 ! /APPLY_AS_SUFFIX_TO_SIGNAL_NAME=FALSE ! /APPLY_AS_SUFFIX_TO_SIGNAL_NAME=FALSE
-**;**+; 
 +</code>
  
  
visual3d/documentation/pipeline/expressions/signal_functions.1725053644.txt.gz · Last modified: 2024/08/30 21:34 by wikisysop