impactr is an R package whose main goal is to process raw accelerometer data into mechanical loading-related variables. It contains functions to read the raw data, process the accelerometer signal and to predict some mechanical loading variables such as ground reaction force (GRF) and loading rate (LR). Currently it only works with raw accelerometer data from triaxial ActiGraph accelerometers stored as csv files, but with plans to expand the support for more accelerometer brands and file types.
This vignette provides a short introduction on how to use impactr, guiding you through each of the functions necessary to operate it. If anything is not clear in the package documentation, please let us know by creating an issue in GitHub following this link.
Before we begin, the package needs to be installed and then loaded into your R session.
If you don’t have much experience using R, we recommend you to install the latest impactr release from CRAN, by running:
After the package is installed, it should be loaded into your R session:
The first step is to read the raw accelerometer data into R. We do it
by using the read_acc()
function specifying the path to the
csv file containing the raw accelerometer data:
Remember that currently impactr only accepts raw data from triaxial ActiGraph accelerometers. In the raw data, acceleration values are stored as gravitational acceleration units (1g = 9.81m·s-2).
To show the package functionalities, impactr provides some short example files. The name of these files are shown when running:
When entering one of these file names as an argument to the
impactr_example()
function, we obtain the path to the
example data, and can pass it to read_acc()
:
The output of this function was assigned to the acc_data
object with the R’s assignment operator (<-
).
We can, then, inspect this object.
acc_data
#> # Start time: 2021-04-06 15:43:00
#> # Sampling frequency: 100Hz
#> # Accelerometer placement: Non-specified
#> # Subject body mass: Non-specified
#> # Filter: No filter applied
#> # Data dimensions: 30,000 × 4
#> timestamp acc_X acc_Y acc_Z
#> <dttm> <dbl> <dbl> <dbl>
#> 1 2021-04-06 15:43:00 0.262 -0.688 0.063
#> 2 2021-04-06 15:43:00 0.25 -0.727 0.039
#> 3 2021-04-06 15:43:00 0.254 -0.816 0.191
#> 4 2021-04-06 15:43:00 0.258 -0.891 0.367
#> 5 2021-04-06 15:43:00 0.281 -0.914 0.344
#> 6 2021-04-06 15:43:00 0.316 -0.922 0.23
#> 7 2021-04-06 15:43:00 0.32 -0.891 0.203
#> 8 2021-04-06 15:43:00 0.332 -0.926 0.109
#> 9 2021-04-06 15:43:00 0.363 -1.02 0.168
#> 10 2021-04-06 15:43:00 0.418 -0.996 0.387
#> # ℹ 29,990 more rows
It shows the data with four columns – one for the timestamp and one for each of the accelerometer axes (X, Y and Z) – and a 6-line header with metadata. Among this metadata is the accelerometer data start time and sampling frequency, extracted from the csv file header, and also information about the accelerometer placement and the subject body mass, that are needed for applying the mechanical loading prediction models. It also shows information about the filter applied to the accelerometer signal and the data dimensions (30000 rows and 4 columns in this case).
Remember that, when using this function to read your own data, you
need to specify the correct path to it. For example, if you have a file
named id_001_raw_acceleration.csv
inside the
accelerometer_data
folder in your Desktop
, you
need to write the path to it:
define_region()
is an optional function to be used when
you only want to analyse a specify portion of your data. To use it, you
must specify the start and end time of your region of interest to the
start_time
and end_time
arguments, along with
the data read by the read_acc()
function to the
data
argument:
acc_data <- define_region(
data = acc_data,
start_time = "2021-04-06 15:45:00",
end_time = "2021-04-06 15:46:00"
)
acc_data
#> # Start time: 2021-04-06 15:43:00
#> # Sampling frequency: 100Hz
#> # Accelerometer placement: Non-specified
#> # Subject body mass: Non-specified
#> # Filter: No filter applied
#> # Data dimensions: 6,000 × 4
#> timestamp acc_X acc_Y acc_Z
#> <dttm> <dbl> <dbl> <dbl>
#> 1 2021-04-06 15:45:00 -0.148 -1.05 0.094
#> 2 2021-04-06 15:45:00 -0.098 -1.08 0.176
#> 3 2021-04-06 15:45:00 -0.055 -1.11 0.234
#> 4 2021-04-06 15:45:00 -0.035 -1.12 0.254
#> 5 2021-04-06 15:45:00 -0.02 -1.11 0.23
#> 6 2021-04-06 15:45:00 -0.004 -1.09 0.184
#> 7 2021-04-06 15:45:00 0.004 -1.06 0.152
#> 8 2021-04-06 15:45:00 -0.004 -1.08 0.152
#> 9 2021-04-06 15:45:00 0.008 -1.15 0.176
#> 10 2021-04-06 15:45:00 0.039 -1.20 0.195
#> # ℹ 5,990 more rows
Apart from the raw accelerometer data, the mechanical loading
prediction models need informations regarding the accelerometer body
placement and the subject body mass. These informations are provided to
impactr by the function specify_parameters()
:
acc_data <- specify_parameters(
data = acc_data, acc_placement = "hip", subj_body_mass = 78
)
acc_data
#> # Start time: 2021-04-06 15:43:00
#> # Sampling frequency: 100Hz
#> # Accelerometer placement: Hip
#> # Subject body mass: 78kg
#> # Filter: No filter applied
#> # Data dimensions: 6,000 × 4
#> timestamp acc_X acc_Y acc_Z
#> <dttm> <dbl> <dbl> <dbl>
#> 1 2021-04-06 15:45:00 -0.148 -1.05 0.094
#> 2 2021-04-06 15:45:00 -0.098 -1.08 0.176
#> 3 2021-04-06 15:45:00 -0.055 -1.11 0.234
#> 4 2021-04-06 15:45:00 -0.035 -1.12 0.254
#> 5 2021-04-06 15:45:00 -0.02 -1.11 0.23
#> 6 2021-04-06 15:45:00 -0.004 -1.09 0.184
#> 7 2021-04-06 15:45:00 0.004 -1.06 0.152
#> 8 2021-04-06 15:45:00 -0.004 -1.08 0.152
#> 9 2021-04-06 15:45:00 0.008 -1.15 0.176
#> 10 2021-04-06 15:45:00 0.039 -1.20 0.195
#> # ℹ 5,990 more rows
The supported accelerometer placements are “ankle”, “back” or “hip” and the body mass must be given as kilograms. Notice that these informations are added to the data header.
The raw accelerometer data can be digitally filtered to reduce noise.
The filter_acc()
function does it by getting the
coefficients of a Butterworth digital filter and applying it twice
(forwards and backwards) to the acceleration signal. The simplest way to
use it is to call the filter_acc()
function supplying only
the accelerometer data:
acc_data <- filter_acc(data = acc_data)
acc_data
#> # Start time: 2021-04-06 15:43:00
#> # Sampling frequency: 100Hz
#> # Accelerometer placement: Hip
#> # Subject body mass: 78kg
#> # Filter: Butterworth (4th-ord, low-pass, 20Hz)
#> # Data dimensions: 6,000 × 4
#> timestamp acc_X acc_Y acc_Z
#> <dttm> <dbl> <dbl> <dbl>
#> 1 2021-04-06 15:45:00 -0.0900 -0.742 0.0878
#> 2 2021-04-06 15:45:00 -0.102 -1.08 0.171
#> 3 2021-04-06 15:45:00 -0.0768 -1.20 0.235
#> 4 2021-04-06 15:45:00 -0.0375 -1.16 0.253
#> 5 2021-04-06 15:45:00 -0.00870 -1.09 0.229
#> 6 2021-04-06 15:45:00 0.000810 -1.06 0.188
#> 7 2021-04-06 15:45:00 -0.00329 -1.07 0.156
#> 8 2021-04-06 15:45:00 -0.00753 -1.10 0.148
#> 9 2021-04-06 15:45:00 0.00602 -1.14 0.166
#> 10 2021-04-06 15:45:00 0.0510 -1.19 0.206
#> # ℹ 5,990 more rows
This function lets you select the order, cut-off frequency and type
of the Butterworth filter (more details in the function documentation
help(filter_acc)
). To better reproduce the conditions in
which the models validation were performed, we suggest you not to change
the default values of order
, cutoff
and
type
arguments, unless you have a strong reason to do
so.
The mechanical loading prediction models included in impactr work
with either the acceleration vertical vector or the resultant vector
computed as the Euclidean norm of the three vectors \((r = \sqrt{X^2 + Y^2 + Z^2})\). To compute
the resultant you can use the use_resultant()
function:
acc_data <- use_resultant(data = acc_data)
acc_data
#> # Start time: 2021-04-06 15:43:00
#> # Sampling frequency: 100Hz
#> # Accelerometer placement: Hip
#> # Subject body mass: 78kg
#> # Filter: Butterworth (4th-ord, low-pass, 20Hz)
#> # Data dimensions: 6,000 × 5
#> timestamp acc_X acc_Y acc_Z acc_R
#> <dttm> <dbl> <dbl> <dbl> <dbl>
#> 1 2021-04-06 15:45:00 -0.0900 -0.742 0.0878 0.753
#> 2 2021-04-06 15:45:00 -0.102 -1.08 0.171 1.10
#> 3 2021-04-06 15:45:00 -0.0768 -1.20 0.235 1.22
#> 4 2021-04-06 15:45:00 -0.0375 -1.16 0.253 1.18
#> 5 2021-04-06 15:45:00 -0.00870 -1.09 0.229 1.11
#> 6 2021-04-06 15:45:00 0.000810 -1.06 0.188 1.07
#> 7 2021-04-06 15:45:00 -0.00329 -1.07 0.156 1.08
#> 8 2021-04-06 15:45:00 -0.00753 -1.10 0.148 1.11
#> 9 2021-04-06 15:45:00 0.00602 -1.14 0.166 1.15
#> 10 2021-04-06 15:45:00 0.0510 -1.19 0.206 1.21
#> # ℹ 5,990 more rows
This function add a new column acc_R
with the resultant
acceleration values. We suggest to utilise this function after
filter_acc()
, otherwise the resultant vector computation
will use the non-filtered acceleration signal.
To apply the prediction models, the peaks in the acceleration signal
should be found. The find_peaks()
function does it and
returns the timestamp of the peak in a column and its magnitude in
another. The vector
argument controls in which vector the
peaks should be found and can be set to either vertical
,
resultant
or all
.
acc_data <- find_peaks(data = acc_data, vector = "resultant")
acc_data
#> # Start time: 2021-04-06 15:43:00
#> # Sampling frequency: 100Hz
#> # Accelerometer placement: Hip
#> # Subject body mass: 78kg
#> # Filter: Butterworth (4th-ord, low-pass, 20Hz)
#> # Data dimensions: 32 × 2
#> timestamp resultant_peak_acc
#> <dttm> <dbl>
#> 1 2021-04-06 15:45:00 1.32
#> 2 2021-04-06 15:45:01 1.36
#> 3 2021-04-06 15:45:04 1.30
#> 4 2021-04-06 15:45:04 2.32
#> 5 2021-04-06 15:45:05 1.50
#> 6 2021-04-06 15:45:06 1.68
#> 7 2021-04-06 15:45:06 1.51
#> 8 2021-04-06 15:45:07 1.96
#> 9 2021-04-06 15:45:08 1.37
#> 10 2021-04-06 15:45:08 1.86
#> # ℹ 22 more rows
As with filter_acc()
, find_peaks()
default
values of the minimum height (min_height
) and distance
(min_dist
) of the peaks are set to replicate the values
used in the calibration study. You should only change them if you have a
strong reason to.
Finally, the predict_loading()
is used to predict the
mechanical loading variables based on the acceleration signal.
Currently, impactr provides models to predict ground reaction force
(GRF) and loading rate (LR) of the resultant vector and its vertical
component with a models validated in walking and running activities. The
outcome
, vector
and model
arguments are used to control this parameters. More details regarding
the values accepted by these parameters can be found in the function
documentation (help(predict_loading)
).
predict_loading(
data = acc_data,
outcome = "grf",
vector = "resultant",
model = "walking/running"
)
#> # Start time: 2021-04-06 15:43:00
#> # Sampling frequency: 100Hz
#> # Accelerometer placement: Hip
#> # Subject body mass: 78kg
#> # Filter: Butterworth (4th-ord, low-pass, 20Hz)
#> # Data dimensions: 32 × 3
#> timestamp resultant_peak_acc resultant_peak_grf
#> <dttm> <dbl> <dbl>
#> 1 2021-04-06 15:45:00 1.32 1466.
#> 2 2021-04-06 15:45:01 1.36 1469.
#> 3 2021-04-06 15:45:04 1.30 1464.
#> 4 2021-04-06 15:45:04 2.32 1543.
#> 5 2021-04-06 15:45:05 1.50 1480.
#> 6 2021-04-06 15:45:06 1.68 1494.
#> 7 2021-04-06 15:45:06 1.51 1480.
#> 8 2021-04-06 15:45:07 1.96 1515.
#> 9 2021-04-06 15:45:08 1.37 1470.
#> 10 2021-04-06 15:45:08 1.86 1508.
#> # ℹ 22 more rows
As can be seen above, predict_loading()
adds columns to
the supplied data
corresponding to the outcome
and vector
specified in the arguments. Note that GRF are
expressed as newton (N) and LR as newton per second
(N·s-1)
impactr helps you to move from the raw accelerometer data to discrete
estimates of mechanical loading variables in an easy way. All the
functions necessary to this analysis are described above in a
step-by-step manner. These functions were also designed to be used with
pipe operators (either of the magrittr
package
or the base R package for R version >= 4.1.0). By using the pipe, the
output of a function call is passed directly to the next, avoiding
nested function calls or the need to assign local variables. Below are
examples the whole analysis assigning local variables in intermediate
steps and using the base R pipe:
# Using intermediate steps
acc_data <- read_acc(impactr_example("hip-raw.csv"))
acc_data <- specify_parameters(
data = acc_data, acc_placement = "hip", subj_body_mass = 78
)
acc_data <- filter_acc(data = acc_data)
acc_data <- use_resultant(data = acc_data)
acc_data <- find_peaks(data = acc_data, vector = "resultant")
acc_data <- predict_loading(
data = acc_data,
outcome = "grf",
vector = "resultant",
model = "walking/running"
)
# Using the base R pipe operator
read_acc(impactr_example("hip-raw.csv")) |>
specify_parameters(acc_placement = "hip", subj_body_mass = 78) |>
filter_acc() |>
use_resultant() |>
find_peaks(vector = "resultant") |>
predict_loading(
outcome = "grf",
vector = "resultant",
model = "walking/running"
)