Skip to content
Permalink
main
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
 
 
Cannot retrieve contributors at this time
function HistoricData = split_high_low_using_CEEMDAN(HistoricData, info)
% warning('off', 'Octave:missing-semicolon'); % should be off anyway by default
% high level settings specifying CEEMDAN scope and whether to plot results
PlotFigures = false; % set to true if you would like to see additional figures. Note, this does not include
% the figures in the paper, which are created later.
AnalyseRandomNoise = false; % enter 'true' to conduct an additional analysis that examines whether the observed IMF strengths
% are stronger than those obtained from random noise. This takes about 100 times longer (3-6 hours)
% but gives insight into whether the observed results could have arisen by chance.
% run the CEEMDAN algorithm
HistoricData.precip_annual_IMFs = RunCEEMDAN(HistoricData, AnalyseRandomNoise, PlotFigures, info);
% do a double aggregation:
% (i) for each subarea separately, aggregate across IMFs to create a single low
% frequency timeseries and a single high frequency timeseries for each subarea;
% (ii) for the low frequency only, aggregate across subareas to create a single timeseries.
[precip_ann_HighFreq, precip_ann_LowFreq] = AggregateIMFs(HistoricData, info.LowHighThresh, info);
% append CEEMDAN output to the data structure
HistoricData.precip_ann_HighFreq = precip_ann_HighFreq;
HistoricData.precip_ann_LowFreq = precip_ann_LowFreq;
end
function [IMFs_all, extra] = RunCEEMDAN(HistoricData, AnalyseRandomNoise, PlotFigures, info)
% this version created January 2021 by Keirnan Fowler, based on earlier
% code by Natasha Ballis, both of University of Melbourne.
% inputs 'AnalyseRandomNoise' and 'PlotFigures' are true/false and are
% used to indicate whether the user wants to run these parts of the code.
% for each subarea
SubareaList = info.SubareaList';
for subarea = SubareaList % equivalent of VBA "For Each subarea in SubareaList"
clearvars -except HistoricData AnalyseRandomNoise PlotFigures info subarea SubareaList IMFs_all extra
close all; % Clear all variables and close all figures associated with the previous iteration
% create blank structure to hold observed data for this subarea
R=struct('hist_data',[],'imfs',[],'imf_period',[],'imf_var',[]);
% populate observed data
R.hist_data = HistoricData.precip_annual.(subarea{:});
% observed stats
Obs_length=size(R.hist_data,1);
Obs_std=sqrt(var(R.hist_data,0)); % zero: sample variance
% algorithm settings for CEEMDAN v2014
Nstd = 0.4;
NR = 500;
MaxIter = 1000000;
SNRFlag = 1;
% run CEEMDAN v2014 for this subarea and process results
disp_toggle = false; % change to true if you want to see CEEMDAN warning messages
[imfs,its]=ceemdan_v2014(R.hist_data',Nstd,NR,MaxIter,SNRFlag, disp_toggle);
[imf_var, imf_period] = GetStats(imfs); % compute variance and average period of each IMF
R.imfs = imfs; R.imf_var = imf_var; R.imf_period = imf_period; R.its = its;
% save results to output structures
IMFs_all.(subarea{:}) = imfs;
extra.(subarea{:}) = R;
disp(['CEEMDAN complete for historic data for subarea ' subarea{:}]);
% now repeat for noise replicates (if required) (note, this takes a long time, usually > 5 hours)
if AnalyseRandomNoise
NumReps = 100;
% noise replicates
N=struct('Replicate',[],'imfs',[],'imf_period',[],'imf_var',[]);
% generate noise replicates
for iRep=1:NumReps
N(iRep).Replicate=Obs_std*2*sqrt(3)*rand(Obs_length,1); % uniform white noise
disp_toggle = false; % change to true if you want to see CEEMDAN warning messages
[imfs,its]=ceemdan_v2014(N(iRep).Replicate,Nstd,NR,MaxIter,SNRFlag, disp_toggle);
[imf_var, imf_period] = GetStats(imfs); % compute variance and average period of each IMF
N(iRep).imfs = imfs; N(iRep).imf_var = imf_var; N(iRep).imf_period = imf_period; N(iRep).its = its;
disp(['CEEMDAN complete for noise replicate ' num2str(iRep) ' of ' num2str(NumReps)]);
end
% once all reps are complete, save.
save(['CEEMDAN_output_incl_noise_reps_Subarea' subarea{:} '.mat']);
end
% Figure 1: Timeseries plotting
if PlotFigures
CreateFig1(R);
FigFileName = ['Fig1_Timeseries_Subarea' subarea{:}];
set(gcf, 'PaperUnits', 'centimeters'); set(gcf, 'PaperPosition', [0 0 20 23]);
saveas(gcf,FigFileName, 'png'); print('-painters','-depsc', FigFileName); close;
% Figure 2: Comparison with random noise replicates
if AnalyseRandomNoise
CreateFig2(R, N);
FigFileName = ['Fig2_IMF_freq_var_Subarea' subarea{:}];
set(gcf, 'PaperUnits', 'centimeters'); set(gcf, 'PaperPosition', [0 0 10 12]);
saveas(gcf,FigFileName, 'png'); print('-painters','-depsc', FigFileName); close;
end
end
end
end
function [precip_ann_HighFreq, precip_ann_LowFreq] = AggregateIMFs(HistoricData, LowHighThresh, info)
% do a double aggregation:
% (i) for each subarea separately, aggregate across IMFs to create a single low
% frequency timeseries and a single high frequency timeseries for each subarea;
% (ii) for the low frequency only, aggregate across subareas to create a single timeseries.
% initialise arrays that will hold output data
precip_ann_HighFreq_array = HistoricData.precip_annual.Year;
precip_ann_LowFreq_array = HistoricData.precip_annual.Year;
% (i) for each subarea separately, aggregate across IMFs to create a single low
% frequency timeseries and a single high frequency timeseries for each subarea;
NumSubareas = size(info.SubareaList, 1);
for iSubarea = 1:NumSubareas
% isolate IMFs for this subarea
ThisSubarea = info.SubareaList{iSubarea};
this_IMF_set = HistoricData.precip_annual_IMFs.(ThisSubarea);
this_IMF_set = this_IMF_set(1:(end-1), :); % remove last column (residual) - see note** below
% do the aggregatation across IMFs
high = sum(this_IMF_set(1:LowHighThresh, :));
low = sum(this_IMF_set((LowHighThresh+1):end, :));
% add to output table
precip_ann_HighFreq_array = [precip_ann_HighFreq_array high'];
precip_ann_LowFreq_array = [precip_ann_LowFreq_array low'];
end
% ** note: the last IMF is not actually an IMF, it's the residual from
% the EMD process. The EMD process progressively removes oscillations,
% highest frequency first, but to do so it requires that at least one
% full cycle be contained in the historic record. If the lowest
% frequency osscilation contains less than one full cycle, it is not a
% true IMF and gets lumped in with the residual which may also contain
% a long term trend. If a trend is present (eg. due to climate change
% in the historic record), it is appropriate that it be removed here
% and not inform the final stochastic process, because no stress test
% stochastic timeseries ever has a trend in it - they are all
% stationary by design. Thus, we are interested only in oscillations,
% not trends.
% (ii) for the low frequency only, aggregate across subareas to create a single timeseries.
precip_ann_LowFreq_array(:, end+1) = nan; % create new column at end
NumYears = size(precip_ann_HighFreq_array, 1);
for iYear = 1:NumYears
values = precip_ann_LowFreq_array(iYear, 2:(1+NumSubareas));
weights = info.SubAreaDetails.weighting_lowfreq';
adopted = sum(values.*weights) / sum(weights);
precip_ann_LowFreq_array(iYear, end) = adopted;
end
% convert to tables
precip_ann_HighFreq = array2table(precip_ann_HighFreq_array, 'VariableNames', ['Year'; info.SubareaList]);
precip_ann_LowFreq = array2table(precip_ann_LowFreq_array, 'VariableNames', ['Year'; info.SubareaList; 'adopted_combined']);
end
function [imf_var, imf_period] = GetStats(imfs)
Numimfs = size(imfs,1);
% compute variance for each mode
for iMode = 1:Numimfs, imf_var(iMode) = var(imfs(iMode,:),0); end % zero: sample variance
% compute average period of each mode by examining zero crossings
for iMode = 1:Numimfs
crossings=0; first=0; last=0;
for k=2:size(imfs,2) % k = position in column
if imfs(iMode,k) * imfs(iMode,k-1)<0
crossings=crossings+1;
last=k;
if isequal(first,0)
first=k;
end
end
end
if last>first
imf_period(iMode) = (last-first)/((crossings-1)/2); % assume one data point per one unit of length
else
imf_period(iMode) = NaN;
end
end
end
function CreateFig1(R)
% Plot historic precip
figure(1);
NumIMFs=size(R.imfs,1);
subplot(NumIMFs+1,1,1)
plot(R.hist_data,'r')
ylabel('hist data (mm/yr)','FontSize',7)
set(gca,'XTickLabel',[], 'FontSize', 8)
title('Historic annual precipitation (red) split into intrinsic mode functions (blue)')
% Now plot IMFs
for iMode=1:NumIMFs
subplot(NumIMFs+1,1,iMode+1)
plot(R.imfs(iMode,:))
set(gca,'XTickLabel',[])
ylabel(['IMF' num2str(iMode) ' (mm/yr)'],'FontSize',7)
set(gca, 'FontSize', 8)
grid on;
yl(iMode, 1:2) = ylim;
end
% standardise y axes across all IMFs
y_lim_adopt = max(max(abs(yl(1:(NumIMFs-1), :))));
for iMode=1:(NumIMFs-1)
subplot(NumIMFs+1,1,iMode+1)
ylim([-y_lim_adopt y_lim_adopt]);
end
subplot(NumIMFs+1,1,NumIMFs+1);
ylim([-y_lim_adopt y_lim_adopt]+(mean(yl(NumIMFs, :))));
ylabel('Residual (mm/yr)','FontSize',7) % Rename bottom y-axis
end
function CreateFig2(R, N)
% Figure 2: variance vs average period
figure(2); hold on
% plot results for random noise
for iMode=1:size(N,2), scatter (N(iMode).imf_period', N(iMode).imf_var,4,[0.75 0.75 0.75],'+'); end
% plot results for historic data
for iMode=1:length(R.imf_period(~isnan(R.imf_period))), scatter (R.imf_period(iMode),R.imf_var(iMode),18,'red','filled'); end
% formatting
ylabel('variance','FontSize',8)
xlabel('average period (years)','FontSize',8) % one data point per year
set(gca, 'FontSize', 8)
set(gca,'xscale','log')
set(gca,'yscale','log')
title('Intrinsic Mode Functions: Variance vs average period','FontSize',11,'Interpreter', 'none')
end
function [modes,its]=ceemdan_v2014(x,Nstd,NR,MaxIter,SNRFlag, disp_toggle) % kf added disp_toggle
%Function for CEEMDAN
% This code downloaded January 2021 by Keirnan Fowler from:
% http://bioingenieria.edu.ar/grupos/ldnlys/metorres/metorres_files/ceemdan_v2014.m
%WARNING: for this code works it is necessary to include in the same
%directoy the file emd.m developed by Rilling and Flandrin.
%This file is available at %http://perso.ens-lyon.fr/patrick.flandrin/emd.html
%We use the default stopping criterion.
%We use the last modification: 3.2007
% Syntax
%modes=ceemdan(x,Nstd,NR,MaxIter,SNRFlag)
%[modes its]=ceemdan(x,Nstd,NR,MaxIter,SNRFlag)
% Description
%OUTPUT
%modes: contain the obtained modes in a matrix with the rows being the modes
%its: contain the sifting iterations needed for each mode for each realization (one row for each realization)
%INPUT
%x: signal to decompose
%Nstd: noise standard deviation
%NR: number of realizations
%MaxIter: maximum number of sifting iterations allowed.
%SNRFlag: if equals 1, then the SNR increases for every stage, as in [1].
% If equals 2, then the SNR is the same for all stages, as in [2].
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% The current is an improved version, introduced in:
%[1] Colominas MA, Schlotthauer G, Torres ME. "Improve complete ensemble EMD: A suitable tool for biomedical signal processing"
% Biomedical Signal Processing and Control vol. 14 pp. 19-29 (2014)
%The CEEMDAN algorithm was first introduced at ICASSP 2011, Prague, Czech Republic
%The authors will be thankful if the users of this code reference the work
%where the algorithm was first presented:
%[2] Torres ME, Colominas MA, Schlotthauer G, Flandrin P. "A Complete Ensemble Empirical Mode Decomposition with Adaptive Noise"
% Proc. 36th Int. Conf. on Acoustics, Speech and Signa Processing ICASSP 2011 (May 22-27, Prague, Czech Republic)
%Author: Marcelo A. Colominas
%contact: macolominas@bioingenieria.edu.ar
%Last version: 25 feb 2015
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
x=x(:)';
desvio_x=std(x);
x=x/desvio_x;
modes=zeros(size(x));
temp=zeros(size(x));
aux=zeros(size(x));
iter=zeros(NR,round(log2(length(x))+5));
for i=1:NR
white_noise{i}=randn(size(x));%creates the noise realizations
end;
for i=1:NR
modes_white_noise{i}=emd(white_noise{i});%calculates the modes of white gaussian noise
end;
for i=1:NR %calculates the first mode
xi=x+Nstd*modes_white_noise{i}(1,:)/std(modes_white_noise{i}(1,:));
[temp, o, it]=emd(xi,'MAXMODES',1,'MAXITERATIONS',MaxIter);
temp=temp(1,:);
aux=aux+(xi-temp)/NR;
iter(i,1)=it;
end;
modes= x-aux; %saves the first mode
medias = aux;
k=1;
aux=zeros(size(x));
es_imf = min(size(emd(medias(end,:),'MAXMODES',1,'MAXITERATIONS',MaxIter)));
while es_imf>1 %calculates the rest of the modes
for i=1:NR
tamanio=size(modes_white_noise{i});
if tamanio(1)>=k+1
noise=modes_white_noise{i}(k+1,:);
if SNRFlag == 2
noise=noise/std(noise); %adjust the std of the noise
end;
noise=Nstd*noise;
try
[temp,o,it]=emd(medias(end,:)+std(medias(end,:))*noise,'MAXMODES',1,'MAXITERATIONS',MaxIter);
catch
it=0;
if disp_toggle % added kf
disp('catch 1 '); disp(num2str(k));
end % added kf
temp=emd(medias(end,:)+std(medias(end,:))*noise,'MAXMODES',1,'MAXITERATIONS',MaxIter);
end;
temp=temp(end,:);
else
try
[temp, o, it]=emd(medias(end,:),'MAXMODES',1,'MAXITERATIONS',MaxIter);
catch
temp=emd(medias(end,:),'MAXMODES',1,'MAXITERATIONS',MaxIter);
it=0;
if disp_toggle % added kf
disp('catch 2 sin ruido')
end
end;
temp=temp(end,:);
end;
aux=aux+temp/NR;
iter(i,k+1)=it;
end;
modes=[modes;medias(end,:)-aux];
medias = [medias;aux];
aux=zeros(size(x));
k=k+1;
es_imf = min(size(emd(medias(end,:),'MAXMODES',1,'MAXITERATIONS',MaxIter)));
end;
modes = [modes;medias(end,:)];
modes=modes*desvio_x;
its=iter;
end
% all remaining functions were downloaded as January 2021 by Keirnan Fowler from:
% http://perso.ens-lyon.fr/patrick.flandrin/pack_emd.zip
% ref: 'emd.m'
function [imf,ort,nbits] = emd(varargin)
%EMD computes Empirical Mode Decomposition
%
%
% Syntax
%
%
% IMF = EMD(X)
% IMF = EMD(X,...,'Option_name',Option_value,...)
% IMF = EMD(X,OPTS)
% [IMF,ORT,NB_ITERATIONS] = EMD(...)
%
%
% Description
%
%
% IMF = EMD(X) where X is a real vector computes the Empirical Mode
% Decomposition [1] of X, resulting in a matrix IMF containing 1 IMF per row, the
% last one being the residue. The default stopping criterion is the one proposed
% in [2]:
%
% at each point, mean_amplitude < THRESHOLD2*envelope_amplitude
% &
% mean of boolean array {(mean_amplitude)/(envelope_amplitude) > THRESHOLD} < TOLERANCE
% &
% |#zeros-#extrema|<=1
%
% where mean_amplitude = abs(envelope_max+envelope_min)/2
% and envelope_amplitude = abs(envelope_max-envelope_min)/2
%
% IMF = EMD(X) where X is a complex vector computes Bivariate Empirical Mode
% Decomposition [3] of X, resulting in a matrix IMF containing 1 IMF per row, the
% last one being the residue. The default stopping criterion is similar to the
% one proposed in [2]:
%
% at each point, mean_amplitude < THRESHOLD2*envelope_amplitude
% &
% mean of boolean array {(mean_amplitude)/(envelope_amplitude) > THRESHOLD} < TOLERANCE
%
% where mean_amplitude and envelope_amplitude have definitions similar to the
% real case
%
% IMF = EMD(X,...,'Option_name',Option_value,...) sets options Option_name to
% the specified Option_value (see Options)
%
% IMF = EMD(X,OPTS) is equivalent to the above syntax provided OPTS is a struct
% object with field names corresponding to option names and field values being the
% associated values
%
% [IMF,ORT,NB_ITERATIONS] = EMD(...) returns an index of orthogonality
% ________
% _ |IMF(i,:).*IMF(j,:)|
% ORT = \ _____________________
% /
% ¯ || X ||²
% i~=j
%
% and the number of iterations to extract each mode in NB_ITERATIONS
%
%
% Options
%
%
% stopping criterion options:
%
% STOP: vector of stopping parameters [THRESHOLD,THRESHOLD2,TOLERANCE]
% if the input vector's length is less than 3, only the first parameters are
% set, the remaining ones taking default values.
% default: [0.05,0.5,0.05]
%
% FIX (int): disable the default stopping criterion and do exactly <FIX>
% number of sifting iterations for each mode
%
% FIX_H (int): disable the default stopping criterion and do <FIX_H> sifting
% iterations with |#zeros-#extrema|<=1 to stop [4]
%
% bivariate/complex EMD options:
%
% COMPLEX_VERSION: selects the algorithm used for complex EMD ([3])
% COMPLEX_VERSION = 1: "algorithm 1"
% COMPLEX_VERSION = 2: "algorithm 2" (default)
%
% NDIRS: number of directions in which envelopes are computed (default 4)
% rem: the actual number of directions (according to [3]) is 2*NDIRS
%
% other options:
%
% T: sampling times (line vector) (default: 1:length(x))
%
% MAXITERATIONS: maximum number of sifting iterations for the computation of each
% mode (default: 2000)
%
% MAXMODES: maximum number of imfs extracted (default: Inf)
%
% DISPLAY: if equals to 1 shows sifting steps with pause
% if equals to 2 shows sifting steps without pause (movie style)
% rem: display is disabled when the input is complex
%
% INTERP: interpolation scheme: 'linear', 'cubic', 'pchip' or 'spline' (default)
% see interp1 documentation for details
%
% MASK: masking signal used to improve the decomposition according to [5]
%
%
% Examples
%
%
%X = rand(1,512);
%
%IMF = emd(X);
%
%IMF = emd(X,'STOP',[0.1,0.5,0.05],'MAXITERATIONS',100);
%
%T=linspace(0,20,1e3);
%X = 2*exp(i*T)+exp(3*i*T)+.5*T;
%IMF = emd(X,'T',T);
%
%OPTIONS.DISLPAY = 1;
%OPTIONS.FIX = 10;
%OPTIONS.MAXMODES = 3;
%[IMF,ORT,NBITS] = emd(X,OPTIONS);
%
%
% References
%
%
% [1] N. E. Huang et al., "The empirical mode decomposition and the
% Hilbert spectrum for non-linear and non stationary time series analysis",
% Proc. Royal Soc. London A, Vol. 454, pp. 903-995, 1998
%
% [2] G. Rilling, P. Flandrin and P. Gonçalves
% "On Empirical Mode Decomposition and its algorithms",
% IEEE-EURASIP Workshop on Nonlinear Signal and Image Processing
% NSIP-03, Grado (I), June 2003
%
% [3] G. Rilling, P. Flandrin, P. Gonçalves and J. M. Lilly.,
% "Bivariate Empirical Mode Decomposition",
% Signal Processing Letters (submitted)
%
% [4] N. E. Huang et al., "A confidence limit for the Empirical Mode
% Decomposition and Hilbert spectral analysis",
% Proc. Royal Soc. London A, Vol. 459, pp. 2317-2345, 2003
%
% [5] R. Deering and J. F. Kaiser, "The use of a masking signal to improve
% empirical mode decomposition", ICASSP 2005
%
%
% See also
% emd_visu (visualization),
% emdc, emdc_fix (fast implementations of EMD),
% cemdc, cemdc_fix, cemdc2, cemdc2_fix (fast implementations of bivariate EMD),
% hhspectrum (Hilbert-Huang spectrum)
%
%
% G. Rilling, last modification: 3.2007
% gabriel.rilling@ens-lyon.fr
[x,t,sd,sd2,tol,MODE_COMPLEX,ndirs,display_sifting,sdt,sd2t,r,imf,k,nbit,NbIt,MAXITERATIONS,FIXE,FIXE_H,MAXMODES,INTERP,mask] = init(varargin{:});
if display_sifting
fig_h = figure;
end
%main loop : requires at least 3 extrema to proceed
while (~stop_EMD(r,MODE_COMPLEX,ndirs) && (k < MAXMODES+1 || MAXMODES == 0) && ~any(mask))
% current mode
m = r;
% mode at previous iteration
mp = m;
%computation of mean and stopping criterion
if FIXE
[stop_sift,moyenne] = stop_sifting_fixe(t,m,INTERP,MODE_COMPLEX,ndirs);
elseif FIXE_H
stop_count = 0;
[stop_sift,moyenne] = stop_sifting_fixe_h(t,m,INTERP,stop_count,FIXE_H,MODE_COMPLEX,ndirs);
else
[stop_sift,moyenne] = stop_sifting(m,t,sd,sd2,tol,INTERP,MODE_COMPLEX,ndirs);
end
% in case the current mode is so small that machine precision can cause
% spurious extrema to appear
if (max(abs(m))) < (1e-10)*(max(abs(x)))
if ~stop_sift
warning('emd:warning','forced stop of EMD : too small amplitude')
else
disp('forced stop of EMD : too small amplitude')
end
break
end
% sifting loop
while ~stop_sift && nbit<MAXITERATIONS
if(~MODE_COMPLEX && nbit>MAXITERATIONS/5 && mod(nbit,floor(MAXITERATIONS/10))==0 && ~FIXE && nbit > 100)
disp(['mode ',int2str(k),', iteration ',int2str(nbit)])
if exist('s','var')
disp(['stop parameter mean value : ',num2str(s)])
end
[im,iM] = extr(m);
disp([int2str(sum(m(im) > 0)),' minima > 0; ',int2str(sum(m(iM) < 0)),' maxima < 0.'])
end
%sifting
m = m - moyenne;
%computation of mean and stopping criterion
if FIXE
[stop_sift,moyenne] = stop_sifting_fixe(t,m,INTERP,MODE_COMPLEX,ndirs);
elseif FIXE_H
[stop_sift,moyenne,stop_count] = stop_sifting_fixe_h(t,m,INTERP,stop_count,FIXE_H,MODE_COMPLEX,ndirs);
else
[stop_sift,moyenne,s] = stop_sifting(m,t,sd,sd2,tol,INTERP,MODE_COMPLEX,ndirs);
end
% display
if display_sifting && ~MODE_COMPLEX
NBSYM = 2;
[indmin,indmax] = extr(mp);
[tmin,tmax,mmin,mmax] = boundary_conditions(indmin,indmax,t,mp,mp,NBSYM);
envminp = interp1(tmin,mmin,t,INTERP);
envmaxp = interp1(tmax,mmax,t,INTERP);
envmoyp = (envminp+envmaxp)/2;
if FIXE || FIXE_H
display_emd_fixe(t,m,mp,r,envminp,envmaxp,envmoyp,nbit,k,display_sifting)
else
sxp=2*(abs(envmoyp))./(abs(envmaxp-envminp));
sp = mean(sxp);
display_emd(t,m,mp,r,envminp,envmaxp,envmoyp,s,sp,sxp,sdt,sd2t,nbit,k,display_sifting,stop_sift)
end
end
mp = m;
nbit=nbit+1;
NbIt=NbIt+1;
if(nbit==(MAXITERATIONS-1) && ~FIXE && nbit > 100)
if exist('s','var')
warning('emd:warning',['forced stop of sifting : too many iterations... mode ',int2str(k),'. stop parameter mean value : ',num2str(s)])
else
warning('emd:warning',['forced stop of sifting : too many iterations... mode ',int2str(k),'.'])
end
end
end % sifting loop
imf(k,:) = m;
if display_sifting
disp(['mode ',int2str(k),' stored'])
end
nbits(k) = nbit;
k = k+1;
r = r - m;
nbit=0;
end %main loop
if any(r) && ~any(mask)
imf(k,:) = r;
end
ort = io(x,imf);
if display_sifting
close
end
end
function stop = stop_EMD(r,MODE_COMPLEX,ndirs)
%---------------------------------------------------------------------------------------------------
% tests if there are enough (3) extrema to continue the decomposition
if MODE_COMPLEX
for k = 1:ndirs
phi = (k-1)*pi/ndirs;
[indmin,indmax] = extr(real(exp(i*phi)*r));
ner(k) = length(indmin) + length(indmax);
end
stop = any(ner < 3);
else
[indmin,indmax] = extr(r);
ner = length(indmin) + length(indmax);
stop = ner < 3;
end
end
function [envmoy,nem,nzm,amp] = mean_and_amplitude(m,t,INTERP,MODE_COMPLEX,ndirs)
%---------------------------------------------------------------------------------------------------
% computes the mean of the envelopes and the mode amplitude estimate
NBSYM = 2;
if MODE_COMPLEX
switch MODE_COMPLEX
case 1
for k = 1:ndirs
phi = (k-1)*pi/ndirs;
y = real(exp(-i*phi)*m);
[indmin,indmax,indzer] = extr(y);
nem(k) = length(indmin)+length(indmax);
nzm(k) = length(indzer);
[tmin,tmax,zmin,zmax] = boundary_conditions(indmin,indmax,t,y,m,NBSYM);
envmin(k,:) = interp1(tmin,zmin,t,INTERP);
envmax(k,:) = interp1(tmax,zmax,t,INTERP);
end
envmoy = mean((envmin+envmax)/2,1);
if nargout > 3
amp = mean(abs(envmax-envmin),1)/2;
end
case 2
for k = 1:ndirs
phi = (k-1)*pi/ndirs;
y = real(exp(-i*phi)*m);
[indmin,indmax,indzer] = extr(y);
nem(k) = length(indmin)+length(indmax);
nzm(k) = length(indzer);
[tmin,tmax,zmin,zmax] = boundary_conditions(indmin,indmax,t,y,y,NBSYM);
envmin(k,:) = exp(i*phi)*interp1(tmin,zmin,t,INTERP);
envmax(k,:) = exp(i*phi)*interp1(tmax,zmax,t,INTERP);
end
envmoy = mean((envmin+envmax),1);
if nargout > 3
amp = mean(abs(envmax-envmin),1)/2;
end
end
else
[indmin,indmax,indzer] = extr(m);
nem = length(indmin)+length(indmax);
nzm = length(indzer);
[tmin,tmax,mmin,mmax] = boundary_conditions(indmin,indmax,t,m,m,NBSYM);
envmin = interp1(tmin,mmin,t,INTERP);
envmax = interp1(tmax,mmax,t,INTERP);
envmoy = (envmin+envmax)/2;
if nargout > 3
amp = mean(abs(envmax-envmin),1)/2;
end
end
end
function [stop,envmoy,s] = stop_sifting(m,t,sd,sd2,tol,INTERP,MODE_COMPLEX,ndirs)
%-------------------------------------------------------------------------------
% default stopping criterion
try
[envmoy,nem,nzm,amp] = mean_and_amplitude(m,t,INTERP,MODE_COMPLEX,ndirs);
sx = abs(envmoy)./amp;
s = mean(sx);
stop = ~((mean(sx > sd) > tol | any(sx > sd2)) & (all(nem > 2)));
if ~MODE_COMPLEX
stop = stop && ~(abs(nzm-nem)>1);
end
catch
stop = 1;
envmoy = zeros(1,length(m));
s = NaN;
end
end
function [stop,moyenne]= stop_sifting_fixe(t,m,INTERP,MODE_COMPLEX,ndirs)
%-------------------------------------------------------------------------------
% stopping criterion corresponding to option FIX
try
moyenne = mean_and_amplitude(m,t,INTERP,MODE_COMPLEX,ndirs);
stop = 0;
catch
moyenne = zeros(1,length(m));
stop = 1;
end
end
function [stop,moyenne,stop_count]= stop_sifting_fixe_h(t,m,INTERP,stop_count,FIXE_H,MODE_COMPLEX,ndirs)
%-------------------------------------------------------------------------------
% stopping criterion corresponding to option FIX_H
try
[moyenne,nem,nzm] = mean_and_amplitude(m,t,INTERP,MODE_COMPLEX,ndirs);
if (all(abs(nzm-nem)>1))
stop = 0;
stop_count = 0;
else
stop_count = stop_count+1;
stop = (stop_count == FIXE_H);
end
catch
moyenne = zeros(1,length(m));
stop = 1;
end
end
function display_emd(t,m,mp,r,envmin,envmax,envmoy,s,sb,sx,sdt,sd2t,nbit,k,display_sifting,stop_sift)
%-------------------------------------------------------------------------------
% displays the progression of the decomposition with the default stopping criterion
subplot(4,1,1)
plot(t,mp);hold on;
plot(t,envmax,'--k');plot(t,envmin,'--k');plot(t,envmoy,'r');
title(['IMF ',int2str(k),'; iteration ',int2str(nbit),' before sifting']);
set(gca,'XTick',[])
hold off
subplot(4,1,2)
plot(t,sx)
hold on
plot(t,sdt,'--r')
plot(t,sd2t,':k')
title('stop parameter')
set(gca,'XTick',[])
hold off
subplot(4,1,3)
plot(t,m)
title(['IMF ',int2str(k),'; iteration ',int2str(nbit),' after sifting']);
set(gca,'XTick',[])
subplot(4,1,4);
plot(t,r-m)
title('residue');
disp(['stop parameter mean value : ',num2str(sb),' before sifting and ',num2str(s),' after'])
if stop_sift
disp('last iteration for this mode')
end
if display_sifting == 2
pause(0.01)
else
pause
end
end
function display_emd_fixe(t,m,mp,r,envmin,envmax,envmoy,nbit,k,display_sifting)
%---------------------------------------------------------------------------------------------------
% displays the progression of the decomposition with the FIX and FIX_H stopping criteria
subplot(3,1,1)
plot(t,mp);hold on;
plot(t,envmax,'--k');plot(t,envmin,'--k');plot(t,envmoy,'r');
title(['IMF ',int2str(k),'; iteration ',int2str(nbit),' before sifting']);
set(gca,'XTick',[])
hold off
subplot(3,1,2)
plot(t,m)
title(['IMF ',int2str(k),'; iteration ',int2str(nbit),' after sifting']);
set(gca,'XTick',[])
subplot(3,1,3);
plot(t,r-m)
title('residue');
if display_sifting == 2
pause(0.01)
else
pause
end
end
function [tmin,tmax,zmin,zmax] = boundary_conditions(indmin,indmax,t,x,z,nbsym)
%---------------------------------------------------------------------------------------
% defines new extrema points to extend the interpolations at the edges of the
% signal (mainly mirror symmetry)
lx = length(x);
if (length(indmin) + length(indmax) < 3)
error('not enough extrema')
end
% boundary conditions for interpolations :
if indmax(1) < indmin(1)
if x(1) > x(indmin(1))
lmax = fliplr(indmax(2:min(end,nbsym+1)));
lmin = fliplr(indmin(1:min(end,nbsym)));
lsym = indmax(1);
else
lmax = fliplr(indmax(1:min(end,nbsym)));
lmin = [fliplr(indmin(1:min(end,nbsym-1))),1];
lsym = 1;
end
else
if x(1) < x(indmax(1))
lmax = fliplr(indmax(1:min(end,nbsym)));
lmin = fliplr(indmin(2:min(end,nbsym+1)));
lsym = indmin(1);
else
lmax = [fliplr(indmax(1:min(end,nbsym-1))),1];
lmin = fliplr(indmin(1:min(end,nbsym)));
lsym = 1;
end
end
if indmax(end) < indmin(end)
if x(end) < x(indmax(end))
rmax = fliplr(indmax(max(end-nbsym+1,1):end));
rmin = fliplr(indmin(max(end-nbsym,1):end-1));
rsym = indmin(end);
else
rmax = [lx,fliplr(indmax(max(end-nbsym+2,1):end))];
rmin = fliplr(indmin(max(end-nbsym+1,1):end));
rsym = lx;
end
else
if x(end) > x(indmin(end))
rmax = fliplr(indmax(max(end-nbsym,1):end-1));
rmin = fliplr(indmin(max(end-nbsym+1,1):end));
rsym = indmax(end);
else
rmax = fliplr(indmax(max(end-nbsym+1,1):end));
rmin = [lx,fliplr(indmin(max(end-nbsym+2,1):end))];
rsym = lx;
end
end
tlmin = 2*t(lsym)-t(lmin);
tlmax = 2*t(lsym)-t(lmax);
trmin = 2*t(rsym)-t(rmin);
trmax = 2*t(rsym)-t(rmax);
% in case symmetrized parts do not extend enough
if tlmin(1) > t(1) || tlmax(1) > t(1)
if lsym == indmax(1)
lmax = fliplr(indmax(1:min(end,nbsym)));
else
lmin = fliplr(indmin(1:min(end,nbsym)));
end
if lsym == 1
error('bug')
end
lsym = 1;
tlmin = 2*t(lsym)-t(lmin);
tlmax = 2*t(lsym)-t(lmax);
end
if trmin(end) < t(lx) || trmax(end) < t(lx)
if rsym == indmax(end)
rmax = fliplr(indmax(max(end-nbsym+1,1):end));
else
rmin = fliplr(indmin(max(end-nbsym+1,1):end));
end
if rsym == lx
error('bug')
end
rsym = lx;
trmin = 2*t(rsym)-t(rmin);
trmax = 2*t(rsym)-t(rmax);
end
zlmax =z(lmax);
zlmin =z(lmin);
zrmax =z(rmax);
zrmin =z(rmin);
tmin = [tlmin t(indmin) trmin];
tmax = [tlmax t(indmax) trmax];
zmin = [zlmin z(indmin) zrmin];
zmax = [zlmax z(indmax) zrmax];
end
function [indmin, indmax, indzer] = extr(x,t)
%---------------------------------------------------------------------------------------------------
%extracts the indices of extrema
if(nargin==1)
t=1:length(x);
end
m = length(x);
if nargout > 2
x1=x(1:m-1);
x2=x(2:m);
indzer = find(x1.*x2<0);
if any(x == 0)
iz = find( x==0 );
indz = [];
if any(diff(iz)==1)
zer = x == 0;
dz = diff([0 zer 0]);
debz = find(dz == 1);
finz = find(dz == -1)-1;
indz = round((debz+finz)/2);
else
indz = iz;
end
indzer = sort([indzer indz]);
end
end
d = diff(x);
n = length(d);
d1 = d(1:n-1);
d2 = d(2:n);
indmin = find(d1.*d2<0 & d1<0)+1;
indmax = find(d1.*d2<0 & d1>0)+1;
% when two or more successive points have the same value we consider only one extremum in the middle of the constant area
% (only works if the signal is uniformly sampled)
if any(d==0)
imax = [];
imin = [];
bad = (d==0);
dd = diff([0 bad 0]);
debs = find(dd == 1);
fins = find(dd == -1);
if debs(1) == 1
if length(debs) > 1
debs = debs(2:end);
fins = fins(2:end);
else
debs = [];
fins = [];
end
end
if length(debs) > 0
if fins(end) == m
if length(debs) > 1
debs = debs(1:(end-1));
fins = fins(1:(end-1));
else
debs = [];
fins = [];
end
end
end
lc = length(debs);
if lc > 0
for k = 1:lc
if d(debs(k)-1) > 0
if d(fins(k)) < 0
imax = [imax round((fins(k)+debs(k))/2)];
end
else
if d(fins(k)) > 0
imin = [imin round((fins(k)+debs(k))/2)];
end
end
end
end
if length(imax) > 0
indmax = sort([indmax imax]);
end
if length(imin) > 0
indmin = sort([indmin imin]);
end
end
end
function ort = io(x,imf)
% ort = IO(x,imf) computes the index of orthogonality
%
% inputs : - x : analyzed signal
% - imf : empirical mode decomposition
n = size(imf,1);
s = 0;
for i = 1:n
for j =1:n
if i~=j
s = s + abs(sum(imf(i,:).*conj(imf(j,:)))/sum(x.^2));
end
end
end
ort = 0.5*s;
end
function [x,t,sd,sd2,tol,MODE_COMPLEX,ndirs,display_sifting,sdt,sd2t,r,imf,k,nbit,NbIt,MAXITERATIONS,FIXE,FIXE_H,MAXMODES,INTERP,mask] = init(varargin)
x = varargin{1};
if nargin == 2
if isstruct(varargin{2})
inopts = varargin{2};
else
error('when using 2 arguments the first one is the analyzed signal X and the second one is a struct object describing the options')
end
elseif nargin > 2
try
inopts = struct(varargin{2:end});
catch
error('bad argument syntax')
end
end
% default for stopping
defstop = [0.05,0.5,0.05];
opt_fields = {'t','stop','display','maxiterations','fix','maxmodes','interp','fix_h','mask','ndirs','complex_version'};
defopts.stop = defstop;
defopts.display = 0;
defopts.t = 1:max(size(x));
defopts.maxiterations = 2000;
defopts.fix = 0;
defopts.maxmodes = 0;
defopts.interp = 'spline';
defopts.fix_h = 0;
defopts.mask = 0;
defopts.ndirs = 4;
defopts.complex_version = 2;
opts = defopts;
if(nargin==1)
inopts = defopts;
elseif nargin == 0
error('not enough arguments')
end
names = fieldnames(inopts);
for nom = names'
if ~any(strcmpi(char(nom), opt_fields))
error(['bad option field name: ',char(nom)])
end
if ~isempty(eval(['inopts.',char(nom)])) % empty values are discarded
eval(['opts.',lower(char(nom)),' = inopts.',char(nom),';'])
end
end
t = opts.t;
stop = opts.stop;
display_sifting = opts.display;
MAXITERATIONS = opts.maxiterations;
FIXE = opts.fix;
MAXMODES = opts.maxmodes;
INTERP = opts.interp;
FIXE_H = opts.fix_h;
mask = opts.mask;
ndirs = opts.ndirs;
complex_version = opts.complex_version;
if ~isvector(x)
error('X must have only one row or one column')
end
if size(x,1) > 1
x = x.';
end
if ~isvector(t)
error('option field T must have only one row or one column')
end
if ~isreal(t)
error('time instants T must be a real vector')
end
if size(t,1) > 1
t = t';
end
if (length(t)~=length(x))
error('X and option field T must have the same length')
end
if ~isvector(stop) || length(stop) > 3
error('option field STOP must have only one row or one column of max three elements')
end
if ~all(isfinite(x))
error('data elements must be finite')
end
if size(stop,1) > 1
stop = stop';
end
L = length(stop);
if L < 3
stop(3)=defstop(3);
end
if L < 2
stop(2)=defstop(2);
end
if ~ischar(INTERP) || ~any(strcmpi(INTERP,{'linear','cubic','spline'}))
error('INTERP field must be ''linear'', ''cubic'', ''pchip'' or ''spline''')
end
%special procedure when a masking signal is specified
if any(mask)
if ~isvector(mask) || length(mask) ~= length(x)
error('masking signal must have the same dimension as the analyzed signal X')
end
if size(mask,1) > 1
mask = mask.';
end
opts.mask = 0;
imf1 = emd(x+mask,opts);
imf2 = emd(x-mask,opts);
if size(imf1,1) ~= size(imf2,1)
warning('emd:warning',['the two sets of IMFs have different sizes: ',int2str(size(imf1,1)),' and ',int2str(size(imf2,1)),' IMFs.'])
end
S1 = size(imf1,1);
S2 = size(imf2,1);
if S1 ~= S2
if S1 < S2
tmp = imf1;
imf1 = imf2;
imf2 = tmp;
end
imf2(max(S1,S2),1) = 0;
end
imf = (imf1+imf2)/2;
end
sd = stop(1);
sd2 = stop(2);
tol = stop(3);
lx = length(x);
sdt = sd*ones(1,lx);
sd2t = sd2*ones(1,lx);
if FIXE
MAXITERATIONS = FIXE;
if FIXE_H
error('cannot use both ''FIX'' and ''FIX_H'' modes')
end
end
MODE_COMPLEX = ~isreal(x)*complex_version;
if MODE_COMPLEX && complex_version ~= 1 && complex_version ~= 2
error('COMPLEX_VERSION parameter must equal 1 or 2')
end
% number of extrema and zero-crossings in residual
ner = lx;
nzr = lx;
r = x;
if ~any(mask) % if a masking signal is specified "imf" already exists at this stage
imf = [];
end
k = 1;
% iterations counter for extraction of 1 mode
nbit=0;
% total iterations counter
NbIt=0;
end