Title: | Processing Force-Plate Data |
---|---|
Description: | Process raw force-plate data (txt-files) by segmenting them into trials and, if needed, calculating (user-defined) descriptive statistics of variables for user-defined time bins (relative to trigger onsets) for each trial. When segmenting the data a baseline correction, a filter, and a data imputation can be applied if needed. Experimental data can also be processed and combined with the segmented force-plate data. This procedure is suggested by Johannsen et al. (2023) <doi:10.6084/m9.figshare.22190155> and some of the options (e.g., choice of low-pass filter) are also suggested by Winter (2009) <doi:10.1002/9780470549148>. |
Authors: | Raphae Hartmann [aut, cre] , Anton Koger [aut, ctb] , Leif Johannsen [ctb] |
Maintainer: | Raphae Hartmann <[email protected]> |
License: | GPL (>= 2) |
Version: | 1.1-3 |
Built: | 2024-11-07 04:26:58 UTC |
Source: | https://github.com/raphaelhartmann/forceplate |
Combine two data.table
s, either two force-plate data, two exeperimental data, or one
force-plate and one experimental data.
combine_data( dt1, dt2, by = list(subj = "subj", block = "block", trial = "trial"), continuous = FALSE )
combine_data( dt1, dt2, by = list(subj = "subj", block = "block", trial = "trial"), continuous = FALSE )
dt1 |
A |
dt2 |
A |
by |
A list of three variable names in the experimental data that reflect the subj (subject number), block (block number), and trial (trial number) in the force-plate data. This argument is only necessary for combining experimental data with force-plate data. |
continuous |
A logical value. Default is |
A data.table
either of the same class as dt1
and dt2
, if they
share the same class, or of the class dt.comb
.
Raphael Hartmann & Anton Koger
Processing the experimental data by removing unnecessary variables and removing rows in the data
that are not trials. The output is a data.table
.
prep_exp_data( filenames, na.strings = c(",,", "[]", "None"), excl.vars = NULL, blacklist.vars = NULL, whitelist.vars = NULL, sort = TRUE )
prep_exp_data( filenames, na.strings = c(",,", "[]", "None"), excl.vars = NULL, blacklist.vars = NULL, whitelist.vars = NULL, sort = TRUE )
filenames |
A (vector of) character(s) providing the raw experimental data file name(s). Files can be .txt, .csv, or any common type. |
na.strings |
A (vector of) character(s) naming the strings that should be treated as NA. |
excl.vars |
A (vector of) number(s) or character(s) providing the column number(s) or name(s)
of the data which will be used for spotting rows that are not trials, that is, rows that are
NA in each of the columns |
blacklist.vars |
A (vector of) number(s) or character(s) providing the column number(s) or name(s) of variables to be deleted from the data. NULL means no variable will be deleted. |
whitelist.vars |
A (vector of) number(s) or character(s) providing the column number(s) or name(s) of variables to be kept in the data. All others will be deleted. NULL means all variables will be kept. |
sort |
TRUE or FALSE. If TRUE the data will be sorted by subject number and block number. |
A data.table
of the class exp.prep
.
Raphael Hartmann & Anton Koger
# Using example data from github which requires internet if (curl::has_internet()) { url <- paste0("https://raw.githubusercontent.com/RaphaelHartmann/forceplate/", "main/data/subj13_exp_data.csv") # Safe download, handling potential errors tryCatch({ filenames <- tempfile(pattern = c("subj13_exp_data"), tmpdir = tempdir(), fileext = ".csv") download.file(url, filenames) # prepare experimental data exp.dt <- prep_exp_data(filenames = filenames, excl.vars = 2:5) # Clean up unlink(filenames) }, error = function(e) { message("Failed to download data: ", e$message) }) }
# Using example data from github which requires internet if (curl::has_internet()) { url <- paste0("https://raw.githubusercontent.com/RaphaelHartmann/forceplate/", "main/data/subj13_exp_data.csv") # Safe download, handling potential errors tryCatch({ filenames <- tempfile(pattern = c("subj13_exp_data"), tmpdir = tempdir(), fileext = ".csv") download.file(url, filenames) # prepare experimental data exp.dt <- prep_exp_data(filenames = filenames, excl.vars = 2:5) # Clean up unlink(filenames) }, error = function(e) { message("Failed to download data: ", e$message) }) }
Processing force-plate data by segmenting the data in trials, baseline correct each trial (optional),
applying a low-pass 4th order Butterworth filter (optional), labeling stimuli and response onsets
in each trial, labeling conditions in each trial, and some more (see below). The output is a
data.table
.
segment_fp_data( filenames, n.trials, start.trigger, start.prepend = 0, baseline.trigger, baseline.intv, stimulus.trigger.list, response.trigger.list, cond.trigger.list, variable.names = NULL, skip = 19, az0 = 0, sampling.freq = 1000, cutoff.freq = 10, imputation = NULL, sort = TRUE )
segment_fp_data( filenames, n.trials, start.trigger, start.prepend = 0, baseline.trigger, baseline.intv, stimulus.trigger.list, response.trigger.list, cond.trigger.list, variable.names = NULL, skip = 19, az0 = 0, sampling.freq = 1000, cutoff.freq = 10, imputation = NULL, sort = TRUE )
filenames |
A (vector of) character(s) providing the raw force-plate file name(s). Files should be in tab-delimited .txt-format. |
n.trials |
A (vector of) number(s) providing the number of trial (per filename). |
start.trigger |
A (vector of) number(s) providing the trigger(s) marking the beginning of a trial. |
start.prepend |
A number giving the number of milliseconds to prepend before the |
baseline.trigger |
A (vector of) number(s) providing the trigger number(s) providing the reference for
the intervall for the baseline correction. For example, if set to 1 the onset of event with trigger 1 is
used as zero point for the next argument ( |
baseline.intv |
A vector of length 2 providing the lower and upper bounds of the interval that will be used as baseline interval (in milliseconds). For each measurement variable, the mean of the data points that fall into this interval will be subtracted from all data points within a trial. |
stimulus.trigger.list |
If a trial contains one task only, then a vector providing the trigger(s)
marking the onset of the stimulus. If a trial contains more than one task, then a named list of vectors
providing the trigger(s) marking the onset of stimuli. For example,
|
response.trigger.list |
Same as |
cond.trigger.list |
A named list of vectors providing the trigger(s) marking the conditions. |
variable.names |
If used (i.e., not NULL), a named list of names. This will rename the variables of the force-plate data. There are three cases to consider:
|
skip |
A number giving the number of lines in the raw force-plate data to skip. In BioWare this is 19. The real data starts at line 20. Therefore the default value is set to 19. |
az0 |
Thickness parameter of the force plate in millimeter and negative. If this value (e.g., -41 for the Kistler force plate type 9260AA) is not 0 then the center of pressure in the x- and y-direction is calculated (like in Johannsen et al., 2023) using this value. |
sampling.freq |
A number giving the sampling frequency. Typically 1000 Hz. |
cutoff.freq |
A number giving the cut-off frequency used for the low-pass 4th order Butterworth filter. If set to 0, no low-pass filter will be applied. Default is 10 Hz. |
imputation |
If you expect any NaNs in your raw force-plate data you might use this argument. Use either of the
following options: "fmm", "periodic", "natural", "monoH.FC", or "hyman". These are method options in the
|
sort |
TRUE or FALSE. If TRUE the data will be sorted by subject number and block number. |
A data.table
of the class fp.segm
.
The following variables are included in the data.table
:
subj
: subject number,
block
: block number,
trial
: trial number,
forceplate
: force-plate data of each trial as data.table
. Use, for example,
fp.dt$forceplate[[1]]
to open the force-plate data of the first trial, first block, and first subject.
Raphael Hartmann & Anton Koger
Johannsen, L., Stephan, D. N., Straub, E., Döhring, F., Kiesel, A., Koch, I., & Müller, H. (2023). Assessing the influence of cognitive response conflict on balance control: An event-related approach using response-aligned force-plate time series data. Psychological Research, 87, 2297–2315.
Winter, D. A. (2009). Biomechanics and Motor Control of Human Movement.
# Using example data from GitHub which requires internet # takes longer than 5 seconds if (curl::has_internet()) { url <- paste0("https://raw.githubusercontent.com/RaphaelHartmann/forceplate/", "main/data/subj013_block001.txt") # Safe download, handling potential errors tryCatch({ filenames <- tempfile(pattern = c("subj013_block001_"), tmpdir = tempdir(), fileext = ".txt") download.file(url, filenames) # segment raw text file from Bioware fp.dt <- segment_fp_data(filenames = filenames, n.trials = 80, baseline.trigger = 128, baseline.intv = c(0, 215), start.trigger = 128, start.prepend = 0, stimulus.trigger.list = c(1, 2, 4, 8), response.trigger.list = c(32, 64), cond.trigger.list = list(stimulus = c(1, 2, 4, 8), correctness = c(32, 64))) # Clean up unlink(filenames) }, error = function(e) { message("Failed to download data: ", e$message) }) }
# Using example data from GitHub which requires internet # takes longer than 5 seconds if (curl::has_internet()) { url <- paste0("https://raw.githubusercontent.com/RaphaelHartmann/forceplate/", "main/data/subj013_block001.txt") # Safe download, handling potential errors tryCatch({ filenames <- tempfile(pattern = c("subj013_block001_"), tmpdir = tempdir(), fileext = ".txt") download.file(url, filenames) # segment raw text file from Bioware fp.dt <- segment_fp_data(filenames = filenames, n.trials = 80, baseline.trigger = 128, baseline.intv = c(0, 215), start.trigger = 128, start.prepend = 0, stimulus.trigger.list = c(1, 2, 4, 8), response.trigger.list = c(32, 64), cond.trigger.list = list(stimulus = c(1, 2, 4, 8), correctness = c(32, 64))) # Clean up unlink(filenames) }, error = function(e) { message("Failed to download data: ", e$message) }) }
Processing segmented force-plate data by calculating descriptive statistics like mean, standard deviation, and range for defined time bins around time-locked events, such as stimulus onset or response onset etc.
time_lock_stats( fp.dt, vars, time.lock.trigger, bins, bin.width = NULL, n.bins = NULL, FUN = list(mean = mean, sd = sd, range = function(x) diff(range(x))) )
time_lock_stats( fp.dt, vars, time.lock.trigger, bins, bin.width = NULL, n.bins = NULL, FUN = list(mean = mean, sd = sd, range = function(x) diff(range(x))) )
fp.dt |
A |
vars |
A (vector of) character(s) giving the variable names in |
time.lock.trigger |
A (vector of) number(s) containing the trigger(s) marking the onset of the time locking (the event of interest like stimulus onset or response onset). The onset of this trigger will be treated as reference (point zero) for the bins to be defined in the next argument(s). |
bins |
Either a vector of length 2 or a list of vectors of length 2 providing the lower and upper boundaries of the bins (in milliseconds). If only one vector is used either one of the next two arguments can be used to make (equaly sized) bins. If a list is used the next two arguments are ignored. |
bin.width |
If |
n.bins |
If |
FUN |
A list of functions. These functions should be statistics that take as input a vector and return a scalar. See usage for an example (mean, standard deviation, range). |
A data.table
of the class fp.tl
.
The following variables are included in the data.table
:
subj
: subject number,
block
: block number,
trial
: trial number,
forceplate
: force-plate data of each trial as data.table
. Use, for example,
fp.dt$forceplate[[1]]
to open the force-plate data of the first trial, first block, and first subject
(if sort
in the segment_fp_data
was set to TRUE
.
For each combination of variable vars
and bin
a new variable is created by the function(s) provided
by FUN
.
Raphael Hartmann & Anton Koger
Johannsen, L., Stephan, D. N., Straub, E., Döhring, F., Kiesel, A., Koch, I., & Müller, H. (2023). Assessing the influence of cognitive response conflict on balance control: An event-related approach using response-aligned force-plate time series data. Psychological Research, 87, 2297–2315.
# Using example data from github which requires internet # takes longer than 5 seconds if (curl::has_internet()) { url <- paste0("https://raw.githubusercontent.com/RaphaelHartmann/forceplate/", "main/data/subj013_block001.txt") # Safe download, handling potential errors tryCatch({ filenames <- tempfile(pattern = c("subj013_block001_"), tmpdir = tempdir(), fileext = ".txt") download.file(url, filenames) fp.dt <- segment_fp_data(filenames = filenames, n.trials = 80, baseline.trigger = 128, baseline.intv = c(0, 215), start.trigger = 128, start.prepend = 0, stimulus.trigger.list = c(1, 2, 4, 8), response.trigger.list = c(32, 64), cond.trigger.list = list(stimulus = c(1, 2, 4, 8), correctness = c(32, 64))) # Response-locking with 2 bins before and 2 bins after response onset. Each bin is 100 ms. tl.dt <- time_lock_stats(fp.dt = fp.dt, vars = c("Mx", "My"), time.lock.trigger = c(1,2,4,8), bins = c(-150, 150), n.bins = 2, FUN = list(mean = mean, sd = sd, range = function(x) diff(range(x)))) # Clean up unlink(filenames) }, error = function(e) { message("Failed to download data: ", e$message) }) }
# Using example data from github which requires internet # takes longer than 5 seconds if (curl::has_internet()) { url <- paste0("https://raw.githubusercontent.com/RaphaelHartmann/forceplate/", "main/data/subj013_block001.txt") # Safe download, handling potential errors tryCatch({ filenames <- tempfile(pattern = c("subj013_block001_"), tmpdir = tempdir(), fileext = ".txt") download.file(url, filenames) fp.dt <- segment_fp_data(filenames = filenames, n.trials = 80, baseline.trigger = 128, baseline.intv = c(0, 215), start.trigger = 128, start.prepend = 0, stimulus.trigger.list = c(1, 2, 4, 8), response.trigger.list = c(32, 64), cond.trigger.list = list(stimulus = c(1, 2, 4, 8), correctness = c(32, 64))) # Response-locking with 2 bins before and 2 bins after response onset. Each bin is 100 ms. tl.dt <- time_lock_stats(fp.dt = fp.dt, vars = c("Mx", "My"), time.lock.trigger = c(1,2,4,8), bins = c(-150, 150), n.bins = 2, FUN = list(mean = mean, sd = sd, range = function(x) diff(range(x)))) # Clean up unlink(filenames) }, error = function(e) { message("Failed to download data: ", e$message) }) }