<- file.path(getwd(), "data") data_dir
Suboptimal sensory reweighting in car sick individuals: a postural study
Environment initialization
Specifying the paths for the data and scripts directories :
The data directory hosts the .brute files generated by our posturography platform.
The first part of the name of each files (i.e. s046) corresponds to the identification number of each participant.
The second part of the name corresponds to the number of the trial. Respectively cd1, cd2 and cd3 for the first, second and third trials.
The first column of these files (temps
) is the timestamp of each measure (every 10 ms during 180s).
The second column Consigne
correspond to the angle the platform must output to maintain sway-reference.
The third column Angle
corresponds of the current angle of the platform in space in the anteroposterior axis.
The four following columns (Capteur (Kg) (Nord Ouest)
, Capteur (Kg) (Nord Est)
, Capteur (Kg) (Sud Est)
, Capteur (Kg) (Sud Ouest)
), account for the force sensed on each of the four cardinally placed force sensors in Kg.
From these forces, the last two columns were computed to represent the Barycenter in mm (respectively on the x and y axis) of the participant on the plate.
<- file.path(getwd(), "scripts") scripts_dir
Source the load-packages script and load/install (if necessary) needed packages :
# Specify the packages needed for the project
<- c("tidyverse",
pkgs "psych",
"signal",
"psd",
"tools",
"viridis",
"rmarkdown",
"writexl")
# Load the packages and install them if necessary
lpkg(pkgs)
tidyverse psych signal psd tools viridis rmarkdown writexl
TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
Data setup
Loading the questionnaire data and compute the car-sickness score.
<- read_csv(file.path(data_dir, "subj_quest.csv")) subj_quest
<-
subj_quest %>%
subj_quest mutate(CarSick = replace_na(CarMoun +
+
CarStraigh +
CarFront +
CarBack 0)) CarRead,
Setting-up signal parameters :
# Sampling frequency (in Hz)
<- 100
samp_freq
# Duration of each phase (static/sway-ref/static, in sec)
<- 60
phase_dur
# Minimum and maximum frequencies of the spectral analysis
<- 0
min_freq <- 5
max_freq
# FFT window duration (in sec)
<- 10
window_dur
# Decimation ratio (not used since reasonable compute time)
<- 1
dratio # Rotation function for future plots
<- function(x) t(apply(x, 2, rev))
rotate
# Normalization function for the spectra
<- function(x) {
sp_norm / max(x)
x
}
# Number of samples in the analysis
<- floor(3 * phase_dur * samp_freq)
nb_samp
# Width of the FFT analysis window
<- round(window_dur * samp_freq)
window_size
# Window profile
<- hamming(window_size)
window
# Initial and final sample indices
<- max(c(
initial_idx 1, floor(window_size * min_freq / samp_freq)))
<- floor(window_size * max_freq / samp_freq)
final_idx
# Number of steps for FFT analysis
<- nb_samp - window_size nb_step
Initialization of the spectra storage :
# Temporary matrix for storing the spectra
<- matrix(
spectra NA, nrow = nb_step/dratio, ncol = final_idx - initial_idx + 1)
# List for the storing of results
<- list()
rspec <- list()
rsptat <- tibble(
datastat subject = character(),
condition = character(),
er1 = numeric(),
er2 = numeric(),
er3 = numeric(),
er4 = numeric(),
er5 = numeric(),
er2_er1 = numeric(),
er4_er3 = numeric(),
carsick = numeric(),
age = numeric(),
sexe = character(),
height = numeric(),
weight = numeric(),
validity = numeric())
<- c("cd1", "cd2", "cd3") cond
Extracting participants weights from the COP files :
<- list()
weightlist
# Looping through the subjects brute data and extracting weights :
for (s in seq(1, nrow(subj_quest))) {
<- subj_quest$Id[s]
subject
<- paste0(
filename file_path_sans_ext(as.character(subject)),
"-",
"cd1",
".brute")
<- read.table(file.path(data_dir, filename),
weightdf sep = "\t",
skip = 1, header = TRUE)
<- weightdf[1,4]+
weight 1,5]+
weightdf[1,6]+
weightdf[1,7]
weightdf[
<- weight
weightlist [subject]
}
#Creating a dataframe with weights and subj Id
<- as.data.frame(do.call(rbind,weightlist))
weightdf <- rownames_to_column(weightdf, var="Id")
weightdf colnames(weightdf)[1]="Id"
colnames(weightdf)[2]="weight"
<- merge(subj_quest,weightdf,by="Id")
subj_quest
#Remove Invalid participans
<- subj_quest[subj_quest$isvalid != 0,] subj_quest
Calculating PSDs sequences (spectra)
Since the spectra for each trial and each participant is relatively long to compute, they are saved in a rspec.dat in the data directory. For future runs this file will be used, if present, instead of computing the spectra again.
# Check if the rspec is already available in the directory
#and if not, compute it
if (file.exists(file.path(data_dir, "rspec.dat"))) {
load(file.path(data_dir, "rspec.dat"))
print("rspec.dat already exists, loading it from save...",
quote = F)
else {
}
# Looping through the subjects
for (s in seq(1, nrow(subj_quest)))
# Loop through the subjects :
{
# Get the subject id
<- subj_quest$Id[s]
subject
# Check the validity of each trial for this subject
<- subj_quest$valid1[subj_quest$Id == subject] == 1
valid1 <- subj_quest$valid2[subj_quest$Id == subject] == 1
valid2 <- subj_quest$valid3[subj_quest$Id == subject] == 1
valid3
# Creating vector mask for validity
<- c(valid1, valid2, valid3)
vvec
# Applying the mask to the trials vector
<- cond[!!vvec]
trials
for (j in seq(1, length(trials))) { # Loop through the trials :
# Get the conditions
<- trials[j]
trial <- round(((s/nrow(subj_quest))*100),2)
perct
<- paste0(file_path_sans_ext(
filename as.character(subject))
"-", trial,".brute")
, cat(paste0(
"\r", " Computing the spectra for the file : ",
filename," ( ",
perct,"% finished )"))
# Get the posturography data
<- read.table(file.path(data_dir, filename),
data sep = "\t",
skip = 1, header = TRUE)
<- head(data, nb_samp)
data
<- data$Barycentre.y..mm.
y
# Compute the spectra
for (i in seq(1, nb_step/dratio)) {
<- i * dratio
t <- seq(t, t + window_size - 1)
idx <- psdcore(y [idx])
p
<- 10 * log10(p$spec)
spec <- spec [initial_idx : final_idx]
spectra [i, ]
}
# Extract trial result in a list
<- list(spectra = spectra)
rspec [[subject]] [[trial]]
}}
save (rspec, file = file.path (data_dir, "rspec.dat"))
}
[1] rspec.dat already exists, loading it from save...
cat("\r Done computing spectra ! \n Saved in data/rspec.dat")
Done computing spectra !
Saved in data/rspec.dat
Computing Energy Ratios
Setting the time and frequency bands of interest for the computing of energy ratios :
# Setting the two frequency bands
<- c(1:7) # get the columns corresponding
bf #to the 0.1 to 0.7 Hz range
<- c(7:13) # get the columns corresponding
hf #to the 0.7 to 1.3 Hz range
# Setting the five time windows
<- c((5000/dratio):(6000/dratio)) # get the rows corresponding
t1 #to the 50s to 60 sec range
<- c((6000/dratio):(7000/dratio)) # get the rows corresponding
t2 #to the 60s to 70 sec range
<- c((11000/dratio):(12000/dratio)) # get the rows corresponding
t3 #to the 110s to 120 sec range
<- c((12000/dratio):(13000/dratio)) # get the rows corresponding
t4 #to the 120s to 130 sec range
<- c((16000/dratio):(17000/dratio)) # get the rows corresponding
t5 #to the 160s to 170 sec range
Computing Energy ratios for each trials of each participants and extracting them from a list to make a single data frame :
# Looping over each condition for all subjects
for (s in names(rspec)){
for ( c in names (rspec [[s]])) {
# Get low frequency band for each time window
#(Peterka : 0.1 - 0.7 Hz)
<- rspec [[s]][[c]]$spectra[t1, bf]
l1 <- rspec [[s]][[c]]$spectra[t2, bf]
l2 <- rspec [[s]][[c]]$spectra[t3, bf]
l3 <- rspec [[s]][[c]]$spectra[t4, bf]
l4 <- rspec [[s]][[c]]$spectra[t5, bf]
l5
# Get high frequency band for each time window
#(Peterka : 0.7 - 1.3 Hz)
<- rspec [[s]][[c]]$spectra[t1, hf]
h1 <- rspec [[s]][[c]]$spectra[t2, hf]
h2 <- rspec [[s]][[c]]$spectra[t3, hf]
h3 <- rspec [[s]][[c]]$spectra[t4, hf]
h4 <- rspec [[s]][[c]]$spectra[t5, hf]
h5
#Compute Energy Ratio
=(sum(h1)/sum(l1))
er1=(sum(h2)/sum(l2))
er2=(sum(h3)/sum(l3))
er3=(sum(h4)/sum(l4))
er4=(sum(h5)/sum(l5))
er5
#Create a list with only these bands and energy ratios
<- list(
rsptat [[s]] [[c]]h1 = h1, # High frequencies over each time windows
h2 = h2,
h3 = h3,
h4 = h4,
h5 = h5,
l1 = l1, # Low frequencies over each time windows
l2 = l2,
l3 = l3,
l4 = l4,
l5 = l5,
er1 = er1, # Energy ratio over each time windows
er2 = er2,
er3 = er3,
er4 = er4,
er5 = er5,
er2_er1 = er2-er1,
er4_er3 = er4-er3,
carsick = subj_quest$CarSick[subj_quest$Id == s],
age = subj_quest$Age[subj_quest$Id == s],
sexe = subj_quest$Sexe[subj_quest$Id == s],
height = subj_quest$Height[subj_quest$Id == s],
weight = subj_quest$weight[subj_quest$Id == s],
validity = subj_quest$isvalid[subj_quest$Id == s])
}}
for (s in names (rsptat))
# Loop over vision conditions
for (c in names (rsptat [[s]]))
# Loop over SR conditions
{
<- data.frame(
datatemp subject = s,
condition = c,
er1 = rsptat [[s]] [[c]]$er1,
er2 = rsptat [[s]] [[c]]$er2,
er3 = rsptat [[s]] [[c]]$er3,
er4 = rsptat [[s]] [[c]]$er4,
er5 = rsptat [[s]] [[c]]$er5,
er2_er1 = rsptat [[s]] [[c]]$er2_er1,
er4_er3 = rsptat [[s]] [[c]]$er4_er3,
carsick = rsptat [[s]] [[c]]$carsick,
age = rsptat [[s]] [[c]]$age,
sexe = rsptat [[s]] [[c]]$sexe,
height = rsptat [[s]] [[c]]$height,
weight = rsptat [[s]] [[c]]$weight,
validity = rsptat [[s]] [[c]]$validity)
<- rbind(datastat,datatemp)
datastat }
Reformatting the dataframe by averaging ERs for every trials succeeded by each participants :
<- aggregate(list(
datamean er1 = datastat$er1,
er2 = datastat$er2,
er3 = datastat$er3,
er4 = datastat$er4,
er5 = datastat$er5,
er2_er1 = datastat$er2_er1,
er4_er3 = datastat$er4_er3,
carsick = datastat$carsick,
age= datastat$age,
weight = datastat$weight,
validity = datastat$validity
),by = list(subject = datastat$subject),
FUN = mean)
names(subj_quest)[names(subj_quest) == 'Id'] <- "subject"
<- subj_quest[,c("subject","Sexe")]
sexe
<- merge(datamean,sexe,by="subject") datamean
Car sickness quartiles computation
Computing quartiles values for the car sickness score and adding quartile categorization in the dataframe :
# Extracting q1 and q3 (quartiles) values for car sickness
<- quantile(datamean$carsick, 0.25)
q1 <- quantile(datamean$carsick, 0.75) q3
<- datamean %>%
datamean mutate(carsick_quart =
ifelse(datamean$carsick < q1,-1,
ifelse(datamean$carsick > q3, 1, 0)),
.after = validity)
Saving and displaying the final dataframe
write_xlsx(datamean,"datamean.xlsx")
paged_table(datamean)