Template
TEST remote repository
This commit is contained in:
1 parent
5491738fff
commit
ba8df083e2
32 files changed
+6008
No files matched your search
@@ -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);
|
||||||
|
|
||||||
@@ -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
|
||||||
@@ -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);
|
||||||
|
|
||||||
@@ -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);
|
||||||
|
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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) 5360 [ 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
|
||||||
@@ -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');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -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 it is too large.
Load diff
Binary file not shown.
File diff suppressed because it is too large.
Load diff
@@ -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
|
||||||
|
%
|
||||||
|
%
|
||||||
|
|
||||||
|
|
||||||
@@ -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
|
||||||
@@ -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;
|
||||||
@@ -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
|
||||||
Binary file not shown.
@@ -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?.
|
||||||
|
|
||||||
@@ -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;
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -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);␍␍
|
||||||
@@ -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);␍␍␍
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
function [Lambda]=div_wolf_fixed_evolv(states, fs, min_dist, max_dist, max_dist_mult, max_theta, period, evolv)
%% Description
% Calculate maximum lyapunov exponent from state space according to Wolf's method:
% Wolf, A., et al., Determining Lyapunov exponents from a time series.
% Physica D: 8 Nonlinear Phenomena, 1985. 16(3): p. 285-317.
%
% Input:
% states: states in state space
% fs: sample frequency
% min_dist: neighbours should be more than this distandce away to be
% selected (assumed noise amplitude )
% max_dist: maximum distance to which the divergence may grow before
% replacing the neighbour
% max_theta: maximum angle between vectors from feducial point to old and
% new neighbours, this is the absolute maximum, first search
% nearer
% period: indicates period of time-wise near samples to exclude in
% nearest neighbour search
% evolv: time step after which the neighbour is replaced
%
% Output:
% Lambda: the estimated Lyapunov exponent
% ExtraArgs: optional struct containing additional info for debugging or
% analysis of the method
%
%% 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
% 23 October 2012, initial version based on div_wolf
[N,D]=size(states);
N_opt = N-evolv;
states_opt = states(1:N_opt,:);
One2N_opt=(1:N_opt)';
is=1;
% search closest point to states(1,:), but further than min_dist away
DeltaFidPoint = zeros(N_opt,D);
for dim = 1:D,
DeltaFidPoint(:,dim) = states_opt(:,dim)-states(is,dim);
end
DeltaFidPointSqr = DeltaFidPoint.^2;
DistSqr = sum(DeltaFidPointSqr,2);
Distances = sqrt(DistSqr);
CosTh = zeros(N_opt,1);
in = find(DistSqr==min(DistSqr(DistSqr>=min_dist^2 & abs(One2N_opt-is)>period)) & abs(One2N_opt-is)>period,1,'first');
if isempty(in)
warning('Cannot calculate Wolf''s Lyapunov exponent, no states further than min_dist from starting point');
Lambda = nan;
return;
end
DistStart = Distances(in);
LnDistReplacementsSum = 0;
for is=(1+evolv):evolv:N,
in = in+evolv;
% fill distance and cos matrices with new values
DeltaOld = (states(in,:)-states(is,:))';
DistOld = sqrt(sum(DeltaOld.^2));
for dim = 1:D,
DeltaFidPoint(:,dim) = states_opt(:,dim)-states(is,dim);
end
DeltaFidPointSqr(:,:) = DeltaFidPoint.^2;
DistSqr(:,:) = sum(DeltaFidPointSqr,2);
Distances(:,:) = sqrt(DistSqr);
CosTh(:,:) = abs(DeltaFidPoint*DeltaOld)./DistOld./Distances;
Index = [];
search_theta = max_theta;
while isempty(Index) && search_theta < pi
dist_mult = 1;
while isempty(Index) && dist_mult <= max_dist_mult
search_dist = dist_mult*max_dist;
Candidates = find(Distances <= search_dist & CosTh >= cos(search_theta) ...
& Distances>= min_dist & abs(One2N_opt-is)>period);
if ~isempty(Candidates)
% find the best of candidates
if numel(Candidates) > 1
Candidates = Candidates(CosTh(Candidates)==max(CosTh(Candidates)));
if numel(Candidates) > 1
Candidates = Candidates(Distances(Candidates)==min(Distances(Candidates)));
if numel(Candidates) > 1
Candidates = Candidates(abs(One2N_opt(Candidates)-is)==max(abs(One2N_opt(Candidates)-is)));
end
end
end
Index = Candidates(1);
end
dist_mult = dist_mult+1;
end
search_theta = search_theta*2;
end
if isempty(Index) && in > N_opt % we can not evolve the old point and no new one was found
Index = find(DistSqr==min(DistSqr(DistSqr>=min_dist^2 & abs(One2N_opt-is)>period))& abs(One2N_opt-is)>period,1,'first');
if isempty(Index)
warning('Cannot calculate Wolf''s Lyapunov exponent, no states further than min_dist from fiducial point');
Lambda = nan;
return;
end
end
if ~isempty(Index)
LnDistReplacementsSum = LnDistReplacementsSum + log(DistOld/Distances(Index));
in = Index;
end
end
DistEnd = sqrt(sum((states(is,:)-states(in,:)).^2));
Lambda = (log(DistEnLine truncated
|
||||||
@@ -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
|
||||||
@@ -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
@@ -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
|
||||||
|
}
|
||||||
|
|
||||||
@@ -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
|
||||||
Reference in new issue
Block a user