function varargout = manual_check(varargin)
% MANUAL_CHECK MATLAB code for manual_check.fig
% MANUAL_CHECK, by itself, creates a new MANUAL_CHECK or raises the existing
% singleton*.
%
% H = MANUAL_CHECK returns the handle to a new MANUAL_CHECK or the handle to
% the existing singleton*.
%
% MANUAL_CHECK('CALLBACK',hObject,eventData,handles,...) calls the local
% function named CALLBACK in MANUAL_CHECK.M with the given input arguments.
%
% MANUAL_CHECK('Property','Value',...) creates a new MANUAL_CHECK or raises the
% existing singleton*. Starting from the left, property value pairs are
% applied to the GUI before manual_check_OpeningFcn gets called. An
% unrecognized property name or invalid value makes property application
% stop. All inputs are passed to manual_check_OpeningFcn via varargin.
%
% *See GUI Options on GUIDE's Tools menu. Choose "GUI allows only one
% instance to run (singleton)".
%
% See also: GUIDE, GUIDATA, GUIHANDLES
% Edit the above text to modify the response to help manual_check
% Last Modified by GUIDE v2.5 29-Oct-2014 11:41:26
% Begin initialization code - DO NOT EDIT
gui_Singleton = 1;
gui_State = struct('gui_Name', mfilename, ...
'gui_Singleton', gui_Singleton, ...
'gui_OpeningFcn', @manual_check_OpeningFcn, ...
'gui_OutputFcn', @manual_check_OutputFcn, ...
'gui_LayoutFcn', [] , ...
'gui_Callback', []);
if nargin && ischar(varargin{1})
gui_State.gui_Callback = str2func(varargin{1});
end
if nargout
[varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
else
gui_mainfcn(gui_State, varargin{:});
end
% End initialization code - DO NOT EDIT
% --- Executes just before manual_check is made visible.
function manual_check_OpeningFcn(hObject, eventdata, handles, varargin)
% This function has no output args, see OutputFcn.
% hObject handle to figure
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
% varargin command line arguments to manual_check (see VARARGIN)
% Choose default command line output for manual_check
handles.output = hObject;
% Update handles structure
guidata(hObject, handles);
% UIWAIT makes manual_check wait for user response (see UIRESUME)
% uiwait(handles.figure1);
% --- Outputs from this function are returned to the command line.
function varargout = manual_check_OutputFcn(hObject, eventdata, handles)
% varargout cell array for returning output args (see VARARGOUT);
% hObject handle to figure
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
% Get default command line output from handles structure
varargout{1} = handles.output;
% --- Executes on button press in bt_open.
function bt_open_Callback(hObject, eventdata, handles)
% hObject handle to bt_open (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
global signal peaks current nbeats foldername filename accepted rejected rejectpoint
[filename,foldername,~] = uigetfile('*.csv');
if isequal(filename,0)|| isequal(foldername,0)
return;
end
set(handles.txt_filename, 'String', filename);
rawdata = csvread(strcat(foldername,'\',filename));
filtered = ECG_filter(rawdata);
signal = filtered(64:end);
peaks = ECG_Peak_Detection(signal);
if(peaks(1)<64)
peaks(1) = [];
end
if(peaks(end)>length(signal)-96)
peaks(end) = 0;
end
nbeats = length(peaks);
accepted = [];
rejected = 0;
current = 1;
if(nbeats<1)
return;
elseif(nbeats>1)
set(handles.bt_next,'Enable', 'on');
end
set(handles.bt_previous,'Enable', 'off');
set(handles.bt_open,'Enable', 'off');
%set(handles.bt_accept,'Enable', 'on');
%set(handles.bt_reject,'Enable', 'on');
axes(handles.axes1);
OneBeat = plot(1:160, signal(peaks(1)-63:peaks(1)+96),'b-', 64,signal(peaks(1)), 'r^' );
set(handles.axes1,'XLim',[0 160]);
set(handles.axes1,'YLim',[-15000 25000]);
set(handles.txt_total,'String',num2str(nbeats));
set(handles.txt_current,'String',num2str(1));
set(handles.txt_accepted,'String',num2str(0));
set(handles.txt_rejected,'String',num2str(0));
rejectpoint = zeros(1,length(signal));
for i=1:length(peaks)
rejectpoint(peaks(i))=1;
end
function txt_filename_Callback(hObject, eventdata, handles)
% hObject handle to txt_filename (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
% Hints: get(hObject,'String') returns contents of txt_filename as text
% str2double(get(hObject,'String')) returns contents of txt_filename as a double
% --- Executes during object creation, after setting all properties.
function txt_filename_CreateFcn(hObject, eventdata, handles)
% hObject handle to txt_filename (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles empty - handles not created until after all CreateFcns called
% Hint: edit controls usually have a white background on Windows.
% See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
set(hObject,'BackgroundColor','white');
end
% --- Executes on button press in bt_accept.
function bt_accept_Callback(hObject, eventdata, handles)
% hObject handle to bt_accept (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
global accepted current peaks
accepted = [accepted;peaks(current)];
current = current+1;
set(handles.txt_accepted, 'String', num2str(length(accepted)));
if strcmp(get(handles.bt_previous,'Enable'), 'off')
set(handles.bt_previous,'Enable', 'on')
end
if(current > length(peaks))
save(accepted);
set(handles.bt_next,'Enable', 'off');
set(handles.bt_previous,'Enable', 'off');
set(handles.bt_accept,'Enable', 'off');
set(handles.bt_reject,'Enable', 'off');
set(handles.bt_open,'Enable', 'on');
else
showBeat(current,handles);
end
% --- Executes on button press in bt_reject.
function bt_reject_Callback(hObject, eventdata, handles)
% hObject handle to bt_reject (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
global accepted current peaks rejected
current = current+1;
rejected = rejected + 1;
set(handles.txt_rejected, 'String', num2str(rejected));
if strcmp(get(handles.bt_previous,'Enable'), 'off')
set(handles.bt_previous,'Enable', 'on')
end
if(current > length(peaks))
save(accepted);
set(handles.bt_next,'Enable', 'off');
set(handles.bt_previous,'Enable', 'off');
set(handles.bt_accept,'Enable', 'off');
set(handles.bt_reject,'Enable', 'off');
set(handles.bt_open,'Enable', 'on');
else
showBeat(current,handles);
end
% --- Executes on button press in bt_previous.
function bt_previous_Callback(hObject, eventdata, handles)
% hObject handle to bt_previous (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
global current accepted
if (current>1)
current = current-1;
accepted(end) = [];
showBeat(current,handles);
end
if(current==1)
accepted(end) = [];
showBeat(current,handles);
set(handles.bt_previous,'Enable', 'off'); %%%%%%%%%%%%%%%%%modify
end
% --- Executes on button press in bt_next.
function bt_next_Callback(hObject, eventdata, handles)
% hObject handle to bt_next (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
global current peaks num signal
len = 1360;
if(current==1)
current =2;
end
num=0;
if (current<length(peaks)) % solve the edge problem
num =0;
while(peaks(current+num)+96<peaks(current)+len-63)
num=num+1;
if(current+num == length(peaks))
current=current -1
break
end
end
showBeat(current,handles);
axes1_ButtonDownFcn(handles.axes1, [], handles)
current = current+num;
end
% --- Executes on key press with focus on figure1 or any of its controls.
function figure1_WindowKeyPressFcn(hObject, eventdata, handles)
% hObject handle to figure1 (see GCBO)
% eventdata structure with the following fields (see FIGURE)
% Key: name of the key that was pressed, in lower case
% Character: character interpretation of the key(s) that was pressed
% Modifier: name(s) of the modifier key(s) (i.e., control, shift) pressed
% handles structure with handles and user data (see GUIDATA)
switch eventdata.Key
case 'uparrow'
bt_accept_Callback(handles.bt_accept, [], handles);
case 'downarrow'
bt_reject_Callback(handles.bt_reject, [], handles);
case 'leftarrow'
bt_previous_Callback(handles.bt_previous, [], handles);
case 'rightarrow'
bt_next_Callback(handles.bt_next, [], handles);
end
% --- Executes on mouse press over axes background.
function axes1_ButtonDownFcn(hObject, eventdata, handles)
% hObject handle to axes1 (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
%axes1_ButtonDownFcn(handles.axes1, [], handles)
global pointX current peaks rejectpoint num
hold on
disp('单击鼠标左键点取需要的点');
but=1;
while but==1
dist =[];
[xi,yi,but]=ginput(1);
if (yi<-1.5)
break
end
plot(xi,yi,'bo')
for i=1:num+1
dist =[dist norm(xi-pointX(i))]; %judge the nearest point base on x-label
end
[C,I]=min(dist);
I
rejectpoint(peaks(current+I))= -1 ;
end
hold off
% --- Executes on button press in pushbutton11.
function pushbutton11_Callback(hObject, eventdata, handles)
% hObject handle to pushbutton11 (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
global rejectpoint
xlswrite('label.csv', rejectpoint') %write the data into file
%%%%%%---------------------------- subroutines ----------------------%%%%%%
function [] = save(accepted)
global signal foldername filename peaks
accepted = unique(accepted);
data = [-ones(length(signal),1)*32768,signal];
data(accepted,1) = 1;
[~,name,~] = fileparts(filename);
csvwrite(strcat(foldername,name,'_chked.csv' ),data);
fid = fopen(strcat(foldername,'\summary.txt'),'a+');
fprintf(fid, '%26s %6d %6d %8.2f \n', name, length(peaks),length(accepted),length(accepted)/length(peaks));
fclose(fid);
function [] = showBeat(current,handles)
global signal peaks pointX pointY num
axes(handles.axes1);
%
% current
% num
%
s = signal(peaks(current)-63:peaks(current+num)+96); %show one more peak = num +1
s = detrend(s);
len = length(s); %indicate the size of the windows can change
p = []; %p store the x-value of each peaks
pointX = [64];
pointY= [s(64)];
for i=current:current+num
p = [p peaks(i+1)-peaks(current)+64]; %sizeof p = num+1
end
% length(p)
hold off
plot(1:len, s(1:len),'b-')
hold on
for k= 1:num
pointX = [pointX p(k)] ;
pointY = [pointY s(p(k))];
end
% length(pointX) %size = num +1
% pointX
for kk= 1:num
plot(pointX(kk),pointY(kk),'r^')% plot the peak point
end
plot(pointX(num+1),pointY(num+1),'g^') %plot the first peak in the next frame
Asort=sort(pointY);
set(handles.axes1,'XLim',[0 len]);
%set(handles.axes1,'YLim',[-15000 25000]);
set(handles.axes1,'YLim',[-15000 Asort(length(Asort)-0)*1.1]);
set(handles.txt_current,'String',num2str(current));
function [filtered] = ECG_filter(rawdata)
% band pass fir filter, order:127, pass band: [3Hz ~ 40Hz]
fir_coef = fir1(127,[1.0/125,40/125]);
ecgFir = filter(fir_coef, 1, rawdata);
ecgFirDc = filter(ones(1,128)./128, 1, ecgFir);
filtered = ecgFir - ecgFirDc;
function peak = ECG_Peak_Detection(ECG_raw)
%%% parameter setting
Fs = 250; % sampling frequency
Sig_max = 5000;
Sig_min = 0.0;
hpf_len = 40;
bpf_len = 42;
lpf_len = 11;
QRSwindow = round(240*Fs/1000); %240ms
MIN_QRS_interval = 240*Fs/1000; %240ms
local_max_window_len = 15;
% coefficient for threshold update
coef_thr_udt_k = .5;
coef_thr_udt_b = .1;
% coefficient for threshold min update
coef_thr_min_a = 0.05; %0.005;
coef_thr_min_b = 0.95;
coef_thr_min_c = 1-coef_thr_min_b;
coef_thr_min_d = 0.2;
% coefficient for ecg_lpf_max/min_lim
coef_ecg_lpf_max_lim = 0.1;
coef_ecg_lpf_min_lim = 0.1;
%%% Initialization
% coef_bpf = fir1(bpf_len-1,[10 25]/(Fs/2));
% coef_lpf = fir1(lpf_len-1, 10/Fs/2);
coef_bpf = [0.0013 0.0007 0.0001 -0.0001 0.0005 0.0025 0.0057 0.0089 0.0097 0.0052 -0.0065 -0.0251 -0.0470 -0.0657 -0.0735 -0.0642 -0.0359 0.0075 0.0566 0.0993 0.1240 0.1240 0.0993 0.0566 0.0075 -0.0359 -0.0642 -0.0735 -0.0657 -0.0470 -0.0251 -0.0065 0.0052 0.0097 0.0089 0.0057 0.0025 0.0005 -0.0001 0.0001 0.0007 0.0013];
coef_lpf = [0.0144 0.0304 0.0724 0.1245 0.1668 0.1830 0.1668 0.1245 0.0724 0.0304 0.0144];
ECG_hpf = zeros(size(ECG_raw));
ECG_bpf = zeros(size(ECG_raw));
ECG_abs = zeros(size(ECG_raw));
ECG_lpf = zeros(size(ECG_raw));
thr_c = 0; % current threshold
thr_n = 0; % next threshold
thr_p1 = 0; % 1st previous threshold
thr_p2 = 0; % 2nd previous threshold
thr_hist = zeros(size(ECG_raw)); % history of threshold
QRS_raw = zeros(ceil(size(ECG_raw)/QRSwindow)); % QRS (R-peak) index for raw ECG data
QRS_lpf = zeros(ceil(size(ECG_raw)/QRSwindow)); % QRS (R-peak) index for lpf ECG data
QRS_num = 0;
newQRS = 0;
ecg_lpf_max_lim = coef_ecg_lpf_max_lim*(Sig_max-Sig_min);
ecg_lpf_min_lim = coef_ecg_lpf_min_lim/(Sig_max-Sig_min);
thr_min = coef_thr_min_a*(Sig_max-Sig_min);
thr_min_hist = zeros(size(ECG_raw));
%%% ECG algorithm start
for i=2:length(ECG_raw)/QRSwindow-2
newQRS = 0;
index_s = (i-1)*QRSwindow+1; % start index for i-th processing unit
index_e = i*QRSwindow; % end index for i-th processing unit
% threshold calculation
thr_p2 = thr_p1;
thr_p1 = thr_c;
thr_c = thr_p1 - coef_thr_udt_k*(thr_p1 - thr_min) - coef_thr_udt_b*( thr_p1 - thr_p2 );
thr_n = thr_c - coef_thr_udt_k*(thr_c - thr_min) - coef_thr_udt_b*( thr_c - thr_p1 );
thr_hist(index_s:index_e) = thr_c - (thr_c-thr_n)./(QRSwindow+1).*[0:QRSwindow-1];
thr_min_hist(index_s:index_e) = thr_min;
% R-peak (QRS) detection
% high pass filtering
for j=0:QRSwindow-1
ECG_hpf(index_s+j) = ECG_raw(index_s+j) - mean( ECG_raw([-floor(hpf_len/2)+1:ceil(hpf_len/2)]+index_s+j) );
end
% band pass filtering
for j=0:QRSwindow-1
% fprintf('%d, %d\n', length(coef_bpf), length(ECG_raw( [-floor(bpf_len/2)+1:ceil(bpf_len/2)]+index_s+j)));
ECG_bpf(index_s+j) = coef_bpf * ECG_raw( [-floor(bpf_len/2)+1:ceil(bpf_len/2)]+index_s+j);
end
% differentiation and abs operation
ECG_abs(index_s:index_e) = abs( ECG_bpf(index_s:index_e) - ECG_bpf(index_s-1:index_e-1) );
% low pass filtering
for j=0:QRSwindow-1
ECG_lpf(index_s+j) = coef_lpf * ECG_abs([-floor(lpf_len/2)+1:ceil(lpf_len/2)]+index_s+j);
end
[ecg_lpf_max_val, ecg_lpf_max_idx] = max(ECG_lpf(index_s:index_e));
ecg_lpf_max_idx = ecg_lpf_max_idx + index_s - 1;
% Start of R-peak (QRS) detection
if (QRS_num == 0) || (ecg_lpf_max_val > thr_hist(ecg_lpf_max_idx))
[local_max_val, local_max_idx] = max( ECG_hpf([-local_max_window_len:local_max_window_len]+ecg_lpf_max_idx));
local_max_idx = local_max_idx + ecg_lpf_max_idx - (local_max_window_len+1);
[local_min_val, local_min_idx] = min( ECG_hpf([-local_max_window_len:local_max_window_len]+ecg_lpf_max_idx));
local_min_idx = local_min_idx + ecg_lpf_max_idx - (local_max_window_len+1);
if local_max_val*2 < abs(local_min_val)
Rpeak_idx_tmp = local_min_idx;
Rpeak_val_tmp = ECG_raw(local_max_idx);
else
Rpeak_idx_tmp = local_max_idx;
Rpeak_val_tmp = ECG_raw(local_min_idx);
end
if QRS_num == 0
newQRS = 1;
QRS_num = QRS_num+1;
elseif Rpeak_idx_tmp - QRS_raw(QRS_num) > MIN_QRS_interval
newQRS = 1;
QRS_num = QRS_num+1;
elseif ecg_lpf_max_val > ecg_lpf_max_val_p
newQRS = 1;
end
end
if newQRS == 1
QRS_lpf(QRS_num) = ecg_lpf_max_idx;
QRS_raw(QRS_num) = Rpeak_idx_tmp;
thr_c = ECG_lpf(ecg_lpf_max_idx);
ecg_lpf_max_val_p = ecg_lpf_max_val;
if ecg_lpf_max_lim > ecg_lpf_max_val > ecg_lpf_min_lim
thr_min = coef_thr_min_b*thr_min + coef_thr_min_c*coef_thr_min_d*ecg_lpf_max_val;
end
end
end
peak = QRS_raw(1:QRS_num);
% MANUAL_CHECK MATLAB code for manual_check.fig
% MANUAL_CHECK, by itself, creates a new MANUAL_CHECK or raises the existing
% singleton*.
%
% H = MANUAL_CHECK returns the handle to a new MANUAL_CHECK or the handle to
% the existing singleton*.
%
% MANUAL_CHECK('CALLBACK',hObject,eventData,handles,...) calls the local
% function named CALLBACK in MANUAL_CHECK.M with the given input arguments.
%
% MANUAL_CHECK('Property','Value',...) creates a new MANUAL_CHECK or raises the
% existing singleton*. Starting from the left, property value pairs are
% applied to the GUI before manual_check_OpeningFcn gets called. An
% unrecognized property name or invalid value makes property application
% stop. All inputs are passed to manual_check_OpeningFcn via varargin.
%
% *See GUI Options on GUIDE's Tools menu. Choose "GUI allows only one
% instance to run (singleton)".
%
% See also: GUIDE, GUIDATA, GUIHANDLES
% Edit the above text to modify the response to help manual_check
% Last Modified by GUIDE v2.5 29-Oct-2014 11:41:26
% Begin initialization code - DO NOT EDIT
gui_Singleton = 1;
gui_State = struct('gui_Name', mfilename, ...
'gui_Singleton', gui_Singleton, ...
'gui_OpeningFcn', @manual_check_OpeningFcn, ...
'gui_OutputFcn', @manual_check_OutputFcn, ...
'gui_LayoutFcn', [] , ...
'gui_Callback', []);
if nargin && ischar(varargin{1})
gui_State.gui_Callback = str2func(varargin{1});
end
if nargout
[varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
else
gui_mainfcn(gui_State, varargin{:});
end
% End initialization code - DO NOT EDIT
% --- Executes just before manual_check is made visible.
function manual_check_OpeningFcn(hObject, eventdata, handles, varargin)
% This function has no output args, see OutputFcn.
% hObject handle to figure
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
% varargin command line arguments to manual_check (see VARARGIN)
% Choose default command line output for manual_check
handles.output = hObject;
% Update handles structure
guidata(hObject, handles);
% UIWAIT makes manual_check wait for user response (see UIRESUME)
% uiwait(handles.figure1);
% --- Outputs from this function are returned to the command line.
function varargout = manual_check_OutputFcn(hObject, eventdata, handles)
% varargout cell array for returning output args (see VARARGOUT);
% hObject handle to figure
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
% Get default command line output from handles structure
varargout{1} = handles.output;
% --- Executes on button press in bt_open.
function bt_open_Callback(hObject, eventdata, handles)
% hObject handle to bt_open (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
global signal peaks current nbeats foldername filename accepted rejected rejectpoint
[filename,foldername,~] = uigetfile('*.csv');
if isequal(filename,0)|| isequal(foldername,0)
return;
end
set(handles.txt_filename, 'String', filename);
rawdata = csvread(strcat(foldername,'\',filename));
filtered = ECG_filter(rawdata);
signal = filtered(64:end);
peaks = ECG_Peak_Detection(signal);
if(peaks(1)<64)
peaks(1) = [];
end
if(peaks(end)>length(signal)-96)
peaks(end) = 0;
end
nbeats = length(peaks);
accepted = [];
rejected = 0;
current = 1;
if(nbeats<1)
return;
elseif(nbeats>1)
set(handles.bt_next,'Enable', 'on');
end
set(handles.bt_previous,'Enable', 'off');
set(handles.bt_open,'Enable', 'off');
%set(handles.bt_accept,'Enable', 'on');
%set(handles.bt_reject,'Enable', 'on');
axes(handles.axes1);
OneBeat = plot(1:160, signal(peaks(1)-63:peaks(1)+96),'b-', 64,signal(peaks(1)), 'r^' );
set(handles.axes1,'XLim',[0 160]);
set(handles.axes1,'YLim',[-15000 25000]);
set(handles.txt_total,'String',num2str(nbeats));
set(handles.txt_current,'String',num2str(1));
set(handles.txt_accepted,'String',num2str(0));
set(handles.txt_rejected,'String',num2str(0));
rejectpoint = zeros(1,length(signal));
for i=1:length(peaks)
rejectpoint(peaks(i))=1;
end
function txt_filename_Callback(hObject, eventdata, handles)
% hObject handle to txt_filename (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
% Hints: get(hObject,'String') returns contents of txt_filename as text
% str2double(get(hObject,'String')) returns contents of txt_filename as a double
% --- Executes during object creation, after setting all properties.
function txt_filename_CreateFcn(hObject, eventdata, handles)
% hObject handle to txt_filename (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles empty - handles not created until after all CreateFcns called
% Hint: edit controls usually have a white background on Windows.
% See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
set(hObject,'BackgroundColor','white');
end
% --- Executes on button press in bt_accept.
function bt_accept_Callback(hObject, eventdata, handles)
% hObject handle to bt_accept (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
global accepted current peaks
accepted = [accepted;peaks(current)];
current = current+1;
set(handles.txt_accepted, 'String', num2str(length(accepted)));
if strcmp(get(handles.bt_previous,'Enable'), 'off')
set(handles.bt_previous,'Enable', 'on')
end
if(current > length(peaks))
save(accepted);
set(handles.bt_next,'Enable', 'off');
set(handles.bt_previous,'Enable', 'off');
set(handles.bt_accept,'Enable', 'off');
set(handles.bt_reject,'Enable', 'off');
set(handles.bt_open,'Enable', 'on');
else
showBeat(current,handles);
end
% --- Executes on button press in bt_reject.
function bt_reject_Callback(hObject, eventdata, handles)
% hObject handle to bt_reject (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
global accepted current peaks rejected
current = current+1;
rejected = rejected + 1;
set(handles.txt_rejected, 'String', num2str(rejected));
if strcmp(get(handles.bt_previous,'Enable'), 'off')
set(handles.bt_previous,'Enable', 'on')
end
if(current > length(peaks))
save(accepted);
set(handles.bt_next,'Enable', 'off');
set(handles.bt_previous,'Enable', 'off');
set(handles.bt_accept,'Enable', 'off');
set(handles.bt_reject,'Enable', 'off');
set(handles.bt_open,'Enable', 'on');
else
showBeat(current,handles);
end
% --- Executes on button press in bt_previous.
function bt_previous_Callback(hObject, eventdata, handles)
% hObject handle to bt_previous (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
global current accepted
if (current>1)
current = current-1;
accepted(end) = [];
showBeat(current,handles);
end
if(current==1)
accepted(end) = [];
showBeat(current,handles);
set(handles.bt_previous,'Enable', 'off'); %%%%%%%%%%%%%%%%%modify
end
% --- Executes on button press in bt_next.
function bt_next_Callback(hObject, eventdata, handles)
% hObject handle to bt_next (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
global current peaks num signal
len = 1360;
if(current==1)
current =2;
end
num=0;
if (current<length(peaks)) % solve the edge problem
num =0;
while(peaks(current+num)+96<peaks(current)+len-63)
num=num+1;
if(current+num == length(peaks))
current=current -1
break
end
end
showBeat(current,handles);
axes1_ButtonDownFcn(handles.axes1, [], handles)
current = current+num;
end
% --- Executes on key press with focus on figure1 or any of its controls.
function figure1_WindowKeyPressFcn(hObject, eventdata, handles)
% hObject handle to figure1 (see GCBO)
% eventdata structure with the following fields (see FIGURE)
% Key: name of the key that was pressed, in lower case
% Character: character interpretation of the key(s) that was pressed
% Modifier: name(s) of the modifier key(s) (i.e., control, shift) pressed
% handles structure with handles and user data (see GUIDATA)
switch eventdata.Key
case 'uparrow'
bt_accept_Callback(handles.bt_accept, [], handles);
case 'downarrow'
bt_reject_Callback(handles.bt_reject, [], handles);
case 'leftarrow'
bt_previous_Callback(handles.bt_previous, [], handles);
case 'rightarrow'
bt_next_Callback(handles.bt_next, [], handles);
end
% --- Executes on mouse press over axes background.
function axes1_ButtonDownFcn(hObject, eventdata, handles)
% hObject handle to axes1 (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
%axes1_ButtonDownFcn(handles.axes1, [], handles)
global pointX current peaks rejectpoint num
hold on
disp('单击鼠标左键点取需要的点');
but=1;
while but==1
dist =[];
[xi,yi,but]=ginput(1);
if (yi<-1.5)
break
end
plot(xi,yi,'bo')
for i=1:num+1
dist =[dist norm(xi-pointX(i))]; %judge the nearest point base on x-label
end
[C,I]=min(dist);
I
rejectpoint(peaks(current+I))= -1 ;
end
hold off
% --- Executes on button press in pushbutton11.
function pushbutton11_Callback(hObject, eventdata, handles)
% hObject handle to pushbutton11 (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
global rejectpoint
xlswrite('label.csv', rejectpoint') %write the data into file
%%%%%%---------------------------- subroutines ----------------------%%%%%%
function [] = save(accepted)
global signal foldername filename peaks
accepted = unique(accepted);
data = [-ones(length(signal),1)*32768,signal];
data(accepted,1) = 1;
[~,name,~] = fileparts(filename);
csvwrite(strcat(foldername,name,'_chked.csv' ),data);
fid = fopen(strcat(foldername,'\summary.txt'),'a+');
fprintf(fid, '%26s %6d %6d %8.2f \n', name, length(peaks),length(accepted),length(accepted)/length(peaks));
fclose(fid);
function [] = showBeat(current,handles)
global signal peaks pointX pointY num
axes(handles.axes1);
%
% current
% num
%
s = signal(peaks(current)-63:peaks(current+num)+96); %show one more peak = num +1
s = detrend(s);
len = length(s); %indicate the size of the windows can change
p = []; %p store the x-value of each peaks
pointX = [64];
pointY= [s(64)];
for i=current:current+num
p = [p peaks(i+1)-peaks(current)+64]; %sizeof p = num+1
end
% length(p)
hold off
plot(1:len, s(1:len),'b-')
hold on
for k= 1:num
pointX = [pointX p(k)] ;
pointY = [pointY s(p(k))];
end
% length(pointX) %size = num +1
% pointX
for kk= 1:num
plot(pointX(kk),pointY(kk),'r^')% plot the peak point
end
plot(pointX(num+1),pointY(num+1),'g^') %plot the first peak in the next frame
Asort=sort(pointY);
set(handles.axes1,'XLim',[0 len]);
%set(handles.axes1,'YLim',[-15000 25000]);
set(handles.axes1,'YLim',[-15000 Asort(length(Asort)-0)*1.1]);
set(handles.txt_current,'String',num2str(current));
function [filtered] = ECG_filter(rawdata)
% band pass fir filter, order:127, pass band: [3Hz ~ 40Hz]
fir_coef = fir1(127,[1.0/125,40/125]);
ecgFir = filter(fir_coef, 1, rawdata);
ecgFirDc = filter(ones(1,128)./128, 1, ecgFir);
filtered = ecgFir - ecgFirDc;
function peak = ECG_Peak_Detection(ECG_raw)
%%% parameter setting
Fs = 250; % sampling frequency
Sig_max = 5000;
Sig_min = 0.0;
hpf_len = 40;
bpf_len = 42;
lpf_len = 11;
QRSwindow = round(240*Fs/1000); %240ms
MIN_QRS_interval = 240*Fs/1000; %240ms
local_max_window_len = 15;
% coefficient for threshold update
coef_thr_udt_k = .5;
coef_thr_udt_b = .1;
% coefficient for threshold min update
coef_thr_min_a = 0.05; %0.005;
coef_thr_min_b = 0.95;
coef_thr_min_c = 1-coef_thr_min_b;
coef_thr_min_d = 0.2;
% coefficient for ecg_lpf_max/min_lim
coef_ecg_lpf_max_lim = 0.1;
coef_ecg_lpf_min_lim = 0.1;
%%% Initialization
% coef_bpf = fir1(bpf_len-1,[10 25]/(Fs/2));
% coef_lpf = fir1(lpf_len-1, 10/Fs/2);
coef_bpf = [0.0013 0.0007 0.0001 -0.0001 0.0005 0.0025 0.0057 0.0089 0.0097 0.0052 -0.0065 -0.0251 -0.0470 -0.0657 -0.0735 -0.0642 -0.0359 0.0075 0.0566 0.0993 0.1240 0.1240 0.0993 0.0566 0.0075 -0.0359 -0.0642 -0.0735 -0.0657 -0.0470 -0.0251 -0.0065 0.0052 0.0097 0.0089 0.0057 0.0025 0.0005 -0.0001 0.0001 0.0007 0.0013];
coef_lpf = [0.0144 0.0304 0.0724 0.1245 0.1668 0.1830 0.1668 0.1245 0.0724 0.0304 0.0144];
ECG_hpf = zeros(size(ECG_raw));
ECG_bpf = zeros(size(ECG_raw));
ECG_abs = zeros(size(ECG_raw));
ECG_lpf = zeros(size(ECG_raw));
thr_c = 0; % current threshold
thr_n = 0; % next threshold
thr_p1 = 0; % 1st previous threshold
thr_p2 = 0; % 2nd previous threshold
thr_hist = zeros(size(ECG_raw)); % history of threshold
QRS_raw = zeros(ceil(size(ECG_raw)/QRSwindow)); % QRS (R-peak) index for raw ECG data
QRS_lpf = zeros(ceil(size(ECG_raw)/QRSwindow)); % QRS (R-peak) index for lpf ECG data
QRS_num = 0;
newQRS = 0;
ecg_lpf_max_lim = coef_ecg_lpf_max_lim*(Sig_max-Sig_min);
ecg_lpf_min_lim = coef_ecg_lpf_min_lim/(Sig_max-Sig_min);
thr_min = coef_thr_min_a*(Sig_max-Sig_min);
thr_min_hist = zeros(size(ECG_raw));
%%% ECG algorithm start
for i=2:length(ECG_raw)/QRSwindow-2
newQRS = 0;
index_s = (i-1)*QRSwindow+1; % start index for i-th processing unit
index_e = i*QRSwindow; % end index for i-th processing unit
% threshold calculation
thr_p2 = thr_p1;
thr_p1 = thr_c;
thr_c = thr_p1 - coef_thr_udt_k*(thr_p1 - thr_min) - coef_thr_udt_b*( thr_p1 - thr_p2 );
thr_n = thr_c - coef_thr_udt_k*(thr_c - thr_min) - coef_thr_udt_b*( thr_c - thr_p1 );
thr_hist(index_s:index_e) = thr_c - (thr_c-thr_n)./(QRSwindow+1).*[0:QRSwindow-1];
thr_min_hist(index_s:index_e) = thr_min;
% R-peak (QRS) detection
% high pass filtering
for j=0:QRSwindow-1
ECG_hpf(index_s+j) = ECG_raw(index_s+j) - mean( ECG_raw([-floor(hpf_len/2)+1:ceil(hpf_len/2)]+index_s+j) );
end
% band pass filtering
for j=0:QRSwindow-1
% fprintf('%d, %d\n', length(coef_bpf), length(ECG_raw( [-floor(bpf_len/2)+1:ceil(bpf_len/2)]+index_s+j)));
ECG_bpf(index_s+j) = coef_bpf * ECG_raw( [-floor(bpf_len/2)+1:ceil(bpf_len/2)]+index_s+j);
end
% differentiation and abs operation
ECG_abs(index_s:index_e) = abs( ECG_bpf(index_s:index_e) - ECG_bpf(index_s-1:index_e-1) );
% low pass filtering
for j=0:QRSwindow-1
ECG_lpf(index_s+j) = coef_lpf * ECG_abs([-floor(lpf_len/2)+1:ceil(lpf_len/2)]+index_s+j);
end
[ecg_lpf_max_val, ecg_lpf_max_idx] = max(ECG_lpf(index_s:index_e));
ecg_lpf_max_idx = ecg_lpf_max_idx + index_s - 1;
% Start of R-peak (QRS) detection
if (QRS_num == 0) || (ecg_lpf_max_val > thr_hist(ecg_lpf_max_idx))
[local_max_val, local_max_idx] = max( ECG_hpf([-local_max_window_len:local_max_window_len]+ecg_lpf_max_idx));
local_max_idx = local_max_idx + ecg_lpf_max_idx - (local_max_window_len+1);
[local_min_val, local_min_idx] = min( ECG_hpf([-local_max_window_len:local_max_window_len]+ecg_lpf_max_idx));
local_min_idx = local_min_idx + ecg_lpf_max_idx - (local_max_window_len+1);
if local_max_val*2 < abs(local_min_val)
Rpeak_idx_tmp = local_min_idx;
Rpeak_val_tmp = ECG_raw(local_max_idx);
else
Rpeak_idx_tmp = local_max_idx;
Rpeak_val_tmp = ECG_raw(local_min_idx);
end
if QRS_num == 0
newQRS = 1;
QRS_num = QRS_num+1;
elseif Rpeak_idx_tmp - QRS_raw(QRS_num) > MIN_QRS_interval
newQRS = 1;
QRS_num = QRS_num+1;
elseif ecg_lpf_max_val > ecg_lpf_max_val_p
newQRS = 1;
end
end
if newQRS == 1
QRS_lpf(QRS_num) = ecg_lpf_max_idx;
QRS_raw(QRS_num) = Rpeak_idx_tmp;
thr_c = ECG_lpf(ecg_lpf_max_idx);
ecg_lpf_max_val_p = ecg_lpf_max_val;
if ecg_lpf_max_lim > ecg_lpf_max_val > ecg_lpf_min_lim
thr_min = coef_thr_min_b*thr_min + coef_thr_min_c*coef_thr_min_d*ecg_lpf_max_val;
end
end
end
peak = QRS_raw(1:QRS_num);