knitr::opts_chunk$set( collapse = TRUE, comment = "#>" )
library(biomechanics)
Processing marker data involves the following steps:
Noting that filtering data is not really necessary for a static trial (where the participant is not moving), and that virtual markers are not necessary in all cases (particularly dynamic trials).
For the following example, we assume that we have extracted and clipped the data (no rotations applied yet).
First, we read a .trc file.
library(dplyr) #read in trc file, assuming that this is raw and not rotated df = read_trc("./data/static_z_up.trc")
We can create a 3D visual for a specified frame. Here, we can see that the orientation of the data appears incorrect. This is because motion capture systems typically have a "Z-up" coordinate system, but OpenSim expects a "Y-up".
#quick visual to check visualise_3D_marker_position(df, selected_frame = 1)
We can rotate our data using the rotate_markers()
function.
#now rotate to OpenSim coordinate system (if needed) df_rotated = #raw data df %>% #rotate anti-clockwise around z axis rotate_markers(., angle_deg = 90, axis = "z") %>% #rotate anti-clockwise around x axis rotate_markers(., angle_deg = 90, axis = "x") #visualise to check correct rotation visualise_3D_marker_position(df_rotated, selected_frame = 1)
The rotate_markers()
function takes a data.frame of marker trajectories (from read_trc()
) and rotates around specified axes by a specified amount. For intuition around the rotation, first recognise that a clockwise rotation around an axis that is pointing to you would be negative. Therefore, rotating our data from positive y-axis = forward (i.e., Vicon system) to positive x-axis = forward (i.e., OpenSim system) could be achieved in multiple ways, one being two anti-clockwise rotations of 90 degrees, from the z- then the x-axis.
We often filter our marker data to smooth it. This won't make a big difference in this case as it is a static trial, but the same function (filter_lowpass_pad_df()
) can be used for any .trc data. Note that the functions also pads the signal by a specified amount on either side prior to filtering, then removes that padding after. This helps to remove artefact from entering your data.
#now lets add filtering (won't change much since this is static) df_filtered = #get the rotated data df_rotated %>% #filter with zero-lag 4th order Butterworth filter (cutoff = 6Hz) filter_lowpass_pad_df(., time_col = "Time", exclude_cols = c(1, 2), #don't filter the Frame and Time data cut_off = 6, #in Hz sample_rate = 200, #in Hz order = 2, #zero-lag filter, so the order doubles to 4 pad_time = 0.5) #pad data by 500ms either side to avoid artefacts
Choosing an appropriate filter is another discussion, but for context, a low-pass Butterworth filter with a cut-off of 6-15Hz is fairly typical.
For static trials, we often want to compute joint centres. The following demonstrates how to compute the hip joint centre using regression equations (either "harrington" or "bell" can be specified), or a mid-point method for the knee ankle.
#finally, let's compute joint centres df_processed = #get the filtered data df_filtered %>% #compute hip joint centres compute_hjc_regression(., LASIS_name = "L.ASIS", RASIS_name = "R.ASIS", LPSIS_name = "L.PSIS", RPSIS_name = "R.PSIS", RHJC_name = "R.HJC", LHJC_name = "L.HJC", method = "harrington") %>% #most accurate regression method #compute knee joint centres compute_jc_mid(., marker_name_1 = "L.Knee.Med", marker_name_2 = "L.Knee.Lat", jc_name = "L.Knee") %>% compute_jc_mid(., marker_name_1 = "R.Knee.Med", marker_name_2 = "R.Knee.Lat", jc_name = "R.Knee") %>% #compute ankle joint centres compute_jc_mid(., marker_name_1 = "L.Ankle.Med", marker_name_2 = "L.Ankle.Lat", jc_name = "L.Ankle") %>% compute_jc_mid(., marker_name_1 = "R.Ankle.Med", marker_name_2 = "R.Ankle.Lat", jc_name = "R.Ankle") #re-visualise, which should show the new joint centre markers visualise_3D_marker_position(df_processed, selected_frame = 1)
This step is not needed for all trial types, but is important for static trials that we use for scaling models.
Finally, we can write our processed marker data to file for subsequent analysis.
#then write to file write_trc(df_processed, unit = "mm", "./data/static_processed.trc")
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.