%% Function - Curvefit to recovery %------------------------------------------------------------------ %function [Curvefit, goodness, x] = myfitY(y1,makeplot,si,unitsY,fig) % [Curvefit, goodness] = myfity2(y1,makeplot,si,yUnit) % Curve Fit % % Input % y1 - curve to be fitted must be exponential rising curve % makeplot - enter plot option PLOT (y), DONT PLOT (n) % si - sample interval in seconds (si) % unitsY - units of y-axis % fig - figure number % % Output % Curvefit - curve fit to data % goodness - goodness of fit least square error % fitx - x data vector with time in seconds Y = y1(:);%curve, make column vector %Y data index starts at 1 % Translate Y to origin, eliminating constant terms minY = min(Y); Y = Y - minY; % Create time vector x = 0:(length(Y)-1); %start x-axis from zero x = x*si; %convert to seconds x = x(:); %make column vector %x = x+(5*FrameTreat); %shift the curve to match time stamp %myc = round(min(Y)); %myalpha = round(max(Y)-myc); myalpha = max(Y); %temp = 0.63*myalpha+myc; %find value 63% temp = 0.63*myalpha; %find value 63% temp = abs(Y-temp); %subtract value 66% of max from curve [~, tempx] = min(temp); %get index of min difference = index of 63%myalpha+myc mybeta = 1/(x(tempx)); %r = 5*FrameTreat; %create right shift known constant (seconds) % s = fitoptions('Mehtod','NonlinearLeastSquares','Robust','LAR',... % 'Lower',[myalpha-.01,0,myc-.01],... % 'Upper',[myalpha+.01,inf,myc+.01],... % 'Startpoint',[myalpha,mybeta,myc]); %set the fitting parameters s = fitoptions('Mehtod','NonlinearLeastSquares','Robust','LAR',... 'Lower',[myalpha-1,0],... 'Upper',[myalpha+1,inf],... 'Startpoint',[myalpha,mybeta]); %set the fitting parameters % f = fittype( @(alpha,beta,c,x) alpha*(1 - exp(-beta *(x-r))) +c,... % 'coefficients',{'alpha','beta','c'},'options',s ); %set the curve fit function % f = fittype( @(alpha,beta,x) alpha*(exp(-beta *(x))),... % 'coefficients',{'alpha','beta'},'options',s ); %set the curve fit function f = fittype( @(alpha,beta,x) alpha*(1 - exp(-beta *(x))),... 'coefficients',{'alpha','beta'},'options',s ); %set the curve fit function [Curvefit, goodness] = fit(x,Y,f); %fit data to an exponential rise curve % Plot the original waveform, fit, and fit stats in figure % make plot of curve fit if requested if strncmpi(makeplot,'y',1) %case insensitive comparison of first character %figure; figure(fig); plot(Curvefit,'r--'),hold on; %create a plot of the curve fit and original data plot(x, Y,'b.','markersize',12); %plot data points legend('Fit Curve', 'Data','Location','SouthEast'); %place legend xlabel('Time(seconds)','FontSize',20); %x-axis label ylabel(['Amplitude (', unitsY, ')'], 'FontSize',20); %y-axis label Txticks = get(gca,'XTick'); %x-axis tick array Pxticks = round(length(get(gca,'XTick'))/4); %1/4 length of x-axis tick array xticks = Txticks(Pxticks); %1/4 length value of x-axis ticks tempytick = abs(x-xticks); %x-axis data - x-axis 1/4 length tick value [~, tempytick] = min(tempytick); %find position of min difference % make strings of equations using tex syntax strn1 = '$y={\alpha}\left(1-\exp({-\beta}{x})\right)$'; strn2 = sprintf('$y={%0.4f}\\left(1-\\exp({-%0.g}{x})\\right)$',Curvefit.alpha, Curvefit.beta); strn3 = sprintf('$R^2={%0.4f}$',abs(goodness.rsquare)); strn4 = sprintf('$\\tau=\\frac{1}{\\beta}={%0.4g}\\left( seconds \\right)$',(1/Curvefit.beta)); % % For plotting w.r.t. origin text('Interpreter','latex','string',... {strn1;strn2;strn3;strn4},... 'Position',[xticks,Y(tempytick)],... 'VerticalAlignment','Cap','FontSize',16) end end %------------------------------------------------------------------ %% Function - Axon binary read %------------------------------------------------------------------ %function [d,si]=abfload1(fn,varargin) % 139 & 321 % ** function [d,si]=abfload(fn,varargin) % loads and returns data in the Axon abf format. % Data may have been acquired in the following modes: % (1) event-driven variable-length % (2) event-driven fixed-length % (3) gap-free % Information about scaling, the time base and the number of channels and % episodes is extracted from the header of the abf file (see also abfinfo.m). % All optional input parameters listed below (= all except the file name) % must be specified as parameter/value pairs, e.g. as in % d=abfload('d:\data01.abf','start',100,'stop','e'); % % %Credits: Harald Hentschk, University of Tuebingen % % % >>> INPUT VARIABLES >>> % % NAME TYPE, DEFAULT DESCRIPTION % fn char array abf data file name % start scalar, 0 only gap-free-data: start of cutout to be read (unit: sec) % stop scalar or char, only gap-free-data: end of cutout to be read (unit: sec). % 'e' May be set to 'e' (end of file). % sweeps 1d-array or char, only episodic data: sweep numbers to be read. By default, % 'a' all sweeps will be read ('a') % channels cell array names of channels to be read, like {'IN 0','IN 8'}; % or char, 'a' ** make sure spelling is 100% correct (including blanks) ** % if set to 'a', all channels will be read % chunk scalar, 0.05 only gap-free-data: the elementary chunk size (Megabytes) % to be used for the 'discontinuous' mode of reading data % (when less channels shall be read than exist in file) % machineF char array, the 'machineformat' input parameter of the % 'ieee-le' matlab fopen function. 'ieee-le' is the correct % option for windows; depending on the % platform the data were recorded/shall be read % by abfload 'ieee-be' is the alternative. % % <<< OUTPUT VARIABLES <<< % % NAME TYPE DESCRIPTION % d the data read, the format depending on the recording mode % 1. GAP-FREE: % 2d array 2d array of size % '' by '' % Examples of access: % d(:,2) data from channel 2 at full length % d(1:100,:) first 100 data points from all channels % 2. EPISODIC FIXED-LENGTH: % 3d array 3d array of size % '' by '' by '' % Examples of access: % d(:,2,:) is a matrix which contains all events (at full length) % of channel 2 in its columns % d(1:200,:,[1 11]) contains first 200 data points of events #1 % and #11 of all channels % 3. EPISODIC VARIABLE-LENGTH: % cell array cell array whose elements correspond to single sweeps. Each element is % a (regular) array of size % '' by '' % Examples of access: % d{1} a 2d-array which contains sweep #1 (all of it, all channels) % d{2}(1:100,2) a 1d-array containing first 100 data points of of channel 2 in sweep #1 % % si scalar the sampling interval in usec % % Date of this version: Nov 23, 2006 % future improvements: % - handle expansion of header in transition to file version 1.65 better % --- defaults % gap-free start=0.0; stop='e'; % episodic sweeps='a'; % general channels='a'; % the size of data chunks (see above) in Mb. 0.05 Mb is an empirical value % which works well for abf with 6-16 channels and recording durations of % 5-30 min chunk=0.05; machineF='ieee-le'; verbose=1; % assign values of optional input parameters, if any were given pvpmod(varargin); %if verbose, disp(['** ' mfilename]); end d=[]; si=[]; if ischar(stop) if ~strcmpi(stop,'e') error('input parameter ''stop'' must be specified as ''e'' (=end of recording) or as a scalar'); end end % --- obtain vital header parameters and initialize them with -1 % temporary initializing var tmp=repmat(-1,1,16); % for the sake of typing economy set up a cell array (and convert it to a struct below) % column order is % name, position in header in bytes, type, value) headPar={ 'fFileVersionNumber',4,'float',-1; 'nOperationMode',8,'int16',-1; 'lActualAcqLength',10,'int32',-1; 'nNumPointsIgnored',14,'int16',-1; 'lActualEpisodes',16,'int32',-1; 'lFileStartTime',24,'int32',-1; 'lDataSectionPtr',40,'int32',-1; 'lSynchArrayPtr',92,'int32',-1; 'lSynchArraySize',96,'int32',-1; 'nDataFormat',100,'int16',-1; 'nADCNumChannels', 120, 'int16', -1; 'fADCSampleInterval',122,'float', -1; 'fSynchTimeUnit',130,'float',-1; 'lNumSamplesPerEpisode',138,'int32',-1; 'lPreTriggerSamples',142,'int32',-1; 'lEpisodesPerRun',146,'int32',-1; 'fADCRange', 244, 'float', -1; 'lADCResolution', 252, 'int32', -1; 'nFileStartMillisecs', 366, 'int16', -1; 'nADCPtoLChannelMap', 378, 'int16', tmp; 'nADCSamplingSeq', 410, 'int16', tmp; 'sADCChannelName',442, 'uchar', repmat(tmp,1,10); 'fADCProgrammableGain', 730, 'float', tmp; 'fInstrumentScaleFactor', 922, 'float', tmp; 'fInstrumentOffset', 986, 'float', tmp; 'fSignalGain', 1050, 'float', tmp; 'fSignalOffset', 1114, 'float', tmp; 'nTelegraphEnable',4512,'int16',tmp; 'fTelegraphAdditGain',4576,'float',tmp }; fields={'name','offs','numType','value'}; s=cell2struct(headPar,fields,2); numOfParams=size(s,1); clear tmp headPar; if ~exist(fn,'file'), error(['could not find file ' fn]); end %if verbose, disp(['opening ' fn '..']); end [fid,messg]=fopen(fn,'r',machineF); if fid == -1,error(messg);end; % determine absolute file size fseek(fid,0,'eof'); fileSz=ftell(fid); fseek(fid,0,'bof'); % read all vital information in header % convert names in structure to variables and read value from header for g=1:numOfParams, if fseek(fid, s(g).offs,'bof')~=0, fclose(fid); error(['something went wrong locating ' s(g).name]); end; sz=length(s(g).value); eval(['[' s(g).name ',n]=fread(fid,sz,''' s(g).numType ''');']); if n~=sz, fclose(fid); error(['something went wrong reading value(s) for ' s(g).name]); end; end; if lActualAcqLength=1.65 addGain=nTelegraphEnable.*fTelegraphAdditGain; addGain(addGain==0)=1; else addGain=ones(size(fTelegraphAdditGain)); end % tell me where the data start blockSz=512; switch nDataFormat case 0 dataSz=2; % bytes/point precision='int16'; case 1 dataSz=4; % bytes/point precision='float32'; otherwise fclose(fid); error('invalid number format'); end; headOffset=lDataSectionPtr*blockSz+nNumPointsIgnored*dataSz; % fADCSampleInterval is the TOTAL sampling interval si=fADCSampleInterval*nADCNumChannels; if ischar(sweeps) && sweeps=='a' nSweeps=lActualEpisodes; sweeps=1:lActualEpisodes; else nSweeps=length(sweeps); end; switch nOperationMode case 1 if verbose, disp('data were acquired in event-driven variable-length mode'); end warndlg('function abfload has not yet been thorougly tested for data in event-driven variable-length mode - please double-check that the data loaded is correct','Just a second, please'); if (lSynchArrayPtr<=0 || lSynchArraySize<=0), fclose(fid); error('internal variables ''lSynchArraynnn'' are zero or negative'); end switch fSynchTimeUnit case 0 % time information in synch array section is in terms of ticks synchArrTimeBase=1; otherwise % time information in synch array section is in terms of usec synchArrTimeBase=fSynchTimeUnit; end; % the byte offset at which the SynchArraySection starts lSynchArrayPtrByte=blockSz*lSynchArrayPtr; % before reading Synch Arr parameters check if file is big enough to hold them % 4 bytes/long, 2 values per episode (start and length) if lSynchArrayPtrByte+2*4*lSynchArraySize0, fclose(fid); error('number of data points in episode not OK'); end % separate channels.. tmpd=reshape(tmpd,nADCNumChannels,dataPtsPerChan); % retain only requested channels tmpd=tmpd(chInd,:); tmpd=tmpd'; % if data format is integer, scale appropriately; if it's float, tmpd is fine if ~nDataFormat for j=1:length(chInd), ch=recChIdx(chInd(j))+1; tmpd(:,j)=tmpd(:,j)/(fInstrumentScaleFactor(ch)*fSignalGain(ch)*fADCProgrammableGain(ch)*addGain(ch))... *fADCRange/lADCResolution+fInstrumentOffset(ch)-fSignalOffset(ch); end; end % now place in cell array, an element consisting of one sweep with channels in columns d{i}=tmpd; end; case {2,5} if nOperationMode==2 if verbose disp('data were acquired in event-driven fixed-length mode'); end % else % if verbose % disp('data were acquired in waveform fixed-length mode (clampex only)'); % end end % determine first point and number of points to be read startPt=0; dataPts=lActualAcqLength; dataPtsPerChan=dataPts/nADCNumChannels; if rem(dataPts,nADCNumChannels)>0, fclose(fid); error('number of data points not OK'); end dataPtsPerChanPerSweep=dataPtsPerChan/lActualEpisodes; if rem(dataPtsPerChan,lActualEpisodes)>0 fclose(fid); error('number of data points not OK'); end dataPtsPerSweep=dataPtsPerChanPerSweep*nADCNumChannels; if fseek(fid,startPt*dataSz+headOffset,'bof')~=0 fclose(fid); error('something went wrong positioning file pointer (too few data points ?)'); end d=zeros(dataPtsPerChanPerSweep,length(chInd),nSweeps); % the starting ticks of episodes in sample points WITHIN THE DATA FILE selectedSegStartInPts=((sweeps-1)*dataPtsPerSweep)*dataSz+headOffset; for i=1:nSweeps, fseek(fid,selectedSegStartInPts(i),'bof'); [tmpd,n]=fread(fid,dataPtsPerSweep,precision); if n~=dataPtsPerSweep, fclose(fid); error(['something went wrong reading episode ' int2str(sweeps(i)) ': ' dataPtsPerSweep ' points should have been read, ' int2str(n) ' points actually read']); end; dataPtsPerChan=n/nADCNumChannels; if rem(n,nADCNumChannels)>0 fclose(fid); error('number of data points in episode not OK'); end; % separate channels.. tmpd=reshape(tmpd,nADCNumChannels,dataPtsPerChan); % retain only requested channels tmpd=tmpd(chInd,:); tmpd=tmpd'; % if data format is integer, scale appropriately; if it's float, d is fine if ~nDataFormat for j=1:length(chInd), ch=recChIdx(chInd(j))+1; tmpd(:,j)=tmpd(:,j)/(fInstrumentScaleFactor(ch)*fSignalGain(ch)*fADCProgrammableGain(ch)*addGain(ch))... *fADCRange/lADCResolution+fInstrumentOffset(ch)-fSignalOffset(ch); end; end % now fill 3d array d(:,:,i)=tmpd; end; case 3 if verbose, disp('data were acquired in gap-free mode'); end % from start, stop, headOffset and fADCSampleInterval calculate first point to be read % and - unless stop is given as 'e' - number of points startPt=floor(1e6*start*(1/fADCSampleInterval)); % this corrects undesired shifts in the reading frame due to rounding errors in the previous calculation startPt=floor(startPt/nADCNumChannels)*nADCNumChannels; % if stop is a char array, it can only be 'e' at this point (other values would have % been caught above) if ischar(stop), dataPtsPerChan=lActualAcqLength/nADCNumChannels-floor(1e6*start/si); dataPts=dataPtsPerChan*nADCNumChannels; else dataPtsPerChan=floor(1e6*(stop-start)*(1/si)); dataPts=dataPtsPerChan*nADCNumChannels; if dataPts<=0 fclose(fid); error('start is larger than or equal to stop'); end end if rem(dataPts,nADCNumChannels)>0 fclose(fid); error('number of data points not OK'); end if fseek(fid,startPt*dataSz+headOffset,'bof')~=0, fclose(fid); error('something went wrong positioning file pointer (too few data points ?)'); end % *** decide on the most efficient way to read data: % (i) all (of one or several) channels requested: read, done % (ii) one (of several) channels requested: use the 'skip' feature of % fread % (iii) more than one but not all (of several) channels requested: % 'discontinuous' mode of reading data. Read a reasonable chunk of data % (all channels), separate channels, discard non-requested ones (if % any), place data in preallocated array, repeat until done. This is % faster than reading the data in one big lump, separating channels and % discarding the ones not requested if length(chInd)==1 && nADCNumChannels>1 % --- situation (ii) % jump to proper reading frame position in file if fseek(fid,(chInd-1)*dataSz,'cof')~=0 fclose(fid); error('something went wrong positioning file pointer (too few data points ?)'); end % read, skipping nADCNumChannels-1 data points after each read dataPtsPerChan=dataPts/nADCNumChannels; [d,n]=fread(fid,dataPtsPerChan,precision,dataSz*(nADCNumChannels-1)); if n~=dataPtsPerChan, fclose(fid); error(['something went wrong reading file (' int2str(dataPtsPerChan) ' points should have been read, ' int2str(n) ' points actually read']); end elseif length(chInd)/nADCNumChannels<1 % --- situation (iii) % prepare chunkwise upload: % preallocate d d=repmat(nan,dataPtsPerChan,length(chInd)); % the number of data points corresponding to the maximal chunk size, % rounded off such that from each channel the same number of points is % read (do not forget that each data point will by default be made a % double of 8 bytes, no matter what the original data format is) chunkPtsPerChan=floor(chunk*2^20/8/nADCNumChannels); chunkPts=chunkPtsPerChan*nADCNumChannels; % the number of those chunks.. nChunk=floor(dataPts/chunkPts); % ..and the remainder restPts=dataPts-nChunk*chunkPts; restPtsPerChan=restPts/nADCNumChannels; % chunkwise row indices into d dix=(1:chunkPtsPerChan:dataPtsPerChan)'; dix(:,2)=dix(:,1)+chunkPtsPerChan-1; dix(end,2)=dataPtsPerChan; if verbose && nChunk disp(['reading file in ' int2str(nChunk) ' chunks of ~' num2str(chunk) ' Mb']); end % do it for ci=1:size(dix,1)-1 [tmpd,n]=fread(fid,chunkPts,precision); if n~=chunkPts fclose(fid); error(['something went wrong reading chunk #' int2str(ci) ' (' ... int2str(chunkPts) ' points should have been read, ' int2str(n) ' points actually read']); end % separate channels.. tmpd=reshape(tmpd,nADCNumChannels,chunkPtsPerChan); d(dix(ci,1):dix(ci,2),:)=tmpd(chInd,:)'; end % collect the rest [tmpd,n]=fread(fid,restPts,precision); if n~=restPts fclose(fid); error(['something went wrong reading last chunk (' ... int2str(restPts) ' points should have been read, ' int2str(n) ' points actually read']); end % separate channels.. tmpd=reshape(tmpd,nADCNumChannels,restPtsPerChan); d(dix(end,1):dix(end,2),:)=tmpd(chInd,:)'; else % --- situation (i) [d,n]=fread(fid,dataPts,precision); if n~=dataPts, fclose(fid); error(['something went wrong reading file (' int2str(dataPts) ' points should have been read, ' int2str(n) ' points actually read']); end; % separate channels.. d=reshape(d,nADCNumChannels,dataPtsPerChan); d=d'; end % if data format is integer, scale appropriately; if it's float, d is fine if ~nDataFormat for j=1:length(chInd), ch=recChIdx(chInd(j))+1; d(:,j)=d(:,j)/(fInstrumentScaleFactor(ch)*fSignalGain(ch)*fADCProgrammableGain(ch)*addGain(ch))... *fADCRange/lADCResolution+fInstrumentOffset(ch)-fSignalOffset(ch); end; end otherwise disp('recording mode of data must be event-driven variable-length (1), event-driven fixed-length (2) or gap-free (3) -- returning empty matrix'); d=[]; si=[]; end; fclose(fid); %------------------------------------------------------------------ %% Automatic Population Spike detection %------------------------------------------------------------------ %function [M1, M2, M3] = markers(waveform) %Input a typical stimulation + popsipike waveform %Output M1 = marker indices for 1st marker % M2 = marker indices for 2nd marker % M3 = marker indices for 3rd marker %acquire indices and value of max [y1, p1] = max(waveform); %partition waveform starting from the max index to end of file waveform1 = waveform(p1:length(waveform)); %get indices and value of marker#2 w.r.t. partitioned waveform [y2, m2] = min(waveform1); M2 = [waveform(m2 + p1-1), m2 + p1-1]; %marker position on waveform not waveform1 %determine the position of 2nd marker wavem1m2 = waveform1(1:m2); %compute the discrete derivative for k = 1:length(wavem1m2) - 1 dwavem1m2(k) = wavem1m2(k+1) - wavem1m2(k); end %find the edges of the original waveform using the 1st derivative n = 1; redge = []; fedge = []; dghost = dwavem1m2; trim = floor(0.2*length(dwavem1m2)); %trim search to avoid false positives dwavem1m2 = dwavem1m2(trim:length(dwavem1m2)-trim); for k = 1:length(dwavem1m2) - 1 if dwavem1m2(k) < 0 && dwavem1m2(k+1) >= 0 redge(n) = k; n = n+1; elseif dwavem1m2(k) >= 0 && dwavem1m2(k+1) < 0 fedge(n) = k; n = n+1; end end %try alternate algorithm if no peaks exist if isempty(fedge) %guess position of marker#1 as halfway point between max and marker#2 tempM1pos = ceil(m2/2); %if the guessed value is the correct value, where dy/dx=0 %then keep the gussed index if waveform1(tempM1pos+1) - waveform1(tempM1pos) <= 0.0005 M1 = [waveform(tempM1pos + p1-1), tempM1pos + p1-1]; else %if the guessed position is incorrect then sweep across a %region that spans 25% of distance (between max and marker#2) %to the left and right of guessed index. It is probable that %the dy/dx!=0 so assign marker#2 to the index that has the %smallest dy/dx dghost(1:tempM1pos-ceil(0.25*m2)) = nan; dghost(tempM1pos+ceil(0.25*m2):length(dghost)) = nan; [yi, xi] = max(dghost); M1 = [waveform(xi + p1-1), xi + p1-1]; % tol = .00075; % i = tempM1pos - ceil(0.25*m2); % count = 0; % while waveform(i+1) - waveform1(i) >= tol % i = i+1; % if i == tempM1pos + ceil(0.25*m2) % i = tempM1pos - ceil(0.25*m2); % tol = tol + 0.00025; % count = count+1; % end % if count > 500 % tempM1pos = i; % break; % end % tempM1pos = i; % end % % M1 = [waveform(tempM1pos + p1-1), tempM1pos + p1-1]; end %try peak detection algorithm to find 1st marker else fedge = trim + fedge; redge = trim + redge; if length(fedge) > 1 [ymax, xmax] = max(fedge); fedge = fedge(xmax); end %find the leftmost value of peak. Done to get midpoint of plateu. leftedge = fedge; boarder = 0; while boarder ~= 1 if wavem1m2(leftedge) == wavem1m2(leftedge-1) leftedge = leftedge - 1; else boarder = 1; end end %find the rightmost value of peak. Done to get midpoint of plateu. rightedge = fedge; boarder = 0; while boarder ~= 1 if wavem1m2(rightedge) == wavem1m2(rightedge+1) rightedge = rightedge + 1; else boarder = 1; end end %shift the marker acccordingly left = floor((leftedge - fedge)/2); right = floor((rightedge - fedge)/2); fedge = fedge + right + left; %assign marker position M1 = [waveform(fedge + p1-1), fedge + p1-1]; end %the position of marker#3 relative to marker#2 and end of sweep is %the max of partitioned waveform [y3, m3] = max(waveform1(m2:length(waveform1))); M3 = [waveform(m3 + p1-1 + m2-1), m3 + p1-1 + m2-1]; %------------------------------------------------------------------ %% Modified questdlg %------------------------------------------------------------------ %function ButtonName=myquestdlg(Question,Title,Btn1,Btn2,Btn3,Default) % ln-110: FigPos(1) = 950; %EDITED%get(0,'DefaultFigurePosition'); % ln-114: %EDITEDT%FigPos = getnicedialoglocation(FigPos, get(0,'DefaultFigureUnits')); % ln-172: %EDITED%FigPos(3)=max(FigPos(3),MsgTxtXOffset+NumButtons*(BtnWidth+2*DefOffset)); % ln-279: %EDITED%set(QuestFig ,'Position',getnicedialoglocation(FigPos, get(QuestFig,'Units'))); % ln-305-308: %EDITED% % if DefaultValid % setdefaultbutton(QuestFig, BtnHandle(DefaultButton)); % end