TEST remote repository

This commit is contained in:
Lars 2020-11-07 16:46:05 +01:00
parent 5491738fff
commit ba8df083e2
32 changed files with 6008 additions and 0 deletions

7
AutocorrRegSymmSteps.m Normal file
View File

@ -0,0 +1,7 @@
% autocorrelation for step symmetrie
function [c, lags] = AutocorrRegSymmSteps(x)
[c,lags] = xcov(x,200,'unbiased');
c = c/c(lags==0);
c = c(lags>=0);
lags = lags(lags>=0);

43
AutocorrStrides.m Normal file
View File

@ -0,0 +1,43 @@
function [ResultStruct] = AutocorrStrides(data,FS, StrideTimeRange,ResultStruct);
%% Stride-times measures
% Stride time and regularity from auto correlation (according to Moe-Nilssen and Helbostad, Estimation of gait cycle characteristics by trunk accelerometry. J Biomech, 2004. 37: 121-6.)
RangeStart = round(FS*StrideTimeRange(1));
RangeEnd = round(FS*StrideTimeRange(2));
[AutocorrResult,Lags]=xcov(data,RangeEnd,'unbiased');
AutocorrSum = sum(AutocorrResult(:,[1 5 9]),2); % This sum is independent of sensor re-orientation, as long as axes are kept orthogonal
AutocorrResult2= [AutocorrResult(:,[1 5 9]),AutocorrSum];
IXRange = (numel(Lags)-(RangeEnd-RangeStart)):numel(Lags);
% check that autocorrelations are positive for any direction,
AutocorrPlusTrans = AutocorrResult+AutocorrResult(:,[1 4 7 2 5 8 3 6 9]);
IXRangeNew = IXRange( ...
AutocorrPlusTrans(IXRange,1) > 0 ...
& prod(AutocorrPlusTrans(IXRange,[1 5]),2) > prod(AutocorrPlusTrans(IXRange,[2 4]),2) ...
& prod(AutocorrPlusTrans(IXRange,[1 5 9]),2) + prod(AutocorrPlusTrans(IXRange,[2 6 7]),2) + prod(AutocorrPlusTrans(IXRange,[3 4 8]),2) ...
> prod(AutocorrPlusTrans(IXRange,[1 6 8]),2) + prod(AutocorrPlusTrans(IXRange,[2 4 9]),2) + prod(AutocorrPlusTrans(IXRange,[3 5 7]),2) ...
);
if isempty(IXRangeNew)
StrideTimeSamples = Lags(IXRange(AutocorrSum(IXRange)==max(AutocorrSum(IXRange)))); % to be used in other estimations
StrideTimeSeconds = nan;
ResultStruct.StrideTimeSamples = StrideTimeSamples;
ResultStruct.StrideTimeSeconds = StrideTimeSeconds;
else
StrideTimeSamples = Lags(IXRangeNew(AutocorrSum(IXRangeNew)==max(AutocorrSum(IXRangeNew))));
StrideRegularity = AutocorrResult2(Lags==StrideTimeSamples,:)./AutocorrResult2(Lags==0,:); % Moe-Nilssen&Helbostatt,2004
RelativeStrideVariability = 1-StrideRegularity;
StrideTimeSeconds = StrideTimeSamples/FS;
ResultStruct.StrideRegularity_V = StrideRegularity(1);
ResultStruct.StrideRegularity_ML = StrideRegularity(2);
ResultStruct.StrideRegularity_AP = StrideRegularity(3);
ResultStruct.StrideRegularity_All = StrideRegularity(4);
ResultStruct.RelativeStrideVariability_V = RelativeStrideVariability(1);
ResultStruct.RelativeStrideVariability_ML = RelativeStrideVariability(2);
ResultStruct.RelativeStrideVariability_AP = RelativeStrideVariability(3);
ResultStruct.RelativeStrideVariability_All = RelativeStrideVariability(4);
ResultStruct.StrideTimeSamples = StrideTimeSamples;
ResultStruct.StrideTimeSeconds = StrideTimeSeconds;
end

118
CalcMaxLyapConvGait.m Normal file
View File

@ -0,0 +1,118 @@
function [L_Estimate,ExtraArgsOut] = CalcMaxLyapConvGait(ThisTimeSeries,FS,ExtraArgsIn)
if nargin > 2
if isfield(ExtraArgsIn,'J')
J=ExtraArgsIn.J;
end
if isfield(ExtraArgsIn,'m')
m=ExtraArgsIn.m;
end
if isfield(ExtraArgsIn,'FitWinLen')
FitWinLen=ExtraArgsIn.FitWinLen;
end
end
%% Initialize output args
L_Estimate=nan;ExtraArgsOut.Divergence=nan;ExtraArgsOut.J=nan;ExtraArgsOut.m=nan;ExtraArgsOut.FitWinLen=nan;
%% Some checks
% predefined J and m should not be NaN or Inf
if (exist('J','var') && ~isempty(J) && ~isfinite(J)) || (exist('m','var') && ~isempty(m) && ~isfinite(m))
warning('Predefined J and m cannot be NaN or Inf');
return;
end
% multidimensional time series need predefined J and m
if size(ThisTimeSeries,2) > 1 && (~exist('J','var') || ~exist('m','var') || isempty(J) || isempty(m))
warning('Multidimensional time series needs predefined J and m, can''t determine Lyapunov');
return;
end
%Check that there are no NaN or Inf values in the TimeSeries
if any(~isfinite(ThisTimeSeries(:)))
warning('Time series contains NaN or Inf, can''t determine Lyapunov');
return;
end
%Check that there is variation in the TimeSeries
if ~(nanstd(ThisTimeSeries) > 0)
warning('Time series is constant, can''t determine Lyapunov');
return;
end
%% Determine FitWinLen (=cycle time) of ThisTimeSeries
if ~exist('FitWinLen','var') || isempty(FitWinLen)
if size(ThisTimeSeries,2)>1
for dim=1:size(ThisTimeSeries,2),
[Pd(:,dim),F] = pwelch(detrend(ThisTimeSeries(:,dim)),[],[],[],FS);
end
P = sum(Pd,2);
else
[P,F] = pwelch(detrend(ThisTimeSeries),[],[],[],FS);
end
MeanF = sum(P.*F)./sum(P);
CycleTime = 1/MeanF;
FitWinLen = round(CycleTime*FS);
else
CycleTime = FitWinLen/FS;
end
ExtraArgsOut.FitWinLen=FitWinLen;
%% Determine J
if ~exist('J','var') || isempty(J)
% Calculate mutual information and take first local minimum Tau as J
bV = min(40,floor(sqrt(size(ThisTimeSeries,1))));
tauVmax = FitWinLen;
[mutMPro,cummutMPro,minmuttauVPro] = MutualInformationHisPro(ThisTimeSeries,(0:tauVmax),bV,1); % (xV,tauV,bV,flag)
if isnan(minmuttauVPro)
display(mutMPro);
warning('minmuttauVPro is NaN. Consider increasing tauVmax.');
return;
end
J=minmuttauVPro;
end
ExtraArgsOut.J=J;
%% Determine m
if ~exist('m','var') || isempty(m)
escape = 10;
max_m = 20;
max_fnnM = 0.02;
mV = 0;
fnnM = 1;
for mV = 2:max_m % for m=1, FalseNearestNeighbors is slow and lets matlab close if N>500000
fnnM = FalseNearestNeighborsSR(ThisTimeSeries,J,mV,escape,FS); % (xV,tauV,mV,escape,theiler)
if fnnM <= max_fnnM || isnan(fnnM)
break
end
end
if fnnM <= max_fnnM
m = mV;
else
warning('Too many false nearest neighbours');
return;
end
end
ExtraArgsOut.m=m;
%% Create state space based upon J and m
N_ss = size(ThisTimeSeries,1)-(m-1)*J;
StateSpace=nan(N_ss,m*size(ThisTimeSeries,2));
for dim=1:size(ThisTimeSeries,2),
for delay=1:m,
StateSpace(:,(dim-1)*m+delay)=ThisTimeSeries((1:N_ss)'+(delay-1)*J,dim);
end
end
%% Parameters for Lyapunov
WindowLen = floor(min(N_ss/5,10*FitWinLen));
if WindowLen < FitWinLen
warning('Not enough samples for Lyapunov estimation');
return;
end
WindowLenSec=WindowLen/FS;
%% Calculate divergence
Divergence=div_calc(StateSpace,WindowLenSec,FS,CycleTime,0);
ExtraArgsOut.Divergence=Divergence;
%% Calculate slope of first FitWinLen samples of divergence curve
p = polyfit((1:FitWinLen)/FS,Divergence(1:FitWinLen),1);
L_Estimate = p(1);

134
CalcMaxLyapWolfFixedEvolv.m Normal file
View File

@ -0,0 +1,134 @@
function [L_Estimate,ExtraArgsOut] = CalcMaxLyapWolfFixedEvolv(ThisTimeSeries,FS,ExtraArgsIn)
%% Description
% This function calculates the maximum Lyapunov exponent from a time
% series, based on the method described by Wolf et al. in
% Wolf, A., et al., Determining Lyapunov exponents from a time series.
% Physica D: 8 Nonlinear Phenomena, 1985. 16(3): p. 285-317.
%
% Input:
% ThisTimeSeries: a vector or matrix with the time series
% FS: sample frequency of the ThisTimeSeries
% ExtraArgsIn: a struct containing optional input arguments
% J (embedding delay)
% m (embedding dimension)
% Output:
% L_Estimate: The Lyapunov estimate
% ExtraArgsOut: a struct containing the additional output arguments
% J (embedding delay)
% m (embedding dimension)
%% Copyright
% COPYRIGHT (c) 2012 Sietse Rispens, VU University Amsterdam
%
% This program is free software: you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with this program. If not, see <http://www.gnu.org/licenses/>.
%% Author
% Sietse Rispens
%% History
% April 2012, initial version of CalcMaxLyapWolf
% 23 October 2012, use fixed evolve time instead of adaptable
if nargin > 2
if isfield(ExtraArgsIn,'J')
J=ExtraArgsIn.J;
end
if isfield(ExtraArgsIn,'m')
m=ExtraArgsIn.m;
end
end
%% Initialize output args
L_Estimate=nan;ExtraArgsOut.J=nan;ExtraArgsOut.m=nan;
%% Some checks
% predefined J and m should not be NaN or Inf
if (exist('J','var') && ~isempty(J) && ~isfinite(J)) || (exist('m','var') && ~isempty(m) && ~isfinite(m))
warning('Predefined J and m cannot be NaN or Inf');
return;
end
% multidimensional time series need predefined J and m
if size(ThisTimeSeries,2) > 1 && (~exist('J','var') || ~exist('m','var') || isempty(J) || isempty(m))
warning('Multidimensional time series needs predefined J and m, can''t determine Lyapunov');
return;
end
%Check that there are no NaN or Inf values in the TimeSeries
if any(~isfinite(ThisTimeSeries(:)))
warning('Time series contains NaN or Inf, can''t determine Lyapunov');
return;
end
%Check that there is variation in the TimeSeries
if ~(nanstd(ThisTimeSeries) > 0)
warning('Time series is constant, can''t determine Lyapunov');
return;
end
%% Determine J
if ~exist('J','var') || isempty(J)
% Calculate mutual information and take first local minimum Tau as J
bV = min(40,floor(sqrt(size(ThisTimeSeries,1))));
tauVmax = 70;
[mutMPro,cummutMPro,minmuttauVPro] = MutualInformationHisPro(ThisTimeSeries,(0:tauVmax),bV,1); % (xV,tauV,bV,flag)
if isnan(minmuttauVPro)
display(mutMPro);
warning('minmuttauVPro is NaN. Consider increasing tauVmax.');
return;
end
J=minmuttauVPro;
end
ExtraArgsOut.J=J;
%% Determine m
if ~exist('m','var') || isempty(m)
escape = 10;
max_m = 20;
max_fnnM = 0.02;
mV = 0;
fnnM = 1;
for mV = 2:max_m % for m=1, FalseNearestNeighbors is slow and lets matlab close if N>500000
fnnM = FalseNearestNeighborsSR(ThisTimeSeries,J,mV,escape,FS); % (xV,tauV,mV,escape,theiler)
if fnnM <= max_fnnM || isnan(fnnM)
break
end
end
if fnnM <= max_fnnM
m = mV;
else
warning('Too many false nearest neighbours');
return;
end
end
ExtraArgsOut.m=m;
%% Create state space based upon J and m
N_ss = size(ThisTimeSeries,1)-(m-1)*J;
StateSpace=nan(N_ss,m*size(ThisTimeSeries,2));
for dim=1:size(ThisTimeSeries,2),
for delay=1:m,
StateSpace(:,(dim-1)*m+delay)=ThisTimeSeries((1:N_ss)'+(delay-1)*J,dim);
end
end
%% Parameters for Lyapunov estimation
CriticalLen=J*m;
max_dist = sqrt(sum(std(StateSpace).^2))/10;
max_dist_mult = 5;
min_dist = max_dist/2;
max_theta = 0.3;
evolv = J;
%% Calculate Lambda
[L_Estimate]=div_wolf_fixed_evolv(StateSpace, FS, min_dist, max_dist, max_dist_mult, max_theta, CriticalLen, evolv);

View File

@ -0,0 +1,48 @@
function [ResultStruct] = CalculateNonLinearParametersFunc(ResultStruct,dataAccCut,WindowLen,FS,Lyap_m,Lyap_FitWinLen,Sen_m,Sen_r)
%% Calculation non-linear parameters;
% cut into windows of size WindowLen
N_Windows = floor(size(dataAccCut,1)/WindowLen);
N_SkipBegin = ceil((size(dataAccCut,1)-N_Windows*WindowLen)/2);
LyapunovWolf = nan(N_Windows,3);
LyapunovRosen = nan(N_Windows,3);
SE= nan(N_Windows,3);
for WinNr = 1:N_Windows;
AccWin = dataAccCut(N_SkipBegin+(WinNr-1)*WindowLen+(1:WindowLen),:);
for j=1:3
[LyapunovWolf(WinNr,j),~] = CalcMaxLyapWolfFixedEvolv(AccWin(:,j),FS,struct('m',Lyap_m));
[LyapunovRosen(WinNr,j),outpo] = CalcMaxLyapConvGait(AccWin(:,j),FS,struct('m',Lyap_m,'FitWinLen',Lyap_FitWinLen));
[SE(WinNr,j)] = funcSampleEntropy(AccWin(:,j), Sen_m, Sen_r);
% no correction for FS; SE does increase with higher FS but effect is considered negligible as range is small (98-104HZ). Might consider updating r to account for larger ranges.
end
end
LyapunovWolf = nanmean(LyapunovWolf,1);
LyapunovRosen = nanmean(LyapunovRosen,1);
SampleEntropy = nanmean(SE,1);
ResultStruct.LyapunovWolf_V = LyapunovWolf(1);
ResultStruct.LyapunovWolf_ML = LyapunovWolf(2);
ResultStruct.LyapunovWolf_AP = LyapunovWolf(3);
ResultStruct.LyapunovRosen_V = LyapunovRosen(1);
ResultStruct.LyapunovRosen_ML = LyapunovRosen(2);
ResultStruct.LyapunovRosen_AP = LyapunovRosen(3);
ResultStruct.SampleEntropy_V = SampleEntropy(1);
ResultStruct.SampleEntropy_ML = SampleEntropy(2);
ResultStruct.SampleEntropy_AP = SampleEntropy(3);
if isfield(ResultStruct,'StrideFrequency')
LyapunovPerStrideWolf = LyapunovWolf/ResultStruct.StrideFrequency;
LyapunovPerStrideRosen = LyapunovRosen/ResultStruct.StrideFrequency;
end
ResultStruct.LyapunovPerStrideWolf_V = LyapunovPerStrideWolf(1);
ResultStruct.LyapunovPerStrideWolf_ML = LyapunovPerStrideWolf(2);
ResultStruct.LyapunovPerStrideWolf_AP = LyapunovPerStrideWolf(3);
ResultStruct.LyapunovPerStrideRosen_V = LyapunovPerStrideRosen(1);
ResultStruct.LyapunovPerStrideRosen_ML = LyapunovPerStrideRosen(2);
ResultStruct.LyapunovPerStrideRosen_AP = LyapunovPerStrideRosen(3);
end

View File

@ -0,0 +1,48 @@
function [ResultStruct] = CalculateStrideParametersFunc(dataAccCut_filt,FS,ApplyRemoveSteps,dataAcc,dataAcc_filt,StrideTimeRange)
%% Calculate stride parameters
ResultStruct = struct; % create empty struct
% Run function AutoCorrStrides, Outcomeparameters: StrideRegularity,RelativeStrideVariability,StrideTimeSamples,StrideTime
[ResultStruct] = AutocorrStrides(dataAccCut_filt,FS, StrideTimeRange,ResultStruct);
StrideTimeSamples = ResultStruct.StrideTimeSamples; % needed as input for other functions
% Calculate Step symmetry --> method 1
ij = 1;
dirSymm = [1,3]; % Gait Synmmetry is only informative in AP/V direction: See Tura A, Raggi M, Rocchi L, Cutti AG, Chiari L: Gait symmetry and regularity in transfemoral amputees assessed by trunk accelerations. J Neuroeng Rehabil 2010, 7:4.
for jk=1:length(dirSymm)
[C, lags] = AutocorrRegSymmSteps(dataAccCut_filt(:,dirSymm(jk)));
[Ad,p] = findpeaks(C,'MinPeakProminence',0.2, 'MinPeakHeight', 0.2);
if size(Ad,1) > 1
Ad1 = Ad(1);
Ad2 = Ad(2);
GaitSymm(:,ij) = abs((Ad1-Ad2)/mean([Ad1+Ad2]))*100;
else
GaitSymm(:,ij) = NaN;
end
ij = ij +1;
end
% Save outcome in struct;
ResultStruct.GaitSymm_V = GaitSymm(1);
ResultStruct.GaitSymm_AP = GaitSymm(2);
% Calculate Step symmetry --> method 2
[PksAndLocsCorrected] = StepcountFunc(dataAccCut_filt,StrideTimeSamples,FS);
LocsSteps = PksAndLocsCorrected(2:2:end,2);
if rem(size(LocsSteps,1),2) == 0; % is number of steps is even
LocsSteps2 = LocsSteps(1:2:end);
else
LocsSteps2 = LocsSteps(3:2:end);
end
LocsSteps1 = LocsSteps(2:2:end);
DiffLocs2 = diff(LocsSteps2);
DiffLocs1 = diff(LocsSteps1);
StepTime2 = DiffLocs2(1:end-1)/FS; % leave last one out because it is higher
StepTime1 = DiffLocs1(1:end-1)/FS;
SI = abs((2*(StepTime2-StepTime1))./(StepTime2+StepTime1))*100;
ResultStruct.GaitSymmIndex = nanmean(SI);
end

18
FilterandRealignFunc.m Normal file
View File

@ -0,0 +1,18 @@
function [dataAcc, dataAcc_filt] = FilterandRealignFunc(inputData,FS,ApplyRealignment)
%% Filter and Realign Accdata
% Apply Realignment & Filter data
if ApplyRealignment % apply relignment as described in Rispens S, Pijnappels M, van Schooten K, Beek PJ, Daffertshofer A, van Die?n JH (2014).
data = inputData(:, [3,2,4]); % reorder data to 1 = V; 2= ML, 3 = AP%
% Consistency of gait characteristics as determined from acceleration data collected at different trunk locations. Gait Posture 2014;40(1):187-92.
[RealignedAcc, ~] = RealignSensorSignalHRAmp(data, FS);
dataAcc = RealignedAcc;
[B,A] = butter(2,20/(FS/2),'low');
dataAcc_filt = filtfilt(B,A,dataAcc);
else % we asume tat data is already reorderd to 1 = V; 2= ML, 3 = AP in an earlier stage;
[B,A] = butter(2,20/(FS/2),'low');
dataAcc = inputData;
dataAcc_filt = filtfilt(B,A,dataAcc);
end

View File

@ -0,0 +1,210 @@
function [ResultStruct] = GaitOutcomesTrunkAccFuncIH(inputData,FS,LegLength,WindowLen,ApplyRealignment,ApplyRemoveSteps)
% DESCRIPTON: Trunk analysis of Iphone data without the need for step detection
% CL Nov 2019
% Adapted IH feb-april 2020
% koloms data of smartphone
% 1st column is time data;
% 2nd column is X, medio-lateral: + left, - right
% 3rd column is Y, vertical: + downwards, - upwards
% 4th column is Z, anterior- posterior : + forwards, - backwards
%% Input Trunk accelerations during locomotion in VT, ML, AP direction
% InputData: Acceleration signal with time and accelerations in VT,ML and
% AP direction.
% FS: sample frequency of the Accdata
% LegLength: length of the leg of the participant in m;
%% Output
% ResultStruct: structure coninting all outcome measured calculated
% Spectral parameters, spatiotemporal gait parameters, non-linear
% parameters
% fields and subfields: include the multiple measurements of a subject
%% Literature
% Richman & Moorman, 2000; [ sample entropy]
% Bisi & Stagni Gait & Posture 2016, 47 (6) 37-42
% Kavagnah et al., Eur J Appl Physiol 2005 94: 468?475; Human Movement Science 24(2005) 574?587 [ synchrony]
% Moe-Nilsen J Biomech 2004 37, 121-126 [ autorcorrelation step regularity and symmetry
% Kobsar et al. Gait & Posture 2014 39, 553?557 [ synchrony ]
% Rispen et al; Gait & Posture 2014, 40, 187 - 192 [realignment axes]
% Zijlstra & HofGait & Posture 2003 18,2, 1-10 [spatiotemporal gait variables]
% Lamoth et al, 2002 [index of harmonicity]
% Costa et al. 2003 Physica A 330 (2003) 53–60 [ multiscale entropy]
% Cignetti F, Decker LM, Stergiou N. Ann Biomed Eng. 2012
% May;40(5):1122-30. doi: 10.1007/s10439-011-0474-3. Epub 2011 Nov 25. [
% Wofl vs. Rosenstein Lyapunov]
%% Settings
Gr = 9.81; % Gravity acceleration, multiplication factor for accelerations
StrideFreqEstimate = 1.00; % Used to set search for stride frequency from 0.5*StrideFreqEstimate until 2*StrideFreqEstimate
StrideTimeRange = [0.2 4.0]; % Range to search for stride time (seconds)
IgnoreMinMaxStrides = 0.10; % Number or percentage of highest&lowest values ignored for improved variability estimation
N_Harm = 12; % Number of harmonics used for harmonic ratio, index of harmonicity and phase fluctuation
LowFrequentPowerThresholds = ...
[0.7 1.4]; % Threshold frequencies for estimation of low-frequent power percentages
Lyap_m = 7; % Embedding dimension (used in Lyapunov estimations)
Lyap_FitWinLen = round(60/100*FS); % Fitting window length (used in Lyapunov estimations Rosenstein's method)
Sen_m = 5; % Dimension, the length of the subseries to be matched (used in sample entropy estimation)
Sen_r = 0.3; % Tolerance, the maximum distance between two samples to qualify as match, relative to std of DataIn (used in sample entropy estimation)
NStartEnd = [100];
M = 5; % maximum template length
ResultStruct = struct();
%% Filter and Realign Accdata
% Apply Realignment & Filter data
if ApplyRealignment % apply relignment as described in Rispens S, Pijnappels M, van Schooten K, Beek PJ, Daffertshofer A, van Die?n JH (2014).
data = inputData(:, [3,2,4]); % reorder data to 1 = V; 2= ML, 3 = AP%
% Consistency of gait characteristics as determined from acceleration data collected at different trunk locations. Gait Posture 2014;40(1):187-92.
[RealignedAcc, ~] = RealignSensorSignalHRAmp(data, FS);
dataAcc = RealignedAcc;
[B,A] = butter(2,20/(FS/2),'low');
dataAcc_filt = filtfilt(B,A,dataAcc);
else % we asume tat data is already reorderd to 1 = V; 2= ML, 3 = AP in an earlier stage;
[B,A] = butter(2,20/(FS/2),'low');
dataAcc = inputData;
dataAcc_filt = filtfilt(B,A,dataAcc);
end
%% Step dectection
% Determines the number of steps in the signal so that the first 30 and last 30 steps in the signal can be removed
if ApplyRemoveSteps
% In order to run the step detection script we first need to run an autocorrelation function;
[ResultStruct] = AutocorrStrides(dataAcc_filt,FS, StrideTimeRange,ResultStruct);
% StrideTimeSamples is needed as an input for the stepcountFunc;
StrideTimeSamples = ResultStruct.StrideTimeSamples;
% Calculate the number of steps;
[PksAndLocsCorrected] = StepcountFunc(dataAcc_filt,StrideTimeSamples,FS);
% This function selects steps based on negative and positive values.
% However to determine the steps correctly we only need one of these;
LocsSteps = PksAndLocsCorrected(1:2:end,2);
%% Cut data & remove currents results
% Remove 20 steps in the beginning and end of data
dataAccCut = dataAcc(LocsSteps(31):LocsSteps(end-30),:);
dataAccCut_filt = dataAcc_filt(LocsSteps(31):LocsSteps(end-30),:);
% Clear currently saved results from Autocorrelation Analysis
clear ResultStruct;
clear PksAndLocsCorrected;
clear LocsSteps;
else;
dataAccCut = dataAcc;
dataAccCut_filt = dataAcc_filt;
end
%% Calculate stride parameters
ResultStruct = struct; % create empty struct
% Run function AutoCorrStrides, Outcomeparameters: StrideRegularity,RelativeStrideVariability,StrideTimeSamples,StrideTime
[ResultStruct] = AutocorrStrides(dataAccCut_filt,FS, StrideTimeRange,ResultStruct);
StrideTimeSamples = ResultStruct.StrideTimeSamples; % needed as input for other functions
% Calculate Step symmetry --> method 1
ij = 1;
dirSymm = [1,3]; % Gait Synmmetry is only informative in AP/V direction: See Tura A, Raggi M, Rocchi L, Cutti AG, Chiari L: Gait symmetry and regularity in transfemoral amputees assessed by trunk accelerations. J Neuroeng Rehabil 2010, 7:4.
for jk=1:length(dirSymm)
[C, lags] = AutocorrRegSymmSteps(dataAccCut_filt(:,dirSymm(jk)));
[Ad,p] = findpeaks(C,'MinPeakProminence',0.2, 'MinPeakHeight', 0.2);
if size(Ad,1) > 1
Ad1 = Ad(1);
Ad2 = Ad(2);
GaitSymm(:,ij) = abs((Ad1-Ad2)/mean([Ad1+Ad2]))*100;
else
GaitSymm(:,ij) = NaN;
end
ij = ij +1;
end
% Save outcome in struct;
ResultStruct.GaitSymm_V = GaitSymm(1);
ResultStruct.GaitSymm_AP = GaitSymm(2);
% Calculate Step symmetry --> method 2
[PksAndLocsCorrected] = StepcountFunc(dataAccCut_filt,StrideTimeSamples,FS);
LocsSteps = PksAndLocsCorrected(2:2:end,2);
if rem(size(LocsSteps,1),2) == 0; % is number of steps is even
LocsSteps2 = LocsSteps(1:2:end);
else
LocsSteps2 = LocsSteps(3:2:end);
end
LocsSteps1 = LocsSteps(2:2:end);
DiffLocs2 = diff(LocsSteps2);
DiffLocs1 = diff(LocsSteps1);
StepTime2 = DiffLocs2(1:end-1)/FS; % leave last one out because it is higher
StepTime1 = DiffLocs1(1:end-1)/FS;
SI = abs((2*(StepTime2-StepTime1))./(StepTime2+StepTime1))*100;
ResultStruct.GaitSymmIndex = nanmean(SI);
%% Calculate spatiotemporal stride parameters
% Measures from height variation by double integration of VT accelerations and high-pass filtering
[ResultStruct] = SpatioTemporalGaitParameters(dataAccCut_filt,StrideTimeSamples,ApplyRealignment,LegLength,FS,IgnoreMinMaxStrides,ResultStruct);
%% Measures derived from spectral analysis
AccVectorLen = sqrt(sum(dataAccCut_filt(:,1:3).^2,2));
[ResultStruct] = SpectralAnalysisGaitfunc(dataAccCut_filt,WindowLen,FS,N_Harm,LowFrequentPowerThresholds,AccVectorLen,ResultStruct);
%% Calculation non-linear parameters;
% cut into windows of size WindowLen
N_Windows = floor(size(dataAccCut,1)/WindowLen);
N_SkipBegin = ceil((size(dataAccCut,1)-N_Windows*WindowLen)/2);
LyapunovWolf = nan(N_Windows,3);
LyapunovRosen = nan(N_Windows,3);
SE= nan(N_Windows,3);
for WinNr = 1:N_Windows;
AccWin = dataAccCut(N_SkipBegin+(WinNr-1)*WindowLen+(1:WindowLen),:);
for j=1:3
[LyapunovWolf(WinNr,j),~] = CalcMaxLyapWolfFixedEvolv(AccWin(:,j),FS,struct('m',Lyap_m));
[LyapunovRosen(WinNr,j),outpo] = CalcMaxLyapConvGait(AccWin(:,j),FS,struct('m',Lyap_m,'FitWinLen',Lyap_FitWinLen));
[SE(WinNr,j)] = funcSampleEntropy(AccWin(:,j), Sen_m, Sen_r);
% no correction for FS; SE does increase with higher FS but effect is considered negligible as range is small (98-104HZ). Might consider updating r to account for larger ranges.
end
end
LyapunovWolf = nanmean(LyapunovWolf,1);
LyapunovRosen = nanmean(LyapunovRosen,1);
SampleEntropy = nanmean(SE,1);
ResultStruct.LyapunovWolf_V = LyapunovWolf(1);
ResultStruct.LyapunovWolf_ML = LyapunovWolf(2);
ResultStruct.LyapunovWolf_AP = LyapunovWolf(3);
ResultStruct.LyapunovRosen_V = LyapunovRosen(1);
ResultStruct.LyapunovRosen_ML = LyapunovRosen(2);
ResultStruct.LyapunovRosen_AP = LyapunovRosen(3);
ResultStruct.SampleEntropy_V = SampleEntropy(1);
ResultStruct.SampleEntropy_ML = SampleEntropy(2);
ResultStruct.SampleEntropy_AP = SampleEntropy(3);
if isfield(ResultStruct,'StrideFrequency')
LyapunovPerStrideWolf = LyapunovWolf/ResultStruct.StrideFrequency;
LyapunovPerStrideRosen = LyapunovRosen/ResultStruct.StrideFrequency;
end
ResultStruct.LyapunovPerStrideWolf_V = LyapunovPerStrideWolf(1);
ResultStruct.LyapunovPerStrideWolf_ML = LyapunovPerStrideWolf(2);
ResultStruct.LyapunovPerStrideWolf_AP = LyapunovPerStrideWolf(3);
ResultStruct.LyapunovPerStrideRosen_V = LyapunovPerStrideRosen(1);
ResultStruct.LyapunovPerStrideRosen_ML = LyapunovPerStrideRosen(2);
ResultStruct.LyapunovPerStrideRosen_AP = LyapunovPerStrideRosen(3);
end

View File

@ -0,0 +1,74 @@
% Gait Variability Analysis
% Script created for BAP students 2020
% Iris Hagoort
% April 2020
% Input: needs mat file which contains all raw accelerometer data
% Input: needs excel file containing the participant information including
% leg length.
%% Clear and close;
clear;
close all;
%% Load data
load('Phyphoxdata.mat'); % loads accelerometer data, is stored in struct with name AccData
load('ExcelInfo.mat');
Participants = fields(AccData);
%% Settings
FS = 100; % sample frequency
LegLengths = excel.data.GeneralInformation(:,5); % leglength info is in 5th column
LegLengthsM = LegLengths/100; % convert to m
%% Calculate parameters;
for i = 1: length(Participants);
tic;
LegLength = LegLengthsM(i);
WalkingConditions = fields(AccData.([char(Participants(i))]));
for j = 1: length(WalkingConditions);
if strcmp(char(WalkingConditions(j)),'Treadmill')
SubConditions = fieldnames(AccData.([char(Participants(i))]).([char(WalkingConditions(j))]));
for k = 1: length(SubConditions);
inputData = AccData.([char(Participants(i))]).([char(WalkingConditions(j))]).([char(SubConditions(k))]);
WindowLength = FS*10;
ApplyRealignment = true;
ApplyRemoveSteps = true;
[ResultStruct] = GaitOutcomesTrunkAccFuncIH(inputData,FS,LegLength,WindowLen,ApplyRealignment,ApplyRemoveSteps);
OutcomesAcc.([char(Participants(i))]).([char(WalkingConditions(j))]).([char(SubConditions(k))]) = ResultStruct;
end
elseif strcmp(char(WalkingConditions(j)),'Balance') || strcmp(char(WalkingConditions(j)),'TwoMWT')
disp('Files are not used for current analysis');
elseif strcmp(char(WalkingConditions(j)),'InsideStraight')
inputData = AccData.([char(Participants(i))]).([char(WalkingConditions(j))]);
ApplyRealignment = true;
ApplyRemoveSteps = false; % don't remove steps for the straight conditions
% function specific for the walking conditions containing a lot
% of turns
[ResultStruct] = GaitVariabilityAnalysisIH_WithoutTurns(inputData,FS,LegLength,ApplyRealignment,ApplyRemoveSteps);
OutcomesAcc.([char(Participants(i))]).([char(WalkingConditions(j))]) = ResultStruct;
else
inputData = AccData.([char(Participants(i))]).([char(WalkingConditions(j))]);
ApplyRealignment = true;
ApplyRemoveSteps = true;
WindowLen = FS*10;
[ResultStruct] = GaitOutcomesTrunkAccFuncIH(inputData,FS,LegLength,WindowLen,ApplyRealignment,ApplyRemoveSteps)
OutcomesAcc.([char(Participants(i))]).([char(WalkingConditions(j))]) = ResultStruct;
end
end
toc;
end
% Save struct as .mat file
save('GaitVarOutcomes30pril.mat', 'OutcomesAcc');

View File

@ -0,0 +1,108 @@
function [ResultStruct] = GaitVariabilityAnalysisIH_WithoutTurns(inputData,FS,LegLength,ApplyRealignment,ApplyRemoveSteps);
% SCRIPT FOR ANAlysis straight parts
% NOG GOEDE BESCHRIJVING TOEVOEGEN.
%% Realign data
data = inputData(:, [3,2,4]); % reorder data to 1 = V; 2= ML, 3 = AP
%Realign sensor data to VT-ML-AP frame
if ApplyRealignment % apply relignment as described in Rispens S, Pijnappels M, van Schooten K, Beek PJ, Daffertshofer A, van Die?n JH (2014).
% Consistency of gait characteristics as determined from acceleration data collected at different trunk locations. Gait Posture 2014;40(1):187-92.
[RealignedAcc, ~] = RealignSensorSignalHRAmp(data, FS);
dataAcc = RealignedAcc;
end
%% Filter data strongly & Determine location of steps
% Filter data
[B,A] = butter(2,3/(FS/2),'low'); % Filters data very strongly which is needed to determine turns correctly
dataStepDetection = filtfilt(B,A,dataAcc);
% Determine steps;
%%%%%%% HIER MISSCHIEN ALTERNATIEF VOOR VAN RISPENS %%%%%%%%%%%%%
% Explanation of method: https://nl.mathworks.com/help/supportpkg/beagleboneblue/ref/counting-steps-using-beagleboneblue-hardware-example.html
% From website: To convert the XYZ acceleration vectors at each point in time into scalar values,
% calculate the magnitude of each vector. This way, you can detect large changes in overall acceleration,
% such as steps taken while walking, regardless of device orientation.
magfilt = sqrt(sum((dataStepDetection(:,1).^2) + (dataStepDetection(:,2).^2) + (dataStepDetection(:,3).^2), 2));
magNoGfilt = magfilt - mean(magfilt);
minPeakHeight2 = std(magNoGfilt);
[pks, locs] = findpeaks(magNoGfilt, 'MINPEAKHEIGHT', minPeakHeight2); % for step detection
numStepsOption2_filt = numel(pks); % counts number of steps;
%%%%%%%%%%%%%%%%%%%%%%%% TOT HIER %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Determine locations of turns;
diffLocs = diff(locs); % calculates difference in step location
avg_diffLocs = mean(diffLocs); % average distance between steps
std_diffLocs = std(diffLocs); % standard deviation of distance between steps
figure;
findpeaks(diffLocs, 'MINPEAKHEIGHT', avg_diffLocs, 'MINPEAKDISTANCE',5); % these values have been chosen based on visual inspection of the signal
line([1 length(diffLocs)],[avg_diffLocs avg_diffLocs])
[pks_diffLocs, locs_diffLocs] = findpeaks(diffLocs, 'MINPEAKHEIGHT', avg_diffLocs,'MINPEAKDISTANCE',5);
locsTurns = [locs(locs_diffLocs), locs(locs_diffLocs+1)];
%% Visualizing turns
% Duplying signal + visualing
% to make second signal with the locations of the turns filled with NaN, so
% that both signals can be plotted above each other in a different colour
magNoGfilt_copy = magNoGfilt;
for k = 1: size(locsTurns,1);
magNoGfilt_copy(locsTurns(k,1):locsTurns(k,2)) = NaN;
end
% visualising signal;
figure;
subplot(2,1,1)
hold on;
plot(magNoGfilt,'b')
plot(magNoGfilt_copy, 'r');
title('Inside Straight: Filtered data with turns highlighted in blue')
hold off;
%% Calculation
% VRAAG LAURENS zie blauwe blaadje
startPos = 1;
for i = 1: size(locsTurns,1);
endPos = locsTurns(i,1)-1;
inputData = dataAcc(startPos:endPos,:);
WindowLen = size(inputData,1);
ApplyRealignment = false;
[ResultStruct] = GaitOutcomesTrunkAccFuncIH(inputData,FS,LegLength,WindowLen,ApplyRealignment,ApplyRemoveSteps); % Naam van deze moet nog aangepast.
if i ==1 % only the firs time
Parameters = fieldnames(ResultStruct);
NrParameters = length(Parameters);
end
for j = 1:NrParameters % only works if for every bin we get the same outcomes (which is the case in this script)
DataStraight.([char(Parameters(j))])(i) = ResultStruct.([char(Parameters(j))]);
end
startPos = locsTurns(i,2)+1;
end
clear ResultStruct;
% Calculate mean over the bins without turns to get 1 outcome value per parameter for inside
% straight;
for j = 1:NrParameters;
ResultStruct.([char(Parameters(j))]) = nanmean(DataStraight.([char(Parameters(j))]))
end
end

File diff suppressed because one or more lines are too long

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,103 @@
%% Gait Variability Analysis CLBP
% Gait Variability Analysis
% Script created for MAP 2020-2021
% adapted from Claudine Lamoth and Iris Hagoort
% version1 October 2020
% Input: needs mat file which contains all raw accelerometer data
% Input: needs excel file containing the participant information including
% leg length.
%% Clear and close;
clear;
close all;
%% Load data;
% Select 1 trial.
% For loop to import all data will be used at a later stage
[FNaam,FilePad] = uigetfile('*.xls','Load phyphox data...');
filename =[FilePad FNaam];
PhyphoxData = xlsread(filename)
%load('Phyphoxdata.mat'); % loads accelerometer data, is stored in struct with name AccData
%load('ExcelInfo.mat');
%Participants = fields(AccData);
%% Settings;
%adapted from GaitOutcomesTrunkAccFuncIH
LegLength = 98; % LegLength info not available!
FS = 100; % Sample frequency
Gr = 9.81; % Gravity acceleration, multiplication factor for accelerations
StrideFreqEstimate = 1.00; % Used to set search for stride frequency from 0.5*StrideFreqEstimate until 2*StrideFreqEstimate
StrideTimeRange = [0.2 4.0]; % Range to search for stride time (seconds)
IgnoreMinMaxStrides = 0.10; % Number or percentage of highest&lowest values ignored for improved variability estimation
N_Harm = 12; % Number of harmonics used for harmonic ratio, index of harmonicity and phase fluctuation
LowFrequentPowerThresholds = ...
[0.7 1.4]; % Threshold frequencies for estimation of low-frequent power percentages
Lyap_m = 7; % Embedding dimension (used in Lyapunov estimations)
Lyap_FitWinLen = round(60/100*FS); % Fitting window length (used in Lyapunov estimations Rosenstein's method)
Sen_m = 5; % Dimension, the length of the subseries to be matched (used in sample entropy estimation)
Sen_r = 0.3; % Tolerance, the maximum distance between two samples to qualify as match, relative to std of DataIn (used in sample entropy estimation)
NStartEnd = [100];
M = 5; % Maximum template length
ResultStruct = struct(); % Empty struct
inputData = (PhyphoxData(:,[1 2 3 4])); % matrix with accelerometer data
ApplyRealignment = true;
ApplyRemoveSteps = true;
WindowLen = FS*10;
%% Filter and Realign Accdata
% dataAcc depends on ApplyRealignment = true/false
% dataAcc_filt (low pass Butterworth Filter + zerophase filtering
[dataAcc, dataAcc_filt] = FilterandRealignFunc(inputData,FS,ApplyRealignment);
%% Step dectection
% Determines the number of steps in the signal so that the first 30 and last 30 steps in the signal can be removed
% StrideTimeSamples is needed for calculation stride parameters!
[dataAccCut,dataAccCut_filt,StrideTimeSamples] = StepDetectionFunc(FS,ApplyRemoveSteps,dataAcc,dataAcc_filt,StrideTimeRange);
%% Calculate Stride Parameters
% Outcomeparameters: StrideRegularity,RelativeStrideVariability,StrideTimeSamples,StrideTime
[ResultStruct] = CalculateStrideParametersFunc(dataAccCut_filt,FS,ApplyRemoveSteps,dataAcc,dataAcc_filt,StrideTimeRange);
%% Calculate spatiotemporal stride parameters
% Measures from height variation by double integration of VT accelerations and high-pass filtering
% StepLengthMean; Distance; WalkingSpeedMean; StrideTimeVariability; StrideSpeedVariability;
% StrideLengthVariability; StrideTimeVariabilityOmitOutlier; StrideSpeedVariabilityOmitOutlier; StrideLengthVariabilityOmitOutlier;
[ResultStruct] = SpatioTemporalGaitParameters(dataAccCut_filt,StrideTimeSamples,ApplyRealignment,LegLength,FS,IgnoreMinMaxStrides,ResultStruct);
%% Measures derived from spectral analysis
% IndexHarmonicity_V/ML/AP/ALL ; HarmonicRatio_V/ML/AP ; HarmonicRatioP_V/ML/AP ; FrequencyVariability_V/ML/AP; Stride Frequency
AccVectorLen = sqrt(sum(dataAccCut_filt(:,1:3).^2,2));
[ResultStruct] = SpectralAnalysisGaitfunc(dataAccCut_filt,WindowLen,FS,N_Harm,LowFrequentPowerThresholds,AccVectorLen,ResultStruct);
%% calculate non-linear parameters
% Outcomeparameters: Sample Entropy, Lyapunov exponents
[ResultStruct] = CalculateNonLinearParametersFunc(ResultStruct,dataAccCut,WindowLen,FS,Lyap_m,Lyap_FitWinLen,Sen_m,Sen_r);
% Save struct as .mat file
% save('GaitVarOutcomesParticipantX.mat', 'OutcomesAcc');
%% AggregateFunction (seperate analysis per minute);
% see AggregateEpisodeValues.m
%
%

View File

@ -0,0 +1,95 @@
%% Description file
%% Clear and close
clear;
close all;
%% Load data;
load('GaitVarOutcomes30april.mat')
Participants = fields(OutcomesAcc);
%% Settings;
counter = 1;
run = 1;
ParticipantNr = 0;
ConditionNames = {'TwoMWT','InsidePath','InsideStraight','Outside','Treadmill_Comfortable','Treadmill_Condition1','Treadmill_Condition2','Treadmill_Condition3','Treadmill_Condition4','Treadmill_Condition5','Treadmill_Condition6','Treadmill_Condition7','Treadmill_Condition8'};
%% Reorder data;
for i = 1: length(Participants);
% Participant Nr;
ParticipantNr = ParticipantNr + 1;
% Group Nr;
if contains(Participants(i),'Y');
Group = 1;
else
Group = 2;
end
WalkingConditions = fields(OutcomesAcc.([char(Participants(i))]));
for j = 1: length(WalkingConditions);
if strcmp(char(WalkingConditions(j)),'Treadmill')
SubConditions = fieldnames(OutcomesAcc.([char(Participants(i))]).([char(WalkingConditions(j))]));
for k = 1: length(SubConditions);
NameTreadmill = [char(WalkingConditions(j)),'_',char(SubConditions(k))];
ConditionNr = find(strcmp(ConditionNames, NameTreadmill));
Parameters = fieldnames(OutcomesAcc.([char(Participants(i))]).([char(WalkingConditions(j))]).([char(SubConditions(k))]));
for l = 1: length(Parameters);
Data(counter+1,1) = {([char(Participants(i))])};
Data(counter+1,2) = {ParticipantNr};
Data(counter+1,3) = {Group};
Data(counter+1,4) = {([char(NameTreadmill)])};
Data(counter+1,5) = {ConditionNr};
Data(counter+1,l+5) = {OutcomesAcc.([char(Participants(i))]).([char(WalkingConditions(j))]).([char(SubConditions(k))]).([char(Parameters(l))])(1)};
end
counter = counter+1;
end
else
ConditionNr = find(strcmp(ConditionNames, WalkingConditions(j)));
Parameters = fieldnames(OutcomesAcc.([char(Participants(i))]).([char(WalkingConditions(j))]));
for l = 1: length(Parameters);
Data(counter+1,1) = {([char(Participants(i))])};
Data(counter+1,2) = {ParticipantNr};
Data(counter+1,3) = {Group};
Data(counter+1,4) = {([char(WalkingConditions(j))])};
Data(counter+1,5) = {ConditionNr};
Data(counter+1,l+5) = {OutcomesAcc.([char(Participants(i))]).([char(WalkingConditions(j))]).([char(Parameters(l))])(1)};
end
counter = counter+1;
end
if run == 1;
Data(1,1) = {'ParticipantCode'};
Data(1,2) = {'ParticipantNr'};
Data(1,3) = {'Group'};
Data(1,4) = {'ConditionName'};
Data(1,5) = {'ConditionNr'};
Data(1,6:(size(Parameters,1)+5)) = Parameters'; % First row with variable names;
run = run+1;
end
end
end
if ispc;
xlswrite('GaitVariabilityOutcomes.xls', 'Data');
elseif ismac;
filename = 'GaitVariabilityOutcomes.xlsx';
writecell(Data,filename);
else
end

83
HarmonicityFrequency.m Normal file
View File

@ -0,0 +1,83 @@
function [ResultStruct] = HarmonicityFrequency(dataAccCut_filt,P,F, StrideFrequency,dF,LowFrequentPowerThresholds,N_Harm,FS,AccVectorLen,ResultStruct)
% Add sum of power spectra (as a rotation-invariant spectrum)
P = [P,sum(P,2)];
PS = sqrt(P);
% Calculate the measures for the power per separate dimension
for i=1:size(P,2);
% Relative cumulative power and frequencies that correspond to these cumulative powers
PCumRel = cumsum(P(:,i))/sum(P(:,i));
PSCumRel = cumsum(PS(:,i))/sum(PS(:,i));
FCumRel = F+0.5*dF;
% Derive relative cumulative power for threshold frequencies
Nfreqs = size(LowFrequentPowerThresholds,2);
LowFrequentPercentage(i,1:Nfreqs) = interp1(FCumRel,PCumRel,LowFrequentPowerThresholds)*100;
% Calculate relative power of first 10 harmonics, taking the power of each harmonic with a band of + and - 10% of the first
% harmonic around it
PHarm = zeros(N_Harm,1);
PSHarm = zeros(N_Harm,1);
for Harm = 1:N_Harm,
FHarmRange = (Harm+[-0.1 0.1])*StrideFrequency;
PHarm(Harm) = diff(interp1(FCumRel,PCumRel,FHarmRange));
PSHarm(Harm) = diff(interp1(FCumRel,PSCumRel,FHarmRange));
end
% Derive index of harmonicity
if i == 2 % for ML we expect odd instead of even harmonics
IndexHarmonicity(i) = PHarm(1)/sum(PHarm(1:2:12));
elseif i == 4
IndexHarmonicity(i) = sum(PHarm(1:2))/sum(PHarm(1:12));
else
IndexHarmonicity(i) = PHarm(2)/sum(PHarm(2:2:12));
end
% Calculate the phase speed fluctuations
StrideFreqFluctuation = nan(N_Harm,1);
StrSamples = round(FS/StrideFrequency);
for h=1:N_Harm,
CutOffs = [StrideFrequency*(h-(1/3)) , StrideFrequency*(h+(1/3))]/(FS/2);
if all(CutOffs<1) % for Stride frequencies above FS/20/2, the highest harmonics are not represented in the power spectrum
[b,a] = butter(2,CutOffs);
if i==4 % Take the vector length as a rotation-invariant signal
AccFilt = filtfilt(b,a,AccVectorLen);
else
AccFilt = filtfilt(b,a,dataAccCut_filt(:,i));
end
Phase = unwrap(angle(hilbert(AccFilt)));
SmoothPhase = sgolayfilt(Phase,1,2*(floor(FS/StrideFrequency/2))+1); % This is in fact identical to a boxcar filter with linear extrapolation at the edges
StrideFreqFluctuation(h) = std(Phase(1+StrSamples:end,1)-Phase(1:end-StrSamples,1));
end
end
FrequencyVariability(i) = nansum(StrideFreqFluctuation./(1:N_Harm)'.*PHarm)/nansum(PHarm);
if i<4,
% Derive harmonic ratio (two variants)
if i == 2 % for ML we expect odd instead of even harmonics
HarmonicRatio(i) = sum(PSHarm(1:2:end-1))/sum(PSHarm(2:2:end)); % relative to summed 3d spectrum
HarmonicRatioP(i) = sum(PHarm(1:2:end-1))/sum(PHarm(2:2:end)); % relative to own spectrum
else
HarmonicRatio(i) = sum(PSHarm(2:2:end))/sum(PSHarm(1:2:end-1));
HarmonicRatioP(i) = sum(PHarm(2:2:end))/sum(PHarm(1:2:end-1));
end
end
end
ResultStruct.IndexHarmonicity_V = IndexHarmonicity(1); % higher smoother more regular patter
ResultStruct.IndexHarmonicity_ML = IndexHarmonicity(2); % higher smoother more regular patter
ResultStruct.IndexHarmonicity_AP = IndexHarmonicity(3); % higher smoother more regular patter
ResultStruct.IndexHarmonicity_All = IndexHarmonicity(4);
ResultStruct.HarmonicRatio_V = HarmonicRatio(1);
ResultStruct.HarmonicRatio_ML = HarmonicRatio(2);
ResultStruct.HarmonicRatio_AP = HarmonicRatio(3);
ResultStruct.HarmonicRatioP_V = HarmonicRatioP(1);
ResultStruct.HarmonicRatioP_ML = HarmonicRatioP(2);
ResultStruct.HarmonicRatioP_AP = HarmonicRatioP(3);
ResultStruct.FrequencyVariability_V = FrequencyVariability(1);
ResultStruct.FrequencyVariability_ML = FrequencyVariability(2);
ResultStruct.FrequencyVariability_AP = FrequencyVariability(3);
ResultStruct.StrideFrequency = StrideFrequency;

146
MutualInformationHisPro.m Normal file
View File

@ -0,0 +1,146 @@
function [mutM,cummutM,minmuttauV] = MutualInformationHisPro(xV,tauV,bV,flag)
% [mutM,cummutM,minmuttauV] = MutualInformationHisPro(xV,tauV,bV,flag)
% MUTUALINFORMATIONHISPRO computes the mutual information on the time
% series 'xV' for given delays in 'tauV'. The estimation of mutual
% information is based on 'b' partitions of equal probability at each dimension.
% A number of different 'b' can be given in the input vector 'bV'.
% According to a given flag, it can also compute the cumulative mutual
% information for each given lag, as well as the time of the first minimum
% of the mutual information.
% INPUT
% - xV : a vector for the time series
% - tauV : a vector of the delays to be evaluated for
% - bV : a vector of the number of partitions of the histogram-based
% estimate.
% - flag : if 0-> compute only mutual information,
% : if 1-> compute the mutual information, the first minimum of
% mutual information and the cumulative mutual information.
% if 2-> compute (also) the cumulative mutual information
% if 3-> compute (also) the first minimum of mutual information
% OUTPUT
% - mutM : the vector of the mutual information values s for the given
% delays.
% - cummutM : the vector of the cumulative mutual information values for
% the given delays
% - minmuttauV : the time of the first minimum of the mutual information.
%========================================================================
% <MutualInformationHisPro.m>, v 1.0 2010/02/11 22:09:14 Kugiumtzis & Tsimpiris
% This is part of the MATS-Toolkit http://eeganalysis.web.auth.gr/
%========================================================================
% Copyright (C) 2010 by Dimitris Kugiumtzis and Alkiviadis Tsimpiris
% <dkugiu@gen.auth.gr>
%========================================================================
% Version: 1.0
% LICENSE:
% This program is free software; you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation; either version 3 of the License, or
% any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with this program. If not, see http://www.gnu.org/licenses/>.
%=========================================================================
% Reference : D. Kugiumtzis and A. Tsimpiris, "Measures of Analysis of Time Series (MATS):
% A Matlab Toolkit for Computation of Multiple Measures on Time Series Data Bases",
% Journal of Statistical Software, in press, 2010
% Link : http://eeganalysis.web.auth.gr/
%=========================================================================
nsam = 1;
n = length(xV);
if nargin==3
flag = 1;
elseif nargin==2
flag = 1;
bV = round(sqrt(n/5));
end
if isempty(bV)
bV = round(sqrt(n/5));
end
bV(bV==0)=round(sqrt(n/5));
tauV = sort(tauV);
ntau = length(tauV);
taumax = tauV(end);
nb = length(bV);
[oxV,ixV]=sort(xV);
[tmpV,ioxV]=sort(ixV);
switch flag
case 0
% Compute only the mutual information for the given lags
mutM = NaN*ones(ntau,nb);
for ib=1:nb
b = bV(ib);
if n<2*b
break;
end
mutM(:,ib)=mutinfHisPro(xV,tauV,b,ioxV,ixV);
end % for ib
cummutM=[];
minmuttauV=[];
case 1
% Compute the mutual information for all lags up to the
% largest given lag, then compute the lag of the first minimum of
% mutual information and the cumulative mutual information for the
% given lags.
mutM = NaN*ones(ntau,nb);
cummutM = NaN*ones(ntau,nb);
minmuttauV = NaN*ones(nb,1);
miM = NaN*ones(taumax+1,nb);
for ib=1:nb
b = bV(ib);
if n<2*b
break;
end
miM(:,ib)=mutinfHisPro(xV,[0:taumax]',b,ioxV,ixV);
mutM(:,ib) = miM(tauV+1,ib);
minmuttauV(ib) = findminMutInf(miM(:,ib),nsam);
% Compute the cumulative mutual information for the given delays
for i=1:ntau
cummutM(i,ib) = sum(miM(1:tauV(i)+1,ib));
end
end % for ib
case 2
% Compute the mutual information for all lags up to the largest
% given lag and then sum up to get the cumulative mutual information
% for the given lags.
cummutM = NaN*ones(ntau,nb);
miM = NaN*ones(taumax+1,nb);
for ib=1:nb
b = bV(ib);
if n<2*b
break;
end
miM(:,ib)=mutinfHisPro(xV,[0:taumax]',b,ioxV,ixV);
% Compute the cumulative mutual information for the given delays
for i=1:ntau
cummutM(i,ib) = sum(miM(1:tauV(i)+1,ib));
end
end % for ib
mutM = [];
minmuttauV=[];
case 3
% Compute the mutual information for all lags up to the largest
% given lag and then compute the lag of the first minimum of the
% mutual information.
minmuttauV = NaN*ones(nb,1);
miM = NaN*ones(taumax+1,nb);
for ib=1:nb
b = bV(ib);
if n<2*b
break;
end
miM(:,ib)=mutinfHisPro(xV,[0:taumax]',b,ioxV,ixV);
minmuttauV(ib) = findminMutInf(miM(:,ib),nsam);
end % for ib
mutM = [];
cummutM=[];
end

BIN
Phyphoxdata.mat Normal file

Binary file not shown.

275
RealignSensorSignalHRAmp.m Normal file
View File

@ -0,0 +1,275 @@
function [RealignedAcc,RotationMatrixT,Flags] = RealignSensorSignalHRAmp(Acc, FS)
% History
% 2013/05/31 SR solve problem of ML-AP rotation of appr. 90 degrees ("Maximum number of function evaluations has been exceeded")
% 2013/08/15 SR use literature HR (i.e. amplitude not power, and harmonic frequencies not sin^4 windows)
% 2013/08/16 SR correct: use abs(X) instead of sqrt(X.*X)
% 2013/09/11 SR use only relevant F (containing odd or even harmonics) and speed up determination of harmonic frequencies
%% Define VT direction (RVT) as direction of mean acceleration
MeanAcc = mean(Acc);
RVT = MeanAcc'/norm(MeanAcc);
RMLGuess = cross([0;0;1],RVT); RMLGuess = RMLGuess/norm(RMLGuess);
RAPGuess = cross(RVT,RMLGuess); RAPGuess = RAPGuess/norm(RAPGuess);
%% Estimate stride frequency
StrideFrequency = StrideFrequencyFrom3dAcc(Acc, FS);
AccDetrend = detrend(Acc,'constant');
N = size(AccDetrend,1);
%% calculate complex DFT
F = FS*(0:(N-1))'/N;
dF = FS/N;
FHarmRange = [(1:20)'-0.1, (1:20)'+0.1]*StrideFrequency;
EvenRanges = FHarmRange(2:2:end,:);
OddRanges = FHarmRange(1:2:end,:);
EvenHarmonics = zeros(size(F));
for j=1:size(EvenRanges,1)
IXRange = [EvenRanges(j,1)/dF, EvenRanges(j,2)/dF]+1;
IXRangeRound = min(N,round(IXRange));
EvenHarmonics(IXRangeRound(1):IXRangeRound(2)) = EvenHarmonics(IXRangeRound(1):IXRangeRound(2)) + 1;
EvenHarmonics(IXRangeRound(1)) = EvenHarmonics(IXRangeRound(1)) - (IXRange(1)-IXRangeRound(1)+0.5);
EvenHarmonics(IXRangeRound(2)) = EvenHarmonics(IXRangeRound(2)) - (IXRangeRound(2)-IXRange(2)+0.5);
end
OddHarmonics = zeros(size(F));
for j=1:size(OddRanges,1)
IXRange = [OddRanges(j,1)/dF, OddRanges(j,2)/dF]+1;
IXRangeRound = min(N,round(IXRange));
OddHarmonics(IXRangeRound(1):IXRangeRound(2)) = OddHarmonics(IXRangeRound(1):IXRangeRound(2)) + 1;
OddHarmonics(IXRangeRound(1)) = OddHarmonics(IXRangeRound(1)) - (IXRange(1)-IXRangeRound(1)+0.5);
OddHarmonics(IXRangeRound(2)) = OddHarmonics(IXRangeRound(2)) - (IXRangeRound(2)-IXRange(2)+0.5);
end
%% select only frequencies that contain odd or even harmonics
RelevantF = OddHarmonics~=0 | EvenHarmonics~=0;
OddHarmonics = OddHarmonics(RelevantF);
EvenHarmonics = EvenHarmonics(RelevantF);
DFT = fft(AccDetrend,N,1);
DFT = DFT(RelevantF,:);
DFTMLG = DFT*RMLGuess;
DFTAPG = DFT*RAPGuess;
%% Initial estimation of ML-AP realignment (educated guess)
% We start of by finding the directions ML = MLguess + x*APguess for which
% the 'harmonic ratio' for the ML directions is maximal or minimal, and we
% do this by varying x in still the power variant of HR instead of amplitude:
HRML = @(x) real(((OddHarmonics'.*(DFTMLG'+x*DFTAPG'))*(DFTMLG+x*DFTAPG))...
/((EvenHarmonics'.*(DFTMLG'+x*DFTAPG'))*(DFTMLG+x*DFTAPG)));
% or by substititutions
a = real((OddHarmonics.*DFTAPG)'*DFTAPG);
b = real((OddHarmonics.*DFTMLG)'*DFTAPG + (OddHarmonics.*DFTAPG)'*DFTMLG);
c = real((OddHarmonics.*DFTMLG)'*DFTMLG);
d = real((EvenHarmonics.*DFTAPG)'*DFTAPG);
e = real((EvenHarmonics.*DFTMLG)'*DFTAPG + (EvenHarmonics.*DFTAPG)'*DFTMLG);
f = real((EvenHarmonics.*DFTMLG)'*DFTMLG);
% and by setting d/dx(HRML(x))==0 we get the quadratic formula
aq = a*e-b*d;
bq = 2*a*f-2*c*d;
cq = b*f-c*e;
% DT = bq^2-4*aq*cq = 4*(a*f-*c*d)*(a*f-c*d) - 4*(a*e-b*d)*(b*f-c*e)
% = 4aaff +4ccdd -8acdf -4abef -4bcde +4acee + 4bbdf
% = 4aaff +4ccdd -4abef -4bcde +4ac(ee-df) +4(bb-ac)df
x = (-bq +[1 -1]*sqrt(bq.^2-4*aq*cq))/(2*aq);
% with hopefully two solutions for x.
% from here on use amplitude HR:
HRML = @(x) real((OddHarmonics'*abs(DFTMLG+x*DFTAPG))...
/(EvenHarmonics'*abs(DFTMLG+x*DFTAPG)));
% now we take the x for which the HR is maximal, and the x rotated 90
% degrees fo which it is minimal, and take the mean angle between them
HR1 = HRML(x(1));
HR2 = HRML(x(2));
if HR1 > HR2
thetas = atan([x(1),-1/x(2)]);
else
thetas = atan([-1/x(1),x(2)]);
end
theta = mean(thetas);
xeg = tan(theta);
if abs(diff(thetas)) > pi/2 % thetas are more than 90 degrees apart, and the 'mean of the two axes' should be rotated 90 degrees
xeg = -1/xeg;
end
%% Numerical search for best harmonic ratios product
% Now we want to improve the solution, since the two above directions are
% not necessarily orthogonal. Thus we want to find the orthogonal
% directions ML = MLguess + x*APguess, and AP = APguess - x*MLguess,
% for which the product of 'harmonic ratios' for the ML and AP directions
% is maximal, and we do this by varying x, starting with the educated guess
% above using power instead of amplitude:
% HRML = ((OddHarmonics'.*(DFTMLG'+x*DFTAPG'))*(DFTMLG+x*DFTAPG))...
% /((EvenHarmonics'.*(DFTMLG'+x*DFTAPG'))*(DFTMLG+x*DFTAPG));
% HRAP = ((EvenHarmonics'.*(-x*DFTMLG'+DFTAPG'))*(-x*DFTMLG+DFTAPG))...
% /((OddHarmonics'.*(-x*DFTMLG'+DFTAPG'))*(-x*DFTMLG+DFTAPG));
% and
% HR_Prod = HRML*HRAP = ...
% Now use amplitude
Minus_HR_Prod = @(x) -real(...
(OddHarmonics'*abs(DFTMLG+x*DFTAPG))...
/(EvenHarmonics'*abs(DFTMLG+x*DFTAPG))...
*(EvenHarmonics'*abs(-x*DFTMLG+DFTAPG))...
/(OddHarmonics'*abs(-x*DFTMLG+DFTAPG)));
[xopt1,Minus_HR_Prod_opt1,exitflag1]=fminsearch(Minus_HR_Prod,xeg);
if exitflag1 == 0 && abs(xopt1) > 100 % optimum for theta beyond +- pi/2
[xopt1a,Minus_HR_Prod_opt1a,exitflag1a]=fminsearch(Minus_HR_Prod,-xopt1);
if ~(exitflag1a == 0 && abs(xopt1a) > 100)
xopt1org = xopt1;
xopt1 = xopt1a;
Minus_HR_Prod_opt1 = Minus_HR_Prod_opt1a;
end
end
options = optimset('LargeScale','off','GradObj','off','Display','notify');
[xopt2,Minus_HR_Prod_opt2,exitflag2]=fminunc(Minus_HR_Prod,xopt1,options);
if exitflag2 == 0 && abs(xopt2) > 100 % optimum for theta beyond +- pi/2
[xopt2a,Minus_HR_Prod_opt2a,exitflag2a]=fminsearch(Minus_HR_Prod,-xopt2);
if ~(exitflag2a == 0 && abs(xopt2a) > 100)
xopt2 = xopt2a;
Minus_HR_Prod_opt2 = Minus_HR_Prod_opt2a;
end
end
RML = (RMLGuess+xopt2*RAPGuess)/sqrt(1+xopt2^2);
RAP = cross(RVT,RML); RAP = RAP/norm(RAP);
RT = [RVT,RML,RAP];
if nargout > 1
RotationMatrixT = RT;
end
RealignedAcc = Acc*RT;
if nargout > 2
Flags = [exitflag1,exitflag2];
end
if nargin > 2 && plotje
Thetas = pi*(-0.49:0.01:0.49)';
Xs = tan(Thetas);
HR_Prod = nan(size(Xs));
HRMLs = nan(size(Xs));
for i=1:numel(Xs),
HR_Prod(i,1) = -Minus_HR_Prod(Xs(i));
HRMLs(i,1) = HRML(Xs(i));
end
figure();
semilogy(Thetas,[HR_Prod,HRMLs.^2]);
hold on;
semilogy(atan(x),[HR1,HR2].^2,'r.');
semilogy(atan([xopt1;xopt2]),-[Minus_HR_Prod_opt1;Minus_HR_Prod_opt2],'g.');
semilogy(atan(xeg),-Minus_HR_Prod(xeg),'kx');
end
%% attempt to solve it analytically:
% % We can rewrite HR_Prod as:
% % HR_Prod =
% % ( (x.^2)*((OddHarmonics.*DFTAPG)'*DFTAPG) ...
% % + x*((OddHarmonics.*DFTMLG)'*DFTAPG + (OddHarmonics.*DFTAPG)'*DFTMLG)...
% % + ((OddHarmonics.*DFTMLG)'*DFTMLG) )...
% % /
% % ( (x.^2)*((EvenHarmonics.*DFTAPG)'*DFTAPG) ...
% % + x*((EvenHarmonics.*DFTMLG)'*DFTAPG + (EvenHarmonics.*DFTAPG)'*DFTMLG)...
% % + ((EvenHarmonics.*DFTMLG)'*DFTMLG) )
% % *
% % ( (x.^2)*((EvenHarmonics.*DFTMLG)'*DFTMLG) ...
% % - x*((EvenHarmonics.*DFTMLG)'*DFTAPG + (EvenHarmonics.*DFTAPG)'*DFTMLG)...
% % + ((EvenHarmonics.*DFTAPG)'*DFTAPG) )...
% % /
% % ( (x.^2)*((OddHarmonics.*DFTMLG)'*DFTMLG) ...
% % - x*((OddHarmonics.*DFTMLG)'*DFTAPG + (OddHarmonics.*DFTAPG)'*DFTMLG)...
% % + ((OddHarmonics.*DFTAPG)'*DFTAPG) )
% %
% % or by making these substitutions:
% a2 = (OddHarmonics.*DFTAPG)'*DFTAPG;
% a1 = (OddHarmonics.*DFTMLG)'*DFTAPG + (OddHarmonics.*DFTAPG)'*DFTMLG;
% a0 = (OddHarmonics.*DFTMLG)'*DFTMLG;
% c2 = (EvenHarmonics.*DFTAPG)'*DFTAPG;
% c1 = (EvenHarmonics.*DFTMLG)'*DFTAPG + (EvenHarmonics.*DFTAPG)'*DFTMLG;
% c0 = (EvenHarmonics.*DFTMLG)'*DFTMLG;
% b2 = c0;
% b1 = c1;
% b0 = c2;
% d2 = a0;
% d1 = a1;
% d0 = a2;
% % we get:
% % HR_Prod = (x.^2*a2 + x*a1 + a0) * (x.^2*b2 + x*b1 + b0) / (x.^2*c2 + x*c1 + c0) * (x.^2*d2 + x*d1 + d0)
% % or:
% % HR_Prod = N/D
% % with
% % N = ( x.^4*(a2*b2)...
% % +x.^3*(a2*b1+a1*b2)...
% % +x.^2*(a2*b0+a1*b1+a0*b2)...
% % +x *(a1*b0+a0*b1)...
% % + a0*b0 )...
% % and with
% % D = ( x.^4*(c2*d2)...
% % +x.^3*(c2*d1+c1*d2)...
% % +x.^2*(c2*d0+c1*d1+c0*d2)...
% % +x *(c1*d0+c0*d1)...
% % + c0*d0 )
% % or D = ( x.^4*(a0*b0)...
% % +x.^3*(a1*b0+a0*b1)...
% % +x.^2*(a2*b0+a1*b1+a0*b2)...
% % +x *(a2*b1+a1*b2)...
% % + a2*b2 )
% % or by substition of
% n4 = a2*b2;
% n3 = a2*b1+a1*b2;
% n2 = a2*b0+a1*b1+a0*b2;
% n1 = a1*b0+a0*b1;
% n0 = a0*b0;
% % d4 = n0;
% % d3 = n1;
% % d2 = n2;
% % d1 = n3;
% % d0 = n4;
% % we get
% % N = sum(ni*x^i) and D=sum(di*x^i)
% %
% % Then HR_Prod reaches a maximum or minimum when d/dx (N/D) = 0
% % or (dN/dx)/D - N/(D^2)*(dD/dx) = 0
% % or (dN/dx)*D - (dD/dx)*N = 0
% % or
% % x^7*(4*n4*d4 - 4*n4*d4)
% % + x^6*(4*n4*d3 - 4*n3*d4 + 3*n3*d4 - 3*n4*d3)
% % + x^5*(4*n4*d2 - 4*n2*d4 + 3*n3*d3 - 3*n3*d3 + 2*n2*d4 - 2*n4*d2)
% % + x^4*(4*n4*d1 - 4*n1*d4 + 3*n3*d2 - 3*n2*d3 + 2*n2*d3 - 2*n3*d2 + 1*n1*d4 - 1*n4*d1)
% % + x^3*(4*n4*d0 - 4*n0*d4 + 3*n3*d1 - 3*n1*d3 + 2*n2*d2 - 2*n2*d2 + 1*n1*d3 - 1*n3*d1)
% % + x^2*( 3*n3*d0 - 3*n0*d3 + 2*n2*d1 - 2*n1*d2 + 1*n1*d2 - 1*n2*d1)
% % + x^1*( 2*n2*d0 - 2*n0*d2 + 1*n1*d1 - 1*n1*d1)
% % + x^0*( 1*n1*d0 - 1*n0*d1)
% % = 0
% % or
% % x^6*(1*n4*d3 - 1*n3*d4)
% % + x^5*(2*n4*d2 - 2*n2*d4)
% % + x^4*(3*n4*d1 - 3*n1*d4 + 1*n3*d2 - 1*n2*d3)
% % + x^3*(4*n4*d0 - 4*n0*d4 + 2*n3*d1 - 2*n1*d3)
% % + x^2*( 3*n3*d0 - 3*n0*d3 + 1*n2*d1 - 1*n1*d2)
% % + x^1*( 2*n2*d0 - 2*n0*d2)
% % + x^0*( 1*n1*d0 - 1*n0*d1)
% % = 0
% % or
% % (x^6+x^0) * (1*n4*n1 - 1*n3*n0)
% % + (x^5+x^1) * (2*n4*n2 - 2*n2*n0)
% % + (x^4+x^2) * (3*n4*n3 - 3*n1*n0 + 1*n3*n2 - 1*n2*n1)
% % + x^3 * (4*n4*n4 - 4*n0*n0 + 2*n3*n3 - 2*n1*n1)
% % = 0
% % or
% % (x^6+x^0) * (1*(a2*b2)*(a1*b0+a0*b1) - 1*(a2*b1+a1*b2)*(a0*b0))
% % + (x^5+x^1) * (2*(a2*b2)*(a2*b0+a1*b1+a0*b2) - 2*(a2*b0+a1*b1+a0*b2)*(a0*b0))
% % + (x^4+x^2) * (3*(a2*b2)*(a2*b1+a1*b2) - 3*(a1*b0+a0*b1)*(a0*b0) + 1*(a2*b1+a1*b2)*(a2*b0+a1*b1+a0*b2) - 1*(a2*b0+a1*b1+a0*b2)*(a1*b0+a0*b1))
% % + x^3 * (4*(a2*b2)*(a2*b2) - 4*(a0*b0)*(a0*b0) + 2*(a2*b1+a1*b2)*(a2*b1+a1*b2) - 2*(a1*b0+a0*b1)*(a1*b0+a0*b1))
% % = 0
% % or
% % (x^6+x^0) * (a2*b2*a1*b0 + a2*b2*b1*a0 - a2*b1*a0*b0 - b2*a1*a0*b0)
% % + (x^5+x^1) * (2*(a2*a2*b2*b0+a2*b2*b2*a0+a2*b2*a1*b1) - 2*(a2*a0*b0*b0+b2*a0*a0*b0+a1*b1*a0*b0))
% % + (x^4+x^2) * (3*a2*a2*b2*b1 +a2*a2*b1*b0 +3*a2*b2*b2*a1 +a2*b2*a1*b0 +a2*b2*b1*a0 +a2*a1*b1*b1 -a2*a1*b0*b0 -a2*a0*b1*b0 +b2*b2*a1*a0 +b2*a1*a1*b1 -b2*a1*a0*b0 -b2*b1*a0*a0 -a1*a1*b1*b0 -a1*b1*b1*a0 -3*a1*a0*b0*b0 -3*b1*a0*a0*b0)
% % + x^3 * (4*a2*a2*b2*b2 +2*a2*a2*b1*b1 +4*a2*b2*a1*b1 +2*b2*b2*a1*a1 -2*a1*a1*b0*b0 -4*a1*b1*a0*b0 -2*b1*b1*a0*a0 -4*a0*a0*b0*b0)
% % = 0
% % which can probably not be solved analytically?.

View File

@ -0,0 +1,118 @@
function [ResultStruct] = SpatioTemporalGaitParameters(dataAccCut_filt,StrideTimeSamples,ApplyRealignment,LegLength,FS,IgnoreMinMaxStrides,ResultStruct);
Cutoff = 0.1;
MinDist = floor(0.7*0.5*StrideTimeSamples); % Use StrideTimeSamples estimated above
DatalFilt = dataAccCut_filt;
% From acceleration to velocity
Vel = cumsum(detrend(DatalFilt,'constant'))/FS;
[B,A] = butter(2,Cutoff/(FS/2),'high');
Pos = cumsum(filtfilt(B,A,Vel))/FS;
PosFilt = filtfilt(B,A,Pos);
PosFiltVT = PosFilt(:,1);
% Find minima and maxima in vertical position
% if ~ApplyRealignment % Signals were not realigned, so it has to be done here
% MeanAcc = mean(AccLoco);
% VT = MeanAcc'/norm(MeanAcc);
% PosFiltVT = PosFilt*VT;
% end
% Find minima and maxima in vertical position
[PosPks,PosLocs] = findpeaks(PosFiltVT(:,1),'minpeakdistance',MinDist);
[NegPks,NegLocs] = findpeaks(-PosFiltVT(:,1),'minpeakdistance',MinDist);
NegPks = -NegPks;
if isempty(PosPks) && isempty(NegPks)
PksAndLocs = zeros(0,3);
else
PksAndLocs = sortrows([PosPks,PosLocs,ones(size(PosPks)) ; NegPks,NegLocs,-ones(size(NegPks))], 2);
end
% Correct events for two consecutive maxima or two consecutive minima
Events = PksAndLocs(:,2);
NewEvents = PksAndLocs(:,2);
Signs = PksAndLocs(:,3);
FalseEventsIX = find(diff(Signs)==0);
PksAndLocsToAdd = zeros(0,3);
PksAndLocsToAddNr = 0;
for i=1:numel(FalseEventsIX),
FIX = FalseEventsIX(i);
if FIX <= 2
% remove the event
NewEvents(FIX) = nan;
elseif FIX >= numel(Events)-2
% remove the next event
NewEvents(FIX+1) = nan;
else
StrideTimesWhenAdding = [Events(FIX+1)-Events(FIX-2),Events(FIX+3)-Events(FIX)];
StrideTimesWhenRemoving = Events(FIX+3)-Events(FIX-2);
if max(abs(StrideTimesWhenAdding-StrideTimeSamples)) < abs(StrideTimesWhenRemoving-StrideTimeSamples)
% add an event
[M,IX] = min(Signs(FIX)*PosFiltVT((Events(FIX)+1):(Events(FIX+1)-1)));
PksAndLocsToAddNr = PksAndLocsToAddNr+1;
PksAndLocsToAdd(PksAndLocsToAddNr,:) = [M,Events(FIX)+IX,-Signs(FIX)];
else
% remove an event
if FIX >= 5 && FIX <= numel(Events)-5
ExpectedEvent = (Events(FIX-4)+Events(FIX+5))/2;
else
ExpectedEvent = (Events(FIX-2)+Events(FIX+3))/2;
end
if abs(Events(FIX)-ExpectedEvent) > abs(Events(FIX+1)-ExpectedEvent)
NewEvents(FIX) = nan;
else
NewEvents(FIX+1) = nan;
end
end
end
end
PksAndLocsCorrected = sortrows([PksAndLocs(~isnan(NewEvents),:);PksAndLocsToAdd],2);
% Find delta height and delta time
DH = abs(diff(PksAndLocsCorrected(:,1),1,1));
DT = diff(PksAndLocsCorrected(:,2),1,1);
% Correct outliers in delta h
MaxDH = min(median(DH)+3*mad(DH,1),LegLength/2);
DH(DH>MaxDH) = MaxDH;
% Estimate total length and speed
% (Use delta h and delta t to calculate walking speed: use formula from
% Z&H, but divide by 2 (skip factor 2)since we get the difference twice
% each step, and multiply by 1.25 which is the factor suggested by Z&H)
HalfStepLen = 1.25*sqrt(2*LegLength*DH-DH.^2);
Distance = sum(HalfStepLen);
WalkingSpeedMean = Distance/(sum(DT)/FS);
% Estimate variabilities between strides
StrideLengths = HalfStepLen(1:end-3) + HalfStepLen(2:end-2) + HalfStepLen(3:end-1) + HalfStepLen(4:end);
StrideTimes = PksAndLocsCorrected(5:end,2)-PksAndLocsCorrected(1:end-4,2);
StrideSpeeds = StrideLengths./(StrideTimes/FS);
WSS = nan(1,4);
STS = nan(1,4);
for i=1:4,
STS(i) = std(StrideTimes(i:4:end))/FS;
WSS(i) = std(StrideSpeeds(i:4:end));
end
StepLengthMean=mean(StrideLengths);
StrideTimeVariability = min(STS);
StrideSpeedVariability = min(WSS);
StrideLengthVariability = std(StrideLengths);
% Estimate Stride time variability and stride speed variability by removing highest and lowest part
if ~isinteger(IgnoreMinMaxStrides)
IgnoreMinMaxStrides = ceil(IgnoreMinMaxStrides*size(StrideTimes,1));
end
StrideTimesSorted = sort(StrideTimes);
StrideTimeVariabilityOmitOutlier = std(StrideTimesSorted(1+IgnoreMinMaxStrides:end-IgnoreMinMaxStrides));
StrideSpeedSorted = sort(StrideSpeeds);
StrideSpeedVariabilityOmitOutlier = std(StrideSpeedSorted(1+IgnoreMinMaxStrides:end-IgnoreMinMaxStrides));
StrideLengthsSorted = sort(StrideLengths);
StrideLengthVariabilityOmitOutlier = std(StrideLengthsSorted(1+IgnoreMinMaxStrides:end-IgnoreMinMaxStrides));
ResultStruct.StepLengthMean = StepLengthMean;
ResultStruct.Distance = Distance;
ResultStruct.WalkingSpeedMean = WalkingSpeedMean;
ResultStruct.StrideTimeVariability = StrideTimeVariability;
ResultStruct.StrideSpeedVariability = StrideSpeedVariability;
ResultStruct.StrideLengthVariability = StrideLengthVariability;
ResultStruct.StrideTimeVariabilityOmitOutlier = StrideTimeVariabilityOmitOutlier;
ResultStruct.StrideSpeedVariabilityOmitOutlier = StrideSpeedVariabilityOmitOutlier;
ResultStruct.StrideLengthVariabilityOmitOutlier = StrideLengthVariabilityOmitOutlier;

View File

@ -0,0 +1,15 @@
function [ResultStruct] = SpectralAnalysisGaitfunc(dataAccCut_filt,WindowLen,FS,N_Harm,LowFrequentPowerThresholds,AccVectorLen,ResultStruct)
P=zeros(0,size(dataAccCut_filt,2));
for i=1:size(dataAccCut_filt,2)
[P1,~] = pwelch(dataAccCut_filt(:,i),hamming(WindowLen),[],WindowLen,FS);
[P2,F] = pwelch(dataAccCut_filt(end:-1:1,i),hamming(WindowLen),[],WindowLen,FS);
P(1:numel(P1),i) = (P1+P2)/2;
end
dF = F(2)-F(1);
% Calculate stride frequency and peak widths
[StrideFrequency, ~, PeakWidth, MeanNormalizedPeakWidth] = StrideFrequencyRispen(P,F);
[ResultStruct] = HarmonicityFrequency(dataAccCut_filt, P,F, StrideFrequency,dF,LowFrequentPowerThresholds,N_Harm,FS,AccVectorLen,ResultStruct);
end

35
StepDetectionFunc.m Normal file
View File

@ -0,0 +1,35 @@
function [dataAccCut,dataAccCut_filt,StrideTimeSamples] = StepDetectionFunc(FS,ApplyRemoveSteps,dataAcc,dataAcc_filt,StrideTimeRange)
%% Step detecection
% Determines the number of steps in the signal so that the first 30 and last 30 steps in the signal can be removed
ResultStruct = struct();
if ApplyRemoveSteps
% In order to run the step detection script we first need to run an autocorrelation function;
[ResultStruct] = AutocorrStrides(dataAcc_filt,FS,StrideTimeRange,ResultStruct);
% StrideTimeSamples is needed as an input for the stepcountFunc;
StrideTimeSamples = ResultStruct.StrideTimeSamples;
% Calculate the number of steps;
[PksAndLocsCorrected] = StepcountFunc(dataAcc_filt,StrideTimeSamples,FS);
% This function selects steps based on negative and positive values.
% However to determine the steps correctly we only need one of these;
LocsSteps = PksAndLocsCorrected(1:2:end,2);
%% Cut data & remove currents results
% Remove 20 steps in the beginning and end of data
dataAccCut = dataAcc(LocsSteps(31):LocsSteps(end-30),:);
dataAccCut_filt = dataAcc_filt(LocsSteps(31):LocsSteps(end-30),:);
% Clear currently saved results from Autocorrelation Analysis
clear ResultStruct;
clear PksAndLocsCorrected;
clear LocsSteps;
else;
dataAccCut = dataAcc;
dataAccCut_filt = dataAcc_filt;
end

65
StepcountFunc.m Normal file
View File

@ -0,0 +1,65 @@
function [PksAndLocsCorrected] = StepcountFunc(dataAcc_filt,StrideTimeSamples,FS);
% Step count funciton extracted from other function called:
Cutoff = 0.1;
MinDist = floor(0.7*0.5*StrideTimeSamples); % Use StrideTimeSamples estimated above
DataLFilt = dataAcc_filt;
% From acceleration to
Vel = cumsum(detrend(DataLFilt,'constant'))/FS;
[B,A] = butter(2,Cutoff/(FS/2),'high');
Pos = cumsum(filtfilt(B,A,Vel))/FS;
PosFilt = filtfilt(B,A,Pos);
PosFiltVT = PosFilt(:,1);
% Find minima and maxima in vertical position
[PosPks,PosLocs] = findpeaks(PosFiltVT(:,1),'minpeakdistance',MinDist);
[NegPks,NegLocs] = findpeaks(-PosFiltVT(:,1),'minpeakdistance',MinDist);
NegPks = -NegPks;
if isempty(PosPks) && isempty(NegPks)
PksAndLocs = zeros(0,3);
else
PksAndLocs = sortrows([PosPks,PosLocs,ones(size(PosPks)) ; NegPks,NegLocs,-ones(size(NegPks))], 2);
end
% Correct events for two consecutive maxima or two consecutive minima
Events = PksAndLocs(:,2);
NewEvents = PksAndLocs(:,2);
Signs = PksAndLocs(:,3);
FalseEventsIX = find(diff(Signs)==0);
PksAndLocsToAdd = zeros(0,3);
PksAndLocsToAddNr = 0;
for i=1:numel(FalseEventsIX),
FIX = FalseEventsIX(i);
if FIX <= 2
% remove the event
NewEvents(FIX) = nan;
elseif FIX >= numel(Events)-2
% remove the next event
NewEvents(FIX+1) = nan;
else
StrideTimesWhenAdding = [Events(FIX+1)-Events(FIX-2),Events(FIX+3)-Events(FIX)];
StrideTimesWhenRemoving = Events(FIX+3)-Events(FIX-2);
if max(abs(StrideTimesWhenAdding-StrideTimeSamples)) < abs(StrideTimesWhenRemoving-StrideTimeSamples)
% add an event
[M,IX] = min(Signs(FIX)*PosFiltVT((Events(FIX)+1):(Events(FIX+1)-1)));
PksAndLocsToAddNr = PksAndLocsToAddNr+1;
PksAndLocsToAdd(PksAndLocsToAddNr,:) = [M,Events(FIX)+IX,-Signs(FIX)];
else
% remove an event
if FIX >= 5 && FIX <= numel(Events)-5
ExpectedEvent = (Events(FIX-4)+Events(FIX+5))/2;
else
ExpectedEvent = (Events(FIX-2)+Events(FIX+3))/2;
end
if abs(Events(FIX)-ExpectedEvent) > abs(Events(FIX+1)-ExpectedEvent)
NewEvents(FIX) = nan;
else
NewEvents(FIX+1) = nan;
end
end
end
end
PksAndLocsCorrected = sortrows([PksAndLocs(~isnan(NewEvents),:);PksAndLocsToAdd],2);
end

150
StrideFrequencyFrom3dAcc.m Normal file
View File

@ -0,0 +1,150 @@
function [StrideFrequency, QualityInd, PeakWidth, MeanNormalizedPeakWidth] = StrideFrequencyFrom3dAcc(AccXYZ, F)
%% Description
% Estimate stride frequency in 3d accelerometer data, using multi-taper and
% pwelch spectral densities
%
% Input:
% AccXYZ: a three-dimensional time series with trunk accelerations
% FS: the sample frequency of the time series
% StrideFreqGuess: a first guess of the stride frequency
%
% Output:
% StrideFrequency: the estimated stride frequency
% QualityInd: a number (0-1, 0=no confidence, 1=fully confident) indicating how much confidence we have in the
% estimated stride frequency
%% Copyright
% COPYRIGHT (c) 2012 Sietse Rispens, VU University Amsterdam
%
% This program is free software: you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with this program. If not, see <http://www.gnu.org/licenses/>.
%% Author
% Sietse Rispens
%% History
% February 2013, version 1.1, adapted from StrideFrequencyFrom3dAcc
%% Check input
if size(AccXYZ,2) ~= 3
error('AccXYZ must be 3-d time series, i.e. contain 3 columns');
elseif size(AccXYZ,1) < 10*F
error('AccXYZ must be at least ten seconds long');
end
%% Get PSD
if numel(F) == 1, % Calculate the PSD from time series AccXYZ, F is the sample frequency
AccFilt = detrend(AccXYZ,'constant'); % Detrend data to get rid of DC component in most of the specific windows
LenPSD = 10*F;
for i=1:3,
[P1,Fwf] = pwelch(AccFilt(:,i),hamming(LenPSD),[],LenPSD,F);
[P2,Fwf] = pwelch(AccFilt(end:-1:1,i),hamming(LenPSD),[],LenPSD,F);
Pwf(:,i) = (P1+P2)/2;
end
elseif numel(F)==size(AccXYZ,1), % F are the frequencies of the power spectrum AccXYZ
Fwf = F;
Pwf = AccXYZ;
end
Pwf(:,4) = sum(Pwf,2);
%% Estimate stride frequency
% set parameters
HarmNr = [2 1 2];
CommonRange = [0.6 1.2];
% Get modal frequencies and the 'mean freq. of the peak'
for i=1:4,
MF1I = find([zeros(5,1);Pwf(6:end,i)]==max([zeros(5,1);Pwf(6:end,i)]),1);
MF1 = Fwf(MF1I,1);
IndAround = Fwf>=MF1*0.5 & Fwf<=MF1*1.5;
MeanAround = mean(Pwf(IndAround,i));
PeakBeginI = find(IndAround & Fwf<MF1 & Pwf(:,i) < mean([MeanAround,Pwf(MF1I,i)]),1,'last');
PeakEndI = find(IndAround & Fwf>MF1 & Pwf(:,i) < mean([MeanAround,Pwf(MF1I,i)]),1,'first');
if isempty(PeakBeginI), PeakBeginI = find(IndAround,1,'first'); end
if isempty(PeakEndI), PeakEndI = find(IndAround,1,'last'); end
ModalF(i) = sum(Fwf(PeakBeginI:PeakEndI,1).*Pwf(PeakBeginI:PeakEndI,i))/sum(Pwf(PeakBeginI:PeakEndI,i));
if i==4
HarmNr(4) = HarmNr(find(Pwf(MF1I,1:3)==max(Pwf(MF1I,1:3)),1));
end
end
% Get stride frequency and quality indicator from modal frequencies
StrFreqFirstGuesses = ModalF./HarmNr;
StdOverMean = std(StrFreqFirstGuesses)/mean(StrFreqFirstGuesses);
StrideFrequency1 = median(StrFreqFirstGuesses(1:3));
if StrideFrequency1 > CommonRange(2) && min(StrFreqFirstGuesses(1:3)) < CommonRange(2) && min(StrFreqFirstGuesses(1:3)) > CommonRange(1)
StrideFrequency1 = min(StrFreqFirstGuesses(1:3));
end
if StrideFrequency1 < CommonRange(1) && max(StrFreqFirstGuesses(1:3)) > CommonRange(1) && max(StrFreqFirstGuesses(1:3)) < CommonRange(2)
StrideFrequency1 = min(StrFreqFirstGuesses(1:3));
end
HarmGuess = ModalF/StrideFrequency1;
StdHarmGuessRoundErr = std(HarmGuess - round(HarmGuess));
if StdOverMean < 0.1
QI1 = 1;
StrideFrequency = mean(StrFreqFirstGuesses);
else
if StdHarmGuessRoundErr < 0.1 && all(round(HarmGuess) >= 1)
QI1 = 0.5;
StrideFrequency = mean(ModalF./round(HarmGuess));
else
QI1 = 0;
StrideFrequency = StrideFrequency1;
end
end
if nargout >= 2
QualityInd = QI1;
end
if nargout >= 3
N_Harm = 20;
PeakWidth = nan(1,3);
if nargout >= 4
MeanNormalizedPeakWidth = nan(1,3);
end
%% Get (mean) widths of harmonic peaks
for i=1:3,
WidthHarm = nan(1,N_Harm);
PowerHarm = nan(1,N_Harm);
for HarmonicNr = 1:N_Harm,
FreqRangeIndices = ...
Fwf >= StrideFrequency*(HarmonicNr-0.5) ...
& Fwf <= StrideFrequency*(HarmonicNr+0.5);
PeakPower = sum(Pwf(FreqRangeIndices,i));
PeakMean = sum(Pwf(FreqRangeIndices,i).*Fwf(FreqRangeIndices))/PeakPower;
PeakMeanSquare = sum(Pwf(FreqRangeIndices,i).*Fwf(FreqRangeIndices).^2)/PeakPower;
WidthHarm(HarmonicNr) = sqrt(PeakMeanSquare-PeakMean.^2);
PowerHarm(HarmonicNr) = PeakPower;
end
PeakWidth(i) = WidthHarm(HarmNr(i)); % Take the 1st or 2nd harmonic width as original measure
if nargout >= 4
MeanNormalizedPeakWidth(i) = sum(WidthHarm./(1:N_Harm).*PowerHarm)/sum(PowerHarm);
end
end
end
if nargout == 0
IXplotw = Fwf<10;
figure();
for i=1:3,
subplot(2,2,i);
plot(Fwf(IXplotw,1),Pwf(IXplotw,i));
end
subplot(2,2,4);
plot(Fwf(IXplotw,1),Pwf(IXplotw,1:3));
end

150
StrideFrequencyRispen.m Normal file
View File

@ -0,0 +1,150 @@
function [StrideFrequency, QualityInd, PeakWidth, MeanNormalizedPeakWidth] = StrideFrequencyRispen(AccXYZ, F)
%% Description
% Estimate stride frequency in 3d accelerometer data, using multi-taper and
% pwelch spectral densities
%
% Input:
% AccXYZ: a three-dimensional time series with trunk accelerations
% FS: the sample frequency of the time series
% StrideFreqGuess: a first guess of the stride frequency
%
% Output:
% StrideFrequency: the estimated stride frequency
% QualityInd: a number (0-1, 0=no confidence, 1=fully confident) indicating how much confidence we have in the
% estimated stride frequency
%% Copyright
% COPYRIGHT (c) 2012 Sietse Rispens, VU University Amsterdam
%
% This program is free software: you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with this program. If not, see <http://www.gnu.org/licenses/>.
%% Author
% Sietse Rispens
%% History
% February 2013, version 1.1, adapted from StrideFrequencyFrom3dAcc
%% Check input
if size(AccXYZ,2) ~= 3
error('AccXYZ must be 3-d time series, i.e. contain 3 columns');
elseif size(AccXYZ,1) < 10*F
error('AccXYZ must be at least ten seconds long');
end
%% Get PSD
if numel(F) == 1, % Calculate the PSD from time series AccXYZ, F is the sample frequency
AccFilt = detrend(AccXYZ,'constant'); % Detrend data to get rid of DC component in most of the specific windows
LenPSD = 10*F;
for i=1:3,
[P1,Fwf] = pwelch(AccFilt(:,i),hamming(LenPSD),[],LenPSD,F);
[P2,Fwf] = pwelch(AccFilt(end:-1:1,i),hamming(LenPSD),[],LenPSD,F);
Pwf(:,i) = (P1+P2)/2;
end
elseif numel(F)==size(AccXYZ,1), % F are the frequencies of the power spectrum AccXYZ
Fwf = F;
Pwf = AccXYZ;
end
Pwf(:,4) = sum(Pwf,2);
%% Estimate stride frequency
% set parameters
HarmNr = [2 1 2];
CommonRange = [0.6 1.2];
% Get modal frequencies and the 'mean freq. of the peak'
for i=1:4,
MF1I = find([zeros(5,1);Pwf(6:end,i)]==max([zeros(5,1);Pwf(6:end,i)]),1);
MF1 = Fwf(MF1I,1);
IndAround = Fwf>=MF1*0.5 & Fwf<=MF1*1.5;
MeanAround = mean(Pwf(IndAround,i));
PeakBeginI = find(IndAround & Fwf<MF1 & Pwf(:,i) < mean([MeanAround,Pwf(MF1I,i)]),1,'last');
PeakEndI = find(IndAround & Fwf>MF1 & Pwf(:,i) < mean([MeanAround,Pwf(MF1I,i)]),1,'first');
if isempty(PeakBeginI), PeakBeginI = find(IndAround,1,'first'); end
if isempty(PeakEndI), PeakEndI = find(IndAround,1,'last'); end
ModalF(i) = sum(Fwf(PeakBeginI:PeakEndI,1).*Pwf(PeakBeginI:PeakEndI,i))/sum(Pwf(PeakBeginI:PeakEndI,i));
if i==4
HarmNr(4) = HarmNr(find(Pwf(MF1I,1:3)==max(Pwf(MF1I,1:3)),1));
end
end
% Get stride frequency and quality indicator from modal frequencies
StrFreqFirstGuesses = ModalF./HarmNr;
StdOverMean = std(StrFreqFirstGuesses)/mean(StrFreqFirstGuesses);
StrideFrequency1 = median(StrFreqFirstGuesses(1:3));
if StrideFrequency1 > CommonRange(2) && min(StrFreqFirstGuesses(1:3)) < CommonRange(2) && min(StrFreqFirstGuesses(1:3)) > CommonRange(1)
StrideFrequency1 = min(StrFreqFirstGuesses(1:3));
end
if StrideFrequency1 < CommonRange(1) && max(StrFreqFirstGuesses(1:3)) > CommonRange(1) && max(StrFreqFirstGuesses(1:3)) < CommonRange(2)
StrideFrequency1 = min(StrFreqFirstGuesses(1:3));
end
HarmGuess = ModalF/StrideFrequency1;
StdHarmGuessRoundErr = std(HarmGuess - round(HarmGuess));
if StdOverMean < 0.1
QI1 = 1;
StrideFrequency = mean(StrFreqFirstGuesses);
else
if StdHarmGuessRoundErr < 0.1 && all(round(HarmGuess) >= 1)
QI1 = 0.5;
StrideFrequency = mean(ModalF./round(HarmGuess));
else
QI1 = 0;
StrideFrequency = StrideFrequency1;
end
end
if nargout >= 2
QualityInd = QI1;
end
if nargout >= 3
N_Harm = 20;
PeakWidth = nan(1,3);
if nargout >= 4
MeanNormalizedPeakWidth = nan(1,3);
end
%% Get (mean) widths of harmonic peaks
for i=1:3,
WidthHarm = nan(1,N_Harm);
PowerHarm = nan(1,N_Harm);
for HarmonicNr = 1:N_Harm,
FreqRangeIndices = ...
Fwf >= StrideFrequency*(HarmonicNr-0.5) ...
& Fwf <= StrideFrequency*(HarmonicNr+0.5);
PeakPower = sum(Pwf(FreqRangeIndices,i));
PeakMean = sum(Pwf(FreqRangeIndices,i).*Fwf(FreqRangeIndices))/PeakPower;
PeakMeanSquare = sum(Pwf(FreqRangeIndices,i).*Fwf(FreqRangeIndices).^2)/PeakPower;
WidthHarm(HarmonicNr) = sqrt(PeakMeanSquare-PeakMean.^2);
PowerHarm(HarmonicNr) = PeakPower;
end
PeakWidth(i) = WidthHarm(HarmNr(i)); % Take the 1st or 2nd harmonic width as original measure
if nargout >= 4
MeanNormalizedPeakWidth(i) = sum(WidthHarm./(1:N_Harm).*PowerHarm)/sum(PowerHarm);
end
end
end
if nargout == 0
IXplotw = Fwf<10;
figure();
for i=1:3,
subplot(2,2,i);
plot(Fwf(IXplotw,1),Pwf(IXplotw,i));
end
subplot(2,2,4);
plot(Fwf(IXplotw,1),Pwf(IXplotw,1:3));
end

1
div_calc.m Normal file
View File

@ -0,0 +1 @@
function Divergence=div_calc(state,ws_sec,fs,period_sec,progress) % calculate divergence curve (needed for max lyapunov exponent). % Input: % state: state space % ws_sec: window size over which divergence will be calculated(in seconds) % fs: sample frequency % period_sec: indicates period of time-wise near samples to exclude in % nearest neighbour search % progress: show progress or not % % Output: % Divergence: the divergence curve % % History: % August 2011: v1, Sietse Rispens based on version KvS en SMB % 1 November 2012, Sietse Rispens: Use div_calc_shorttimeseries for short % time series if size(state,1) <= 10000 Divergence=div_calc_shorttimeseries(state,ws_sec,fs,period_sec,progress); return; end [N,D]=size(state); ws=round(ws_sec*fs); Period=round(period_sec*fs); if N<ws, error('ws shall not be larger than N'); end NCompleteWindow = N-ws+1; Divergence_sum=zeros(1,ws); Divergence_count=zeros(1,ws); SumStd = sqrt(sum(std(state,1).^2)); DistLimStart = SumStd*nthroot(1/NCompleteWindow,D); DistLim = DistLimStart; TreeRoot=kdtree_build(state(1:NCompleteWindow,:)); k0 = 2; % The initial number of nearest neighbors to look for kmax = min(2*Period + 2, NCompleteWindow); % The maximum number of nearest neighbors to look for for i = 1:NCompleteWindow StateI = state(i,:); if ~isnan(StateI) DistLim = DistLim*nthroot(1/5,D); DistLim = min(DistLim,DistLimStart); Index = []; k=k0; kmaxreached = 0; while isempty(Index) && ~kmaxreached [Idx, Dist] = kdtree_k_nearest_neighbors(TreeRoot,StateI,k); Dist(abs(i-Idx) < Period)=nan; Index = Idx(find(Dist==min(Dist),1,'first')); if k >= kmax kmaxreached = 1; elseif isempty(Index) k = min(kmax,k*2); end end if ~isempty(Index) if i+ws>N || Index+ws>N % do not use these data else if ~isempty(Index) DistCurve = log(sqrt(sum((state(i:i+ws-1,:)-state(Index:Index+ws-1,:)).^2,2))); NotNan = ~isnan(DistCurve); Divergence_sum(NotNan) = Divergence_sum(NotNan) + DistCurve(NotNan)'; Divergence_count(NotNan) = Divergence_count(NotNan) + 1; end end end end if progress > 0 if mod(i,round(progress))==0 if i>round(progress) fprintf('\b\b\b\b\b\b\b\b\b\b'); end fprintf('i=%8d', i); end end end kdtree_delete(TreeRoot); % Free the pointer to k-d-tree if progress > 0 fprintf('\n'); end Divergence= (Divergence_sum./Divergence_count);

View File

@ -0,0 +1 @@
function divergence=div_calc_shorttimeseries(state,ws_sec,fs,period_sec,progress) % calculate local dynamic stability (max lyapunov exponent). % Input: % state: appropriate state space % ws: window size over which divergence should be calculated(in seconds) % fs: sample frequency % period: ..... (can be dominant period in the signal(in seconds)) % plotje: show a graph. % % Note that in this version ws should be larger than 4*period, as the long % term divergence is calculated from 4*period to ws*fs. % % Output: % divergence: the divergence curve % lds: the 2 estimates of the maximum lyapunov exponents (short term and long term) % % Earlier versions by KvS en SMB. Made the routine faster, 14/01/2011, Sietse Rispens % Use less memory to prevent memory error, 01/02/2011, Sietse Rispens % Take mean of the log of divergence instead of log of the mean of divergence, 26/05/2011, Sietse Rispens % Allow non-integer ws_sec and period_sec and change fitting-range, 01/08/2011, Sietse Rispens % Do not try to find neighbours that need to be followed beyond end of time series, 01/11/2012, Sietse Rispens % Exclude neighbours closer than Period in time (instead of period/2), 01/11/2012, Sietse Rispens [m,n]=size(state); ws=round(ws_sec*fs); period=round(period_sec*fs); mcompletewindow = m-ws+1; statecw = state(1:mcompletewindow,:); divergence_sum=zeros(1,ws); divergence_count=zeros(1,ws); diff_state = statecw*0; diff_state_sqr = diff_state; diff_total = zeros(size(diff_state,1),1); for i = 1:mcompletewindow if ~isnan(state(i,:)) start=round(max([1,i-period+1])); stop=round(min([mcompletewindow,i+period-1])); for j=1:n, diff_state(:,j) = statecw(:,j)-statecw(i,j); diff_state_sqr(:,j)=diff_state(:,j).^2; end diff_total(:,1)=sum(diff_state_sqr,2); diff_total(start:stop,1)=NaN; [mini,index]=min(diff_total); if i+ws>m || index+ws>m % do not use these data else divergence_sum = divergence_sum + log(sqrt(sum((state(i:i+ws-1,:)-state(index:index+ws-1,:)).^2,2)))'; divergence_count = divergence_count + 1; end end if progress > 0 if mod(i,round(progress))==0 if i>round(progress) fprintf('\b\b\b\b\b\b\b\b\b\b'); end fprintf('i=%8d', i); end end end if progress > 0 fprintf('\n'); end divergence= (divergence_sum./divergence_count);

1
div_wolf_fixed_evolv.m Normal file

File diff suppressed because one or more lines are too long

55
findminMutInf.m Normal file
View File

@ -0,0 +1,55 @@
function minmuttau = findminMutInf(miV,nsam)
% minmuttau = findminMutInf(miV,nsam)
% findminMutInf finds the lag tau of the first local minimum of mutual
% information 'miV' (given from lag 0 and up to a maximum lag 'taumax')
% and using a sliding window of length 2*nsam+1.
%========================================================================
% <findminMutInf.m>, v 1.0 2010/02/11 22:09:14 Kugiumtzis & Tsimpiris
% This is part of the MATS-Toolkit http://eeganalysis.web.auth.gr/
%========================================================================
% Copyright (C) 2010 by Dimitris Kugiumtzis and Alkiviadis Tsimpiris
% <dkugiu@gen.auth.gr>
%========================================================================
% Version: 1.0
% LICENSE:
% This program is free software; you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation; either version 3 of the License, or
% any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with this program. If not, see http://www.gnu.org/licenses/>.
%=========================================================================
% Reference : D. Kugiumtzis and A. Tsimpiris, "Measures of Analysis of Time Series (MATS):
% A Matlab Toolkit for Computation of Multiple Measures on Time Series Data Bases",
% Journal of Statistical Software, in press, 2010
% Link : http://eeganalysis.web.auth.gr/
%=========================================================================
taumax = length(miV)-1;
minmuttau = NaN;
if taumax>2*nsam
i=nsam+1;
found = 0;
while i<taumax+1-nsam & found==0
winx = miV([i-nsam:i-1 i+1:i+nsam]);
check = find(miV(i) < winx);
if length(check) == length(winx)
found=1;
else
i=i+1;
end
end
if found
minmuttau = i-1;
end
end

79
funcSampleEntropy.m Normal file
View File

@ -0,0 +1,79 @@
function [SE] = funcSampleEntropy(DataIn, m, r)
%% Description
% Calculate the sample entropy as described in
% Richman JS, Moorman JR (2000)
% "Physiological time-series analysis using approximate entropy and sample entropy"
% American Journal of Physiology. Heart and Circulatory Physiology [2000, 278(6):H2039-49]
%
% The sample entropy is calculated as the natural logarithm of the
% probability that two samples of length m that are within a distance of r,
% remain within a distance of r when adding one additional sample. Note
% that distance is considered as the maximum of the distances for the
% individual dimensions 1 to m, and that the input data is normalised.
%
% Input:
% DataIn: a one-dimensional time series
% m: the dimension of the vectors to be used. The vectors consist of m
% consecutive samples
% r: the maximum distance between two samples to qualify as a
% mathch, relative to the std of DataIn
%
% Output:
% SE: the calculated sample entropy
%
%% Copyright
% COPYRIGHT (c) 2012 Sietse Rispens, VU University Amsterdam
%
% This program is free software: you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with this program. If not, see <http://www.gnu.org/licenses/>.
%% Author
% Sietse Rispens
%% History
% 7 May 2012, version 1.0
%% Check input
if size(DataIn,1) ~= 1 && size(DataIn,2) ~= 1
error('DataIn must be a vector');
end
DataIn = DataIn(:)/std(DataIn(:));
N = size(DataIn,1);
if N-m <= 0
error('m must be smaller than the length of the time series DataIn');
end
%% Create the vectors Xm to be compared
Xm = zeros(N-m,m);
for i = 1:m,
Xm(:,i) = DataIn(i:end-1-m+i,1);
end
%% Count the numbers of matches for Xm and Xmplusone
CountXm = 0;
CountXmplusone = 0;
XmDist = nan(size(Xm));
for i = 1:N-m,
for j=1:m,
XmDist(:,j)=abs(Xm(:,j)-Xm(i,j));
end
IdXmi = find(max(XmDist,[],2)<=r);
CountXm = CountXm + length(IdXmi) - 1;
CountXmplusone = CountXmplusone + sum(abs(DataIn(IdXmi+m)-DataIn(i+m))<=r) - 1;
end
%% Return sample entropy
SE = -log(CountXmplusone/CountXm);

104
matlab.sty Normal file
View File

@ -0,0 +1,104 @@
\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{matlab}
\RequirePackage{verbatim}
\RequirePackage{fancyvrb}
\RequirePackage{alltt}
\RequirePackage{upquote}
\RequirePackage[framemethod=tikz]{mdframed}
\RequirePackage{hyperref}
\RequirePackage{color}
\newcommand{\maxwidth}[1]{\ifdim\linewidth>#1 #1\else\linewidth\fi}
\newcommand{\mlcell}[1]{{\color{output}\verbatim@font#1}}
\definecolor{output}{gray}{0.4}
% Unicode character conversions
\DeclareUnicodeCharacter{B0}{\ensuremath{^\circ}}
\DeclareUnicodeCharacter{21B5}{\ensuremath{\hookleftarrow}}
% Paragraph indentation
\setlength{\parindent}{0pt}
% Hyperlink style
\hypersetup{
colorlinks=true,
linkcolor=blue,
urlcolor=blue
}
% environment styles for MATLAB code and output
\mdfdefinestyle{matlabcode}{%
outerlinewidth=.5pt,
linecolor=gray!20!white,
roundcorner=2pt,
innertopmargin=.5\baselineskip,
innerbottommargin=.5\baselineskip,
innerleftmargin=1em,
backgroundcolor=gray!10!white
}
\newenvironment{matlabcode}{\verbatim}{\endverbatim}
\surroundwithmdframed[style=matlabcode]{matlabcode}
\newenvironment{matlaboutput}{%
\Verbatim[xleftmargin=1.25em, formatcom=\color{output}]%
}{\endVerbatim}
\newenvironment{matlabsymbolicoutput}{%
\list{}{\leftmargin=1.25em\relax}%
\item\relax%
\color{output}\verbatim@font%
}{\endlist}
\newenvironment{matlabtableoutput}[1]{%
{\color{output}%
\hspace*{1.25em}#1}%
}{}
% Table of Contents style
\newcounter{multititle}
\newcommand{\matlabmultipletitles}{\setcounter{multititle}{1}}
\newcounter{hastoc}
\newcommand{\matlabhastoc}{\setcounter{hastoc}{1}}
\newcommand{\matlabtitle}[1]{
\ifnum\value{multititle}>0
\ifnum\value{hastoc}>0
\addcontentsline{toc}{section}{#1}
\fi
\fi
\section*{#1}
}
\newcommand{\matlabheading}[1]{
\ifnum\value{hastoc}>0
\addcontentsline{toc}{subsection}{#1}
\fi
\subsection*{#1}
}
\newcommand{\matlabheadingtwo}[1]{
\ifnum\value{hastoc}>0
\addcontentsline{toc}{subsubsection}{#1}
\fi
\subsubsection*{#1}
}
\newcommand{\matlabheadingthree}[1]{
\ifnum\value{hastoc}>0
\addcontentsline{toc}{paragraph}{#1}
\fi
\paragraph*{#1}
}
\newcommand{\matlabtableofcontents}[1]{
\renewcommand{\contentsname}{#1}
\tableofcontents
}

71
mutinfHisPro.m Normal file
View File

@ -0,0 +1,71 @@
function mutV=mutinfHisPro(xV,tauV,b,ioxV,ixV)
% mutV=mutinfHisPro(xV,tauV,b,ioxV,ixV)
% mutinfHisPro computes the mutual information on the time series 'xV'
% for given delays in 'tauV'. The estimation of mutual information is
% based on 'b' partitions of equal probability at each dimension.
% The last two input parameters are the ordered time series and the
% corresponding indices that will be used in the equiprobable binning
% (they both have been computed before and therefore they are passed
% here rather than computing it again).
%========================================================================
% <mutinfHisPro.m>, v 1.0 2010/02/11 22:09:14 Kugiumtzis & Tsimpiris
% This is part of the MATS-Toolkit http://eeganalysis.web.auth.gr/
%========================================================================
% Copyright (C) 2010 by Dimitris Kugiumtzis and Alkiviadis Tsimpiris
% <dkugiu@gen.auth.gr>
%========================================================================
% Version: 1.0
% LICENSE:
% This program is free software; you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation; either version 3 of the License, or
% any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with this program. If not, see http://www.gnu.org/licenses/>.
%=========================================================================
% Reference : D. Kugiumtzis and A. Tsimpiris, "Measures of Analysis of Time Series (MATS):
% A Matlab Toolkit for Computation of Multiple Measures on Time Series Data Bases",
% Journal of Statistical Software, in press, 2010
% Link : http://eeganalysis.web.auth.gr/
%=========================================================================
n = length(xV);
ntau = length(tauV);
mutV = NaN*ones(ntau,1);
hM = NaN*ones(b,b);
cumhM = zeros(b,b+1);
cpxV = [1/b:1/b:1]';
for itau=1:ntau
tau = tauV(itau);
ntotal = n-tau;
rxV = [0;round(cpxV*ntotal)];
ix1V = ixV;
ix1V(ioxV(end-tau+1:end)) = [];
x2prV = prctile(xV(ix1V+tau),cpxV*100);
for i = 1:b
for j = 1:b
cumhM(i,j+1) = length(find(xV(ix1V(rxV(i)+1:rxV(i+1))+tau)<=x2prV(j)));
end
hM(i,:) = diff(cumhM(i,:));
end
% The use of formula H(x)=1, when log_b is used.
mutS = 2;
for j=1:b
for i=1:b
if hM(i,j) > 0
mutS=mutS+(hM(i,j)/ntotal)*log(hM(i,j)/ntotal)/log(b);
end
end
end
mutV(itau) = mutS;
end