\(\newcommand{\eq}[1]{\begin{align*}#1\end{align*}}\)
###################################################### INGESTION ################################################
# Folder with files to be analyzed
source("functions.R") # load functions stored in file functions.R
root = "/Users/jheintz/Box/02_Data_Analytics_Projects/000_KIN_PhD/02_Research/2020_Spring/BDS/" # original data sets
rt = "/Users/jheintz/Box/02_Data_Analytics_Projects/000_KIN_PhD/02_Research/2020_Spring/00_PreProcessed/" # pre-processed data sets
# Trial files files in the folder
all.files = list.files(root)
all.files = all.files[!grepl("info", all.files)]
amount.files = length(all.files)
for (fls in 1:1){
#for (fls in 1:amount.files){
file = all.files[fls]
f = paste0(root, file)
df = read.delim(f)
# Indexing and keeping original for comparison's
df = cbind(Index = 1:dim(df)[1], df)
df.origin = df
# vector with variable names
var.names = names(df)
#################################################### FILTER ####################################################
# butterworth low pass filter
o = 4 # filter order
co = 10 # cut-off frequency
tp = "low" # filter type, low pass
fs = 100 # sampling rate 100Hz
fltrd.dt = apply( df[,-c(1,2)],
2, function(x)
butter.fltr(x,
order = o,
cut.freq = co,
tp = tp,
fs = fs))
# merging to data frame
df = data.frame(df[,c(1,2)], fltrd.dt)
##################################################### IEP #######################################################
# IEP identification, "
df$iep.x = f.iep(x = df$Fx.N.) # x direction
df$iep.y = f.iep(x = df$Fy.N.) # y direction
# Counting IEPs
iep.count = f.number.of.IEP(data = df,
fl = file,
F_hor.1 = "iep.x",
F_hor.2 = "iep.y")
# Index for first and last IEP for subsetting
fi.la.iep.index.x = fivenum(df[!is.na(df$iep.x) & df$iep.x == 1,]$Index)[c(1,5)]
fi.la.iep.index.y = fivenum(df[!is.na(df$iep.y) & df$iep.y == 1,]$Index)[c(1,5)]
# Output IEP | Included in Subject and Trial Overview Table ()
df.IEP = data.frame(
Trial.id = iep.count[,1],
IEPx = iep.count[,2],
Fx.N.mean = mean(df$Fx.N.),
Index.min.x = fi.la.iep.index.x[1],
Index.max.x = fi.la.iep.index.x[2],
IEPy = iep.count[,3],
Fy.N.mean = mean(df$Fy.N.),
Index.min.y = fi.la.iep.index.y[1],
Index.max.y = fi.la.iep.index.y[2]
)
####################################### RAMBLING + SPLINE + Trembling #########################################
# AP(x) rambling, spine, trembling
if (df.IEP$IEPx != 0) {
df$ramb.x = df$iep.x * df$COPx.cm.
df$ramb.x = f.spline(x = df$Time.s., y = df$ramb.x, mtd = 'fmm') # mtd = fmm, natural , periodic
df$tremb.x = df$COPx.cm. - df$ramb.x
} else {
df$ramb.x = "NO.IEP"
df$tremb.x = "NO.IEP"
}
# ML(y) rambling, spine, trembling
if (df.IEP$IEPy != 0) {
df$ramb.y = f.spline(x = df$Time.s., y = df$ramb.y, mtd = 'fmm')
df$ramb.y = df$iep.y * df$COPy.cm.
df$tremb.y = df$COPy.cm. - df$ramb.y
} else {
df$ramb.y = "NO.IEP"
df$tremb.y = "NO.IEP"
}
################################################### Output Writing ##############################################
### Subject Trial Data Preprocessed, stored in csv file, 1 csv file per trial ###
dt = as.character(Sys.Date())
file = paste0(rt, dt, "_", df.IEP$Trial.id, "_", co, "Hz", ".csv")
write.csv(df, file = file, row.names = FALSE)
### Store Features in BDSinfo ###
## read in file
file = "BDSinfo.csv"
f = paste0(rt, file)
df.info = read.csv(f)
# store IEP statistics in BDSinfo
Trial.id = iep.count$Trial.ID # taken from counting IEP points
df.info[df.info$Trial == Trial.id, c("IEPx", "Fx.N.mean", "Index.min.x", 'Index.max.x',
"IEPy", "Fy.N.mean", "Index.min.y", "Index.max.y")] =
df.IEP[,c("IEPx", "Fx.N.mean", "Index.min.x", 'Index.max.x',
"IEPy", "Fy.N.mean", "Index.min.y", "Index.max.y") ]
write.csv(df.info, file = f, row.names = FALSE)
}
Ingestion and indexing includes defining paths to force measurement raw data (root) and define storage path to store pre-processed data (rt). The source function loads defined functions stored in a separate file ‘functions.R’ to keep pipeline clean.
Input: root, rt, function.R file stored in same path as R script
Output: none
Functions: none
Variables: Index
A 4 order low pass Butterworth filter is applied on COPx.cm., COPy.cm., Fx.N. ,Fy.N., Fz.N., Mx.Nm, My.Nm., and Mz.Nm.
Input: cut-off frequency, default co = 5Hz; order of low pass filter, default o = 4; sampling frequency, default fs = 100Hz; filter type, default tp = “low”
Output: filtered raw data
Functions: butter.fltr
Variables: none
Instantaneous equilibrium position (IEP) is assumed when horizontal forces are zero. The IEPs are identified for AP (anterior posterior and ML (medial lateral) for \(F_x = 0, F_y = 0\).
Input: raw data set with horizontal forces
Output: IEPs, min-max index for first and last IEP per trial.
Functions: The function “f.iep” identifies the IEP and provides a vector with “1” for IEP, and NA for everything else. The IEP vector becomes part of the raw data set for each trial. The function f.number.of.IEP provides the index for the first, the last IEP, number of IEPs for each trial, and mean of Fx, and Fy. The variables are part of the BDSinfo file.
Variables: Trial.ID = Trial ID, IEPx = Nummber of identified IEPs for AP, Fx.N.mean = mean of horizontal force Fx, Index.min.x = Index first IEPx (AP), Index.max.x = Index Last IEPx (AP), IEPy = Nummber of identified IEPs for ML, Index.min.y = Index first IEPy (ML), Index.max.y = Index Last IEPy (ML)
| Trial.id | IEPx | Fx.N.mean | Index.min.x | Index.max.x | IEPy | Fy.N.mean | Index.min.y | Index.max.y |
|---|---|---|---|---|---|---|---|---|
| BDS00001 | 0 | -1.731919 | NA | NA | 0 | -3.810546 | NA | NA |
IEPx = 0 means the horizontal forces did not cross the zero line. The mean provides a sense of how much subject in that trial has applied horizontal force on average.
The rambling trajectory is determined by 3 steps. First, identifying IEP’s; IEP \(F_{hor} = 0\) for ML and AP. Second, identifying the values of COPx and COPy at the IEPs. Third, interpolating the values to a curve. For the entire interpolated trajectory it is assumed that \(F_{hor} = 0\) and the subject is in instantaneous equilibrium.
Input: raw data set with horizontal forces; interpolation method (splining) default mtd = ffm
Output: Rambling trajectory
Functions: f.spline
Variables: ramb.x = rambling AP[cm], ramb.y = rambling ML [cm]
The Trembling trajectory is determined by subtracting the Rambling trajectories (ML, AP) from the COPx, COPy trajectories. It describes how a subject migrates his COP around the Rambling trajectory.
Input: raw dat
Output: Trembling trajectory
Functions: none
Variables: tremb.x = trembling AP [cm], tremb.y = trembling ML [cm]
The data generated and processed are stored in BDSInfor file. The BDSInfo file provides contextual information about the subject and trial. All preprocessed trial data are stored in the
IEP
- Trial ID
- IEPx = # IEPs for AP
- Fx.N.mean
- IEPy = # IEPs for ML
- Fy.N.mean
- Index.min.x = Index first IEPx (AP)
- Index.min.y = Index first IEPy (ML)
- Index.max.x = Index Last IEPx (AP)
- Index.max.y = Index Last IEPy (ML)
Rambling
- ramb.x = rambling AP [cm]
- ramb.y = rambling ML [cm]
Trembling
- tremb.x = trembling AP [cm]
- tremb.y = trembling ML [cm]