我正在尝试使用MATLAB2014b中的PARTICLESWARM函数来解决优化问题。借助于开源ECG工具箱,1.0版,2006年11月根据GNU通用公共许可证发布。
该代码的主要目的是找到心电图模型的最佳参数,以达到最小的模型误差。
我使用PSO作为优化器来找到这些最佳参数。出现错误:
Error using particleswarm>makeState (line 683)
Objective function must return scalar values.
Error in particleswarm>pswcore (line 164)
state = makeState(nvars,lbMatrix,ubMatrix,objFcn,options);
Error in particleswarm (line 146)
[x,fval,exitFlag,output] = pswcore(objFcn,nvars,lbRow,ubRow,output,options);
Error in ECGOptimizeModel (line 16)
param = particleswarm(@(InitParams) ECGModelError(InitParams,x,meanphase,0),length(InitParams),InitParams-2,InitParams+2,options)
Error in MY_ECGBeatFitterAuto (line 139)
[params model er] = ECGOptimizeModel(y, indx, meanphase);cannot continue
我的职能在这里:
function b = BaseLine1(x,L,approach)
%
% b = BaseLine1(x,L,approach),
% Baseline wander extraction from biomedical recordings, using a single
% stage of median or moving average filtering.
%
% inputs:
% x: vector or matrix of noisy data (channels x samples)
% L: averaging window length (in samples)
% approach:
% 'md': median filtering
% 'mn': moving average
%
% output:
% b: vector or matrix of baseline wanders (channels x samples)
%
%
% Open Source ECG Toolbox, version 1.0, November 2006
% Released under the GNU General Public License
% Copyright (C) 2006 Reza Sameni
% Sharif University of Technology, Tehran, Iran -- GIPSA-Lab, INPG, Grenoble, France
% reza.sameni@gmail.com
% 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 2 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.
N = size(x,2);
b = zeros(size(x));
flen = floor(L/2);
if (strcmp(approach,'mn')) % moving average filter
for j = 1:N,
index = max(j-flen,1):min(j+flen,N);
b(:,j) = mean(x(:,index),2);
end
elseif (strcmp(approach,'md')) % median filter
for j = 1:N,
index = max(j-flen,1):min(j+flen,N);
b(:,j) = median(x(:,index),2);
end
end
function y = LPFilter(x,fc)
%
% y = LPFilter(x,fc),
% Second order zero-phase Lowpass filter
%
% inputs:
% x: vector or matrix of input data (channels x samples)
% fc: -3dB cut-off frequency normalized by the sampling frequency
%
% output:
% y: vector or matrix of filtered data (channels x samples)
%
%
% Open Source ECG Toolbox, version 1.0, November 2006
% Released under the GNU General Public License
% Copyright (C) 2006 Reza Sameni
% Sharif University of Technology, Tehran, Iran -- GIPSA-Lab, INPG, Grenoble, France
% reza.sameni@gmail.com
% 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 2 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.
k = .7; % cut-off value
alpha = (1-k*cos(2*pi*fc)-sqrt(2*k*(1-cos(2*pi*fc))-k^2*sin(2*pi*fc)^2))/(1-k);
y = zeros(size(x));
for i = 1:size(x,1)
y(i,:) = filtfilt(1-alpha,[1 -alpha],x(i,:));
end
function [ECGmean,ECGsd,meanPhase] = MeanECGExtraction(x,phase,bins,flag)
%
% [ECGmean,ECGsd,meanPhase] = MeanECGExtraction(x,phase,bins,flag)
% Calculation of the mean and SD of ECG waveforms in different beats
%
% inputs:
% x: input ECG signal
% phase: ECG phase
% bins: number of desired phase bins
% flag
% 1: aligns the baseline on zero, by using the mean of the first 10%
% segment of the calculated mean ECG beat
% 0: no baseline alignment
%
% outputs:
% ECGmean: mean ECG beat
% ECGsd: standard deviation of ECG beats
% meanPhase: the corresponding phase for one ECG beat
%
%
% Open Source ECG Toolbox, version 2.0, March 2008
% Released under the GNU General Public License
% Copyright (C) 2008 Reza Sameni
% Sharif University of Technology, Tehran, Iran -- LIS-INPG, Grenoble, France
% reza.sameni@gmail.com
% 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 2 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.
meanPhase = zeros(1,bins);
ECGmean = zeros(1,bins);
ECGsd = zeros(1,bins);
I = find( phase>=(pi-pi/bins) | phase<(-pi+pi/bins) );
if(~isempty(I))
meanPhase(1) = -pi;
ECGmean(1) = mean(x(I));
ECGsd(1) = std(x(I));
else
meanPhase(1) = 0;
ECGmean(1) =0;
ECGsd(1) = -1;
end
for i = 1 : bins-1;
I = find( phase >= 2*pi*(i-0.5)/bins-pi & phase < 2*pi*(i+0.5)/bins-pi );
if(~isempty(I))
meanPhase(i + 1) = mean(phase(I));
ECGmean(i + 1) = mean(x(I));
ECGsd(i + 1) = std(x(I));
else
meanPhase(i + 1) = 0;
ECGmean(i + 1) = 0;
ECGsd(i + 1) = -1;
end
end
K = find(ECGsd==-1);
for i = 1:length(K),
switch K(i)
case 1
meanPhase(K(i)) = -pi;
ECGmean(K(i)) = ECGmean(K(i)+1);
ECGsd(K(i)) = ECGsd(K(i)+1);
case bins
meanPhase(K(i)) = pi;
ECGmean(K(i)) = ECGmean(K(i)-1);
ECGsd(K(i)) = ECGsd(K(i)-1);
otherwise
meanPhase(K(i)) = mean([meanPhase(K(i)-1),meanPhase(K(i)+1)]);
ECGmean(K(i)) = mean([ECGmean(K(i)-1),ECGmean(K(i)+1)]);
ECGsd(K(i)) = mean([ECGsd(K(i)-1),ECGsd(K(i)+1)]);
end
end
if(flag==1)
ECGmean = ECGmean - mean(ECGmean(1:ceil(length(ECGmean)/10)));
end
function phase = PhaseShifting(phasein,teta)
%
% phase = PhaseShifting(phasein,teta),
% Phase shifter.
%
% inputs:
% phasein: calculated ECG phase
% teta: desired phase shift. teta>0 and teta<0 corresponds with phase leads
% and phase lags, respectively.
%
% output:
% phase: the shifted phase.
phase = phasein + teta;
phase = mod(phase + pi, 2*pi) - pi;
function [phase phasepos] = PhaseCalculation(peaks)
phasepos = zeros(1,length(peaks));
I = find(peaks);
for i = 1:length(I)-1;
m = I(i+1) - I(i);
phasepos(I(i)+1:I(i+1)) = 2*pi/m : 2*pi/m : 2*pi;
end
m = I(2) - I(1);
L = length(phasepos(1:I(1)));
phasepos(1:I(1)) = 2*pi-(L-1)*2*pi/m:2*pi/m:2*pi;
m = I(end) - I(end-1);
L = length(phasepos(I(end)+1:end));
phasepos(I(end)+1:end) = 2*pi/m:2*pi/m:L*2*pi/m;
phasepos = mod(phasepos,2*pi);
phase = phasepos;
I = find(phasepos>pi);
phase(I) = phasepos(I) - 2*pi;
function E = ECGModelError(X,ECGmn,Phasemn,flag);
%
% Synthetic ECG model error
%
% Open Source ECG Toolbox, version 1.0, November 2006
% Released under the GNU General Public License
% Copyright (C) 2006 Reza Sameni
% Sharif University of Technology, Tehran, Iran -- LIS-INPG, Grenoble, France
% reza.sameni@gmail.com
% 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 2 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, write to the
% Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
% MA 02110-1301, USA.
L = (length(X)/3);
alphai = X(1:L);
bi = X(L+1:2*L);
tetai = X(2*L+1:3*L);
Z = zeros(size(ECGmn));
for j = 1:length(alphai),
dtetai = rem(Phasemn - tetai(j) + pi,2*pi)-pi;
Z = Z + alphai(j) .* exp(-dtetai .^2 ./ (2*bi(j) .^ 2));
end
if(flag==0)
E = (Z-ECGmn);
elseif(flag==1)
E = (Z);
end
function [params model er] = ECGOptimizeModel(x, indexes, meanphase)
tetai = meanphase(indexes);
alphai = 1*x(indexes); %1.2
bi = .01*ones(size(alphai));%0.04
% options = optimset('TolX',1e-4,'TolFun',1e-4,'MaxIter',100);
%%%options = optimset('TolX',1e-4,'TolFun',1e-4,'MaxIter',50,'Display','off');
InitParams = [alphai bi tetai];
%params = nlinfit(meanphase,x,@ECGModel,InitParams,options);
%%%params = lsqnonlin(@(InitParams) ECGModelError(InitParams,x,meanphase,0),InitParams,InitParams-2,InitParams+2,options);
rng default
options = optimoptions('particleswarm','SwarmSize',50,'HybridFcn',@fminsearch);
%fun =@ECGModelError(InitParams,x,meanphase,0);
param = particleswarm(@(InitParams) ECGModelError(InitParams,x,meanphase,0),length(InitParams),InitParams-2,InitParams+2,options)
% Model0 = ECGModelError(InitParams,x,meanphase,1);
model = ECGModelError(params,x,meanphase,1);
er = 100*mean((x-model).^2)/mean(x.^2);
clc
clear all
close all;
**% THE MAIN CODE**
load('SampleECG2.mat'); data = data(1:15000,3)';
fs = 1000;
t = [0:length(data)-1]/fs;
f = 1; % approximate R-peak frequency
bsline = LPFilter(data,.7/fs); % baseline wander removal (may be replaced by other approaches)
x = data - bsline +.5*randn(size(data));
peaks = PeakDetection(x,f/fs); % peak detection
%peaks = PeakDetection2(x,fs);
[phase phasepos] = PhaseCalculation(peaks); % phase calculation
%% peak detection (Pan-Tompkins)
%peaks2 = PeakDetection2(x,fs); % peak detection (Pan-Tompkins)
%figure;
%plot(t,x,'b');
%hold on
%plot(t,peaks2.*x,'go');
%xlabel('time (sec.)');
%ylabel('ECG Peaks(Pan-Tompkins)')
%%
teta = 0; % desired phase shift
pphase = PhaseShifting(phase,teta); % phase shifting
bins = fs/2; % number of phase bins
[ECGmean,ECGsd,meanphase] = MeanECGExtraction(x,pphase,bins,1);
%% ECGBeatFitterAuto(ECGmean,meanphase)
% inputs:
% ECGmean: the input ECG beat
% meanphase: the phase signal of the ECG beat
% approach: 'fixed number' or 'min error'
% stopth: stopping threshold error percentage
% divisions: number of divisions for random point approach
% maxit: maximum number of iterations for randomized methods
% energyth: the energy threshold used for detecting peaks (default: 0.001)
% wlen: peak search window length (default: 0.01*SignalLength)
% beat length
N = length(ECGmean);
% idle segment at the beginning of the beat
L0 = ceil(N/10);
stopth = .001; % percentage of error
num = 10;
maxitr = 10;
approach = 'min error'; % fixed number/min error
energyth = 0.0001;
th=energyth;
wlen = 3;
%% preprocessing
base = median(ECGmean(1:L0));
x = ECGmean - base;
y = BaseLine1(x,5,'md');%LPFilter(d,25/N);
% y = wden(x,'rigrsure','s','mln',6,'coif5');
y = LPFilter(y,45/N);
% % % figure;
% % % hold on;
% % % plot(x);
% % % plot(y,'r');
% % % grid
%% approach,'min error'
if(strcmp(approach,'min error'))
% zero crossing detection
zc = [0 y(1:end-1).*y(2:end)];
I = find(zc<=0);
E = sum(x.^2);
II = [];
m0 = find(I>L0,1);
m = m0;
for i = m0:length(I),
ind = I(m):I(i);
if(sum(x(ind).^2)>th*E)
if(isempty(II))
II = [I(m) I(i)];
else
II = [II I(i)];
end
m = m + 1;
end
end
%//////////////////////////////////////////////////////////////////////////
% local peak detection
pk = zeros(1,N);
for i = L0:N-L0,
ind = max(i-wlen,1):min(i+wlen,N);
if(y(i)==max(y(ind)) && y(i)>0 && std(y(ind))~=0) % local max with positive amplitudes
pk(i) = 1;
elseif(y(i)==min(y(ind)) && y(i)<0 && std(y(ind))~=0) % local min with negative amplitudes
pk(i) = 1;
end
end
J = find(pk);
E = sum(y.^2);
JJ = [];
m0 = find(J>L0,1);
m = m0;
for i = m0:length(J),
ind = J(m):J(i);
if(sum(y(ind).^2)>th*E)
if(isempty(JJ))
JJ = [J(m) J(i)];
else
JJ = [JJ J(i)];
end
m = m + 1;
end
end
%//////////////////////////////////////////////////////////////////////////
% merge the results
K = sort([I J]);
KK = sort([II JJ]);
% uniform points
UU = L0:round(N/num):N-L0;
%plot(zc),hold on,plot(JJ,zc(JJ),'m*')
%% start optimizing
done = logical(0);
% peaks alone
if(~done)
indx = JJ;
[params model er] = ECGOptimizeModel(y, indx, meanphase);
indexes = indx;
if(er<stopth)
method = 0;
done = 1;
end
end
if(~done)
disp('Info: The specified requirements have not been met with fixed error model; continuing with random point approach.');
approach = 'fixed number';
end
elseif(strcmp(approach,'fixed number'))
%% uniform points
UU = L0:round((N-2*L0)/num):N-L0;
er = 100;
for i = 1:maxitr,
indx = UU + round((rand(size(UU))-.5)*N/10);
indx = sort(indx);
indx = indx(indx>=1);
indx = indx(indx<=N);
[params_ model_ er_] = ECGOptimizeModel(y, indx, meanphase);
if(er_<er)
indexes = indx;
params = params_;
model = model_;
er = er_;
if(er<stopth)
method = 13;
done = 1;
break;
end
end
end
end
disp(['Final model fitting error percentage: ',num2str(er)]);
% plot the results
n = 1:length(x);
figure;
plot(n,x);
hold on;
plot(n,y,'r');
plot(n,model,'k','LineWidth',2);
plot(n(indexes),x(indexes),'ro','linewidth',2);
grid
% % % grid
disp(['Error = ',num2str(er),'%']);
%% display the optimal parameters
L = length(params)/3;
ai = params(1:L);
bi = params(L+1:2*L);
tetai = params(2*L+1:3*L);
figure;
plot(t,data*6/max(data),'b');
hold on
plot(t,peaks*2,'ro');
plot(t,phase,'c--','linewidth',1);
plot(t,pphase,'g','linewidth',1);
grid;
xlabel('time (sec.)');
legend('Scaled ECG','ECG Peaks','phase','shifted phase');
figure;
errorbar(meanphase,ECGmean,ECGsd/2);
hold on;
plot(meanphase,ECGmean,'r');
legend('SD Bar','Mean ECG');
xlabel('phase (rads.)');
grid
% % % plot(d,'g');
% % % plot(dd,'m');
% % % plot(ddd,'k');
% % % plot(n(I),y(I),'ro','linewidth',3);
% % % plot(n(II),y(II),'go','linewidth',3);
% % % plot(n(J),y(J),'ro','linewidth',3);
% % % plot(n(JJ),y(JJ),'go','linewidth',3);
% % % plot(n(K),y(K),'ro','linewidth',1);
% % % plot(n(KK),y(KK),'go','linewidth',3);
% % % plot(n(UU),y(UU),'go','linewidth',3);
% % % grid
数据:https://drive.google.com/open?id=1OieiPKJemlAqPXkhje9s0d5b9uCy0etb