Last active
July 5, 2024 08:00
-
-
Save Antoine-DupuyUL/79ae8aa2f4153757316c712e0d46ba8a to your computer and use it in GitHub Desktop.
This script has been written to pre-process and process uncalibrated triaxial accelerometer (Noraxon sensors) with sample frequency at 500 Hz.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- coding: utf-8 -*- | |
""" | |
Created on Tue Aug 8 10:46:51 2023 | |
@author: antoine dupuy | |
This script has been written to analyse uncalibrated triaxial accelerometer | |
(Noraxon sensors) with sample frequency at 500 Hz. | |
It uses a customed function to extract data from each participant csv file (FileOperation) | |
which will not be available here. | |
The accelerometers were located respectively on the right hand (between the distal | |
3rd metacarpal process, the proximal 2st metacarpal process, and the proximal | |
4th metacarpal process with the x-axis aligned in the continuation of the hand and pointing forward), | |
forearm (half-distance from the olecranon fossa and the imaginary line between | |
the ulnar and radial styloid process with the x-axis aligned in the continuation | |
of the forearm and pointing forward), | |
and arm (half-distance from the acromion and the lateral epicondyle with the x-axis | |
aligned in the continuation of the arm and pointing to the elbow). | |
All the following analysis is concerning the hand, the forearm, and the arm. | |
The script is reading .csv files. It is working with numpy dataframe. | |
In order, this script is: removing unwanted columns and rows, defining columns, | |
calculating the effective time of recording, removing outliers, calculating the percentage of unchanged values | |
imputing for missing values, subtracting the mean of the signal (because accelerometers are uncalibrated), | |
changing the unit (mG) into m.s-2, use an FFT to determine the filter cut-off frequency, | |
applying a 2nd order Butterworth bandpass (0.5-11 Hz) filter, integrating the signal to calculate velocity, | |
integrate again to calculate displacement, calculating position from displacement, accelerationa and velocity norms, | |
Root Mean Square (RMS) of acceleration and velocity, acceleration ratio between hand and forearm & forearm and arm, | |
number of zero crossings in velocity, cumulative distance and displacement ratio, and ellipse of confidence | |
of hand displacements. | |
Then exporting the results of all participants of the same folder to a .csv file. | |
""" | |
"import libraries" | |
import pandas as pd | |
import shutil | |
from scipy.integrate import cumulative_trapezoid | |
import matplotlib.pyplot as plt | |
from matplotlib.patches import Ellipse | |
import matplotlib.transforms as transforms | |
import scipy as sp | |
import numpy as np | |
import os | |
"definition of the different functions used for analysing data" #From https://gist.github.com/CarstenSchelp/b992645537660bda692f218b562d0712 | |
def confidence_ellipse(x, y, ax, n_std=3.0, facecolor='none', **kwargs): | |
""" | |
Created by Carsten Schelp | |
Plot of the covariance confidence ellipse of *x* and *y*. | |
Parameters | |
---------- | |
x, y : array-like, shape (n, ) | |
Input data. | |
ax : matplotlib.axes.Axes | |
The axes object to draw the ellipse into. | |
n_std : float | |
The number of standard deviations to determine the ellipse's radiuses. | |
**kwargs | |
Forwarded to `~matplotlib.patches.Ellipse` | |
Returns | |
------- | |
matplotlib.patches.Ellipse | |
""" | |
if x.size != y.size: | |
raise ValueError("x and y must be the same size") | |
cov = np.cov(x, y) | |
pearson = cov[0, 1]/np.sqrt(cov[0, 0] * cov[1, 1]) | |
# Using a special case to obtain the eigenvalues of this | |
# two-dimensional dataset. | |
ell_radius_x = np.sqrt(1 + pearson) | |
ell_radius_y = np.sqrt(1 - pearson) | |
ellipse = Ellipse((0, 0), width=ell_radius_x * 2, height=ell_radius_y * 2, | |
facecolor=facecolor, **kwargs) | |
# Calculating the standard deviation of x from | |
# the squareroot of the variance and multiplying | |
# with the given number of standard deviations. | |
scale_x = np.sqrt(cov[0, 0]) * n_std | |
mean_x = np.mean(x) | |
# calculating the standard deviation of y ... | |
scale_y = np.sqrt(cov[1, 1]) * n_std | |
mean_y = np.mean(y) | |
transf = transforms.Affine2D() \ | |
.rotate_deg(45) \ | |
.scale(scale_x, scale_y) \ | |
.translate(mean_x, mean_y) | |
ellipse.set_transform(transf + ax.transData) | |
return ax.add_patch(ellipse) | |
def count_sign_changes(values, threshold = 0.01): # Calculate the number of zero-crossings (values input = signal to analyse; threshold = the value to cross | |
# in the negative and positive side) | |
if len(values) < 2: | |
return 0 | |
sign_changes = 0 | |
current_sign = 1 if values[0] >= threshold else -1 if values[0] <= -threshold else 0 | |
i=1 | |
for value in values[1:]: | |
new_sign = 1 if value >= threshold else -1 if value <= -threshold else 0 | |
if new_sign != 0 and new_sign != current_sign: | |
#print (i,value) | |
sign_changes += 1 | |
current_sign = new_sign | |
i=i+1 | |
return sign_changes-1 | |
################################################## | |
"time played" | |
time_played = (endingrow - beginningrow)/500 # Determine how much time participants played | |
print('time played = ', time_played, ' s') | |
"delta t" | |
fs = 500 | |
dt = 1/fs | |
# print(dt) | |
df_output['time'] = time | |
#print (time) | |
"Columns identification" | |
Accel_1_Ax = df.iloc[:, 3] # df['Ultium EMG.Internal Accel 1 Ax (mG)'] | |
Accel_1_Ay = df.iloc[:, 4] # df['Ultium EMG.Internal Accel 1 Ay (mG)'] | |
Accel_1_Az = df.iloc[:, 5] # df['Ultium EMG.Internal Accel 1 Az (mG)'] | |
Accel_2_Ax = df.iloc[:, 6] # df['Ultium EMG.Internal Accel 2 Ax (mG)'] | |
Accel_2_Ay = df.iloc[:, 7] # df['Ultium EMG.Internal Accel 2 Ay (mG)'] | |
Accel_2_Az = df.iloc[:, 8] # df['Ultium EMG.Internal Accel 2 Az (mG)'] | |
Accel_3_Ax = df.iloc[:, 9] # df['Ultium EMG.Internal Accel 3 Ax (mG)'] | |
Accel_3_Ay = df.iloc[:, 10] # df['Ultium EMG.Internal Accel 3 Ay (mG)'] | |
Accel_3_Az = df.iloc[:, 11] # df['Ultium EMG.Internal Accel 3 Az (mG)'] | |
#print(Accel_1_Ay) | |
#plt.plot(time, Accel_1_Ay) | |
# plt.title('raw acceleration in the Medio-Lateral plane in function of time') | |
# plt.xlabel('time in seconds') | |
# plt.ylabel('acceleration in mG') | |
"Outliers management: Replacing data by missing values" | |
# Take the mean of the signal | |
mean_1_x = np.mean(Accel_1_Ax) | |
mean_1_y = np.mean(Accel_1_Ay) | |
mean_1_z = np.mean(Accel_1_Az) | |
mean_2_x = np.mean(Accel_2_Ax) | |
mean_2_y = np.mean(Accel_2_Ay) | |
mean_2_z = np.mean(Accel_2_Az) | |
mean_3_x = np.mean(Accel_3_Ax) | |
mean_3_y = np.mean(Accel_3_Ay) | |
mean_3_z = np.mean(Accel_3_Az) | |
#print(mean_1_x) | |
# Define a threshold | |
thh_1_x_h = mean_1_x + (3*np.std(Accel_1_Ax)) # 3 standard deviations threshold to remove accelerometers' falls and tasks' unrelated movements | |
thh_1_x_l = mean_1_x - (3*np.std(Accel_1_Ax)) | |
thh_1_y_h = mean_1_y + (3*np.std(Accel_1_Ay)) | |
thh_1_y_l = mean_1_y - (3*np.std(Accel_1_Ay)) | |
thh_1_z_h = mean_1_z + (3*np.std(Accel_1_Az)) | |
thh_1_z_l = mean_1_z - (3*np.std(Accel_1_Az)) | |
thh_2_x_h = mean_2_x + (3*np.std(Accel_2_Ax)) | |
thh_2_x_l = mean_2_x - (3*np.std(Accel_2_Ax)) | |
thh_2_y_h = mean_2_y + (3*np.std(Accel_2_Ay)) | |
thh_2_y_l = mean_2_y - (3*np.std(Accel_2_Ay)) | |
thh_2_z_h = mean_2_z + (3*np.std(Accel_2_Az)) | |
thh_2_z_l = mean_2_z - (3*np.std(Accel_2_Az)) | |
thh_3_x_h = mean_3_x + (3*np.std(Accel_3_Ax)) | |
thh_3_x_l = mean_3_x - (3*np.std(Accel_3_Ax)) | |
thh_3_y_h = mean_3_y + (3*np.std(Accel_3_Ay)) | |
thh_3_y_l = mean_3_y - (3*np.std(Accel_3_Ay)) | |
thh_3_z_h = mean_3_z + (3*np.std(Accel_3_Az)) | |
thh_3_z_l = mean_3_z - (3*np.std(Accel_3_Az)) | |
#print(thh_1_x_h) | |
#print(thh_1_x_l) | |
# Replace outliers (above or below 12 sd) by 9999 | |
Accel_1_Ax[(Accel_1_Ax > thh_1_x_h) | (Accel_1_Ax < thh_1_x_l)] = 9999 | |
Accel_1_Ay[(Accel_1_Ay > thh_1_y_h) | (Accel_1_Ay < thh_1_y_l)] = 9999 | |
Accel_1_Az[(Accel_1_Az > thh_1_z_h) | (Accel_1_Az < thh_1_z_l)] = 9999 | |
Accel_2_Ax[(Accel_2_Ax > thh_2_x_h) | (Accel_2_Ax < thh_2_x_l)] = 9999 | |
Accel_2_Ay[(Accel_2_Ay > thh_2_y_h) | (Accel_2_Ay < thh_2_y_l)] = 9999 | |
Accel_2_Az[(Accel_2_Az > thh_2_z_h) | (Accel_2_Az < thh_2_z_l)] = 9999 | |
Accel_3_Ax[(Accel_3_Ax > thh_3_x_h) | (Accel_3_Ax < thh_3_x_l)] = 9999 | |
Accel_3_Ay[(Accel_3_Ay > thh_3_y_h) | (Accel_3_Ay < thh_3_y_l)] = 9999 | |
Accel_3_Az[(Accel_3_Az > thh_3_z_h) | (Accel_3_Az < thh_3_z_l)] = 9999 | |
#plt.plot(time, Accel_1_Ax) | |
#plt.axis([150, 175, -100, 10000]) | |
# Percentage of data unchanged | |
total_data_1_Ax = len(Accel_1_Ax) | |
total_data_1_Ay = len(Accel_1_Ay) | |
total_data_1_Az = len(Accel_1_Az) | |
total_data_2_Ax = len(Accel_2_Ax) | |
total_data_2_Ay = len(Accel_2_Ay) | |
total_data_2_Az = len(Accel_2_Az) | |
total_data_3_Ax = len(Accel_3_Ax) | |
total_data_3_Ay = len(Accel_3_Ay) | |
total_data_3_Az = len(Accel_3_Az) | |
#print(total_data_1_Ax) | |
total_removed_1_Ax = np.count_nonzero(Accel_1_Ax == 9999) | |
total_removed_1_Ay = np.count_nonzero(Accel_1_Ay == 9999) | |
total_removed_1_Az = np.count_nonzero(Accel_1_Az == 9999) | |
total_removed_2_Ax = np.count_nonzero(Accel_2_Ax == 9999) | |
total_removed_2_Ay = np.count_nonzero(Accel_2_Ay == 9999) | |
total_removed_2_Az = np.count_nonzero(Accel_2_Az == 9999) | |
total_removed_3_Ax = np.count_nonzero(Accel_3_Ax == 9999) | |
total_removed_3_Ay = np.count_nonzero(Accel_3_Ay == 9999) | |
total_removed_3_Az = np.count_nonzero(Accel_3_Az == 9999) | |
#print(total_removed_1_Ay) | |
percentage_data_unchanged_1_Ax = 100-(total_removed_1_Ax*100)/total_data_1_Ax | |
percentage_data_unchanged_1_Ay = 100-(total_removed_1_Ay*100)/total_data_1_Ay | |
percentage_data_unchanged_1_Az = 100-(total_removed_1_Az*100)/total_data_1_Az | |
percentage_data_unchanged_2_Ax = 100-(total_removed_2_Ax*100)/total_data_2_Ax | |
percentage_data_unchanged_2_Ay = 100-(total_removed_2_Ay*100)/total_data_2_Ay | |
percentage_data_unchanged_2_Az = 100-(total_removed_2_Az*100)/total_data_2_Az | |
percentage_data_unchanged_3_Ax = 100-(total_removed_3_Ax*100)/total_data_3_Ax | |
percentage_data_unchanged_3_Ay = 100-(total_removed_3_Ay*100)/total_data_3_Ay | |
percentage_data_unchanged_3_Az = 100-(total_removed_3_Az*100)/total_data_3_Az | |
#print(percentage_data_unchanged_1_Ay) | |
data_unchanged_hand = (percentage_data_unchanged_1_Ax + percentage_data_unchanged_1_Ay + percentage_data_unchanged_1_Az)/3 | |
data_unchanged_forearm = (percentage_data_unchanged_2_Ax + percentage_data_unchanged_2_Ay + percentage_data_unchanged_2_Az)/3 | |
data_unchanged_arm = (percentage_data_unchanged_3_Ax + percentage_data_unchanged_3_Ay + percentage_data_unchanged_3_Az)/3 | |
print(data_unchanged_hand, '%') | |
print(data_unchanged_forearm, '%') | |
print(data_unchanged_arm, '%') | |
"Imputation for missing values" | |
# Replace 9999 by Not a Number (nan) | |
Accel_1_Ax.replace(9999, float('nan'), inplace=True) | |
Accel_1_Ay.replace(9999, float('nan'), inplace=True) | |
Accel_1_Az.replace(9999, float('nan'), inplace=True) | |
Accel_2_Ax.replace(9999, float('nan'), inplace=True) | |
Accel_2_Ay.replace(9999, float('nan'), inplace=True) | |
Accel_2_Az.replace(9999, float('nan'), inplace=True) | |
Accel_3_Ax.replace(9999, float('nan'), inplace=True) | |
Accel_3_Ay.replace(9999, float('nan'), inplace=True) | |
Accel_3_Az.replace(9999, float('nan'), inplace=True) | |
# #print(Accel_1_Ax[57000:57500]) | |
df_output['Accel_1_Ax'] = Accel_1_Ax | |
df_output['Accel_1_Ay'] = Accel_1_Ay | |
df_output['Accel_1_Az'] = Accel_1_Az | |
df_output['Accel_2_Ax'] = Accel_2_Ax | |
df_output['Accel_2_Ay'] = Accel_2_Ay | |
df_output['Accel_2_Az'] = Accel_2_Az | |
df_output['Accel_3_Ax'] = Accel_3_Ax | |
df_output['Accel_3_Ay'] = Accel_3_Ay | |
df_output['Accel_3_Az'] = Accel_3_Az | |
Accel_1_Ax = Accel_1_Ax.interpolate(method='linear').ffill().bfill() | |
Accel_1_Ay = Accel_1_Ay.interpolate(method='linear').ffill().bfill() | |
Accel_1_Az = Accel_1_Az.interpolate(method='linear').ffill().bfill() | |
Accel_2_Ax = Accel_2_Ax.interpolate(method='linear').ffill().bfill() | |
Accel_2_Ay = Accel_2_Ay.interpolate(method='linear').ffill().bfill() | |
Accel_2_Az = Accel_2_Az.interpolate(method='linear').ffill().bfill() | |
Accel_3_Ax = Accel_3_Ax.interpolate(method='linear').ffill().bfill() | |
Accel_3_Ay = Accel_3_Ay.interpolate(method='linear').ffill().bfill() | |
Accel_3_Az = Accel_3_Az.interpolate(method='linear').ffill().bfill() | |
# Replace by the mean of the representative window | |
# Accel_1_Ax.fillna(mean_1_x, inplace=True) | |
# Accel_1_Ay.fillna(mean_1_y, inplace=True) | |
# Accel_1_Az.fillna(mean_1_z, inplace=True) | |
# Accel_2_Ax.fillna(mean_2_x, inplace=True) | |
# Accel_2_Ay.fillna(mean_2_y, inplace=True) | |
# Accel_2_Az.fillna(mean_2_z, inplace=True) | |
# Accel_3_Ax.fillna(mean_3_x, inplace=True) | |
# Accel_3_Ay.fillna(mean_3_y, inplace=True) | |
# Accel_3_Az.fillna(mean_3_z, inplace=True) | |
#plt.plot(time, Accel_1_Ax) | |
"mean accelerations all axis + subtracting the mean" | |
# Remove the mean acceleration of the entire signal in all axes (because accelerometers are uncalibrated) | |
Accel_1_Ax = Accel_1_Ax - mean_1_x | |
Accel_1_Ay = Accel_1_Ay - mean_1_y | |
Accel_1_Az = Accel_1_Az - mean_1_z | |
Accel_2_Ax = Accel_2_Ax - mean_2_x | |
Accel_2_Ay = Accel_2_Ay - mean_2_y | |
Accel_2_Az = Accel_2_Az - mean_2_z | |
Accel_3_Ax = Accel_3_Ax - mean_3_x | |
Accel_3_Ay = Accel_3_Ay - mean_3_y | |
Accel_3_Az = Accel_3_Az - mean_3_z | |
# print(mean_Accel_1_Ax) | |
"mg to g" # mg is a "milli graviton" or a 1000th of the gravitational constant | |
Accel_1_Ax = Accel_1_Ax/1000 | |
Accel_1_Ay = Accel_1_Ay/1000 | |
Accel_1_Az = Accel_1_Az/1000 | |
Accel_2_Ax = Accel_2_Ax/1000 | |
Accel_2_Ay = Accel_2_Ay/1000 | |
Accel_2_Az = Accel_2_Az/1000 | |
Accel_3_Ax = Accel_3_Ax/1000 | |
Accel_3_Ay = Accel_3_Ay/1000 | |
Accel_3_Az = Accel_3_Az/1000 | |
# plt.plot(time, Accel_1_Ay) | |
"g to m.s-2" | |
g = 9.80665 | |
Accel_1_Ax = Accel_1_Ax*g | |
Accel_1_Ay = Accel_1_Ay*g | |
Accel_1_Az = Accel_1_Az*g | |
Accel_2_Ax = Accel_2_Ax*g | |
Accel_2_Ay = Accel_2_Ay*g | |
Accel_2_Az = Accel_2_Az*g | |
Accel_3_Ax = Accel_3_Ax*g | |
Accel_3_Ay = Accel_3_Ay*g | |
Accel_3_Az = Accel_3_Az*g | |
#plt.plot(time, Accel_1_Ay) | |
"FFT to determine cut-off frequency" | |
N = len(Accel_1_Ax) | |
FFT_Accel_1_Ax = sp.fftpack.fft(Accel_1_Ax.values) | |
xf = sp.fftpack.fftfreq(N, dt)[0:N//2] | |
#plt.plot(xf, 2.0/N * np.abs(Accel_1_Ax[0:N//2])) | |
#plt.plot(xf, FFT_Accel_1_Ax[0:N//2]) # Uncomment to see the FFT of the signal | |
# plt.axis([0, 2, 0, 4000]) # Uncomment to show the FFT with origin at 0 and to choose the window you want to display (first two digits = x axis) | |
# plt.title('Fast Fourier Transform (FFT) of hand acceleration in the Medio-Lateral plane (zoom in)') | |
# plt.xlabel('frequencies (Hz)') | |
# plt.ylabel('amplitude of the spectral components') | |
"butterworth filter - acceleration" | |
# Apply a 2nd order Butterworth filter with bandpass (0.5-11 Hz) cutoff frequency, 500 Hz frequency sampling | |
sos = sp.signal.butter(2, [0.5, 11], 'bandpass', fs=500, output='sos') | |
Accel_1_Ax_f = sp.signal.sosfilt(sos, Accel_1_Ax) | |
Accel_1_Ay_f = sp.signal.sosfilt(sos, Accel_1_Ay) | |
Accel_1_Az_f = sp.signal.sosfilt(sos, Accel_1_Az) | |
Accel_2_Ax_f = sp.signal.sosfilt(sos, Accel_2_Ax) | |
Accel_2_Ay_f = sp.signal.sosfilt(sos, Accel_2_Ay) | |
Accel_2_Az_f = sp.signal.sosfilt(sos, Accel_2_Az) | |
Accel_3_Ax_f = sp.signal.sosfilt(sos, Accel_3_Ax) | |
Accel_3_Ay_f = sp.signal.sosfilt(sos, Accel_3_Ay) | |
Accel_3_Az_f = sp.signal.sosfilt(sos, Accel_3_Az) | |
# print(Accel_1_Ax_f) | |
# plt.plot(time, Accel_1_Ay_f) | |
df_output['Accel_1_Ax_f'] = Accel_1_Ax_f | |
df_output['Accel_1_Ay_f'] = Accel_1_Ay_f | |
df_output['Accel_1_Az_f'] = Accel_1_Az_f | |
"integration (velocities)" | |
#Veloc_1_Vx_p = cumtrapz_example(Accel_1_Ax_f,time) | |
Veloc_1_Vx_p = cumulative_trapezoid(Accel_1_Ax_f, time, initial=0) | |
Veloc_1_Vy_p = cumulative_trapezoid(Accel_1_Ay_f, time, initial=0) | |
Veloc_1_Vz_p = cumulative_trapezoid(Accel_1_Az_f, time, initial=0) | |
Veloc_2_Vx_p = cumulative_trapezoid(Accel_2_Ax_f, time, initial=0) | |
Veloc_2_Vy_p = cumulative_trapezoid(Accel_2_Ay_f, time, initial=0) | |
Veloc_2_Vz_p = cumulative_trapezoid(Accel_2_Az_f, time, initial=0) | |
Veloc_3_Vx_p = cumulative_trapezoid(Accel_3_Ax_f, time, initial=0) | |
Veloc_3_Vy_p = cumulative_trapezoid(Accel_3_Ay_f, time, initial=0) | |
Veloc_3_Vz_p = cumulative_trapezoid(Accel_3_Az_f, time, initial=0) | |
# print(Veloc_1_Vy_p) | |
df_output['Veloc_1_Vx_p'] = Veloc_1_Vx_p | |
df_output['Veloc_1_Vy_p'] = Veloc_1_Vy_p | |
df_output['Veloc_1_Vz_p'] = Veloc_1_Vz_p | |
df_output['Veloc_2_Vx_p'] = Veloc_2_Vx_p | |
df_output['Veloc_2_Vy_p'] = Veloc_2_Vy_p | |
df_output['Veloc_2_Vz_p'] = Veloc_2_Vz_p | |
df_output['Veloc_3_Vx_p'] = Veloc_3_Vx_p | |
df_output['Veloc_3_Vy_p'] = Veloc_3_Vy_p | |
df_output['Veloc_3_Vz_p'] = Veloc_3_Vz_p | |
# print(Veloc_1_Vy_p) | |
# plt.plot(time, Veloc_1_Vy_p) | |
"double integration (displacement)" | |
# displacement signal | |
Trav_1_Px = cumulative_trapezoid(Veloc_1_Vx_p, time, initial=0) | |
Trav_1_Py = cumulative_trapezoid(Veloc_1_Vy_p, time, initial=0) | |
Trav_1_Pz = cumulative_trapezoid(Veloc_1_Vz_p, time, initial=0) | |
Trav_2_Px = cumulative_trapezoid(Veloc_2_Vx_p, time, initial=0) | |
Trav_2_Py = cumulative_trapezoid(Veloc_2_Vy_p, time, initial=0) | |
Trav_2_Pz = cumulative_trapezoid(Veloc_2_Vz_p, time, initial=0) | |
Trav_3_Px = cumulative_trapezoid(Veloc_3_Vx_p, time, initial=0) | |
Trav_3_Py = cumulative_trapezoid(Veloc_3_Vy_p, time, initial=0) | |
Trav_3_Pz = cumulative_trapezoid(Veloc_3_Vz_p, time, initial=0) | |
# plt.plot(time, Trav_1_Py) | |
# plt.plot(Trav_1_Py, Trav_1_Px) | |
df_output['Trav_1_Px'] = Trav_1_Px | |
df_output['Trav_1_Py'] = Trav_1_Py | |
df_output['Trav_1_Pz'] = Trav_1_Pz | |
df_output['Trav_2_Px'] = Trav_2_Px | |
df_output['Trav_2_Py'] = Trav_2_Py | |
df_output['Trav_2_Pz'] = Trav_2_Pz | |
df_output['Trav_3_Px'] = Trav_3_Px | |
df_output['Trav_3_Py'] = Trav_3_Py | |
df_output['Trav_3_Pz'] = Trav_3_Pz | |
"Displacement to Position" | |
Pos_1_Px = (df_output['Trav_1_Px'].astype(float) - | |
df_output['Trav_1_Px'].shift(-1).astype(float))*-1 | |
Pos_1_Py = (df_output['Trav_1_Py'].astype(float) - | |
df_output['Trav_1_Py'].shift(-1).astype(float))*-1 | |
Pos_1_Pz = (df_output['Trav_1_Pz'].astype(float) - | |
df_output['Trav_1_Pz'].shift(-1).astype(float))*-1 | |
Pos_2_Px = (df_output['Trav_2_Px'].astype(float) - | |
df_output['Trav_2_Px'].shift(-1).astype(float))*-1 | |
Pos_2_Py = (df_output['Trav_2_Py'].astype(float) - | |
df_output['Trav_2_Py'].shift(-1).astype(float))*-1 | |
Pos_2_Pz = (df_output['Trav_2_Pz'].astype(float) - | |
df_output['Trav_2_Pz'].shift(-1).astype(float))*-1 | |
Pos_3_Px = (df_output['Trav_3_Px'].astype(float) - | |
df_output['Trav_3_Px'].shift(-1).astype(float))*-1 | |
Pos_3_Py = (df_output['Trav_3_Py'].astype(float) - | |
df_output['Trav_3_Py'].shift(-1).astype(float))*-1 | |
Pos_3_Pz = (df_output['Trav_3_Pz'].astype(float) - | |
df_output['Trav_3_Pz'].shift(-1).astype(float))*-1 | |
df_output['Pos_1_Px'] = Pos_1_Px | |
df_output['Pos_1_Py'] = Pos_1_Py | |
df_output['Pos_1_Pz'] = Pos_1_Pz | |
df_output['Pos_2_Px'] = Pos_2_Px | |
df_output['Pos_2_Py'] = Pos_2_Py | |
df_output['Pos_2_Pz'] = Pos_2_Pz | |
df_output['Pos_3_Px'] = Pos_3_Px | |
df_output['Pos_3_Py'] = Pos_3_Py | |
df_output['Pos_3_Pz'] = Pos_3_Pz | |
"zero line plot" | |
#plt.axhline(y=0, color='r', linestyle='-') # Display an horizontal line at whatever "y" you want | |
"acceleration norm" | |
# Normalisation of every point of the signal | |
A_hand = np.sqrt(Accel_1_Ax_f**2)+np.sqrt(Accel_1_Ay_f**2)+np.sqrt(Accel_1_Az_f**2) | |
A_forearm = np.sqrt(Accel_2_Ax_f**2) + \ | |
np.sqrt(Accel_2_Ay_f**2)+np.sqrt(Accel_2_Az_f**2) | |
A_arm = np.sqrt(Accel_3_Ax_f**2)+np.sqrt(Accel_3_Ay_f**2) + \ | |
np.sqrt(Accel_3_Az_f**2) | |
#print('Acceleration normalization: ', A_hand) | |
# plt.plot(time, A_hand) | |
df_output['A_hand'] = A_hand | |
"velocity norm" | |
V_hand = np.sqrt(Veloc_1_Vx_p**2)+np.sqrt(Veloc_1_Vy_p**2) + \ | |
np.sqrt(Veloc_1_Vz_p**2) | |
V_forearm = np.sqrt(Veloc_2_Vx_p**2) + \ | |
np.sqrt(Veloc_2_Vy_p**2)+np.sqrt(Veloc_2_Vz_p**2) | |
V_arm = np.sqrt(Veloc_3_Vx_p**2)+np.sqrt(Veloc_3_Vy_p**2) + \ | |
np.sqrt(Veloc_3_Vz_p**2) | |
# print(V_hand) | |
# plt.plot(time, V_hand) | |
"RMS accelerations" | |
rms_Accel_1_Ax_f = np.sqrt(np.mean(Accel_1_Ax_f**2)) | |
rms_Accel_1_Ay_f = np.sqrt(np.mean(Accel_1_Ay_f**2)) | |
rms_Accel_1_Az_f = np.sqrt(np.mean(Accel_1_Az_f**2)) | |
rms_Accel_2_Ax_f = np.sqrt(np.mean(Accel_2_Ax_f**2)) | |
rms_Accel_2_Ay_f = np.sqrt(np.mean(Accel_2_Ay_f**2)) | |
rms_Accel_2_Az_f = np.sqrt(np.mean(Accel_2_Az_f**2)) | |
rms_Accel_3_Ax_f = np.sqrt(np.mean(Accel_3_Ax_f**2)) | |
rms_Accel_3_Ay_f = np.sqrt(np.mean(Accel_3_Ay_f**2)) | |
rms_Accel_3_Az_f = np.sqrt(np.mean(Accel_3_Az_f**2)) | |
# print('rms hand acc x: ', rms_Accel_1_Ax_f) | |
"RMS accelerations all axes" | |
# RMS of hand, forearm and arm acceleration | |
rms_acc_hand = rms_Accel_1_Ax_f + rms_Accel_1_Ay_f + rms_Accel_1_Az_f | |
rms_acc_forearm = rms_Accel_2_Ax_f + rms_Accel_2_Ay_f + rms_Accel_2_Az_f | |
rms_acc_arm = rms_Accel_3_Ax_f + rms_Accel_3_Ay_f + rms_Accel_3_Az_f | |
print('RMS acc hand: ', rms_acc_hand, ' m.s-2') | |
print('RMS acc forearm: ', rms_acc_forearm, ' m.s-2') | |
print('RMS acc arm: ', rms_acc_arm, ' m.s-2') | |
"acceleration ratio" | |
# Ratio of acceleration between hand and forearm & forearm and arm | |
A_hand_forearm_ratio = rms_acc_hand/rms_acc_forearm | |
A_forearm_arm_ratio = rms_acc_forearm/rms_acc_arm | |
print('Acceleration ratio between hand and forearm: ', A_hand_forearm_ratio) | |
print('Acceleration ratio between forearm and arm: ', A_forearm_arm_ratio) | |
"Zero crossings in velocity" | |
# Number of hand direction changes | |
zc_Veloc_1_Vx = count_sign_changes(Veloc_1_Vx_p) # cf. definition of count_sign_changes function | |
print(zc_Veloc_1_Vx, 'zero crossings veloc in x') | |
zc_Veloc_1_Vy = count_sign_changes(Veloc_1_Vy_p) | |
print(zc_Veloc_1_Vy, 'zero crossings veloc in y') | |
zc_Veloc_1_Vz = count_sign_changes(Veloc_1_Vz_p) | |
print(zc_Veloc_1_Vz, 'zero crossings veloc in z') | |
zc_Veloc_hand = zc_Veloc_1_Vx + zc_Veloc_1_Vy + zc_Veloc_1_Vz | |
print(zc_Veloc_hand) | |
"Cumulative distance" | |
# Sum of the absolute position in all axes | |
travelled_dist_hand = np.sum(np.abs(Pos_1_Px)) + \ | |
np.sum(np.abs(Pos_1_Py)) + np.sum(np.abs(Pos_1_Pz)) | |
print('travelled distance: ', travelled_dist_hand, ' m') | |
travelled_dist_forearm = np.sum(np.abs(Pos_2_Px)) + \ | |
np.sum(np.abs(Pos_2_Py)) + np.sum(np.abs(Pos_2_Pz)) | |
print('travelled distance: ', travelled_dist_forearm, ' m') | |
travelled_dist_arm = np.sum(np.abs(Pos_3_Px)) + \ | |
np.sum(np.abs(Pos_3_Py)) + np.sum(np.abs(Pos_3_Pz)) | |
print('travelled distance: ', travelled_dist_arm, ' m') | |
"Ellipse area (95% confidence interval)" | |
# Cf. definition of confidence_ellipse function | |
n_std = 2 # Approximately 95% of trajectories (3 sd = approx. 99.7% of trajectories) | |
cov = np.cov(Trav_1_Px, Trav_1_Py) | |
pearson = cov[0, 1]/np.sqrt(cov[0, 0] * cov[1, 1]) | |
ell_radius_x = np.sqrt(1 + pearson) | |
ell_radius_y = np.sqrt(1 - pearson) | |
scaled_ell_x_radius = np.sqrt(cov[0, 0]) * n_std # Scaling the semi-major axis to be able to calculate the exact width of the ellipse of confidence | |
scaled_ell_y_radius = np.sqrt(cov[1, 1]) * n_std # Scaling the semi-minor axis to be able to calculate the exact width of the ellipse of confidence | |
width_short = scaled_ell_x_radius*2 | |
width_long = scaled_ell_y_radius*2 | |
print('short radius: ', scaled_ell_x_radius, ' m ; ', 'long radius: ', scaled_ell_y_radius, ' m') | |
print('width of the ellipse short : ', width_short, ' m ; ', 'and long: ', width_long, ' m') | |
ell_area_of_use = np.pi*scaled_ell_x_radius*scaled_ell_y_radius # ellipse area formula: pi*a*b (a = length of the semi-major axis; b = length of the semi-minor axis) | |
print('ellipse area of use: ', ell_area_of_use, 'm2') | |
"Ellipse plot" | |
# ax = plt.gca() # plt.plot(Trav_1_Py, Trav_1_Px) to visualize the trajectories contained into the ellipse | |
# confidence_ellipse(Trav_1_Py, Trav_1_Px, ax, n_std=2, edgecolor='red') | |
# ------------------------------------------------------------------------------------------- |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment