image thumbnail
from MLIB - toolbox for analyzing spike data by Maik Stüttgen
Set of functions for the basic analysis of spike data from neurophysiological experiments

checkunit.m
function c = checkunit(waveforms,varargin)
% c = checkunit(waveforms,varargin)
% this function performs a quality check on a set of sorted waveforms
%
% MANDATORY INPUT
% waveforms     a matrix whose rows are events and whose columns are ticks (or vice versa -
%               checkunit.m assumes that the longer dimension represents separate waveforms)
%
% OPTIONAL INPUTS
% markvec       vector of markers of the units in the channel; should be of the same size as waveforms
% target        which marker should be analyzed
% timevec       vector of timestamps of the unit in the channel; should be of the same size as waveform
%               NOTE THAT TIMESTAMPS SHOULD BE GIVEN IN SECONDS!
% binsz         bin size (s) of analog sampling; reciprocal of sampling rate (e.g. 50 s for 20 kHz)
%               if provided, checkunit will compute spike width (FWHM, full width at half maximum)
% tevents       vector with event times; if provided, an additional plot will be generated that depicts
%               spike times relative to event times +- 200 ms; in addition, spike waveforms in a window
%               +- 20 ms will be plotted to verify that these waveforms are indeed spikes and not some
%               event- or stimulus-related artifact
%               NOTE THAT TIMESTAMPS SHOULD BE GIVEN IN SECONDS!
%               also, if tevents is provided, timevec is also needed
% plotno        number of waveforms to plot; default is 5,000
% elimWin       window for elimination of spikes in pecking vicinity (in ms; default [20 20])
%
% OUTPUT
% c             structure with a range of quality indices (mean and sd of waveforms, SNR etc)
%
% EXAMPLES
% checkunit(chan1.adc);                       % performs check on all waveforms in channel 1; stationarity cannot be evaluated
%                                             % because no time vector is given
%
% checkunit(chan1.adc,'timevec',chan1.timings);   % same, but with depiction of stationarity
%
% checkunit(chan1.adc,'timevec',chan1.timings,'markvec',chan1.markers(:,1),'target',1);       % same, but only for markers of code '1' (the target)
%
% checkunit(chan9.adc,'timevec',chan9.timings,'markvec',chan9.markers(:,1),'target',1,...
%           'tevents',chan32.timings(chan32.markers(:,1)==110));       % same, with extra PSTH
% 
% HISTORY
% july 3, 2012        renamed variable 'time', included estimate of overall firing rate
% june 28, 2012       some polishing work for publication
% june 8, 2012        renamed variable tpecks to tevents
% june 4, 2012        changed output figure size; changed critical values
% may 7, 2012         new outputs: estimated percent false negatives, percent refractory period violations
%                     distill recommendations for classification (take e.g. skew and std)
% april 27, 2012      stepsize for histograms calculated automatically
%                     debugged histogram output for subplot 447
% aug 16, 2011        changed sd plot to % of sd
% june 16, 2011       new additional outputs:
%                     - no. of waveforms within pecking range
%                     - zoom in on ISI distribution's first 50 ms
%                     - spike amplitude over session time plus regression line
%                     - firing rate over session time
%                     - Gaussian fit and false negative estimation
%                     added optional input: elimWin
% june 16, 2011       cosmetic fixes to subplot 3
% may 24, 2011        added density plot and waveform samples; incorporated cpecks.m code into this function
% may 04, 2011        constrained number of plotted waveforms to 5,000 (default); optional:
% feb 28, 2011        added cpecks and binsz (optional arguments)
% feb 16, 2011        added examples
% 
% by Maik C. Stttgen, Feb 2011
%% specify and assign defaults
if size(waveforms,1)<size(waveforms,2)
  waveforms=waveforms';
end
target  = 1;
tevents = [];
binsz   = [];
plotno  = 5000;
elimWin = [20 20];
nospx   = 3; % ms - time window in which spikes are not to be expected too often
markvec = ones(size(waveforms,1),1);
timevec = zeros(size(waveforms,1),1);
if nargin
  for i=1:2:size(varargin,2)
    switch varargin{i}
      case 'markvec'
        markvec = varargin{i+1};
      case 'target'
        target = varargin{i+1};
      case 'timevec'
        timevec = varargin{i+1};
      case 'binsz'
        binsz = varargin{i+1};
      case 'plotno'
        plotno = varargin{i+1};
      case 'tevents'
        tevents  = varargin{i+1};
      case 'elimWin'
        elimWin = varargin{i+1};
      otherwise
        errordlg('unknown argument')
    end
  end
end
%% assign criteria for traffic lights (green, yellow)
crit_SNRd = [6 5];  
crit_SNR99 = [2 1.5];
crit_SNR95 = [2.5 2];
crit_skew = [0.5 0.75];
crit_ISI  = [0.02 0.05];
crit_FN   = [0.1 0.25];
%% rearrange input
if size(markvec,1)<size(markvec,2)
  markvec=markvec';
end
markvec = markvec(:,1);
wavs = single(waveforms(markvec==target,:));
spxtimes = single(timevec(markvec==target));
if numel(markvec)~=size(waveforms,1)
  errordlg('vectors do not match')
  return
end
%% calculate indices...
c.spx       = size(wavs,1);
c.fr        = 1/mean(diff(spxtimes));
c.meanwave  = mean(wavs,1);
c.stdev     = std(wavs,0,1);
c.skew      = skewness(wavs,0,1);
if binsz
  maxvolt  = max(c.meanwave);
  minvolt  = min(c.meanwave);
  nullvolt = mean(c.meanwave(1:10));
  firstpassup  = find(c.meanwave>nullvolt+(maxvolt-nullvolt)*0.5,1);
  secondpassup = find(c.meanwave(firstpassup+1:end)<nullvolt+(maxvolt-nullvolt)*0.5,1)+firstpassup;
  firstpassdown  = find(c.meanwave<nullvolt+(minvolt-nullvolt)*0.5,1);
  secondpassdown = find(c.meanwave(firstpassdown+1:end)>nullvolt+(minvolt-nullvolt)*0.5,1)+firstpassdown;
  c.FWHMax = round((secondpassup-firstpassup)*binsz)/1000;
  c.FWHMin = round((secondpassdown-firstpassdown)*binsz)/1000;
end
%% plot 'em
disp('quality check...')
figure('units','normalized','position',[0.02 .1 .6 .8],'name',['unit quality check for marker ',num2str(target),...
       ' with ',num2str(c.spx),' waveforms, overall firing rate is ' num2str(c.fr,2) ' Hz'])
%% subplot 1 - raw waveforms
subplot(441)
title(['up to ' num2str(plotno) ' waveforms']),hold all
if plotno>size(wavs,1),plotno=size(wavs,1);end
plot(wavs(randsample(1:size(wavs,1),plotno),:)','b')
plot(c.meanwave,'k','LineWidth',2);
plot(c.meanwave+c.stdev,'k');
plot(c.meanwave+2*c.stdev,'k');
plot(c.meanwave-c.stdev,'k');
plot(c.meanwave-2*c.stdev,'k');
lower = single(min(c.meanwave)-max(c.stdev)*3);
upper = single(max(c.meanwave)+max(c.stdev)*3);
axis([0 size(wavs,2)+1 lower upper])
xlabel('time (bins)'),ylabel('ADC units')
%% subplot 2 - distributions of peak and baseline voltages
subplot(442)
% adjust stepsize for histograms according to voltage units
step = abs(min(diff(max(wavs))))/10;
title('baseline & peak voltages'),hold on
% baseline voltages
[n,b] = hist(wavs(:,1),min(wavs(:,1)):step:max(wavs(:,1)));
bar(b,n,'b','EdgeColor','b'),hold on
% peak voltages
[a1,b1] = max(wavs,[],2);
[a3,b3] = min(wavs,[],2);
[n2,b2] = hist(a1,min(a1):step:max(a1));
[n4,b4] = hist(a3,min(a3):step:max(a3));
bar(b2,n2,'r','EdgeColor','r'),bar(b4,n4,'g','EdgeColor','g')
xlabel('ADC units'),ylabel('frequency')
%% subplot 3 - waveform variability
subplot(443)
title('waveform variability'),hold all
[ax,h1,h2] = plotyy([5 size(wavs,2)-5],[100 100],[5 size(wavs,2)-5],[mean(c.skew) mean(c.skew)]);
plot(ax(1),1:size(wavs,2),100*c.stdev/mean(c.stdev(1:5)),'b')
plot(ax(1),[5 size(wavs,2)-5],[50 50],'b:')
plot(ax(1),[5 size(wavs,2)-5],[150 150],'b:')
set(gcf,'CurrentAxes',ax(2))
line(1:size(wavs,2),c.skew,'Color','r') % plot seems to destroy parent figure
line([5 size(wavs,2)-5],[-.5 -.5],'Color','r','LineStyle',':')
line([5 size(wavs,2)-5],[.5 .5],'Color','r','LineStyle',':')
xlabel('time (bins)');
set(get(ax(1),'Ylabel'),'String','% of noise SD')
set(ax(1),'Xlim',[0 size(wavs,2)+1],'Ylim',[0 200],'YTick',[0 100 200],'YColor','b')
set(h1,'Color','b')
set(get(ax(2),'Ylabel'),'String','skewness')
yskew = [-1 1];
set(ax(2),'Xlim',[0 size(wavs,2)+1],'Ylim',[-1 1],'YTick',[yskew(1) 0 yskew(2)],'YColor','r')
set(h2,'Color','r')
%% subplot 4 - text box with indices
subplot(444),axis off,axis([0 1.3 0 1.1]),axis tight,hold on
c.SNR_dmax = (mean(a1) - mean(wavs(1,:))) / sqrt(0.5 * var(wavs(:,1)) + var(a1));
c.SNR_dmin = (mean(a3) - mean(wavs(1,:))) / sqrt(0.5 * var(wavs(:,1)) + var(a3));
c.SNR99    = (max(c.meanwave)-min(c.meanwave)) / diff(prctile(wavs(:,1),[.5 99.5]));
c.SNR95    = (max(c.meanwave)-min(c.meanwave)) / diff(prctile(wavs(:,1),[2.5 97.5]));
text(0,1.0,'SNR(dmax) ','FontName','Courier'),text(0.7,1.0,num2str(c.SNR_dmax,2),'FontName' ,'Courier')
text(0,0.9,'SNR(dmin)','FontName','Courier'),text(0.7,0.9,num2str(c.SNR_dmin,2),'FontName' ,'Courier')
text(0,0.75,'SNR99%','FontName','Courier'),text(0.7,0.75,num2str(c.SNR99,2),'FontName','Courier')
text(0,0.65,'SNR95%','FontName','Courier'),text(0.7,0.65,num2str(c.SNR95,2),'FontName','Courier')
text(0,0.5,'SKEW(max) ','FontName','Courier'),text(0.7,0.5,num2str(max(c.skew(5:end-5)),2),'FontName','Courier')
text(0,0.4,'SKEW(min) ','FontName','Courier'),text(0.7,0.4,num2str(min(c.skew(5:end-5)),2),'FontName','Courier')
%% subplot 5 - stationarity: cumulative spikes over time
subplot(445)
try
  title('stability over time'),hold on
  [n,b] = hist(spxtimes,0:1:max(spxtimes));
  plot(b/60,cumsum(n)),xlabel('time (minutes)'),ylabel('cumulative spike count (1s bins)')
  xlim([0 ceil(max(b/60))])
catch
  text(0,0.5,'no timestamps','FontName','Courier')
  axis off
end
%% subplot 6 - stationarity: firing rate histogram over time, amplitudes over time
% w = get(subplot(446),'Position'); % somehow yields different positions
subplot('Position',[0.34264 0.54832 0.12 0.15554]) % left bottom width height

try
  title('stability over time'),hold on
  [n,b] = hist(spxtimes,0:60:max(spxtimes));
  amps = max(wavs')-min(wavs');
  [ax,h1,h2] = plotyy(b/60,n,spxtimes/60,amps,'bar','plot');
  
  pars = polyfit(spxtimes/60,amps',1);
  set(gcf,'CurrentAxes',ax(2))
  line(spxtimes/60,pars(1)*spxtimes/60+pars(2),'Color','r') % plot seems to destroy parent figure
  
  set(h1,'LineStyle','-')
  set(h2,'LineStyle','none','Marker','.','MarkerSize',3)

  set(get(ax(1),'Ylabel'),'String','spike count (60s bins)')
  set(get(ax(2),'Ylabel'),'String','p2p amplitude (ADC units)')
  set(ax(1),'Xlim',[0 ceil(max(b/60))],'Ylim',[0 max(n)*2],'YColor','b')
  set(ax(2),'Xlim',[0 ceil(max(b/60))],'Ylim',[min(amps)*0.2 max(amps)*1.1],'YColor','r')
  set(h2,'Color','r')
  xlabel('time (minutes)')

catch
  text(0,0.5,'no timestamps','FontName','Courier')
  axis off
end
%% subplot 7 - interspike intervals
subplot(447)
try
  title('ISI (10ms bins)'),hold on
  resol = 0.5;
  [n,b]=hist(diff(spxtimes),0.005:0.01:(max(diff(spxtimes))));
  bar(b(1:min([resol*1000 numel(b)])),n(1:min([resol*1000 numel(b)])),'b','EdgeColor','b')
  axis([0 resol 0 ceil(max(n)*1.1)])
  xlabel('interval (s)'),ylabel('frequency')
catch
  text(0,0.5,'no timestamps','FontName','Courier')
  axis off
end
%% subplot 8 - interspike intervals, zoomed in
subplot(448)
try
  title('ISI (1ms bins)'),hold on
  resol = 0.05;
  [n,b]=hist(diff(spxtimes),0.0005:0.001:(max(diff(spxtimes))));
  bar(b(1:resol*1000),n(1:resol*1000),'b','EdgeColor','b')
  axis([0 resol 0 ceil(max(n)*1.1)])
  xlabel('interval (s)'),ylabel('frequency')
  c.violations = sum(n(1:nospx))/c.spx;
  subplot(444)
  text(0,0.25,['ISI <' (num2str(nospx+1)) ' ms'],'FontName','Courier'),text(0.7,0.25,num2str(c.violations,2),'FontName','Courier')
catch
  text(0,0.5,'no timestamps','FontName','Courier')
  axis off
end
%% subplots 9&10 - density plots
subplot(449)
title('density plot'),hold on
clear n b
numTicks = size(wavs,2);
for i = 1:numTicks
  [n(i,:),b(i,:)] = hist(wavs(:,i),linspace(lower,upper,min([numel(unique(wavs))/4 500])));
end
colormap(hot)
% remove extreme outliers
cutoff = 5*std(reshape(n,numel(n),1));
n(n>cutoff) = cutoff;
pcolor(n'),shading interp
axis([1 numTicks 1 size(n,2)])
xlabel('time (bins)')
ylabel('ADC units (bins)')

% density plot in log-coordinates
subplot(4,4,10)
title('density plot in log space'),hold on
colormap(hot)
pcolor(log10(n)'),shading interp
axis([1 numTicks 1 size(n,2)])
xlabel('time (bins)')
ylabel('ADC units (bins)')
%% subplot 11 - sample waveforms
subplot(426)
[numWavs numTicks] = size(wavs);
toPlot = floor(min([numWavs/3 200]));
if numWavs>200
  plot(1:numTicks,wavs(1:toPlot,:)','b'),hold on
  plot(numTicks+1:numTicks*2,wavs(round(numWavs/2-toPlot/2):round(numWavs/2+toPlot/2),:),'c')
  plot(numTicks*2+1:numTicks*3,wavs(end-ceil(toPlot/2):end,:)','r')
  axis([0 numTicks*3+1 lower upper])
  axis tight
  mult = 16:-4:-16;
  x = mult.*ones(1,numel(mult))*c.stdev(1)+c.meanwave(1);
  for i = 1:numel(x)
    plot([1,numTicks*3+1],[c.meanwave(1)+x(i) c.meanwave(1)+x(i)],'k:')
  end
end
axis off
ypos = double(round(max(c.meanwave)+max(c.stdev)*2));
text(1,ypos,['first ' num2str(toPlot) ' spikes'])
text(1+numTicks,ypos,['middle ' num2str(toPlot) ' spikes'])
text(1+numTicks*2,ypos,['last ' num2str(toPlot) ' spikes'])
%% subplots 12&13 - PETH and eliminated waveforms (if any)
if tevents

  % low-pass filter key pecks
  minInt = 0.005;                        % minimum time interval (in s) between two peck events
  todelete = zeros(numel(tevents),1);     % becomes array to index peck events for deletion
  
  % while loop marks peck events for deletion
  i=2;
  while i<=numel(tevents)
    if tevents(i)-tevents(i-1)<minInt,todelete(i)=1;end,i=i+1;
  end
  tevents2 = tevents(todelete==0);
  
  % eliminate spikes in close proximity to key pecks
  % for each key peck, find spikes close to it and note their index
  elimWin = elimWin/1000;
  isclose = 0;
  for p = 1:numel(tevents2);
    isclose = [isclose;find(spxtimes>=tevents2(p)-elimWin(1) & spxtimes<=tevents2(p)+elimWin(2))];
  end
  isclose(1)=[];
  tspikes2 = spxtimes;
  tspikes2(isclose) = [];
  
  plotrange = -0.2:0.001:+0.2;
  peckpsth  = zeros(numel(plotrange),1);
  peckpsth2 = zeros(numel(plotrange),1);
    
  % construct psth for original spike array
  for i = 1:numel(tevents2)
    clear stimes trialtimes
    stimes = spxtimes - tevents2(i);
    trialtimes = round(1000*(stimes(stimes>=plotrange(1) & stimes<=plotrange(end))));
    peckpsth(plotrange(1)*-1000+trialtimes+1) = peckpsth(plotrange(1)*-1000+trialtimes+1)+1;
  end
  
  % construct psth for clean spike array
  for i = 1:numel(tevents2)
    clear stimes trialtimes
    stimes = tspikes2 - tevents2(i);
    trialtimes = round(1000*(stimes(stimes>=plotrange(1) & stimes<=plotrange(end))));
    peckpsth2(plotrange(1)*-1000+trialtimes+1) = peckpsth2(plotrange(1)*-1000+trialtimes+1)+1;
  end
  
  subplot(4,4,13)
  title(['PSTH, elimWin=[' num2str(elimWin(1)) ' ' num2str(elimWin(2)) ']']),hold on
  plot(plotrange,peckpsth,'m')
  plot(plotrange,peckpsth2,'b')
  xlabel('time relative to key peck (s)')
  ylabel('number of spikes')
  
  % waveforms eliminated due to closeness to peck event
  subplot(4,4,14)
  title([num2str(numel(isclose)) ' waveforms in event vicinity']), hold on
  plot(wavs(isclose,:)')
  axis([0 numTicks+1 lower upper])
  xlabel('time (bins)'),ylabel('ADC units')
  
else
  subplot(4,4,13)
  text(0,0.5,'no timestamps','FontName','Courier')
  axis off
  subplot(4,4,14)
  text(0,0.5,'no timestamps','FontName','Courier')
  axis off
  
end
%% subplots 14&15 - estimating false negatives for minimum and maximum peak distributions
% guess mode - from mode_guesser.m
% find the range of the most tightly distributed data
% use median of the tightest range as the guess of the mode
% have to do for minimum and maximum!

p = 0.5;
x = a3;
num_samples = length(x);
shift = round(num_samples*p);
x = sort(x);
[val,m_spot] = min(x(shift+1:end) - x(1:end-shift));
m = x(round(m_spot + (shift/2)));
% now duplicate sorted data set around the mode
if skewness(x)>0 % skewed towards positive values
  y = vertcat(m+m-x(x>m),x(x>m));
else
  y = vertcat(m+m-x(x<m),x(x<m));
end
Gaussmean = mean(y);
Gaussstd  = std(y);
xval         = linspace(min(y),max(y),1000);
distribution = normpdf(xval,Gaussmean,Gaussstd);
distribution = distribution/(max(distribution));
c.FNmin = 1-normcdf(max(b4),Gaussmean,Gaussstd);

subplot(4,4,15)
title('minimum distribution'),hold all
bar(b4,n4,'g','EdgeColor','g')
plot(xval,distribution*max(n4),'k')
xlabel('ADC units'),ylabel('frequency')
xlim([b4(find(n4>0,1,'first'))-2*(b4(2)-b4(1)) 0])

x = a1;
num_samples = length(x);
shift = round(num_samples*p);
x = sort(x);
[val,m_spot] = min(x(shift+1:end) - x(1:end-shift));
m = x(round(m_spot + (shift/2)));
% now duplicate sorted data set around the mode
if skewness(x)>0 % skewed towards positive values
  y = vertcat(m+m-x(x>m),x(x>m));
else
  y = vertcat(m+m-x(x<m),x(x<m));
end
Gaussmean = mean(y);
Gaussstd  = std(y);
xval         = linspace(min(y),max(y),1000);
distribution = normpdf(xval,Gaussmean,Gaussstd);
distribution = distribution/(max(distribution));
c.FNmax = 1-normcdf(-min(b2),-Gaussmean,Gaussstd);

subplot(4,4,16)
title('maximum distribution'),hold all
bar(b2,n2,'r','EdgeColor','r')
hold all
plot(xval,distribution*max(n2),'k')
xlabel('ADC units'),ylabel('frequency')
xlim([0 b2(find(n2>0,1,'last'))+2*(b2(2)-b2(1))])

subplot(444)
text(0,0.15,'FNneg','FontName','Courier')
text(0.7,0.15,num2str(c.FNmin,2),'FontName','Courier')
text(0,0.05,'FNpos','FontName','Courier')
text(0.7,0.05,num2str(c.FNmax,2),'FontName','Courier')
%% recommendations
subplot(444)
if c.SNR_dmax>crit_SNRd(1)
  rectangle('Position',[1.2 0.95 0.1 0.1],'FaceColor','g')
elseif c.SNR_dmax>crit_SNRd(2)
  rectangle('Position',[1.2 0.95 0.1 0.1],'FaceColor','y')
else
  rectangle('Position',[1.2 0.95 0.1 0.1],'FaceColor','r')
end
if c.SNR_dmin<-crit_SNRd(1)
  rectangle('Position',[1.2 0.85 0.1 0.1],'FaceColor','g')
elseif c.SNR_dmin<-crit_SNRd(2)
  rectangle('Position',[1.2 0.85 0.1 0.1],'FaceColor','y')
else
  rectangle('Position',[1.2 0.85 0.1 0.1],'FaceColor','r')
end
if c.SNR99>crit_SNR99(1)
  rectangle('Position',[1.2 0.7 0.1 0.1],'FaceColor','g')
elseif c.SNR99>crit_SNR99(2)
  rectangle('Position',[1.2 0.7 0.1 0.1],'FaceColor','y')
else
  rectangle('Position',[1.2 0.7 0.1 0.1],'FaceColor','r')
end
if c.SNR95>crit_SNR95(1)
  rectangle('Position',[1.2 0.6 0.1 0.1],'FaceColor','g')
elseif c.SNR95>crit_SNR95(2)
  rectangle('Position',[1.2 0.6 0.1 0.1],'FaceColor','y')
else
  rectangle('Position',[1.2 0.6 0.1 0.1],'FaceColor','r')
end
if max(c.skew(5:end-5))<crit_skew(1)
  rectangle('Position',[1.2 0.45 0.1 0.1],'FaceColor','g')
elseif max(c.skew(5:end-5))<crit_skew(2)
  rectangle('Position',[1.2 0.45 0.1 0.1],'FaceColor','y')
else
  rectangle('Position',[1.2 0.45 0.1 0.1],'FaceColor','r')
end
if min(c.skew(5:end-5))>-crit_skew(1)
  rectangle('Position',[1.2 0.35 0.1 0.1],'FaceColor','g')
elseif min(c.skew(5:end-5))>-crit_skew(2)
  rectangle('Position',[1.2 0.35 0.1 0.1],'FaceColor','y')
else
  rectangle('Position',[1.2 0.35 0.1 0.1],'FaceColor','r')
end
if isfield(c,'violations')
  if c.violations<crit_ISI(1)
    rectangle('Position',[1.2 0.2 0.1 0.1],'FaceColor','g')
  elseif c.violations<crit_ISI(2)
    rectangle('Position',[1.2 0.2 0.1 0.1],'FaceColor','y')
  else
    rectangle('Position',[1.2 0.2 0.1 0.1],'FaceColor','r')
  end
else
  rectangle('Position',[1.2 0.2 0.1 0.1],'FaceColor','k')
end
if c.FNmax<crit_FN(1)
  rectangle('Position',[1.2 0.0 0.1 0.1],'FaceColor','g')
elseif c.FNmax<crit_FN(2)
  rectangle('Position',[1.2 0.0 0.1 0.1],'FaceColor','y')
else
  rectangle('Position',[1.2 0.0 0.1 0.1],'FaceColor','r')
end
if c.FNmin<crit_FN(1)
  rectangle('Position',[1.2 0.1 0.1 0.1],'FaceColor','g')
elseif c.FNmin<crit_FN(2)
  rectangle('Position',[1.2 0.1 0.1 0.1],'FaceColor','y')
else
  rectangle('Position',[1.2 0.1 0.1 0.1],'FaceColor','r')
end

Contact us