# HG changeset patch # User Ray Meddis # Date 1306498761 -3600 # Node ID f233164f4c861e324369bce5e148922fa55151c2 first commit diff -r 000000000000 -r f233164f4c86 .gitignore --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.gitignore Fri May 27 13:19:21 2011 +0100 @@ -0,0 +1,5 @@ +*.asv #ignore windows autosaves +*.*~ #ignore mac autosaves +.DS_Store #ignore some other Mac auto generated file +*.doc #ignore MSword +*.docx #ignore newer MSword diff -r 000000000000 -r f233164f4c86 MAP/MAP1_14.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MAP/MAP1_14.m Fri May 27 13:19:21 2011 +0100 @@ -0,0 +1,1106 @@ + +function MAP1_14(inputSignal, sampleRate, BFlist, MAPparamsName, ... + AN_spikesOrProbability, paramChanges) +% To test this function use test_MAP1_14 in this folder +% +% All arguments are mandatory. +% +% BFlist is a list of BFs but can be '-1' to allow MAPparams to choose +% + +% MAPparamsName='Normal'; % source of model parameters +% AN_spikesOrProbability='spikes'; % or 'probability' +% paramChanges is a cell array of strings that can be used to make last +% minute parameter changes, e.g., to simulate OHC loss +% paramChanges{1}= 'DRNLParams.a=0;'; + +% The model parameters are established in the MAPparams<***> file +% and stored as global + +restorePath=path; +addpath (['..' filesep 'parameterStore']) + +global OMEParams DRNLParams IHC_cilia_RPParams IHCpreSynapseParams +global AN_IHCsynapseParams MacGregorParams MacGregorMultiParams + +% All of the results of this function are stored as global +global dt ANdt savedBFlist saveAN_spikesOrProbability saveMAPparamsName... + savedInputSignal OMEextEarPressure TMoutput OMEoutput ARattenuation ... + DRNLoutput IHC_cilia_output IHCrestingCiliaCond IHCrestingV... + IHCoutput ANprobRateOutput ANoutput savePavailable tauCas ... + CNoutput ICoutput ICmembraneOutput ICfiberTypeRates MOCattenuation + +% Normally only ICoutput(logical spike matrix) or ANprobRateOutput will be +% needed by the user; so the following will suffice +% global ANdt ICoutput ANprobRateOutput + +% Note that sampleRate has not changed from the original function call and +% ANprobRateOutput is sampled at this rate +% However ANoutput, CNoutput and IC output are stored as logical +% 'spike' matrices using a lower sample rate (see ANdt). + +% When AN_spikesOrProbability is set to probability, +% no spike matrices are computed. +% When AN_spikesOrProbability is set to 'spikes', +% no probability output is computed + +% Efferent control variables are ARattenuation and MOCattenuation +% These are scalars between 1 (no attenuation) and 0. +% They are represented with dt=1/sampleRate (not ANdt) +% They are computed using either AN probability rate output +% or IC (spikes) output as approrpriate. +% AR is computed using across channel activity +% MOC is computed on a within-channel basis. + + +% save as global for later plotting if required +savedBFlist=BFlist; +saveAN_spikesOrProbability=AN_spikesOrProbability; +saveMAPparamsName=MAPparamsName; + +% Read parameters from MAPparams<***> file in 'parameterStore' folder +cmd=['method=MAPparams' MAPparamsName ... + '(BFlist, sampleRate, 0);']; +eval(cmd); + +% Beware, 'BFlist=-1' is a legitimate argument for MAPparams<> +% if the calling program allows MAPparams to specify the list +BFlist=DRNLParams.nonlinCFs; + +% now accept last mintue parameter changes required by the calling program +if nargin>5 && ~isempty(paramChanges) + nChanges=length(paramChanges); + for idx=1:nChanges + eval(paramChanges{idx}) + end +end + +dt=1/sampleRate; +duration=length(inputSignal)/sampleRate; +% segmentDuration is specified in parameter file (must be >efferent delay) +segmentDuration=method.segmentDuration; +segmentLength=round(segmentDuration/ dt); +segmentTime=dt*(1:segmentLength); % used in debugging plots + +% all spiking activity is computed using longer epochs +ANspeedUpFactor=5; % 5 times longer + +% inputSignal must be row vector +[r c]=size(inputSignal); +if r>c, inputSignal=inputSignal'; end % transpose +% ignore stereo signals +inputSignal=inputSignal(1,:); % drop any second channel +savedInputSignal=inputSignal; + +% Segment the signal +% The sgment length is given but the signal length must be adjusted to be a +% multiple of both the segment length and the reduced segmentlength +[nSignalRows signalLength]=size(inputSignal); +segmentLength=ceil(segmentLength/ANspeedUpFactor)*ANspeedUpFactor; +% Make the signal length a whole multiple of the segment length +nSignalSegments=ceil(signalLength/segmentLength); +padSize=nSignalSegments*segmentLength-signalLength; +pad=zeros(nSignalRows,padSize); +inputSignal=[inputSignal pad]; +[ignore signalLength]=size(inputSignal); + +% AN (spikes) is computed at a lower sample rate when spikes required +% so it has a reduced segment length (see 'ANspeeUpFactor' above) +% AN CN and IC all use this sample interval +ANdt=dt*ANspeedUpFactor; +reducedSegmentLength=round(segmentLength/ANspeedUpFactor); +reducedSignalLength= round(signalLength/ANspeedUpFactor); + +%% Initialise with respect to each stage before computing +% by allocating memory, +% by computing constants +% by establishing easy to read variable names +% The computations are made in segments and boundary conditions must +% be established and stored. These are found in variables with +% 'boundary' or 'bndry' in the name + +%% OME --- +% external ear resonances +OMEexternalResonanceFilters=OMEParams.externalResonanceFilters; +[nOMEExtFilters c]=size(OMEexternalResonanceFilters); +% details of external (outer ear) resonances +OMEgaindBs=OMEexternalResonanceFilters(:,1); +OMEgainScalars=10.^(OMEgaindBs/20); +OMEfilterOrder=OMEexternalResonanceFilters(:,2); +OMElowerCutOff=OMEexternalResonanceFilters(:,3); +OMEupperCutOff=OMEexternalResonanceFilters(:,4); +% external resonance coefficients +ExtFilter_b=cell(nOMEExtFilters,1); +ExtFilter_a=cell(nOMEExtFilters,1); +for idx=1:nOMEExtFilters + Nyquist=sampleRate/2; + [b, a] = butter(OMEfilterOrder(idx), ... + [OMElowerCutOff(idx) OMEupperCutOff(idx)]... + /Nyquist); + ExtFilter_b{idx}=b; + ExtFilter_a{idx}=a; +end +OMEExtFilterBndry=cell(2,1); +OMEextEarPressure=zeros(1,signalLength); % pressure at tympanic membrane + +% pressure to velocity conversion using smoothing filter (50 Hz cutoff) +tau=1/(2*pi*50); +a1=dt/tau-1; a0=1; +b0=1+ a1; +TMdisp_b=b0; TMdisp_a=[a0 a1]; +% figure(9), freqz(TMdisp_b, TMdisp_a) +OME_TMdisplacementBndry=[]; + +% OME high pass (simulates poor low frequency stapes response) +OMEhighPassHighCutOff=OMEParams.OMEstapesLPcutoff; +Nyquist=sampleRate/2; +[stapesDisp_b,stapesDisp_a] = butter(1, OMEhighPassHighCutOff/Nyquist, 'high'); +% figure(10), freqz(stapesDisp_b, stapesDisp_a) + +OMEhighPassBndry=[]; + +% OMEampStapes might be reducdant (use OMEParams.stapesScalar) +stapesScalar= OMEParams.stapesScalar; + +% Acoustic reflex +efferentDelayPts=round(OMEParams.ARdelay/dt); +% smoothing filter +% Nyquist=(1/ANdt)/2; +% [ARfilt_b,ARfilt_a] = butter(1, (1/(2*pi*OMEParams.ARtau))/Nyquist, 'low'); +a1=dt/OMEParams.ARtau-1; a0=1; +b0=1+ a1; +ARfilt_b=b0; ARfilt_a=[a0 a1]; + +ARattenuation=ones(1,signalLength); +ARrateThreshold=OMEParams.ARrateThreshold; % may not be used +ARrateToAttenuationFactor=OMEParams.rateToAttenuationFactor; +ARrateToAttenuationFactorProb=OMEParams.rateToAttenuationFactorProb; +ARboundary=[]; +ARboundaryProb=0; + +% save complete OME record (stapes displacement) +OMEoutput=zeros(1,signalLength); +TMoutput=zeros(1,signalLength); + +%% BM --- +% BM is represented as a list of locations identified by BF +DRNL_BFs=BFlist; +nBFs= length(DRNL_BFs); + +% DRNLchannelParameters=DRNLParams.channelParameters; +DRNLresponse= zeros(nBFs, segmentLength); + +MOCrateToAttenuationFactor=DRNLParams.rateToAttenuationFactor; +rateToAttenuationFactorProb=DRNLParams.rateToAttenuationFactorProb; +MOCrateThreshold=DRNLParams.MOCrateThreshold; + +% smoothing filter for MOC +% Nyquist=(1/ANdt)/2; +% [MOCfilt_b,MOCfilt_a] = ... +% butter(1, (1/(2*pi*DRNLParams.MOCtau))/Nyquist, 'low'); +% figure(10), freqz(stapesDisp_b, stapesDisp_a) +a1=dt/DRNLParams.MOCtau-1; a0=1; +b0=1+ a1; +MOCfilt_b=b0; MOCfilt_a=[a0 a1]; +% figure(9), freqz(stapesDisp_b, stapesDisp_a) +MOCboundary=cell(nBFs,1); +MOCprobBoundary=cell(nBFs,1); + +MOCattSegment=zeros(nBFs,reducedSegmentLength); +MOCattenuation=ones(nBFs,signalLength); + +if DRNLParams.a>0 + DRNLcompressionThreshold=10^((1/(1-DRNLParams.c))* ... + log10(DRNLParams.b/DRNLParams.a)); +else + DRNLcompressionThreshold=inf; +end + +DRNLlinearOrder= DRNLParams.linOrder; +DRNLnonlinearOrder= DRNLParams.nonlinOrder; + +DRNLa=DRNLParams.a; +DRNLb=DRNLParams.b; +DRNLc=DRNLParams.c; +linGAIN=DRNLParams.g; +% +% gammatone filter coefficients for linear pathway +bw=DRNLParams.linBWs'; +phi = 2 * pi * bw * dt; +cf=DRNLParams.linCFs'; +theta = 2 * pi * cf * dt; +cos_theta = cos(theta); +sin_theta = sin(theta); +alpha = -exp(-phi).* cos_theta; +b0 = ones(nBFs,1); +b1 = 2 * alpha; +b2 = exp(-2 * phi); +z1 = (1 + alpha .* cos_theta) - (alpha .* sin_theta) * i; +z2 = (1 + b1 .* cos_theta) - (b1 .* sin_theta) * i; +z3 = (b2 .* cos(2 * theta)) - (b2 .* sin(2 * theta)) * i; +tf = (z2 + z3) ./ z1; +a0 = abs(tf); +a1 = alpha .* a0; +GTlin_a = [b0, b1, b2]; +GTlin_b = [a0, a1]; +GTlinOrder=DRNLlinearOrder; +GTlinBdry=cell(nBFs,GTlinOrder); + +% nonlinear gammatone filter coefficients +bw=DRNLParams.nlBWs'; +phi = 2 * pi * bw * dt; +cf=DRNLParams.nonlinCFs'; +theta = 2 * pi * cf * dt; +cos_theta = cos(theta); +sin_theta = sin(theta); +alpha = -exp(-phi).* cos_theta; +b0 = ones(nBFs,1); +b1 = 2 * alpha; +b2 = exp(-2 * phi); +z1 = (1 + alpha .* cos_theta) - (alpha .* sin_theta) * i; +z2 = (1 + b1 .* cos_theta) - (b1 .* sin_theta) * i; +z3 = (b2 .* cos(2 * theta)) - (b2 .* sin(2 * theta)) * i; +tf = (z2 + z3) ./ z1; +a0 = abs(tf); +a1 = alpha .* a0; +GTnonlin_a = [b0, b1, b2]; +GTnonlin_b = [a0, a1]; +GTnonlinOrder=DRNLnonlinearOrder; +GTnonlinBdry1=cell(nBFs, GTnonlinOrder); +GTnonlinBdry2=cell(nBFs, GTnonlinOrder); + +% complete BM record (BM displacement) +DRNLoutput=zeros(nBFs, signalLength); + + +%% IHC --- +% IHC cilia activity and receptor potential +% viscous coupling between BM and stereocilia displacement +% Nyquist=sampleRate/2; +% IHCcutoff=1/(2*pi*IHC_cilia_RPParams.tc); +% [IHCciliaFilter_b,IHCciliaFilter_a]=... +% butter(1, IHCcutoff/Nyquist, 'high'); +a1=dt/IHC_cilia_RPParams.tc-1; a0=1; +b0=1+ a1; +% high pass (i.e. low pass reversed) +IHCciliaFilter_b=[a0 a1]; IHCciliaFilter_a=b0; +% figure(9), freqz(IHCciliaFilter_b, IHCciliaFilter_a) + +IHCciliaBndry=cell(nBFs,1); + +% IHC apical conductance (Boltzman function) +IHC_C= IHC_cilia_RPParams.C; +IHCu0= IHC_cilia_RPParams.u0; +IHCu1= IHC_cilia_RPParams.u1; +IHCs0= IHC_cilia_RPParams.s0; +IHCs1= IHC_cilia_RPParams.s1; +IHCGmax= IHC_cilia_RPParams.Gmax; +IHCGu0= IHC_cilia_RPParams.Gu0; % (leakage) +IHCGa= IHCGmax./(1+exp(-(0-IHCu0)/IHCs0).*(1+exp(-(0-IHCu1)/IHCs1))); +IHCrestingCiliaCond=IHCGa+IHCGu0; + +% Receptor potential +IHC_Cab= IHC_cilia_RPParams.Cab; +IHC_Gk= IHC_cilia_RPParams.Gk; +IHC_Et= IHC_cilia_RPParams.Et; +IHC_Ek= IHC_cilia_RPParams.Ek; +IHC_Ekp= IHC_Ek+IHC_Et*IHC_cilia_RPParams.Rpc; + +IHCrestingV= -0.06; +IHC_Vnow= IHCrestingV*ones(nBFs,1); % initial voltage +IHC_RP= zeros(nBFs,segmentLength); + +% complete record of IHC receptor potential (V) +IHCciliaDisplacement= zeros(nBFs,segmentLength); +IHCoutput= zeros(nBFs,signalLength); +IHC_cilia_output= zeros(nBFs,signalLength); + + +%% pre-synapse --- +% Each BF is replicated using a different fiber type to make a 'channel' +% The number of channels is nBFs x nANfiberTypes +% Fiber types are specified in terms of tauCa +nANfiberTypes= length(IHCpreSynapseParams.tauCa); +tauCas= IHCpreSynapseParams.tauCa; +nChannels= nANfiberTypes*nBFs; +synapticCa= zeros(nChannels,segmentLength); + +% Calcium control (more calcium, greater release rate) +ECa=IHCpreSynapseParams.ECa; +gamma=IHCpreSynapseParams.gamma; +beta=IHCpreSynapseParams.beta; +tauM=IHCpreSynapseParams.tauM; +mICa=zeros(nChannels,segmentLength); +GmaxCa=IHCpreSynapseParams.GmaxCa; +synapse_z= IHCpreSynapseParams.z; +synapse_power=IHCpreSynapseParams.power; + +% tauCa vector is established across channels to allow vectorization +% (one tauCa per channel). Do not confuse with tauCas (one pre fiber type) +tauCa=repmat(tauCas, nBFs,1); +tauCa=reshape(tauCa, nChannels, 1); + +% presynapse startup values (vectors, length:nChannels) +% proportion (0 - 1) of Ca channels open at IHCrestingV +mICaCurrent=((1+beta^-1 * exp(-gamma*IHCrestingV))^-1)... + *ones(nBFs*nANfiberTypes,1); +% corresponding startup currents +ICaCurrent= (GmaxCa*mICaCurrent.^3) * (IHCrestingV-ECa); +CaCurrent= ICaCurrent.*tauCa; + +% vesicle release rate at startup (one per channel) +% kt0 is used only at initialisation +kt0= -synapse_z * CaCurrent.^synapse_power; + + +%% AN --- +% each row of the AN matrices represents one AN fiber +% The results computed either for probabiities *or* for spikes (not both) +% Spikes are necessary if CN and IC are to be computed +nFibersPerChannel= AN_IHCsynapseParams.numFibers; +nANfibers= nChannels*nFibersPerChannel; + +y=AN_IHCsynapseParams.y; +l=AN_IHCsynapseParams.l; +x=AN_IHCsynapseParams.x; +r=AN_IHCsynapseParams.r; +M=round(AN_IHCsynapseParams.M); + +% probability (NB initial 'P' on everything) +PAN_ydt = repmat(AN_IHCsynapseParams.y*dt, nChannels,1); +PAN_ldt = repmat(AN_IHCsynapseParams.l*dt, nChannels,1); +PAN_xdt = repmat(AN_IHCsynapseParams.x*dt, nChannels,1); +PAN_rdt = repmat(AN_IHCsynapseParams.r*dt, nChannels,1); +PAN_rdt_plus_ldt = PAN_rdt + PAN_ldt; +PAN_M=round(AN_IHCsynapseParams.M); + +% compute starting values +Pcleft = kt0* y* M ./ (y*(l+r)+ kt0* l); +Pavailable = Pcleft*(l+r)./kt0; +Preprocess = Pcleft*r/x; % canbe fractional + +ANprobability=zeros(nChannels,segmentLength); +ANprobRateOutput=zeros(nChannels,signalLength); +% special variables for monitoring synaptic cleft (specialists only) +savePavailableSeg=zeros(nChannels,segmentLength); +savePavailable=zeros(nChannels,signalLength); + +% spikes % ! ! ! ! ! ! ! ! +AN_refractory_period= AN_IHCsynapseParams.refractory_period; +lengthAbsRefractory= round(AN_refractory_period/ANdt); + +AN_ydt= repmat(AN_IHCsynapseParams.y*ANdt, nANfibers,1); +AN_ldt= repmat(AN_IHCsynapseParams.l*ANdt, nANfibers,1); +AN_xdt= repmat(AN_IHCsynapseParams.x*ANdt, nANfibers,1); +AN_rdt= repmat(AN_IHCsynapseParams.r*ANdt, nANfibers,1); +AN_rdt_plus_ldt= AN_rdt + AN_ldt; +AN_M= round(AN_IHCsynapseParams.M); + +% kt0 is initial release rate +% Establish as a vector (length=channel x number of fibers) +kt0= repmat(kt0', nFibersPerChannel, 1); +kt0=reshape(kt0, nANfibers,1); + +% starting values for reservoirs +AN_cleft = kt0* y* M ./ (y*(l+r)+ kt0* l); +AN_available = round(AN_cleft*(l+r)./kt0); %must be integer +AN_reprocess = AN_cleft*r/x; + +% output is in a logical array spikes = 1/ 0. +ANspikes= false(nANfibers,reducedSegmentLength); +ANoutput= false(nANfibers,reducedSignalLength); + + +%% CN (first brain stem nucleus - could be any subdivision of CN) +% Input to a CN neuorn is a random selection of AN fibers within a channel +% The number of AN fibers used is ANfibersFanInToCN +ANfibersFanInToCN=MacGregorMultiParams.fibersPerNeuron; +nCNneuronsPerChannel=MacGregorMultiParams.nNeuronsPerBF; +% CNtauGk (Potassium time constant) determines the rate of firing of +% the unit when driven hard by a DC input (not normally >350 sp/s) +CNtauGk=MacGregorMultiParams.tauGk; +ANavailableFibersPerChan=AN_IHCsynapseParams.numFibers; +nCNneurons=nCNneuronsPerChannel*nChannels; +% nCNneuronsPerFiberType= nCNneurons/nANfiberTypes; + +CNmembranePotential=zeros(nCNneurons,reducedSegmentLength); + +% establish which ANfibers (by name) feed into which CN nuerons +CNinputfiberLists=zeros(nChannels*nCNneuronsPerChannel, ANfibersFanInToCN); +unitNo=1; +for ch=1:nChannels + % Each channel contains a number of units =length(listOfFanInValues) + for idx=1:nCNneuronsPerChannel + fibersUsed=(ch-1)*ANavailableFibersPerChan + ... + ceil(rand(1,ANfibersFanInToCN)* ANavailableFibersPerChan); + CNinputfiberLists(unitNo,:)=fibersUsed; + unitNo=unitNo+1; + end +end + +% input to CN units +AN_PSTH=zeros(nCNneurons,reducedSegmentLength); + +% Generate CNalphaFunction function +% by which spikes are converted to post-synaptic currents +CNdendriteLPfreq= MacGregorMultiParams.dendriteLPfreq; +CNcurrentPerSpike=MacGregorMultiParams.currentPerSpike; +CNspikeToCurrentTau=1/(2*pi*CNdendriteLPfreq); +t=ANdt:ANdt:5*CNspikeToCurrentTau; +CNalphaFunction=... + (CNcurrentPerSpike/CNspikeToCurrentTau)*t.*exp(-t/CNspikeToCurrentTau); +% figure(98), plot(t,CNalphaFunction) +% working memory for implementing convolution +CNcurrentTemp=... + zeros(nCNneurons,reducedSegmentLength+length(CNalphaFunction)-1); +% trailing alphas are parts of humps carried forward to the next segment +CNtrailingAlphas=zeros(nCNneurons,length(CNalphaFunction)); + +CN_tauM=MacGregorMultiParams.tauM; +CN_tauTh=MacGregorMultiParams.tauTh; +CN_cap=MacGregorMultiParams.Cap; +CN_c=MacGregorMultiParams.c; +CN_b=MacGregorMultiParams.dGkSpike; +CN_Ek=MacGregorMultiParams.Ek; +CN_Eb= MacGregorMultiParams.Eb; +CN_Er=MacGregorMultiParams.Er; +CN_Th0= MacGregorMultiParams.Th0; +CN_E= zeros(nCNneurons,1); +CN_Gk= zeros(nCNneurons,1); +CN_Th= MacGregorMultiParams.Th0*ones(nCNneurons,1); +CN_Eb=CN_Eb.*ones(nCNneurons,1); +CN_Er=CN_Er.*ones(nCNneurons,1); +CNtimeSinceLastSpike=zeros(nCNneurons,1); +% tauGk is the main distinction between neurons +% in fact they are all the same in the standard model +tauGk=repmat(CNtauGk,nChannels*nCNneuronsPerChannel,1); + +CN_PSTH=zeros(nChannels,reducedSegmentLength); +CNoutput=false(nCNneurons,reducedSignalLength); + + +%% MacGregor (IC - second nucleus) -------- +nICcells=nChannels; % one cell per channel + +ICspikeWidth=0.00015; % this may need revisiting +epochsPerSpike=round(ICspikeWidth/ANdt); +if epochsPerSpike<1 + error(['MacGregorMulti: sample rate too low to support ' ... + num2str(ICspikeWidth*1e6) ' microsec spikes']); +end + +% short names +IC_tauM=MacGregorParams.tauM; +IC_tauGk=MacGregorParams.tauGk; +IC_tauTh=MacGregorParams.tauTh; +IC_cap=MacGregorParams.Cap; +IC_c=MacGregorParams.c; +IC_b=MacGregorParams.dGkSpike; +IC_Th0=MacGregorParams.Th0; +IC_Ek=MacGregorParams.Ek; +IC_Eb= MacGregorParams.Eb; +IC_Er=MacGregorParams.Er; + +IC_E=zeros(nICcells,1); +IC_Gk=zeros(nICcells,1); +IC_Th=IC_Th0*ones(nICcells,1); + +% Dendritic filtering, all spikes are replaced by CNalphaFunction functions +ICdendriteLPfreq= MacGregorParams.dendriteLPfreq; +ICcurrentPerSpike=MacGregorParams.currentPerSpike; +ICspikeToCurrentTau=1/(2*pi*ICdendriteLPfreq); +t=ANdt:ANdt:3*ICspikeToCurrentTau; +IC_CNalphaFunction= (ICcurrentPerSpike / ... + ICspikeToCurrentTau)*t.*exp(-t / ICspikeToCurrentTau); +% figure(98), plot(t,IC_CNalphaFunction) + +% working space for implementing alpha function +ICcurrentTemp=... + zeros(nICcells,reducedSegmentLength+length(IC_CNalphaFunction)-1); +ICtrailingAlphas=zeros(nICcells, length(IC_CNalphaFunction)); + +ICfiberTypeRates=zeros(nANfiberTypes,reducedSignalLength); +ICoutput=false(nChannels,reducedSignalLength); + +ICmembranePotential=zeros(nICcells,reducedSegmentLength); +ICmembraneOutput=zeros(nICcells,signalLength); + + +%% Main program %% %% %% %% %% %% %% %% %% %% %% %% %% %% + +% Compute the entire model for each segment +segmentStartPTR=1; +reducedSegmentPTR=1; % when sampling rate is reduced +while segmentStartPTRefferentDelayPts + stapesDisplacement= stapesDisplacement.*... + ARattenuation(segmentStartPTR-efferentDelayPts:... + segmentEndPTR-efferentDelayPts); + end + + % segment debugging plots + % figure(98) + % plot(segmentTime, stapesDisplacement), title ('stapesDisplacement') + + % and save + OMEoutput(segmentStartPTR:segmentEndPTR)= stapesDisplacement; + + + %% BM ------------------------------ + % Each location is computed separately + for BFno=1:nBFs + + % *linear* path + linOutput = stapesDisplacement * linGAIN; % linear gain + for order = 1 : GTlinOrder + [linOutput GTlinBdry{BFno,order}] = ... + filter(GTlin_b(BFno,:), GTlin_a(BFno,:), linOutput, GTlinBdry{BFno,order}); + end + + % *nonLinear* path + % efferent attenuation (0 <> 1) + if segmentStartPTR>efferentDelayPts + MOC=MOCattenuation(BFno, segmentStartPTR-efferentDelayPts:... + segmentEndPTR-efferentDelayPts); + else % no MOC available yet + MOC=ones(1, segmentLength); + end + + % first gammatone filter + for order = 1 : GTnonlinOrder + [nonlinOutput GTnonlinBdry1{BFno,order}] = ... + filter(GTnonlin_b(BFno,:), GTnonlin_a(BFno,:), ... + stapesDisplacement, GTnonlinBdry1{BFno,order}); + end + + % broken stick instantaneous compression + % nonlinear gain is weakend by MOC before applied to BM response + y= nonlinOutput.*(MOC* DRNLa); % linear section. + % compress those parts of the signal above the compression + % threshold + abs_x = abs(nonlinOutput); + idx=find(abs_x>DRNLcompressionThreshold); + if ~isempty(idx)>0 + y(idx)=sign(nonlinOutput(idx)).*... + (DRNLb*abs_x(idx).^DRNLc); + end + nonlinOutput=y; + + % second filter removes distortion products + for order = 1 : GTnonlinOrder + [ nonlinOutput GTnonlinBdry2{BFno,order}] = ... + filter(GTnonlin_b(BFno,:), GTnonlin_a(BFno,:), nonlinOutput, GTnonlinBdry2{BFno,order}); + end + + % combine the two paths to give the DRNL displacement + DRNLresponse(BFno,:)=linOutput+nonlinOutput; + end % BF + + % segment debugging plots + % figure(98) + % if size(DRNLresponse,1)>3 + % imagesc(DRNLresponse) % matrix display + % title('DRNLresponse'); % single or double channel response + % else + % plot(segmentTime, DRNLresponse) + % end + + % and save it + DRNLoutput(:, segmentStartPTR:segmentEndPTR)= DRNLresponse; + + + %% IHC ------------------------------------ + % BM displacement to IHCciliaDisplacement is a high-pass filter + % because of viscous coupling + for idx=1:nBFs + [IHCciliaDisplacement(idx,:) IHCciliaBndry{idx}] = ... + filter(IHCciliaFilter_b,IHCciliaFilter_a, ... + DRNLresponse(idx,:), IHCciliaBndry{idx}); + end + + % apply scalar + IHCciliaDisplacement=IHCciliaDisplacement* IHC_C; + + % and save it + IHC_cilia_output(:,segmentStartPTR:segmentStartPTR+segmentLength-1)=... + IHCciliaDisplacement; + + % compute apical conductance + G=1./(1+exp(-(IHCciliaDisplacement-IHCu0)/IHCs0).*... + (1+exp(-(IHCciliaDisplacement-IHCu1)/IHCs1))); + Gu=IHCGmax*G; + % add resting conductance to give apical conductance + Gu= Gu+IHCGu0; + + % Compute receptor potential + for idx=1:segmentLength + IHC_Vnow=IHC_Vnow+ (-Gu(:, idx).*(IHC_Vnow-IHC_Et)-... + IHC_Gk*(IHC_Vnow-IHC_Ekp))* dt/IHC_Cab; + IHC_RP(:,idx)=IHC_Vnow; + end + + % segment debugging plots + % if size(IHC_RP,1)>3 + % surf(IHC_RP), shading interp, title('IHC_RP') + % else + % plot(segmentTime, IHC_RP) + % end + + % and save it + IHCoutput(:, segmentStartPTR:segmentStartPTR+segmentLength-1)=IHC_RP; + + + %% synapse ----------------------------- + % Compute the vesicle release rate for each fiber type at each BF + % replicate IHC_RP for each fiber type + Vsynapse=repmat(IHC_RP, nANfiberTypes,1); + + % look-up table of target fraction channels open for a given IHC_RP + mICaINF= 1./( 1 + exp(-gamma * Vsynapse) /beta); + % fraction of channel open - apply time constant + for idx=1:segmentLength + % mICaINF is the current 'target' value of mICa + mICaCurrent=mICaCurrent+(mICaINF(:,idx)-mICaCurrent)*dt./tauM; + mICa(:,idx)=mICaCurrent; + end + + ICa= (GmaxCa* mICa.^3) .* (Vsynapse- ECa); + + for idx=1:segmentLength + CaCurrent=CaCurrent + ICa(:,idx)*dt - CaCurrent*dt./tauCa; + synapticCa(:,idx)=CaCurrent; + end + synapticCa=-synapticCa; % treat IHCpreSynapseParams as positive substance + + % NB vesicleReleaseRate is /s and is independent of dt + vesicleReleaseRate = synapse_z * synapticCa.^synapse_power; % rate + + % segment debugging plots + % if size(vesicleReleaseRate,1)>3 + % surf(vesicleReleaseRate), shading interp, title('vesicleReleaseRate') + % else + % plot(segmentTime, vesicleReleaseRate) + % end + + + %% AN + switch AN_spikesOrProbability + case 'probability' + % No refractory effect is applied + for t = 1:segmentLength; + M_Pq=PAN_M-Pavailable; + M_Pq(M_Pq<0)=0; + Preplenish = M_Pq .* PAN_ydt; + Pejected = Pavailable.* vesicleReleaseRate(:,t)*dt; + Preprocessed = M_Pq.*Preprocess.* PAN_xdt; + + ANprobability(:,t)= min(Pejected,1); + reuptakeandlost= PAN_rdt_plus_ldt .* Pcleft; + reuptake= PAN_rdt.* Pcleft; + + Pavailable= Pavailable+ Preplenish- Pejected+ Preprocessed; + Pcleft= Pcleft + Pejected - reuptakeandlost; + Preprocess= Preprocess + reuptake - Preprocessed; + Pavailable(Pavailable<0)=0; + savePavailableSeg(:,t)=Pavailable; % synapse tracking + end + % and save it as *rate* + ANrate=ANprobability/dt; + ANprobRateOutput(:, segmentStartPTR:... + segmentStartPTR+segmentLength-1)= ANrate; + % monitor synapse contents (only sometimes used) + savePavailable(:, segmentStartPTR:segmentStartPTR+segmentLength-1)=... + savePavailableSeg; + + % Estimate efferent effects. ARattenuation (0 <> 1) + % acoustic reflex + ARAttSeg=mean(ANrate(1:nBFs,:),1); %LSR channels are 1:nBF + % smooth + [ARAttSeg, ARboundaryProb] = ... + filter(ARfilt_b, ARfilt_a, ARAttSeg, ARboundaryProb); + ARAttSeg=ARAttSeg-ARrateThreshold; + ARAttSeg(ARAttSeg<0)=0; % prevent negative strengths + ARattenuation(segmentStartPTR:segmentEndPTR)=... + (1-ARrateToAttenuationFactorProb.* ARAttSeg); + + % MOC attenuation + % within-channel HSR response only + HSRbegins=nBFs*(nANfiberTypes-1)+1; + rates=ANrate(HSRbegins:end,:); + for idx=1:nBFs + [smoothedRates, MOCprobBoundary{idx}] = ... + filter(MOCfilt_b, MOCfilt_a, rates(idx,:), ... + MOCprobBoundary{idx}); + smoothedRates=smoothedRates-MOCrateThreshold; + smoothedRates(smoothedRates<0)=0; + MOCattenuation(idx,segmentStartPTR:segmentEndPTR)= ... + (1- smoothedRates* rateToAttenuationFactorProb); + end + MOCattenuation(MOCattenuation<0)=0.001; + + + case 'spikes' + ANtimeCount=0; + % implement speed upt + for t = ANspeedUpFactor:ANspeedUpFactor:segmentLength; + ANtimeCount=ANtimeCount+1; + % convert release rate to probabilities + releaseProb=vesicleReleaseRate(:,t)*ANdt; + % releaseProb is the release probability per channel + % but each channel has many synapses + releaseProb=repmat(releaseProb',nFibersPerChannel,1); + releaseProb=reshape(releaseProb, nFibersPerChannel*nChannels,1); + + % AN_available=round(AN_available); % vesicles must be integer, (?needed) + M_q=AN_M- AN_available; % number of missing vesicles + M_q(M_q<0)= 0; % cannot be less than 0 + + % AN_N1 converts probability to discrete events + % it considers each event that might occur + % (how many vesicles might be released) + % and returns a count of how many were released + + % slow line +% probabilities= 1-(1-releaseProb).^AN_available; + probabilities= 1-intpow((1-releaseProb), AN_available); + ejected= probabilities> rand(length(AN_available),1); + + reuptakeandlost = AN_rdt_plus_ldt .* AN_cleft; + reuptake = AN_rdt.* AN_cleft; + + % slow line +% probabilities= 1-(1-AN_reprocess.*AN_xdt).^M_q; + probabilities= 1-intpow((1-AN_reprocess.*AN_xdt), M_q); + reprocessed= probabilities>rand(length(M_q),1); + + % slow line +% probabilities= 1-(1-AN_ydt).^M_q; + probabilities= 1-intpow((1-AN_ydt), M_q); + + replenish= probabilities>rand(length(M_q),1); + + AN_available = AN_available + replenish - ejected ... + + reprocessed; + AN_cleft = AN_cleft + ejected - reuptakeandlost; + AN_reprocess = AN_reprocess + reuptake - reprocessed; + + % ANspikes is logical record of vesicle release events>0 + ANspikes(:, ANtimeCount)= ejected; + end % t + + % zero any events that are preceded by release events ... + % within the refractory period + % The refractory period consist of two periods + % 1) the absolute period where no spikes occur + % 2) a relative period where a spike may occur. This relative + % period is realised as a variable length interval + % where the length is chosen at random + % (esentially a linear ramp up) + + % Andreas has a fix for this + for t = 1:ANtimeCount-2*lengthAbsRefractory; + % identify all spikes across fiber array at time (t) + % idx is a list of channels where spikes occurred + % ?? try sparse matrices? + idx=find(ANspikes(:,t)); + for j=idx % consider each spike + % specify variable refractory period + % between abs and 2*abs refractory period + nPointsRefractory=lengthAbsRefractory+... + round(rand*lengthAbsRefractory); + % disable spike potential for refractory period + % set all values in this range to 0 + ANspikes(j,t+1:t+nPointsRefractory)=0; + end + end %t + + % segment debugging + % plotInstructions.figureNo=98; + % plotInstructions.displaydt=ANdt; + % plotInstructions.numPlots=1; + % plotInstructions.subPlotNo=1; + % UTIL_plotMatrix(ANspikes, plotInstructions); + + % and save it. NB, AN is now on 'speedUp' time + ANoutput(:, reducedSegmentPTR: shorterSegmentEndPTR)=ANspikes; + + + %% CN Macgregor first neucleus ------------------------------- + % input is from AN so ANdt is used throughout + % Each CNneuron has a unique set of input fibers selected + % at random from the available AN fibers (CNinputfiberLists) + + % Create the dendritic current for that neuron + % First get input spikes to this neuron + synapseNo=1; + for ch=1:nChannels + for idx=1:nCNneuronsPerChannel + % determine candidate fibers for this unit + fibersUsed=CNinputfiberLists(synapseNo,:); + % ANpsth has a bin width of dt + % (just a simple sum across fibers) + AN_PSTH(synapseNo,:) = ... + sum(ANspikes(fibersUsed,:), 1); + synapseNo=synapseNo+1; + end + end + + % One alpha function per spike + [alphaRows alphaCols]=size(CNtrailingAlphas); + + for unitNo=1:nCNneurons + CNcurrentTemp(unitNo,:)= ... + conv(AN_PSTH(unitNo,:),CNalphaFunction); + end + % add post-synaptic current left over from previous segment + CNcurrentTemp(:,1:alphaCols)=... + CNcurrentTemp(:,1:alphaCols)+ CNtrailingAlphas; + + % take post-synaptic current for this segment + CNcurrentInput= CNcurrentTemp(:, 1:reducedSegmentLength); + + % trailingalphas are the ends of the alpha functions that + % spill over into the next segment + CNtrailingAlphas= ... + CNcurrentTemp(:, reducedSegmentLength+1:end); + + if CN_c>0 + % variable threshold condition (slow) + for t=1:reducedSegmentLength + CNtimeSinceLastSpike=CNtimeSinceLastSpike-dts; + s=CN_E>CN_Th & CNtimeSinceLastSpike<0 ; + CNtimeSinceLastSpike(s)=0.0005; % 0.5 ms for sodium spike + dE =(-CN_E/CN_tauM + ... + CNcurrentInput(:,t)/CN_cap+(CN_Gk/CN_cap).*(CN_Ek-CN_E))*dt; + dGk=-CN_Gk*dt./tauGk + CN_b*s; + dTh=-(CN_Th-CN_Th0)*dt/CN_tauTh + CN_c*s; + CN_E=CN_E+dE; + CN_Gk=CN_Gk+dGk; + CN_Th=CN_Th+dTh; + CNmembranePotential(:,t)=CN_E+s.*(CN_Eb-CN_E)+CN_Er; + end + else + % static threshold (faster) + for t=1:reducedSegmentLength + CNtimeSinceLastSpike=CNtimeSinceLastSpike-dt; + s=CN_E>CN_Th0 & CNtimeSinceLastSpike<0 ; % =1 if both conditions met + CNtimeSinceLastSpike(s)=0.0005; % 0.5 ms for sodium spike + dE = (-CN_E/CN_tauM + ... + CNcurrentInput(:,t)/CN_cap+(CN_Gk/CN_cap).*(CN_Ek-CN_E))*dt; + dGk=-CN_Gk*dt./tauGk +CN_b*s; + CN_E=CN_E+dE; + CN_Gk=CN_Gk+dGk; + % add spike to CN_E and add resting potential (-60 mV) + CNmembranePotential(:,t)=CN_E+s.*(CN_Eb-CN_E)+CN_Er; + end + end + + % extract spikes. A spike is a substantial upswing in voltage + CN_spikes=CNmembranePotential> -0.01; + + % now remove any spike that is immediately followed by a spike + % NB 'find' works on columns (whence the transposing) + CN_spikes=CN_spikes'; + idx=find(CN_spikes); + idx=idx(1:end-1); + CN_spikes(idx+1)=0; + CN_spikes=CN_spikes'; + + % segment debugging + % plotInstructions.figureNo=98; + % plotInstructions.displaydt=ANdt; + % plotInstructions.numPlots=1; + % plotInstructions.subPlotNo=1; + % UTIL_plotMatrix(CN_spikes, plotInstructions); + + % and save it + CNoutput(:, reducedSegmentPTR:shorterSegmentEndPTR)=... + CN_spikes; + + + %% IC ---------------------------------------------- + % MacGregor or some other second order neurons + + % combine CN neurons in same channel, i.e. same BF & same tauCa + % to generate inputs to single IC unit + channelNo=0; + for idx=1:nCNneuronsPerChannel:nCNneurons-nCNneuronsPerChannel+1; + channelNo=channelNo+1; + CN_PSTH(channelNo,:)=... + sum(CN_spikes(idx:idx+nCNneuronsPerChannel-1,:)); + end + + [alphaRows alphaCols]=size(ICtrailingAlphas); + for ICneuronNo=1:nICcells + ICcurrentTemp(ICneuronNo,:)= ... + conv(CN_PSTH(ICneuronNo,:), IC_CNalphaFunction); + end + + % add the unused current from the previous convolution + ICcurrentTemp(:,1:alphaCols)=ICcurrentTemp(:,1:alphaCols)... + + ICtrailingAlphas; + % take what is required and keep the trailing part for next time + inputCurrent=ICcurrentTemp(:, 1:reducedSegmentLength); + ICtrailingAlphas=ICcurrentTemp(:, reducedSegmentLength+1:end); + + if IC_c==0 + % faster computation when threshold is stable (C==0) + for t=1:reducedSegmentLength + s=IC_E>IC_Th0; + dE = (-IC_E/IC_tauM + inputCurrent(:,t)/IC_cap +... + (IC_Gk/IC_cap).*(IC_Ek-IC_E))*dt; + dGk=-IC_Gk*dt/IC_tauGk +IC_b*s; + IC_E=IC_E+dE; + IC_Gk=IC_Gk+dGk; + ICmembranePotential(:,t)=IC_E+s.*(IC_Eb-IC_E)+IC_Er; + end + else + % threshold is changing (IC_c>0; e.g. bushy cell) + for t=1:reducedSegmentLength + dE = (-IC_E/IC_tauM + ... + inputCurrent(:,t)/IC_cap + (IC_Gk/IC_cap)... + .*(IC_Ek-IC_E))*dt; + IC_E=IC_E+dE; + s=IC_E>IC_Th; + ICmembranePotential(:,t)=IC_E+s.*(IC_Eb-IC_E)+IC_Er; + dGk=-IC_Gk*dt/IC_tauGk +IC_b*s; + IC_Gk=IC_Gk+dGk; + + % After a spike, the threshold is raised + % otherwise it settles to its baseline + dTh=-(IC_Th-Th0)*dt/IC_tauTh +s*IC_c; + IC_Th=IC_Th+dTh; + end + end + + ICspikes=ICmembranePotential> -0.01; + % now remove any spike that is immediately followed by a spike + % NB 'find' works on columns (whence the transposing) + ICspikes=ICspikes'; + idx=find(ICspikes); + idx=idx(1:end-1); + ICspikes(idx+1)=0; + ICspikes=ICspikes'; + + nCellsPerTau= nICcells/nANfiberTypes; + firstCell=1; + lastCell=nCellsPerTau; + for tauCount=1:nANfiberTypes + % separate rates according to fiber types + ICfiberTypeRates(tauCount, ... + reducedSegmentPTR:shorterSegmentEndPTR)=... + sum(ICspikes(firstCell:lastCell, :))... + /(nCellsPerTau*ANdt); + firstCell=firstCell+nCellsPerTau; + lastCell=lastCell+nCellsPerTau; + end + ICoutput(:, reducedSegmentPTR:shorterSegmentEndPTR)=ICspikes; + + if nBFs==1 % single channel + x= repmat(ICmembranePotential(1,:), ANspeedUpFactor,1); + x= reshape(x,1,segmentLength); + if nANfiberTypes>1 % save HSR and LSR + y= repmat(ICmembranePotential(end,:), ANspeedUpFactor,1); + y= reshape(y,1,segmentLength); + x=[x; y]; + end + ICmembraneOutput(:, segmentStartPTR:segmentEndPTR)= x; + end + + % estimate efferent effects. + % ARis based on LSR units. LSR channels are 1:nBF + if nANfiberTypes>1 % AR is multi-channel only + ARAttSeg=sum(ICspikes(1:nBFs,:),1)/ANdt; + [ARAttSeg, ARboundary] = ... + filter(ARfilt_b, ARfilt_a, ARAttSeg, ARboundary); + ARAttSeg=ARAttSeg-ARrateThreshold; + ARAttSeg(ARAttSeg<0)=0; % prevent negative strengths + % scale up to dt from ANdt + x= repmat(ARAttSeg, ANspeedUpFactor,1); + x=reshape(x,1,segmentLength); + ARattenuation(segmentStartPTR:segmentEndPTR)=... + (1-ARrateToAttenuationFactor* x); + ARattenuation(ARattenuation<0)=0.001; + else + % single channel model; disable AR + ARattenuation(segmentStartPTR:segmentEndPTR)=... + ones(1,segmentLength); + end + + % MOC attenuation using HSR response only + % Separate MOC effect for each BF + HSRbegins=nBFs*(nANfiberTypes-1)+1; + rates=ICspikes(HSRbegins:end,:)/ANdt; + for idx=1:nBFs + [smoothedRates, MOCboundary{idx}] = ... + filter(MOCfilt_b, MOCfilt_a, rates(idx,:), ... + MOCboundary{idx}); + MOCattSegment(idx,:)=smoothedRates; + % expand timescale back to model dt from ANdt + x= repmat(MOCattSegment(idx,:), ANspeedUpFactor,1); + x= reshape(x,1,segmentLength); + MOCattenuation(idx,segmentStartPTR:segmentEndPTR)= ... + (1- MOCrateToAttenuationFactor* x); + end + MOCattenuation(MOCattenuation<0)=0.04; + % segment debugging + % plotInstructions.figureNo=98; + % plotInstructions.displaydt=ANdt; + % plotInstructions.numPlots=1; + % plotInstructions.subPlotNo=1; + % UTIL_plotMatrix(ICspikes, plotInstructions); + + end % AN_spikesOrProbability + segmentStartPTR=segmentStartPTR+segmentLength; + reducedSegmentPTR=reducedSegmentPTR+reducedSegmentLength; + + +end % segment + +path(restorePath) \ No newline at end of file diff -r 000000000000 -r f233164f4c86 MAP/filteredSACF.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MAP/filteredSACF.m Fri May 27 13:19:21 2011 +0100 @@ -0,0 +1,235 @@ +function [P, BFlist, sacf, boundaryValue] = ... + filteredSACF(inputSignalMatrix, method, params) +% UTIL_filteredSACF computes within-channel, running autocorrelations (acfs) +% and finds the sum across channels (sacf). +% The SACF is smoothed to give the 'p function' (P). +% +% INPUT +% inputSignalMatrix: a matrix (channel x time) of AN activity +% method.dt: the signal sampling interval in seconds +% method.segmentNo: +% method.nonlinCF +% +% params: a list of parmeters to guide the computation: +% filteredSACFParams.lags: an array of lags to be computed (seconds) +% filteredSACFParams.acfTau: time constant (sec) of the running acf calculations +% if acfTau>1 it is assumed that Wiegrebe'sacf method +% for calculating tau is to be used (see below) +% filteredSACFParams.Lambda: time constant for smoothing thsacf to make P +% filteredSACFParams.lagsProcedure identifies a strategy for omitting some lags. +% Options are: 'useAllLags', 'omitShortLags', or 'useBernsteinLagWeights' +% filteredSACFParams.usePressnitzer applies lower weights longer lags +% parafilteredSACFParamsms.plotACFs (=1) creates movie of acf matrix (optional) +% +% +% OUTPUT +% P: P function (time x lags), a low pass filtered version of sacf. +% method: updated version of input method (to include lags used) +% sacf: (time x lags) + +%% +boundaryValue=[]; +[nChannels inputLength]= size(inputSignalMatrix); +% list of BFs must be repeated is many fiber types used +BFlist=method.nonlinCF; +nfibertypes=nChannels/length(BFlist); +BFlist=repmat(BFlist',2,1)'; + +dt=method.dt; +% adjust sample rate, if required +if isfield(params,'dt') + [inputSignalMatrix dt]=UTIL_adjustDT(params.dt, method.dt, inputSignalMatrix); + method.dt=dt; +end + +% create acf movie +if isfield(params, 'plotACFs') && params.plotACFs==1 + plotACF=1; +else + plotACF=0; % default +end + +if isfield(params,'lags') + lags=params.lags; +else + lags=params.minLag:params.lagStep:params.maxLag; +end +nLags=length(lags); + +% Establish lag weightsaccording to params.lagsProcedure +% lagWeights allow some lag computations to be ignored +% lagWeights is a (channel x lag) matrix; +if isfield(params, 'lagsProcedure') + lagsProcedure=params.lagsProcedure; +else + lagsProcedure='useAllLags'; % default +end +% disp(['lag procedure= ''' lagsProcedure '''']) +lagWeights=ones(nChannels,nLags); +switch lagsProcedure + case 'useAllLags' + % no action required lagWeights set above + case 'omitShortLags' + % remove lags that are short relative to CF + allLags=repmat(lags,nChannels,1); + allCFs=repmat(BFlist',1,nLags); + criterionForOmittingLags=1./(params.criterionForOmittingLags*allCFs); + idx= allLags < criterionForOmittingLags; % ignore these lags + lagWeights(idx)=0; + case 'useBernsteinLagWeights' + lagWeights=BernsteinLags(BFlist, lags)'; + otherwise + error ('acf: params.lagProcedure not recognised') +end + + +% Establish matrix of lag time constants +% these are all the same if tau<1 +% if acfTau>1, it is assumed that we are using the Wiegrebe method +% and a different decay factor is applied to each lag +% ( i.e., longer lags have longer time constants) +acfTau=params.acfTau; +if acfTau<1 % all taus are the same + acfTaus=repmat(acfTau, 1, nLags); + acfDecayFactors=ones(size(lags)).*exp(-dt/acfTau); +else % use Wiegrebe method: tau= 2*lag (for example) + WiegrebeFactor=acfTau; + acfTaus=WiegrebeFactor*lags; + idx= acfTaus<0.0025; acfTaus(idx)=0.0025; + acfDecayFactors= exp(-dt./(acfTaus)); +end +% make acfDecayFactors into a (channels x lags) matrix for speedy computation +acfDecayFactors=repmat(acfDecayFactors,nChannels, 1); + +% P function lowpass filter decay (only one value needed) +pDecayFactor=exp(-dt/params.lambda); + +% ACF +% lagPointers is a list of pointers relative to 'time now' +lagPointers=round(lags/dt); +if max(lagPointers)+1>inputLength + error([' filteredSACF: not enough signal to evaluate ACF. Max(lag)= ' num2str(max(lags))]) +end + + +P=zeros(nLags,inputLength+1); % P must match segment length +1 +sacf=zeros(nLags,inputLength); +if ~isfield(method,'segmentNumber') || method.segmentNumber==1 + acf=zeros(nChannels,nLags); + % create a runup buffer of signal + buffer= zeros(nChannels, max(lagPointers)); +else + % boundaryValue picks up from a previous calculation + acf=params.boundaryValue{1}; + P(: , 1)=params.boundaryValue{2}; % NB first value is last value of previous segment + buffer=params.boundaryValue{3}; +end +inputSignalMatrix=[buffer inputSignalMatrix]; +[nChannels inputLength]= size(inputSignalMatrix); + +timeCounter=0; biggestSACF=0; +for timePointer= max(lagPointers)+1:inputLength + % acf is a continuously changing channels x lags matrix + % Only the current value is stored + % sacf is the vertical summary of acf ( a vector) and all values are kept and returned + % P is the smoothed version of sacf and all values are kept and returned + % lagWeights emphasise some BF/lag combinations and ignore others + % NB time now begins at the longest lag. + % E.g. if max(lags) is .04 then this is when the ACf will begin. + % AN AN delayed weights filtering + + % This is the ACF calculation + timeCounter=timeCounter+1; + acf= (repmat(inputSignalMatrix(:, timePointer), 1, nLags) .* inputSignalMatrix(:, timePointer-lagPointers)).*lagWeights *dt + acf.* acfDecayFactors; + x=(mean(acf,1)./acfTaus)'; +% disp(num2str(x')) + sacf(:,timeCounter)=x; + P(:,timeCounter+1)=sacf(:,timeCounter)*(1-pDecayFactor)+P(:,timeCounter)*pDecayFactor; + + % plot at intervals of 200 points + if plotACF && ~mod(timePointer,params.plotACFsInterval) + % mark cursor on chart to signal progress + % this assumes that the user has already plotted + % the signal in subplot(2,1,1) of figure (13) + figure(13) + hold on + subplot(4,1,1) + time=timePointer*dt; + a =ylim; + plot([time time], [a(1) a(1)+(a(2)-a(1))/4]) % current signal point marker + + % plot ACFs one per channel + subplot(2,1,2), cla + cascadePlot(acf, lags, BFlist) + xlim([min(lags) max(lags)]) + % set(gca,'xscale','log') + title(num2str(method.dt*timePointer)) + ylabel('BF'), xlabel('period (lag)') + + % plot SACF + subplot(4,1,2), hold off + plot(lags,sacf(:,timeCounter)-min(sacf(:,timeCounter))) + biggestSACF=max(biggestSACF, max(sacf(:,timeCounter))); + if biggestSACF>0, ylim([0 biggestSACF]), end + % set(gca,'xscale','log') + title('SACF') + pause(params.plotMoviePauses) + end +end +P=P(:,1:end-1); % correction for speed up above + +% Pressnitzer weights +if ~isfield(params, 'usePressnitzer'), params.usePressnitzer=0; end +if params.usePressnitzer + [a nTimePoints]=size(P); + % higher pitches get higher weights + % PressnitzerWeights=repmat(min(lags)./lags,nTimePoints,1); + % weaker weighting + PressnitzerWeights=repmat((min(lags)./lags).^0.5, nTimePoints,1); + P=P.*PressnitzerWeights'; + sacf=sacf.*PressnitzerWeights'; +end + +% wrap up +method.acfLags=lags; +method.filteredSACFdt=dt; + +boundaryValue{1}=acf(:,end-nLags+1:end); +boundaryValue{2}=P(:,end); +% save signal buffer for next segment +boundaryValue{3} = inputSignalMatrix(:, end-max(lagPointers)+1 : end); + +method.displaydt=method.filteredSACFdt; + +% if ~isfield(params, 'plotUnflteredSACF'), params.plotUnflteredSACF=0; end +% if method.plotGraphs +% method.plotUnflteredSACF=params.plotUnflteredSACF; +% if ~method.plotUnflteredSACF +% method=filteredSACFPlot(P,method); +% else +% method=filteredSACFPlot(SACF,method); +% end +% end + + +% ------------------------------------------------ plotting ACFs +function cascadePlot(toPlot, lags, BFs) +% % useful code +[nChannels nLags]=size(toPlot); + +% cunning code to represent channels as parallel lines +[nRows nCols]=size(toPlot); +if nChannels>1 + % max(toPlot) defines the spacing between lines + a=max(max(toPlot))*(0:nRows-1)'; + % a is the height to be added to each channel + peakGain=10; + % peakGain emphasises the peak height + x=peakGain*toPlot+repmat(a,1,nCols); + x=nRows*x/max(max(x)); +else + x=toPlot; % used when only the stimulus is returned +end +plot(lags, x','k') +ylim([0 nRows]) + diff -r 000000000000 -r f233164f4c86 MAP/intpow.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MAP/intpow.c Fri May 27 13:19:21 2011 +0100 @@ -0,0 +1,77 @@ +/* intpow - Nick Clark - 3/5/2011 + * + * Function that raises a double precision vector to an integer power + * vector. The following call to this mex function... + * + * >> z = intpow(x,y) + * + * ... does the equivalent of the following in Matlab... + * + * >> z = x .^ ceil(y) + * + * NOTE: Under most circumstances, this function is slower than MATLAB's + * built in ^ operator, but for the (generally) small integer powers used + * in MAP we observe massive performance boosts using this C function. + */ + +/*************************************************************************/ +/* Header(s) */ +/*************************************************************************/ +#include "mex.h" + +/*************************************************************************/ +/* Input vars */ +/*************************************************************************/ +#define IN_x prhs[0] +#define IN_y prhs[1] + +/*************************************************************************/ +/* Output vars */ +/*************************************************************************/ +#define OUT_z plhs[0] + +/*************************************************************************/ +/* Gateway function and error checking */ +/*************************************************************************/ +void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) +{ + /* variable declarations */ + int numElements, xM, xN, yM, yN; + int nn, kk; + double *x, *y, *z; + + /* check the number of input and output parameters */ + if(nrhs!=2) + mexErrMsgTxt("intpow : Two input args expected"); + if(nlhs > 1) + mexErrMsgTxt("intpow : Too many outputs"); + + /* check that x and y have equal size */ + x = mxGetPr(IN_x); + xM = mxGetM(IN_x); + xN = mxGetN(IN_x); + + y = mxGetPr(IN_y); + yM = mxGetM(IN_y); + yN = mxGetN(IN_y); + + if (xM != yM || xN != yN) + mexErrMsgTxt("intpow : x and y must have equal size"); + + /* find upper loop boundary */ + numElements = xM * xN; + + /* allocate memory and pointer for the output array */ + OUT_z = mxCreateDoubleMatrix(xM,xN,mxREAL); + z = mxGetPr(OUT_z); + + /* do stuff */ + for( nn = 0; nn=LevittControl.TurnsToSmallSteps + currentStep=LevittControl.steadyLevittStep; +else + currentStep=LevittControl.startLevelStep; +end + +% base next stimulus on the basis of the sequence +% any miss requires an 'easier' stimulus next time. +if strcmp(sequence(end),'-') + nextStep= -currentStep; + + % success requires 2 or more successive hits +elseif strcmp(sequence(end-length(rule)+1:end),rule) + sequence=[sequence ' ']; % add space to prevent success on successive trials + LevittControl.LevittValuesUsed=[LevittControl.LevittValuesUsed NaN]; + nextStep=currentStep; + + % not enough hits to provoke a change +else + nextStep=0; +end + +LevittControl.sequence=sequence; + +LevittControl.Nreversals=length(peakTroughList); +% compute threshold estimate +% only if minReversals exceeded and even number of peaks and troughs +if LevittControl.Nreversals>=LevittControl.minReversals && rem(length(peakTroughList),2)==0 + % use only the peaks and troughs at the end of the sequence + peaksAndTroughs=peakTroughList(end-LevittControl.useLastNturns+1:end); + disp(['peak/trough sequence= ' num2str(peaksAndTroughs, '%6.0f') ] ) + + meanPT=mean(peaksAndTroughs); + sdPT=std(peaksAndTroughs); + LevittControl.meanPeakTrough=meanPT; + LevittControl.sd=sdPT; + fprintf('Levitt, mean, sd= %6.1f,%6.1f\n', meanPT, sdPT) + % final check that the sd is low enough + if sdPTLevittControl.maxLevittValue + msg='maximum level exceeded' + return +end + +% required for later use +LevittControl.trialRunning=LevittControl.trialRunning+1; +LevittControl.peakTroughValues=peakTroughList; + +if LevittControl.trialRunning>LevittControl.maxTrials + msg='maximum no of trials exceeded' + return +end + +% Trial continues +msg=''; diff -r 000000000000 -r f233164f4c86 multithreshold 1.46/MAP1_14variables.mat Binary file multithreshold 1.46/MAP1_14variables.mat has changed diff -r 000000000000 -r f233164f4c86 multithreshold 1.46/MAPmodel.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/multithreshold 1.46/MAPmodel.m Fri May 27 13:19:21 2011 +0100 @@ -0,0 +1,136 @@ +function [modelResponse, MacGregorResponse]=MAPmodel( MAPplot, method) + +global experiment stimulusParameters audio withinRuns +global outerMiddleEarParams DRNLParams AN_IHCsynapseParams + +savePath=path; +addpath('..\MAP') +modelResponse=[]; +MacGregorResponse=[]; + +% mono only (column vector) +audio=audio(:,1)'; + +% if stop button pressed earlier +if experiment.stop, return, end + +% -------------------------------------------------------------- run Model +MAPparamsName=experiment.name; +showPlotsAndDetails=experiment.MAPplot; +AN_spikesOrProbability='spikes'; + +% [response, method]=MAPsequenceSeg(audio, method, 1:8); +global ICoutput ANdt + MAP1_14(audio, 1/method.dt, method.nonlinCF,... + MAPparamsName, AN_spikesOrProbability); + +if showPlotsAndDetails + options.showModelParameters=0; + options.showModelOutput=1; + options.printFiringRates=1; + options.showACF=0; + options.showEfferent=1; + showMAP(options) +end + +% No response, probably caused by hitting 'stop' button +if isempty(ICoutput), return, end + +% MacGregor response is the sum total of all final stage spiking +MacGregorResponse= sum(ICoutput,1); % use IC + +% ---------------------------------------------------------- end model run + +dt=ANdt; +time=dt:dt:dt*length(MacGregorResponse); + +% group delay on unit response +MacGonsetDelay= 0.004; +MacGoffsetDelay= 0.022; + +% now find the response of the MacGregor model during the target presentation + group delay +switch experiment.threshEstMethod + case {'2I2AFC++', '2I2AFC+++'} + idx= time>stimulusParameters.testTargetBegins+MacGonsetDelay ... + & timestimulusParameters.testNonTargetBegins+MacGonsetDelay ... + & time0 + % hit + nSpikesDuringTarget=experiment.MacGThreshold+1; + elseif difference<0 + % miss (wrong choice) + nSpikesDuringTarget=experiment.MacGThreshold-1; + else + if rand>0.5 + % hit (random choice) + nSpikesDuringTarget=experiment.MacGThreshold+1; + else + % miss (random choice) + nSpikesDuringTarget=experiment.MacGThreshold-1; + end + end + disp(['level target dummy decision: ' ... + num2str([withinRuns.variableValue nSpikesTrueWindow ... + nSpikesFalseWindow nSpikesDuringTarget], '%4.0f') ] ) + + otherwise + % idx=find(time>stimulusParameters.testTargetBegins+MacGonsetDelay ... + % & timestimulusParameters.testTargetBegins +MacGonsetDelay... + & timestimulusParameters.testTargetBegins-0.02 ... + & time0.2 + modelResponse=2; % gap detected + else + modelResponse=1; % gap not detected + end + [nSpikesDuringTarget maskerRate gapResponse modelResponse] + figure(22), plot(timeX,earObject(idx)) + otherwise + if nSpikesDuringTarget>experiment.MacGThreshold + modelResponse=2; % stimulus detected + else + modelResponse=1; % nothing heard (default) + end +end + + +path(savePath) \ No newline at end of file diff -r 000000000000 -r f233164f4c86 multithreshold 1.46/TADA.WAV Binary file multithreshold 1.46/TADA.WAV has changed diff -r 000000000000 -r f233164f4c86 multithreshold 1.46/Twister.wav Binary file multithreshold 1.46/Twister.wav has changed diff -r 000000000000 -r f233164f4c86 multithreshold 1.46/addToMsg.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/multithreshold 1.46/addToMsg.m Fri May 27 13:19:21 2011 +0100 @@ -0,0 +1,35 @@ +% ---------------------------------------------------------- addToMsg +function addToMsg(message,append, warning) +% 'message' is posted to the message board +% if append==1, message is appended to the current message +global experiment expGUIhandles + +if nargin<3 + % this is not a warning screen + warning=0; +end + +if append +msg=get(expGUIhandles.textMSG,'string'); +[r c]=size(msg); + if length(message)<=c + y=[message blanks(c-length(message))]; + msg(r+1,:)=y; + else + msg=message; + end +else + msg=message; +end + +try + set(expGUIhandles.textMSG,'string', msg,'fontSize', experiment.msgFontSize) + if warning + % flash red to signal a warning + set(expGUIhandles.textMSG,'backgroundcolor','r', 'ForegroundColor', 'w' ) + else + set(expGUIhandles.textMSG,'backgroundcolor','w', 'ForegroundColor', 'b') + end +catch + error(message) +end \ No newline at end of file diff -r 000000000000 -r f233164f4c86 multithreshold 1.46/bestFitPsychometicFunctions.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/multithreshold 1.46/bestFitPsychometicFunctions.m Fri May 27 13:19:21 2011 +0100 @@ -0,0 +1,314 @@ +% ------------------------------------------------------- bestFitPsychometicFunctions +function [psy, levelsPhaseTwoBinVector, logistic, rareEvent]= bestFitPsychometicFunctions (levelsPhaseTwo, responsesPhaseTwo) +% bestFitPsychometicFunctions computes a psychometric function from a matrix of levels and responses +%output +% psy is the empirical probabbility of a detection associated with levels in levelsPhaseTwoBinVector +% logistic is a structure with results for fitting the logistic function +% the logistic fit depends on whether maximum likelihood is used or least squares +% rareEvent is a structure with results for fitting the rareEvent function +% this is always calculated and lest squares is always used + +global experiment stimulusParameters binFrequencies + +% Generate a psychometic function by binning the levelsPhaseTwo +% x is a vector of [levelsPhaseTwo; responsesPhaseTwo] +% experiment.psyBinWidth defines the width of the bin +[psy, levelsPhaseTwoBinVector, binFrequencies,yesResponses, noResponses]= ... + psychometricFunction(levelsPhaseTwo, responsesPhaseTwo, experiment.psyBinWidth); +% [levelsPhaseTwoBinVector; binFrequencies; psy]; + +% undefined slope - return +if isempty(psy) + % slope is undefined + psy=[]; levelsPhaseTwoBinVector=[]; + logistic.bestThreshold=NaN; logistic.bestK=NaN; logistic.predictionsLOG=[]; logistic.predictionLevels=[]; + rareEvent.bestGain=NaN; rareEvent.bestVMin=NaN; rareEvent.predictionsRE=[]; rareEvent.predictionLevels=[]; + rareEvent.thresholddB= NaN; rareEvent.bestPaMindB=NaN; + return +end + +% find best fit rare event function +switch experiment.paradigm + case 'gapDuration' + % i.e. don't attempt this but visit the function to set null results + rareEvent=fitRareEvent([], responsesPhaseTwo, stimulusParameters.targetDuration); + otherwise + rareEvent=fitRareEvent(levelsPhaseTwo, responsesPhaseTwo, stimulusParameters.targetDuration); +end + +% find best logistic fit +logisticFunc=' 1./(1+exp(-a2.*(x-a1)));'; +switch experiment.functionEstMethod + % least squares estimate + case {'logisticLS', 'rareEvent','peaksAndTroughs'} + [a1, a2, Euclid]=fitFunctionUsingLeastSquares(levelsPhaseTwo, responsesPhaseTwo, ... + logisticFunc, experiment.possLogSlopes, experiment.meanSearchStep); +% [a1, a2, Euclid]=fitLogisticUsingLS(psy, levelsPhaseTwoBinVector); %! does not give same result + logistic.bestThreshold=a1; + logistic.bestK=a2; + logistic.predictionsLOG= ... + 1./(1+exp(-logistic.bestK.*(experiment.predictionLevels-logistic.bestThreshold))); + logistic.predictionLevels=experiment.predictionLevels; + logistic.Euclid = Euclid; + % predResponses=1./(1+exp(-logistic.bestK.*(levelsPhaseTwo-logistic.bestThreshold))); + % [levelsPhaseTwo' responsesPhaseTwo' predResponses' responsesPhaseTwo'-predResponses' ] + + % maximum likelihood fitting + case 'logisticML' + [a1, a2, Euclid]=fitFunctionUsingMaxLikelihood (levelsPhaseTwoBinVector,... + psy, yesResponses, noResponses, logisticFunc, experiment.possLogSlopes,experiment.meanSearchStep); + logistic.bestThreshold=a1; + logistic.bestK=a2; + logistic.predictionsLOG= ... + 1./(1+exp(-logistic.bestK.*(experiment.predictionLevels-logistic.bestThreshold))); + logistic.predictionLevels=experiment.predictionLevels; + logistic.Euclid = Euclid; +end + +% disp(num2str([logistic.bestThreshold logistic.bestK logistic.Euclid])) +% disp(num2str([ rareEvent.thresholddB rareEvent.bestGain rareEvent.bestVMin rareEvent.Euclid])) + +% --------------------------------------------- fitLogisticUsingLS +function [mean, slope, Euclid]=fitLogisticUsingLS(p,L) + +%!! each bin needs to be weighted by its size + +idx1=find(p>0); +p=p(idx1); +L=L(idx1); +idx1=find(p<1); +p=p(idx1); +L=L(idx1); + +if length(L)<2 + mean=NaN; + slope=NaN; + Euclid=NaN; + return +end + +y=L; +x=log(1./p -1); +a =polyfit(x, y, 1); +mean=a(2); +slope=-1/a(1); + +% euclid +predy=polyval(a,x); +Euclid=sum((predy-y).^2); +[mean slope Euclid]; + +% --------------------------------------------- fitFunctionUsingLeastSquares +function [a1, a2, Euclid]=fitFunctionUsingLeastSquares(levelsPhaseTwo, responsesPhaseTwo, func, possSlopes, meanSearchStep) + +% nResponses= yesResponses+noResponses; +% idx=find(not(nResponses==0)); +% levelsPhaseTwo=levelsPhaseTwo(idx); +% yesResponses=yesResponses(idx); +% noResponses=noResponses(idx); +% nResponses=nResponses(idx); + +% psy=yesResponses./nResponses; + +possThresholds=min(levelsPhaseTwo):meanSearchStep:max(levelsPhaseTwo); + + +% create vectors representing all combinations of a1 and a2 +nPossThresh=length(possThresholds); +nPossSlopes=length(possSlopes); +a1=repmat(possThresholds',nPossSlopes,1); +a2=repmat(possSlopes,nPossThresh,1); +a2=reshape(a2,nPossThresh*nPossSlopes,1); + +% each response is predicted by every possible threshold and slope +LS=ones(size(a1)); +for i=1:length(levelsPhaseTwo) + x=levelsPhaseTwo(i); + eval(['y=' func]); + actual=responsesPhaseTwo(i); + error= (actual - y).^2; + LS=LS+error; +end + +[Euclid, idx]=min(LS); + +a1=a1(idx); +a2=a2(idx); + +% x=levelsPhaseTwo; +% eval(['y=' func]); +% Euclid= sum((psy-y).^2); + +% plot(levelsPhaseTwo,y,'r') +% hold on +% plot(levelsPhaseTwo,psy,'o') + +% --------------------------------------------- fitFunctionUsingMaxLikelihood +function [a1, a2, Euclid]=fitFunctionUsingMaxLikelihood... + (levelsPhaseTwo,psy, yesResponses, noResponses, func, possible_a2, meanSearchStep) + +% fitFunctionUsingMaxLikelihood fits the function in 'func' to binned yes-no data. +% levelsPhaseTwo specifies the bin centers +% yesResponses and noResponses are the niumber of yes and no responsesPhaseTwo in each bin +% 'func' is a function of a1, b1, x; e.g. func='1./(1+exp(-a2.*(x-a1)));'; +% and a2, a1 are parameters to be discovered. +% If bins are empty (i.e. neither yes or no), these are eliminated +% + +nResponses=yesResponses+noResponses; +possible_a1=min(levelsPhaseTwo):meanSearchStep:max(levelsPhaseTwo); + +% if nargin<6 +% possible_a2=-2:.05:4; +% end + +% create vectors representing all combinations of a1 and a2 +nPossThresh=length(possible_a1); +nPossSlopes=length(possible_a2); +a1=repmat(possible_a1',nPossSlopes,1); +a2=repmat(possible_a2,nPossThresh,1); +a2=reshape(a2,nPossThresh*nPossSlopes,1); + +cumulativeProbability=ones(1, length(a2)); +cumulativeProbability=cumulativeProbability'; + +for i=1:length(levelsPhaseTwo) + x=levelsPhaseTwo(i); + eval(['y=' func]); + funcVal=(1-y).^yesResponses(i); + cumulativeProbability= cumulativeProbability.*funcVal; + funcVal=y.^noResponses(i); + cumulativeProbability= cumulativeProbability.*funcVal; +end + +[maxProb idx]=max(cumulativeProbability); +a1=a1(idx); +a2=a2(idx); + +% x=levelsPhaseTwo; +eval(['y=' func]); +Euclid= sum(nResponses.*(psy-y).^2); + +% figure(1), clf +% plot(levelsPhaseTwo,y) +% hold on +% plot(levelsPhaseTwo,psy,'o') + + + +% --------------------------------------------------- fitRareEvent +function rareEvent=fitRareEvent(stimulusLevels, responsesPhaseTwo, duration, gains, Vmins) +% least squares estimate of *rare event* function +% model is: r = g P – A ... g=events/s/Pa, A= events/s, P= pressure (Pa) +% psy=1- exp(d(gP –A )) ... d=duration +% p(event)=gain*levelmPa -Vmin +% 'responsesPhaseTwo' is a binary vector of subject's decision. +% 'stimulusLevels' are the corresponding signal levesl (values) +% duration is required to compute the expectation of an event occurring +% gains is an optional list of gains to be tried +% Vmins is an optional list of Vmins to be tried + +global experiment +if nargin<5 + minVmin=.1; maxVmin=10; nVmins=100; + Vmins=[0 logspace(log10(minVmin),log10(maxVmin),nVmins)]; + % disp(Vmins) + gainMin=0.0001; gainMax=1; nGains=100; + gains=[1e-5 logspace(log10(gainMin),log10(gainMax),nGains)]; +end + +rareEvent.bestGain=NaN; +rareEvent.bestVMin=NaN; +rareEvent.thresholddB=0; +rareEvent.bestPaMindB=NaN; +rareEvent.predictionLevels=[]; +rareEvent.predictionsRE=[]; +rareEvent.Euclid=NaN; + +if isempty(stimulusLevels), return, end + +% expected slope is negative, rareEvent can not be used +if experiment.psyFunSlope<0 + return +end + +% NB calculations in microPascals! +stimulusLevelsAsPressure=28 * 10.^(stimulusLevels/20); + +% allGains=reshape(repmat(gains,nVmins,1), 1, nVmins*nGains); +% allVmins=repmat(Vmins, 1, nGains); + + predictions=NaN*zeros(1,length(stimulusLevels)); + gainCount=0; + Euclid=inf; bestVmin=0; bestGain=0; + for gain= gains + gainCount=gainCount+1; + VminCount=0; + + % 1 – exp(-d (g P – A)) + for Vmin=Vmins + VminCount=VminCount+1; + % all levelsPhaseTwo are simultaneously assessed + + % original linear function +% gP_Vmin=gain*stimulusLevelsAsPressure-Vmin; +% idx=(gP_Vmin>0); + % predictions(idx)= 1-exp(-duration*(gP_Vmin(idx))); + % new log function log(r) =gP-A + + % log function + gP_Vmin=gain*stimulusLevelsAsPressure-Vmin; + idx=(gP_Vmin>0); + predictions(idx)= 1-exp(-duration*exp(gP_Vmin(idx))); + predictions(~idx)=0; + +% % square function +% P_Vmin=stimulusLevelsAsPressure-Vmin; +% idx=(P_Vmin)>0; +% predictions(idx)= 1-exp(-duration*gain*(P_Vmin(idx)).^2); +% predictions(~idx)=0; + + + % NB the error is equally weighted for each stimulus/response pair + % this is not the same as equal weighting for each distinct level + error=(predictions - responsesPhaseTwo).^2; + error=mean(error(~isnan(error))); + if error.m. These +% files specify values in the stimulusParameter and experiment structures. +% Some minor parameters are specified in the intialiseGUI function below. +% Each configuration is only a start up arrangement and the user can modify +% the parameters on the GUI itself. +% +% the 'RUN' button initiates the measurements and hands control over to the +% subjGUI program. When the measurements are complete control is handed +% back and the stack unwinds without any further action + +function varargout = expGUI_MT(varargin) +%EXPGUI_MT M-file for expGUI_MT.fig +% EXPGUI_MT, by itself, creates a new EXPGUI_MT or raises the existing +% singleton*. +% +% H = EXPGUI_MT returns the handle to a new EXPGUI_MT or the handle to +% the existing singleton*. +% +% EXPGUI_MT('Property','Value',...) creates a new EXPGUI_MT using the +% given property value pairs. Unrecognized properties are passed via +% varargin to expGUI_MT_OpeningFcn. This calling syntax produces a +% warning when there is an existing singleton*. +% +% EXPGUI_MT('CALLBACK') and EXPGUI_MT('CALLBACK',hObject,...) call the +% local function named CALLBACK in EXPGUI_MT.M with the given input +% arguments. +% +% *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 expGUI_MT + +% Last Modified by GUIDE v2.5 07-Apr-2011 07:20:00 + +% Begin initialization code - DO NOT EDIT +gui_Singleton = 1; +gui_State = struct('gui_Name', mfilename, ... + 'gui_Singleton', gui_Singleton, ... + 'gui_OpeningFcn', @expGUI_MT_OpeningFcn, ... + 'gui_OutputFcn', @expGUI_MT_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 + +% -------------------------------------------------- expGUI_MT_OpeningFcn +function expGUI_MT_OpeningFcn(hObject, eventdata, handles, varargin) + +% Choose default command line output for expGUI_MT +handles.output = hObject; + +cla(handles.axes1) +cla(handles.axes2) +cla(handles.axes4) +cla(handles.axes5) + +% Update handles structure +guidata(hObject, handles); + +function varargout = expGUI_MT_OutputFcn(hObject, eventdata, handles) +% Get default command line output from handles structure +initializeGUI(handles) +varargout{1} = handles.output; +setLocationOfGUIs(handles) + +function setLocationOfGUIs(handles) +global checkForPreviousGUI % holds screen positioning across repeated calls +scrnsize=get(0,'screensize'); +checkForPreviousGUI=[]; +% if isstruct(checkForPreviousGUI)... +% && checkForPreviousGUI.GUIalreadyStarted==1 ... +% && isfield(checkForPreviousGUI,'GUIposition') +% set(handles.figure1,'position',checkForPreviousGUI.GUIposition) +% else +% % relocate the GUI only if this is the first time of use +% set(0, 'units','pixels') +% % occupies top to bottom of screen but only 60% width +% % [left bottom width height] +% firstPos=[0.01*scrnsize(4) 0.03*scrnsize(3) 0.6*scrnsize(3) 0.92*scrnsize(4)]; +% firstPos=[4 0.045*scrnsize(4) 0.6*scrnsize(3) 0.93*scrnsize(4)]; +% set(handles.figure1, 'units','pixels') +% set(handles.figure1,'position',firstPos) +% checkForPreviousGUI.GUIalreadyStarted=1; +% checkForPreviousGUI.GUIposition=firstPos; +% end +set(handles.figure1,'color',[.871 .961 .996]) +set(handles.figure1,'name', pwd) + +% MAP model figure; sits alongside GUI if requested +figure(99) +% [left bottom width height] +MAPpos=[0.615*scrnsize(3) 0.05*scrnsize(4) 0.15*scrnsize(3) 0.85*scrnsize(4)]; +% visible only on request. +set(gcf,'position',MAPpos , 'visible','off') + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% -----------------------------------------------------initializeGUI +function initializeGUI(handles) +% Populate the edit boxes and popup menus on the GUI +% Then wait for user action +global stimulusParameters experiment betweenRuns +global targetTypes maskerTypes backgroundTypes +global variableNames paradigmNames threshEstNames cueNames + +% dbstop if error % allow for debugging and user error reporting +% dbstop if warning + +% specify structure fields for pretty automatic printing +% It also initialises some simple variables +orderGlobals + +addpath ('paradigms') % preset paradigm informations is stored here +% filesep is usd to be compatible with other operating systems +% addpath (['..' filesep 'modules'], ['..' filesep 'utilities'], ... +% ['..' filesep 'parameterStore'], ['..' filesep 'wavFileStore'],... +% ['..' filesep 'testPrograms']) + +% specify all variables that need to be set on the GUI +variableNames={'stimulusDelay','maskerDuration','maskerLevel',... + 'maskerRelativeFrequency', 'targetFrequency', 'gapDuration',... + 'targetDuration','targetLevel','rampDuration',... + 'cueTestDifference', 'WRVstartValues', 'WRVsteps', 'WRVlimits'}; + +% Variable variables +% (specifies paradigm paramaters that can changed on a 'between runs' basis) +% make them options in the two between runs variable menus +% NB 'numOHIOtones' is used only to solve a problem; it should not be +% selected manually +betweenRunsVariables={'stimulusDelay','maskerDuration','maskerLevel',... + 'maskerRelativeFrequency','targetFrequency', 'gapDuration',... + 'targetDuration','targetLevel','numOHIOtones'}; +set(handles.popupmenuVaryParameter1,'string',betweenRunsVariables) +set(handles.popupmenuVaryParameter2,'string',betweenRunsVariables) + +% NB 'Warning: popupmenu control requires a scalar Value' +% indicates that an inappropriate 'value' is being set. +% when testing for this, always clear the GUI before running + +% Trial presentation order - randomize at startup +presentationOrderNames={'randomize within blocks', 'fixed sequence', ... + 'randomize across blocks'}; +set(handles.popupmenuRandomize,'string', presentationOrderNames) + +% targetType- value must be set in paradigm +targetTypes={'tone','noise', 'pinkNoise','whiteNoise','24TalkerBabble',... + 'speech', 'Twister','digitStrings'}; +set(handles.popupmenuTargetType, 'string', targetTypes); + +% maskerType - value must be set in paradigm +maskerTypes={'tone','noise', 'pinkNoise','TEN','whiteNoise','24TalkerBabble', ... + 'speech'}; +set(handles.popupmenuMaskerType, 'string', maskerTypes); + +% background Type- value must be set in paradigm (default = 1, 'none') +backgroundTypes={'none','noise', 'pinkNoise', 'TEN','noiseDich',... + 'pinkNoiseDich','whiteNoise','24TalkerBabble',... + '16TalkerBabble','8TalkerBabble','4TalkerBabble',... + '4TalkerReversedBabble','2TalkerBabble','1TalkerBabble'}; +set(handles.popupmenuBackgroundType, 'string', backgroundTypes); +set(handles.editBackgroundLevel,'string',... + num2str(stimulusParameters.backgroundLevel)) + +% Establish available paradigms by scanning paradigms folder +paradigmNames= what('paradigms'); +paradigmNames=paradigmNames.m; % m files only +for i=1:length(paradigmNames), paradigmNames{i}=paradigmNames{i}(10:end-2); end +set(handles.popupmenuParadigm,'string', paradigmNames) + +% startup paradigm, 'training' (could be anywhere on the list) +startupParadigm='training'; +idx= find(strcmp(paradigmNames,startupParadigm)); +if ~isempty(idx) + set(handles.popupmenuParadigm,'value', idx) +else + % training paradigm is always the startup paradigm + error(['expGUI_MT\initializeGUI: No ' startupParadigm... + ' paradigm found in paradigms folder']) +end + +earOptions={'left', 'right', 'diotic', 'dichoticLeft', 'dichoticRight',... + 'MAPmodelListen', 'MAPmodelMultiCh', 'MAPmodelSingleCh'... + 'statsModelLogistic','statsModelRareEvent'}; +set(handles.popupmenuEar,'string', earOptions) +defaultOption=1; +experiment.ear=earOptions{defaultOption}; +set(handles.popupmenuEar,'value', defaultOption) % 'left' is deafult +set(handles.pushbuttonSingleShot, 'visible', 'off') % use only for MAP + +% masker phase box- value must be set in paradigm +phaseOptions={'sin','cos','alt','rand'}; +set(handles.popupmenuPhase,'string', phaseOptions) + +% Cue +cueNames={'cued', 'noCue'}; +set(handles.popupmenuCueNoCue, 'string', cueNames); + +% threshold assessment method - value must be set in paradigm +threshEstNames={'oneIntervalUpDown', 'MaxLikelihood', ... + '2I2AFC++', '2I2AFC+++'}; +set(handles.popupmenuThreshEst, 'string', threshEstNames); +experiment.stopCriteria2IFC=[75 3 5]; +experiment.stopCriteriaSI=[20]; + +% ** editBoxes that are only set by hand +% music (relative) level, 'tada!' (manual setting only) +% increase for the hard of hearing +set(handles.editMusicLevel,'string','0') + +% Catch Trial Rate +set(handles.editCatchTrialRate,'string','0.2 0.1 2 '); + +% calibration +stimulusParameters.restoreCalibration=7; +set(handles.editcalibrationdB,'string',... + stimulusParameters.restoreCalibration) + +% a MAPplot +experiment.MAPplot=0; %default +set(handles.editMAPplot,'string',num2str(experiment.MAPplot)) + +% saveData +experiment.saveData=1; +set(handles.editSaveData,'string',num2str(experiment.saveData)) + +% printTracks +experiment.printTracks=0; +set(handles.editPrintTracks,'string',num2str(experiment.printTracks)) + +% standard delay between button press and initiation of next stimulus +experiment.clickToStimulusPause=1; + +% buttonBoxType: NB no problem if mouse is used instead +experiment.buttonBoxType='square'; + +% estimation of the mean +% {'logisticLS', 'logisticML', 'rareEvent'} +experiment.functionEstMethod='logisticLS'; + +% message box +set(handles.textMSG,'backgroundcolor', 'w', 'ForegroundColor', 'b', 'string', '') +set(handles.editMsgFont,'string','7') +set(handles.editSubjectFont,'string','14') + +% default psychometric bin size and logistic slopes +experiment.psyBinWidth=1; % dB +maxLogisticK=2; % steepest slope contemplated +experiment.maxLogisticK=maxLogisticK; +experiment.numPossLogisticK=100; +experiment.possLogSlopes= ... + 0.01: maxLogisticK/experiment.numPossLogisticK: maxLogisticK; +experiment.meanSearchStep=0.25; % dB + +% indicate that this is the first run and the GUI should be located in +% default location. +experiment.justInitialized=1; + +% set up GUI based on training paradigm +aParadigmSelection(handles); +earSetUp(handles) +aThresholdAssessmentMethod(handles) +aShowRelevantObjects(handles) + +% Done. Now wait for action + +% -------------------------------------------- popupmenuMaskerType_Callback +function popupmenuMaskerType_Callback(hObject, eventdata, handles) +% show or remove masker frequency box +aShowRelevantObjects(handles) + +% -------------------------------------------- popupmenuTargetType_Callback +function popupmenuTargetType_Callback(hObject, eventdata, handles) +% show or remove target frequency box +aShowRelevantObjects(handles) + +% -------------------------------------------- popupmenuParadigm_Callback +function popupmenuParadigm_Callback(hObject, eventdata, handles) +% Any change to the paradigm selection causes all boxes to be shown +% showParameters(handles) +aParadigmSelection(handles); + +% -------------------------------------------- aParadigmSelection +function aParadigmSelection(handles) +global experiment stimulusParameters betweenRuns paradigmNames +global variableNames + +% identify paradigm selected +chosenOption=get(handles.popupmenuParadigm,'value'); +paradigm=paradigmNames{chosenOption}; +experiment.paradigm=paradigm; + +%Paradigm: read in all relevant parameters +% a file must exist with this name 'paradigm_' +% 'handles' are only occasionally used +addpath ('paradigms') +cmd=['paradigm_' paradigm '(handles);']; +try + eval(cmd) +catch + error(['ExpGUI\aParadigmSelection:'... + 'paradigm file not found or error in file']) +end +rmpath ('paradigms') + +% if a variable is subject to change, specify list of values here +% eg. stimulusParameters.targetFrequency=betweenRuns.variableList1; +cmd=['stimulusParameters.' ... + betweenRuns.variableName1 '=betweenRuns.variableList1;']; +eval (cmd); +cmd=['stimulusParameters.' ... + betweenRuns.variableName2 '=betweenRuns.variableList2;']; +eval (cmd); + +% establish popup menus on the basis of the paradigm file +set(handles.popupmenuRandomize,'value', betweenRuns.randomizeSequence) +set(handles.popupmenuPhase,'string', stimulusParameters.maskerPhase) +if stimulusParameters.includeCue + set(handles.popupmenuCueNoCue,'value', 1) +else + set(handles.popupmenuCueNoCue,'value', 2) +end + +set(handles.text34, 'string', stimulusParameters.WRVname) + +% Put the new data values into the edit boxes on the GUI +for i=1:length(variableNames) + cmd=(['set(handles.edit' variableNames{i} ... + ',''string'', num2str(stimulusParameters.' ... + variableNames{i} '));']); + eval(cmd); +end +% backgroundLevel is not a variableName (?!) +set(handles.editBackgroundLevel,'string', num2str... + (stimulusParameters.backgroundLevel)) + +% on RUN the sample rate will be picked from the text box +% However, MAP overrules the sample rate and sets its own +aSetSampleRate(stimulusParameters.subjectSampleRate, handles); + + +% used for plotting functions (NB affected by paradigm settings) +experiment.predictionLevels=stimulusParameters.WRVlimits(1):... + experiment.meanSearchStep:stimulusParameters.WRVlimits(2); +experiment.possLogSlopes=abs(experiment.possLogSlopes)*... + sign(experiment.psyFunSlope); + +aResetPopupMenus(handles) + +% ------------------------------------------------------ aResetPopupMenus +function aResetPopupMenus(handles) +global stimulusParameters betweenRuns variableNames +global targetTypes maskerTypes experiment backgroundTypes + +switch experiment.threshEstMethod + case {'MaxLikelihood','oneIntervalUpDown'} + set(handles.editstopCriteriaBox, 'string', ... + num2str(experiment.singleIntervalMaxTrials)) + + case {'2I2AFC++','2I2AFC+++'} + set(handles.editstopCriteriaBox, 'string', ... + num2str(experiment.stopCriteria2IFC)) + otherwise + error([' aResetPopupMenus: threshEstMethod not recognised -> ' ... + experiment.threshEstMethod]) +end + +% forced noCue +switch experiment.paradigm + case 'discomfort' + set(handles.popupmenuCueNoCue,'value', 2) +end + +%set variables popupmenus as specified in betweenRuns +variableParameter1ID=0; variableParameter2ID=0; +for i=1:length(variableNames) + if strcmp(variableNames{i},betweenRuns.variableName1) + variableParameter1ID=i; + end + if strcmp(variableNames{i},betweenRuns.variableName2) + variableParameter2ID=i; + end +end +if variableParameter1ID==0 || variableParameter2ID==0; + Error('a ResetPopMenu: variableParameter not identified') +end + +% display popupmenus +set(handles.popupmenuVaryParameter1, 'value',round(variableParameter1ID)) +set(handles.popupmenuVaryParameter2, 'value',round(variableParameter2ID)) + +% targetType +idx= find(strcmp(stimulusParameters.targetType, targetTypes)); +set(handles.popupmenuTargetType,'value', idx) + +% paradigm selection may alter the maskerType +idx= find(strcmp(stimulusParameters.maskerType, maskerTypes)); +set(handles.popupmenuMaskerType,'value', idx) + +aShowRelevantObjects(handles) + +% % backgroundType +idx= find(strcmp(stimulusParameters.backgroundType, backgroundTypes)); +set(handles.popupmenuBackgroundType,'value', idx) +set(handles.editBackgroundLevel,'string', ... + num2str(stimulusParameters.backgroundLevel)) + +% ---------------------------------------------- aShowRelevantObjects +function aShowRelevantObjects(handles) +global experiment stimulusParameters +% always on +set(handles.edittargetLevel, 'visible', 'on') +set(handles.edittargetDuration, 'visible', 'on') +set(handles.edittargetFrequency, 'visible', 'on') + +switch experiment.ear + case {'statsModelLogistic', 'statsModelRareEvent'} + set(handles.editStatsModel, 'visible', 'on') + set(handles.textStatsModel, 'visible', 'on') + set(handles.pushbuttonStop, 'visible', 'on') + set(handles.pushbuttonOME, 'visible', 'off') + set(handles.pushbuttonBM, 'visible', 'off') + set(handles.pushbuttonRP, 'visible', 'off') + set(handles.pushbuttonAN, 'visible', 'off') + set(handles.pushbuttonRF, 'visible', 'off') + set(handles.pushbuttonSYN, 'visible', 'off') + set(handles.pushbuttonFM, 'visible', 'off') + set(handles.pushbuttonParams, 'visible', 'off') + set(handles.pushbuttonSingleShot, 'visible', 'off') + set(handles.editCatchTrialRate, 'visible', 'off') + set(handles.textCatchTrials, 'visible', 'off') + set(handles.editcalibrationdB, 'visible', 'off') + set(handles.textcalibration, 'visible', 'off') + set(handles.popupmenuCueNoCue, 'visible', 'off') + set(handles.textCue, 'visible', 'off') + set(handles.editMusicLevel,'visible', 'off') + set(handles.textMusicLevel,'visible', 'off') + set(handles.editMAPplot,'visible', 'off') + set(handles.textMAPplot,'visible', 'off') + + case {'MAPmodel', 'MAPmodelListen', 'MAPmodelMultiCh', 'MAPmodelSingleCh'} + set(handles.popupmenuCueNoCue, 'visible', 'off') + set(handles.editStatsModel, 'visible', 'off') + set(handles.textStatsModel, 'visible', 'off') + set(handles.pushbuttonStop, 'visible', 'on') + set(handles.pushbuttonOME, 'visible', 'on') + set(handles.pushbuttonBM, 'visible', 'on') + set(handles.pushbuttonRP, 'visible', 'on') + set(handles.pushbuttonAN, 'visible', 'on') + set(handles.pushbuttonRF, 'visible', 'on') + set(handles.pushbuttonSYN, 'visible', 'on') + set(handles.pushbuttonFM, 'visible', 'on') + set(handles.pushbuttonParams, 'visible', 'on') + set(handles.pushbuttonSingleShot, 'visible', 'on') + set(handles.editcalibrationdB, 'visible', 'off') + set(handles.textcalibration, 'visible', 'off') + set(handles.textCue, 'visible', 'off') + set(handles.editMusicLevel,'visible', 'off') + set(handles.textMusicLevel,'visible', 'off') + set(handles.editMAPplot,'visible', 'on') + set(handles.textMAPplot,'visible', 'on') + + otherwise + set(handles.editStatsModel, 'visible', 'off') + set(handles.textStatsModel, 'visible', 'off') + set(handles.pushbuttonStop, 'visible', 'off') + set(handles.pushbuttonOME, 'visible', 'off') + set(handles.pushbuttonBM, 'visible', 'off') + set(handles.pushbuttonRP, 'visible', 'off') + set(handles.pushbuttonAN, 'visible', 'off') + set(handles.pushbuttonRF, 'visible', 'off') + set(handles.pushbuttonSYN, 'visible', 'off') + set(handles.pushbuttonFM, 'visible', 'off') + set(handles.pushbuttonParams, 'visible', 'off') + set(handles.pushbuttonSingleShot, 'visible', 'off') + set(handles.editCatchTrialRate, 'visible', 'on') + set(handles.textCatchTrials, 'visible', 'on') + set(handles.editcalibrationdB, 'visible', 'on') + set(handles.textcalibration, 'visible', 'on') + set(handles.popupmenuCueNoCue, 'visible', 'on') + set(handles.textCue, 'visible', 'on') + set(handles.editMusicLevel,'visible', 'on') + set(handles.textMusicLevel,'visible', 'on') + set(handles.editMAPplot,'visible', 'off') + set(handles.textMAPplot,'visible', 'off') +end + +switch experiment.threshEstMethod + case {'MaxLikelihood','oneIntervalUpDown'} + set(handles.popupmenuCueNoCue,'visible', 'on') + set(handles.textCue,'visible', 'on') + set(handles.editstopCriteriaBox, 'string', ... + num2str(experiment.singleIntervalMaxTrials)) + + if stimulusParameters.includeCue==0 + set(handles.editcueTestDifference,'visible', 'off') + set(handles.textcueTestDifference,'visible', 'off') + else + set(handles.editcueTestDifference,'visible', 'on') + set(handles.textcueTestDifference,'visible', 'on') + end + + case {'2I2AFC++','2I2AFC+++'} + set(handles.editCatchTrialRate, 'visible', 'off') + set(handles.textCatchTrials, 'visible', 'off') + set(handles.popupmenuCueNoCue,'visible', 'off') + set(handles.textCue,'visible', 'off') + set(handles.editcueTestDifference,'visible', 'off') + set(handles.textcueTestDifference,'visible', 'off') +end + + +% show/ remove masker related boxes +switch experiment.paradigm + % masker free paradigms + case {'training', 'discomfort','absThreshold', 'absThreshold_8',... + 'TENtest', 'threshold_duration','SRT'} + set(handles.editmaskerDuration,'visible', 'off') + set(handles.editmaskerLevel,'visible', 'off') + set(handles.editmaskerRelativeFrequency,'visible', 'off') + set(handles.editgapDuration,'visible', 'off') + set(handles.textmaskerDuration,'visible', 'off') + set(handles.textmaskerLevel,'visible', 'off') + set(handles.textmaskerRelativeFrequency,'visible', 'off') + set(handles.textgapDuration,'visible', 'off') + set(handles.popupmenuMaskerType,'visible', 'off') + set(handles.textMaskerType,'visible', 'off') + + % paradigms with maskers + case {'forwardMasking','forwardMaskingD','trainingIFMC', 'TMC','TMC_16ms', ... + 'TMCmodel','IFMC','IFMC_8ms','GOM','overShoot','overShootB',... + 'gapDetection', 'psychometric', 'FMreProbe'} + set(handles.editmaskerDuration,'visible', 'on') + set(handles.editmaskerLevel,'visible', 'on') + set(handles.editmaskerRelativeFrequency,'visible', 'on') + set(handles.editgapDuration,'visible', 'on') + set(handles.popupmenuMaskerType,'visible', 'on') + set(handles.textmaskerDuration,'visible', 'on') + set(handles.textmaskerLevel,'visible', 'on') + set(handles.textmaskerRelativeFrequency,'visible', 'on') + set(handles.textgapDuration,'visible', 'on') + set(handles.popupmenuMaskerType,'visible', 'on') + set(handles.textMaskerType,'visible', 'on') + % masker relative frequency /type + chosenOption=get(handles.popupmenuMaskerType,'value'); + maskerTypes=get(handles.popupmenuMaskerType,'string'); + maskerType=maskerTypes{chosenOption}; + switch maskerType + case 'tone' + set(handles.editmaskerRelativeFrequency,'visible', 'on') + otherwise + set(handles.editmaskerRelativeFrequency,'visible', 'off') + end +end + +eval(['set(handles.edit' stimulusParameters.WRVname ... + ',''visible'',''off'' )']) + +% target type +chosenOption=get(handles.popupmenuTargetType,'value'); +targetTypes=get(handles.popupmenuTargetType,'string'); +targetType=targetTypes{chosenOption}; +switch targetType + case 'tone' + set(handles.edittargetFrequency,'visible', 'on') + otherwise + set(handles.edittargetFrequency,'visible', 'off') +end + +if strcmp(stimulusParameters.backgroundType,'none') + set(handles.popupmenuBackgroundType, 'visible', 'on'); + set(handles.editBackgroundLevel,'visible','off') + set(handles.textBGlevel,'visible','off') +else + set(handles.popupmenuBackgroundType, 'visible', 'on'); + set(handles.editBackgroundLevel,'visible','on') + set(handles.textBGlevel,'visible','on') +end + + + +% ------------------------------------------------ pushbuttonRun_Callback +function pushbuttonRun_Callback(hObject, eventdata, handles) +global checkForPreviousGUI % holds screen positioning across repeated calls +global experiment +checkForPreviousGUI.GUIposition=get(handles.figure1,'position'); +experiment.singleShot=0; +run (handles) +experiment.stop=0; + +function run (handles) +global experiment expGUIhandles stimulusParameters +tic +expGUIhandles=handles; +set(handles.pushbuttonStop, 'backgroundColor', [.941 .941 .941]) + +% message box white (removes any previous error message) +set(handles.textMSG,... + 'backgroundcolor', 'w', 'ForegroundColor', 'b', 'string', '') + +errorMsg=aReadAndCheckParameterBoxes(handles); +if ~isempty(errorMsg) + append=0; + warning=1; + addToMsg(['error message:' errorMsg], append, warning) + return +end + +if isnan(stimulusParameters.targetLevel) + addToMsg('Error: targetlevel not set', 1) + error('Error: targetlevel not set') +end + +set(handles.textMSG,'backgroundcolor', 'w') +set(handles.textMSG,'string', ' ') + +% leave the program and start up multiThreshold +subjGUI_MT % leave the program and start up multiThreshold +experiment.justInitialized=0;% prevents moving subjectGUI +toc + +% --- Executes on button press in pushbuttonSingleShot. +function pushbuttonSingleShot_Callback(hObject, eventdata, handles) +global experiment +experiment.singleShot=1; + +% special test for spontaneous activity +x=get(handles.editWRVstartValues, 'string'); +y=get(handles.edittargetDuration, 'string'); +set(handles.editWRVstartValues, 'string', '-20') +set(handles.edittargetDuration, 'string', '1') + +MAPplot=get(handles.editMAPplot, 'string'); +set(handles.editMAPplot, 'string', '1') +drawnow + +run (handles) + +set(handles.editMAPplot, 'string', MAPplot) +set(handles.editWRVstartValues, 'string', x) +set(handles.edittargetDuration, 'string', y) + +% ------------------------------------------aReadAndCheckParameterBoxes +function errorMsg=aReadAndCheckParameterBoxes(handles) +global experiment stimulusParameters betweenRuns statsModel +global variableNames LevittControl +% When the program sets the parameters all should be well +% But when the user changes them... + +errorMsg=''; + +% name +experiment.name=get(handles.editName,'string'); + +% ear/models +option=get(handles.popupmenuEar,'value'); +strings=get(handles.popupmenuEar,'string'); +experiment.ear=strings{option}; + +switch experiment.ear + case { 'MAPmodel', 'MAPmodelMultiCh', ... + 'MAPmodelSingleCh', 'MAPmodelListen'} + % MAPmodel writes forced parameter settings to the screen + % so that they can be read from there + set(handles.popupmenuRandomize,'value',2) % fixed sequence + set(handles.editstimulusDelay,'string','0.01') % no stimulus delay + stimulusParameters.includeCue=0; % no cue for MAP +end + +% find tone type +option=get(handles.popupmenuTargetType,'value'); +strings=get(handles.popupmenuTargetType,'string'); +stimulusParameters.targetType=strings{option}; + +% find masker type +option=get(handles.popupmenuMaskerType,'value'); +strings=get(handles.popupmenuMaskerType,'string'); +stimulusParameters.maskerType=strings{option}; + +% find background type and level +option=get(handles.popupmenuBackgroundType,'value'); +strings=get(handles.popupmenuBackgroundType,'string'); +stimulusParameters.backgroundTypeValue=option; +stimulusParameters.backgroundLevel=... + str2num(get(handles.editBackgroundLevel,'string')); +stimulusParameters.backgroundType=strings{option}; + +% Read all stimulus parameter boxes +for i=1:length(variableNames) + cmd=['stimulusParameters.' variableNames{i} ... + '= str2num(get(handles.edit' variableNames{i} ',''string'' ));']; + eval(cmd); +end +% for multiple levels +stimulusParameters.targetLevels=stimulusParameters.targetLevel; + +% check that all required values are in the edit boxes +for i=1:length(variableNames)-3 % do not include 'level limits' + eval([ 'variableValues=stimulusParameters.' variableNames{i} ';']) + if isempty(variableValues), errorMsg=[ variableNames{i} ... + ' is an empty box']; return, end +end + +chosenOption=get(handles.popupmenuVaryParameter1,'value'); +betweenRuns.variableName1=variableNames{chosenOption}; +eval(['betweenRuns.variableList1 = stimulusParameters.' ... + betweenRuns.variableName1 ';']); + +chosenOption=get(handles.popupmenuVaryParameter2,'value'); +betweenRuns.variableName2=variableNames{chosenOption}; +eval(['betweenRuns.variableList2 = stimulusParameters.' ... + betweenRuns.variableName2 ';']); + +% Check that variable parameters 1 & 2 have different names +if strcmp(betweenRuns.variableName1,betweenRuns.variableName2) ... + && ~strcmp(betweenRuns.variableName1,'none') + errorMsg='variable parameters have the same name'; + return +end + +% calibration +% this is used to *reduce* the output signal from what it otherwise +% would be +% signal values are between 1 - 2^23 +% these are interpreted as microPascals between -29 dB and 128 dB SPL +% calibrationdB adjusts these values to compensate for equipment +% characteristics +% this will change the range. e.g. a 7 dB calibration will yield +% a range of -36 to 121 dB SPL +% Calibration is not used when modelling. Values are treated as dB SPL +stimulusParameters.calibrationdB=... + str2num(get(handles.editcalibrationdB,'string')); + +% check on cue +cueSetUp(handles) + +stimulusParameters.WRVinitialStep=stimulusParameters.WRVsteps(1); +stimulusParameters.WRVsmallStep=stimulusParameters.WRVsteps(2); + +% jitter start value set after reading in new parameters +switch experiment.paradigm + case 'discomfort' + stimulusParameters.jitterStartdB=0; + otherwise + stimulusParameters.jitterStartdB=abs(stimulusParameters.WRVsteps(1)); +end + + +% stats model mean and slope +statsModelParameters= str2num(get(handles.editStatsModel,'string')); +switch experiment.ear + case {'statsModelLogistic'} + statsModel.logisticMean=statsModelParameters(1) ; + statsModel.logisticSlope=statsModelParameters(2); + statsModel.rareEvenGain=NaN ; + statsModel.rareEventVmin=NaN; + case 'statsModelRareEvent' + statsModel.logisticMean=NaN ; + statsModel.logisticSlope=NaN; + statsModel.rareEvenGain=statsModelParameters(2) ; + statsModel.rareEventVmin=statsModelParameters(1); +end + +% MAP plotting +experiment.MAPplot=str2num(get(handles.editMAPplot,'string')); +% if ~isequal(experiment.MAPplot, 0), +% % any other character will do it +% experiment.MAPplot=1; +% end + +% save data +experiment.saveData=str2num(get(handles.editSaveData,'string')); +if ~isequal(experiment.saveData, 0), + % any other character will do it + experiment.saveData=1; +end + +% print tracks +experiment.printTracks=str2num(get(handles.editPrintTracks,'string')); +if ~isequal(experiment.printTracks, 0), + % any other character will do it + experiment.printTracks=1; +end + +% catch trial rate +% (1)= start rate, (2)= base rate, (3)= time constant (trials) +stimulusParameters.catchTrialRates=... + str2num(get(handles.editCatchTrialRate,'string')); +if stimulusParameters.catchTrialRates(1) ... + < stimulusParameters.catchTrialRates(2) + errorMsg=... + 'catch trial base rates must be less than catch trial start rate'; + return, +end + +% sample rate +% The sample rate is set in the paradigm file. +% Normally this is set in the startUp paradigm file and then left +% When the model is used, the multiThreshold sample rate +% overrules anything in the model +stimulusParameters.sampleRate=... + str2num(get(handles.textsampleRate,'string')); + +% music level +stimulusParameters.musicLeveldB=... + str2num(get(handles.editMusicLevel,'string')); + +% set message box font size +experiment.msgFontSize=str2num(get(handles.editMsgFont,'string')); +experiment.subjGUIfontSize=str2num(get(handles.editSubjectFont,'string')); + +% stop criteria +experiment.singleIntervalMaxTrials=... + str2num(get(handles.editstopCriteriaBox,'string')); +experiment.maxTrials=experiment.singleIntervalMaxTrials(1); + +% set up 2IFC is required (? better in atrhesholdAssessmentMethod) +switch experiment.threshEstMethod + case {'2I2AFC++', '2A2AIFC+++'} + experiment.peaksUsed=experiment.singleIntervalMaxTrials(2); + experiment.PeakTroughCriterionSD=... + experiment.singleIntervalMaxTrials(3); + experiment.trialsToBeUsed= 5; + LevittControl.maxTrials=experiment.singleIntervalMaxTrials(1); + % start value for step until reduced + LevittControl.startLevelStep= stimulusParameters.WRVsteps(1); + % reduced step size + LevittControl.steadyLevittStep= stimulusParameters.WRVsteps(2); + LevittControl.TurnsToSmallSteps= 2; + LevittControl.useLastNturns= 2*experiment.peaksUsed; + LevittControl.minReversals= ... + LevittControl.TurnsToSmallSteps+2*experiment.peaksUsed; + LevittControl.targetsdPT = experiment.PeakTroughCriterionSD; + LevittControl.maxLevittValue= stimulusParameters.WRVlimits(2); + Levitt2; +end + +% What kind of randomisation is required? +idx=get(handles.popupmenuRandomize,'value'); +s=get(handles.popupmenuRandomize,'string'); +betweenRuns.randomizeSequence=s{idx}; + +% Make small adjustments to variable values +% to keep values unique against later sorting +x=betweenRuns.variableList1; +[y idx]= sort(x); +for i=1:length(y)-1, if y(i+1)==y(i); y(i+1)=y(i)*1.001; end, end +x(idx)=y; +betweenRuns.variableList1=x; + +x=betweenRuns.variableList2; +[y idx]= sort(x); +for i=1:length(y)-1, if y(i+1)==y(i); y(i+1)=y(i)*1.001; end, end +x(idx)=y; +betweenRuns.variableList2=x; + +% Checks: after reading and setting parameters ------------------------------------------ +% check for finger trouble (more checks possible +if stimulusParameters.maskerDuration>10 + errorMsg='maskerDuration is too long'; return, end +if stimulusParameters.gapDuration>10 + errorMsg='gapDuration is too long'; return, end +if stimulusParameters.targetDuration>10 + errorMsg='targetDuration is too long'; return, end + +% rare event slope check +if experiment.psyFunSlope<0 ... + && strcmp(experiment.functionEstMethod,'rareEvent') + errorMsg='cannot use rareEvent option for negative psychometr slopes'; + return +end + +% check ramps +if stimulusParameters.rampDuration*2> stimulusParameters.targetDuration + errorMsg=' ramp duration is too long for the target'; + return +end + +if max(stimulusParameters.maskerDuration)>0 ... + && max(stimulusParameters.rampDuration... + *2> stimulusParameters.maskerDuration) + errorMsg=' ramp duration is too long for the masker'; + return +end + +% Check WRVstartValues for length and compatibility with randomization +% only one start value supplied so all start values are the same +if length(stimulusParameters.WRVstartValues)==1 + stimulusParameters.WRVstartValues= ... + repmat(stimulusParameters.WRVstartValues, 1, ... + length(betweenRuns.variableList1)... + *length(betweenRuns.variableList2)); +elseif ~isequal(length(stimulusParameters.WRVstartValues), ... + length(betweenRuns.variableList1)... + *length(betweenRuns.variableList2)) + % otherwise we need one value for each combination of var1/ var2 + errorMsg='WRVstartValues not the same length as number of runs'; + return +elseif strcmp(betweenRuns.randomizeSequence, 'randomize within blocks')... + && length(stimulusParameters.WRVstartValues)>1 + errorMsg='multiple WRVstartValues inappropriate'; + return +end + +switch experiment.paradigm + % case { 'TMC', 'TMCmodel','IFMC'} + case {'trainingIFMC', 'TMC','TMC_16ms', 'TMC - ELP', 'IFMC'} + + % For TMC and IFMC multiple target levels can be set + if length(stimulusParameters.targetLevel)==1 + betweenRuns.targetLevels=... + repmat(stimulusParameters.targetLevel, 1, ... + length(betweenRuns.variableList1)... + *length(betweenRuns.variableList2)); + elseif length(stimulusParameters.targetLevel)==... + length(betweenRuns.variableList2) + x=stimulusParameters.targetLevel; + x=repmat(x,length(betweenRuns.variableList1),1); + x=reshape(x,1,length(betweenRuns.variableList1)*length(betweenRuns.variableList2)); + betweenRuns.targetLevels=x; + else + errorMsg='targetLevels not the same length as number of targetFrequencies'; + end +end + +switch experiment.paradigm + case {'gapDetection', 'frequencyDiscrimination'} + if ~isequal(stimulusParameters.targetDuration, ... + stimulusParameters.maskerDuration) + addToMsg(... + 'Warning: masker and target duration not the same.',1,1) + end + if ~isequal(stimulusParameters.maskerLevel, ... + stimulusParameters.targetLevel) + addToMsg(['Warning: masker and target level different.'... + 'They will be changed to be equal',1,1]); + end +end + +% -------------------------------------------- aSetSampleRate +function aSetSampleRate(sampleRate, handles) +global stimulusParameters +stimulusParameters.sampleRate=sampleRate; +set(handles.textsampleRate,'string',num2str(stimulusParameters.sampleRate)) + +% -------------------------------------------- popupmenuEar_Callback +function popupmenuEar_Callback(hObject, eventdata, handles) +global experiment +option=get(handles.popupmenuEar,'value'); +options=get(handles.popupmenuEar,'string'); % left/right/model +experiment.ear=options{option}; +switch experiment.ear + case 'statsModelLogistic' + set(handles.editStatsModel,'string', '15, 0.5') + case 'statsModelRareEvent' + set(handles.editStatsModel,'string', '20 1') +end +earSetUp(handles) + +% -------------------------------------------- earSetUp +function earSetUp(handles) +global experiment stimulusParameters +% option=get(handles.popupmenuEar,'value'); +% options=get(handles.popupmenuEar,'string'); % left/right/model +% experiment.ear=options{option}; + +switch experiment.ear + case {'statsModelLogistic'} + statsModel.logisticSlope=0.5; + statsModel.logisticMean=15; + set(handles.editStatsModel,'string', ... + num2str([statsModel.logisticMean statsModel.logisticSlope])) + set(handles.textStatsModel,... + 'string', {'statsModel',' logistic threshold\ slope'}) + case 'statsModelRareEvent' + set(handles.textStatsModel,'string', ... + {'statsModel',' rareEvent Vmin\ gain'}) +end + +switch experiment.ear + case {'statsModelLogistic', 'statsModelRareEvent'} + set(handles.editStatsModel, 'visible', 'off') + set(handles.textStatsModel, 'visible', 'off') + + % default psychometric bin size and logistic slopes + set(handles.popupmenuRandomize,'value',2) % fixed sequence + set(handles.editName,'string', 'statsModel') + % experiment.headphonesUsed=0; + + case {'MAPmodelListen', 'MAPmodelMultiCh', 'MAPmodelSingleCh'} + stimulusParameters.includeCue=0; % no cue + set(handles.popupmenuCueNoCue,'value', 2) + + set(handles.editCatchTrialRate,'string','0 0 2 ');%no catch trials + set(handles.editName,'string', 'Normal') % force name + experiment.name=get(handles.editName,'string'); % read name back + set(handles.editcalibrationdB,'string','0') + + set(handles.popupmenuRandomize,'value',2) % fixed sequence + set(handles.editstimulusDelay,'string','0') + + set(handles.editSaveData,'string', '0') + set(handles.editSubjectFont,'string', '10'); + experiment.MacGThreshold=0; % num MacG spikes to exceed threshold +end +aResetPopupMenus(handles) + +% --------------------------------------------- popupmenuCueNoCue_Callback +function popupmenuCueNoCue_Callback(hObject, eventdata, handles) +cueSetUp(handles) + +% ------------------------------------------------------------- cueSetUp +function cueSetUp(handles) +global stimulusParameters + +chosenOption=get(handles.popupmenuCueNoCue,'value'); +if chosenOption==1 + stimulusParameters.includeCue=1; + set(handles.editcueTestDifference,'visible', 'on') + set(handles.textcueTestDifference,'visible', 'on') + stimulusParameters.subjectText=stimulusParameters.instructions{2}; +else + stimulusParameters.includeCue=0; + set(handles.editcueTestDifference,'visible', 'off') + set(handles.textcueTestDifference,'visible', 'off') + stimulusParameters.subjectText= stimulusParameters.instructions{1}; +end + +% -------------------------------------------- popupmenuThreshEst_Callback +function popupmenuThreshEst_Callback(hObject, eventdata, handles) +aThresholdAssessmentMethod(handles); + +% --------------------------------------------- aThresholdAssessmentMethod +function aThresholdAssessmentMethod(handles) +% identify the threshold assessment method +% and set various parameters on the GUI appropriately +global stimulusParameters experiment threshEstNames LevittControl + +chosenOption=get(handles.popupmenuThreshEst,'value'); +experiment.threshEstMethod=threshEstNames{chosenOption}; +set(handles.editCatchTrialRate, 'visible', 'on') +set(handles.textCatchTrials, 'visible', 'on') + +% establish appropriate stop criterion and post on GUI +switch experiment.threshEstMethod + case 'MaxLikelihood' + experiment.functionEstMethod='logisticML'; + stimulusParameters.WRVsteps=10*experiment.psyFunSlope; % ??? + set(handles.textstopCriteria,'string', 'stop criteria \ maxTrials') + experiment.singleIntervalMaxTrials=experiment.stopCriteriaSI; + experiment.allowCatchTrials= 1; + switch experiment.paradigm + case 'training' + experiment.possLogSlopes=0.5; + end + + case 'oneIntervalUpDown' + experiment.functionEstMethod='logisticLS'; + set(handles.textstopCriteria,'string', 'stop criteria \ maxTrials') + experiment.singleIntervalMaxTrials=experiment.stopCriteriaSI; + switch experiment.paradigm + case 'discomfort' + experiment.allowCatchTrials= 0; + otherwise + experiment.allowCatchTrials= 1; + end + + case {'2I2AFC++', '2I2AFC+++'} + LevittControl.rule='++'; % e.g. '++' or '+++' + experiment.singleIntervalMaxTrials=experiment.stopCriteria2IFC; + experiment.functionEstMethod='peaksAndTroughs'; + LevittControl.maxTrials=experiment.singleIntervalMaxTrials(1); + set(handles.editWRVsteps,'string', ... + num2str(stimulusParameters.WRVsteps)) + set(handles.textstopCriteria,'string', {'trials peaks sdCrit'}) + experiment.allowCatchTrials= 0; +end + +set(handles.textstopCriteria,'fontSize',8) +set(handles.editstopCriteriaBox,'string',... + num2str(experiment.singleIntervalMaxTrials)) + +% establish the appropriate instructions to the subject +% NB responsibility for this is now transferred to the paradigm file +switch experiment.threshEstMethod + % only one value required for level change + case {'2I2AFC++', '2A2AIFC+++'} + stimulusParameters.subjectText=... + 'did the tone occur in window 1 or 2?'; + case {'MaxLikelihood', 'oneIntervalUpDown'}; + switch stimulusParameters.includeCue + case 0 + stimulusParameters.subjectText=... + stimulusParameters.instructions{1}; + case 1 + stimulusParameters.subjectText= ... + stimulusParameters.instructions{2}; + end +end +stimulusParameters.messageString={'training'}; + +aResetPopupMenus(handles) +% -------------------------------------------------- function orderGlobals +function orderGlobals +global stimulusParameters experiment betweenRuns withinRuns + +stimulusParameters=[]; +stimulusParameters.sampleRate= []; +stimulusParameters.targetType= ''; +stimulusParameters.targetFrequency= []; +stimulusParameters.targetDuration= []; +stimulusParameters.targetLevel= []; +stimulusParameters.gapDuration= []; +stimulusParameters.maskerType= ''; +stimulusParameters.maskerRelativeFrequency= []; +stimulusParameters.maskerDuration= []; +stimulusParameters.maskerLevel= []; +stimulusParameters.backgroundType= ''; +stimulusParameters.backgroundTypeValue= []; +stimulusParameters.backgroundLevel= []; +stimulusParameters.includeCue= []; +experiment.clickToStimulusPause=[]; +stimulusParameters.stimulusDelay= []; +stimulusParameters.rampDuration= []; +stimulusParameters.absThresholds= []; +stimulusParameters.numOHIOtones= []; + +stimulusParameters.WRVname= ''; +stimulusParameters.WRVstartValues= []; +stimulusParameters.WRVsteps= []; +stimulusParameters.WRVlimits= []; +stimulusParameters.WRVinitialStep= []; +stimulusParameters.WRVsmallStep= []; +experiment.singleIntervalMaxTrials= []; +stimulusParameters.calibrationdB= []; + +stimulusParameters.catchTrialRates= []; +stimulusParameters.catchTrialBaseRate= []; +stimulusParameters.catchTrialRate= []; +stimulusParameters.catchTrialTimeConstant= []; + +stimulusParameters.dt= []; + +stimulusParameters.jitterStartdB= []; +stimulusParameters.restoreCalibration= []; +stimulusParameters.messageString= []; +stimulusParameters.cueTestDifference= []; +stimulusParameters.subjectText= ''; +stimulusParameters.testTargetBegins= []; +stimulusParameters.testTargetEnds= []; +stimulusParameters.musicLeveldB= []; + +stimulusParameters.subjectSampleRate=[]; +stimulusParameters.MAPSampleRate=[]; + +experiment=[]; +experiment.name= ''; +experiment.date= ''; +experiment.paradigm= ''; +experiment.ear= ''; +experiment.headphonesUsed=[]; +experiment.singleShot= []; +experiment.randomize= ''; +experiment.maxTrials= []; +experiment.MacGThreshold= []; +experiment.resetCriterion= []; +experiment.runResetCriterion= []; + +experiment.comparisonData= []; +experiment.absThresholds= []; +experiment.threshEstMethod= ''; +experiment.functionEstMethod= ''; +experiment.psyBinWidth= []; +experiment.maxLogisticK=2; +experiment.numPossLogisticK=100; +experiment.possLogSlopes= []; +experiment.meanSearchStep= []; +experiment.psyFunSlope= []; +experiment.predictionLevels=[]; + +experiment.buttonBoxType= ''; +experiment.buttonBoxStatus= ''; +experiment.status= ''; +experiment.stop= 0; +experiment.pleaseRepeat= []; +experiment.justInitialized=[]; + +experiment.MAPplot= []; +experiment.saveData= []; +experiment.printTracks= []; +experiment.msgFontSize= []; +experiment.subjGUIfontSize= []; + +experiment.timeAtStart= ''; +experiment.minElapsed= []; + +betweenRuns=[]; +betweenRuns.variableName1= ''; +betweenRuns.variableList1= []; +betweenRuns.variableName2= ''; +betweenRuns.variableList2= []; +betweenRuns.var1Sequence= []; +betweenRuns.var2Sequence= []; +betweenRuns.randomizeSequence=[]; +betweenRuns.timeNow= []; +betweenRuns.runNumber= []; +% betweenRuns.variableCount1= []; +% betweenRuns.variableCount2= []; +betweenRuns.thresholds= []; +betweenRuns.forceThresholds= []; +betweenRuns.observationCount= []; +betweenRuns.timesOfFirstReversals= []; +betweenRuns.bestThresholdTracks=''; +betweenRuns.bestThresholdMeanTracks=''; +betweenRuns.bestThresholdMedianTracks=''; +betweenRuns.levelTracks=''; +betweenRuns.responseTracks=''; +betweenRuns.slopeKTracks= []; +betweenRuns.gainTracks= []; +betweenRuns.VminTracks= []; +betweenRuns.bestGain= []; +betweenRuns.bestVMin= []; +betweenRuns.bestPaMin= []; +betweenRuns.bestLogisticM= []; +betweenRuns.bestLogisticK= []; +betweenRuns.psychometicFunction=''; +betweenRuns.catchTrials= []; +betweenRuns.caughtOut= []; + +withinRuns=[]; +withinRuns.trialNumber=[]; +withinRuns.nowInPhase2=0; +withinRuns.beginningOfPhase2=0; +withinRuns.variableValue=[]; +withinRuns.direction=''; +withinRuns.peaks=[]; +withinRuns.troughs= []; +withinRuns.levelList= []; +withinRuns.responseList= []; +withinRuns.meanEstTrack= []; +withinRuns.meanLogisticEstTrack=[]; +withinRuns.bestSlopeK= []; +withinRuns.bestGain= []; +withinRuns.bestVMin= []; +withinRuns.forceThreshold=[]; +withinRuns.catchTrial= []; +withinRuns.caughtOut=[]; +withinRuns.catchTrialCount=[]; +withinRuns.wrongButton= []; +withinRuns.babblePlaying=0; + +% --- Executes on selection change in popupmenuBackgroundType. +function popupmenuBackgroundType_Callback(hObject, eventdata, handles) +global backgroundTypes +option=get(handles.popupmenuBackgroundType,'value'); +selectedBackground=backgroundTypes{option}; +stimulusParameters.backgroundType=selectedBackground; + +switch selectedBackground + case 'none' + set(handles.editBackgroundLevel,'visible','off') + set(handles.textBGlevel,'visible','off') + otherwise + set(handles.editBackgroundLevel,'visible','on') + set(handles.textBGlevel,'visible','on') +end + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function pushbuttonStop_Callback(hObject, eventdata, handles) +global experiment +experiment.stop=1; +disp('stop!') +set(handles.pushbuttonStop, 'backgroundColor','r') +pause(.1) +drawnow + +function pushbuttonOME_Callback(hObject, eventdata, handles) +aReadAndCheckParameterBoxes(handles); +testOME + +function pushbuttonBM_Callback(hObject, eventdata, handles) +global stimulusParameters experiment +aReadAndCheckParameterBoxes(handles); +testBM(stimulusParameters.targetFrequency, experiment.name); + +function pushbuttonAN_Callback(hObject, eventdata, handles) +aReadAndCheckParameterBoxes(handles); +% now carry out tests +showPSTHs=0; +testAN + +function pushbuttonRF_Callback(hObject, eventdata, handles) +aReadAndCheckParameterBoxes(handles); +showPSTHs=1; +testRF + +function pushbuttonSYN_Callback(hObject, eventdata, handles) +aReadAndCheckParameterBoxes(handles); +testSynapse + +function pushbuttonFM_Callback(hObject, eventdata, handles) +aReadAndCheckParameterBoxes(handles); +testFM + +function popupmenuPhase_Callback(hObject, eventdata, handles) +global stimulusParameters + +optionNo=get(handles.popupmenuPhase,'value'); +options=get(handles.popupmenuPhase,'string'); +phase=options{optionNo}; +stimulusParameters.maskerPhase=phase; +stimulusParameters.targetPhase=phase; + +function pushbuttonParams_Callback(hObject, eventdata, handles) +global experiment stimulusParameters +aReadAndCheckParameterBoxes(handles); +% print model parameters using the 'name' box (e.g. CTa -> MAPparamsCTa) +showParams=1; BFlist=-1; +paramFunctionName=['method=MAPparams' experiment.name ... + '(BFlist, stimulusParameters.sampleRate, showParams);']; +eval(paramFunctionName) % go and fetch the parameters requesting parameter printout + + +% --- Executes on button press in pushbuttonRP. +function pushbuttonRP_Callback(hObject, eventdata, handles) +global experiment stimulusParameters +aReadAndCheckParameterBoxes(handles); +% now carry out test +testRP(stimulusParameters.targetFrequency,experiment.name) + +% function handles % ?? + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +function editmaskerDuration_Callback(hObject, eventdata, handles) + +function editmaskerDuration_CreateFcn(hObject, eventdata, handles) +if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) + set(hObject,'BackgroundColor','white'); +end + +function editmaskerLevel_Callback(hObject, eventdata, handles) + +function editmaskerLevel_CreateFcn(hObject, eventdata, handles) +if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) + set(hObject,'BackgroundColor','white'); +end + +function editmaskerRelativeFrequency_Callback(hObject, eventdata, handles) + +function editmaskerRelativeFrequency_CreateFcn(hObject, eventdata, handles) +if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) + set(hObject,'BackgroundColor','white'); +end + +function editWRVstartValues_Callback(hObject, eventdata, handles) + +function editWRVstartValues_CreateFcn(hObject, eventdata, handles) +if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) + set(hObject,'BackgroundColor','white'); +end + +function editgapDuration_Callback(hObject, eventdata, handles) + +function editgapDuration_CreateFcn(hObject, eventdata, handles) +if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) + set(hObject,'BackgroundColor','white'); +end + +function edittargetDuration_Callback(hObject, eventdata, handles) + +function edittargetDuration_CreateFcn(hObject, eventdata, handles) +if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) + set(hObject,'BackgroundColor','white'); +end + +function edittargetLevel_Callback(hObject, eventdata, handles) + +function edittargetLevel_CreateFcn(hObject, eventdata, handles) +if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) + set(hObject,'BackgroundColor','white'); +end + +function editrampDuration_Callback(hObject, eventdata, handles) + +function editrampDuration_CreateFcn(hObject, eventdata, handles) +if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) + set(hObject,'BackgroundColor','white'); +end + +function editcueTestDifference_Callback(hObject, eventdata, handles) + +function editcueTestDifference_CreateFcn(hObject, eventdata, handles) +if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) + set(hObject,'BackgroundColor','white'); +end + + +function editWRVsteps_Callback(hObject, eventdata, handles) + +function editWRVsteps_CreateFcn(hObject, eventdata, handles) +if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) + set(hObject,'BackgroundColor','white'); +end + +function editWRVlimits_Callback(hObject, eventdata, handles) + +function editWRVlimits_CreateFcn(hObject, eventdata, handles) +if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) + set(hObject,'BackgroundColor','white'); +end + +function edittargetFrequency_Callback(hObject, eventdata, handles) + +function edittargetFrequency_CreateFcn(hObject, eventdata, handles) +if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) + set(hObject,'BackgroundColor','white'); +end + +function editName_Callback(hObject, eventdata, handles) + +function editName_CreateFcn(hObject, eventdata, handles) +if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) + set(hObject,'BackgroundColor','white'); +end + +function editcalibrationdB_Callback(hObject, eventdata, handles) + +function editcalibrationdB_CreateFcn(hObject, eventdata, handles) +if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) + set(hObject,'BackgroundColor','white'); +end + +function editMAPplot_Callback(hObject, eventdata, handles) + +function editMAPplot_CreateFcn(hObject, eventdata, handles) +if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) + set(hObject,'BackgroundColor','white'); +end + +function editMsgFont_Callback(hObject, eventdata, handles) + +function editMsgFont_CreateFcn(hObject, eventdata, handles) +if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) + set(hObject,'BackgroundColor','white'); +end + +function editCatchTrialRate_Callback(hObject, eventdata, handles) + +function editCatchTrialRate_CreateFcn(hObject, eventdata, handles) +if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) + set(hObject,'BackgroundColor','white'); +end + + +function editSaveData_Callback(hObject, eventdata, handles) + +function editSaveData_CreateFcn(hObject, eventdata, handles) +if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) + set(hObject,'BackgroundColor','white'); +end + +function editStatsModel_Callback(hObject, eventdata, handles) + +function editStatsModel_CreateFcn(hObject, eventdata, handles) +if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) + set(hObject,'BackgroundColor','white'); +end + +function editBackgroundLevel_Callback(hObject, eventdata, handles) + +function editBackgroundLevel_CreateFcn(hObject, eventdata, handles) +if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) + set(hObject,'BackgroundColor','white'); +end + +function editPrintTracks_Callback(hObject, eventdata, handles) + +function editPrintTracks_CreateFcn(hObject, eventdata, handles) +if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) + set(hObject,'BackgroundColor','white'); +end + +function editstopCriteriaBox_Callback(hObject, eventdata, handles) + +function editstopCriteriaBox_CreateFcn(hObject, eventdata, handles) + +if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) + set(hObject,'BackgroundColor','white'); +end + +function editstimulusDelay_Callback(hObject, eventdata, handles) + +function editstimulusDelay_CreateFcn(hObject, eventdata, handles) +if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) + set(hObject,'BackgroundColor','white'); +end + + +function popupmenuCueNoCue_CreateFcn(hObject, eventdata, handles) +if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) + set(hObject,'BackgroundColor','white'); +end + +function popupmenuEar_CreateFcn(hObject, eventdata, handles) +if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) + set(hObject,'BackgroundColor','red'); +end + +function popupmenuVaryParameter1_Callback(hObject, eventdata, handles) + +function popupmenuVaryParameter1_CreateFcn(hObject, eventdata, handles) +if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) + set(hObject,'BackgroundColor','white'); +end + +function popupmenuVaryParameter2_Callback(hObject, eventdata, handles) + +function popupmenuVaryParameter2_CreateFcn(hObject, eventdata, handles) +if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) + set(hObject,'BackgroundColor','white'); +end + +function popupmenuRandomize_Callback(hObject, eventdata, handles) + +function popupmenuRandomize_CreateFcn(hObject, eventdata, handles) +if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) + set(hObject,'BackgroundColor','white'); +end + +function popupmenuParadigm_CreateFcn(hObject, eventdata, handles) +if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) + set(hObject,'BackgroundColor','white'); +end + + +function popupmenuMaskerType_CreateFcn(hObject, eventdata, handles) + +if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) + set(hObject,'BackgroundColor','white'); +end + + +function popupmenuThreshEst_CreateFcn(hObject, eventdata, handles) +if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) + set(hObject,'BackgroundColor','white'); +end + +function popupmenuBackgroundType_CreateFcn(hObject, eventdata, handles) + +if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) + set(hObject,'BackgroundColor','white'); +end + + +function popupmenuTargetType_CreateFcn(hObject, eventdata, handles) +if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) + set(hObject,'BackgroundColor','white'); +end + +function editSubjectFont_Callback(hObject, eventdata, handles) + +function editSubjectFont_CreateFcn(hObject, eventdata, handles) +if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) + set(hObject,'BackgroundColor','white'); +end + +function editMusicLevel_Callback(hObject, eventdata, handles) + +function editMusicLevel_CreateFcn(hObject, eventdata, handles) +if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) + set(hObject,'BackgroundColor','white'); +end + +function figure1_ButtonDownFcn(hObject, eventdata, handles) + + +function edit33_Callback(hObject, eventdata, handles) + +function edit33_CreateFcn(hObject, eventdata, handles) +if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) + set(hObject,'BackgroundColor','white'); +end + + +function popupmenuPhase_CreateFcn(hObject, eventdata, handles) +if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) + set(hObject,'BackgroundColor','white'); +end + +function editsegSize_Callback(hObject, eventdata, handles) + +function editsegSize_CreateFcn(hObject, eventdata, handles) +if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) + set(hObject,'BackgroundColor','white'); +end + + +function editnumOHIOtones_Callback(hObject, eventdata, handles) +% hObject handle to editnumOHIOtones (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 editnumOHIOtones as text +% str2double(get(hObject,'String')) returns contents of editnumOHIOtones as a double + + +% --- Executes during object creation, after setting all properties. +function editnumOHIOtones_CreateFcn(hObject, eventdata, handles) +% hObject handle to editnumOHIOtones (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 + + + diff -r 000000000000 -r f233164f4c86 multithreshold 1.46/hs_err_pid6084.log --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/multithreshold 1.46/hs_err_pid6084.log Fri May 27 13:19:21 2011 +0100 @@ -0,0 +1,258 @@ +# +# An unexpected error has been detected by Java Runtime Environment: +# +# EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x0000000002e47250, pid=6084, tid=5820 +# +# Java VM: Java HotSpot(TM) 64-Bit Server VM (1.6.0-b105 mixed mode) +# Problematic frame: +# C [libmwgui.dll+0x77250] +# +# If you would like to submit a bug report, please visit: +# http://java.sun.com/webapps/bugreport/crash.jsp +# + +--------------- T H R E A D --------------- + +Current thread (0x0000000003d2fc00): JavaThread "main" [_thread_in_native, id=5820] + +siginfo: ExceptionCode=0xc0000005, reading address 0x0000000000000000 + +Registers: +EAX=0x0000000000000000, EBX=0x0000000000000000, ECX=0x0000000000000000, EDX=0x0000000000000000 +ESP=0x00000000010296f8, EBP=0x0000000000000001, ESI=0x0000000000000000, EDI=0x0000000000000000 +EIP=0x0000000002e47250, EFLAGS=0x0000000000010206 + +Top of Stack: (sp=0x00000000010296f8) +0x00000000010296f8: 0000000002fb728f 4010002000000000 +0x0000000001029708: 0000000000000000 0000000035937370 +0x0000000001029718: 0000000002e596dd 0000000008a3cf00 +0x0000000001029728: 0000000002f7fb49 4010000000000000 +0x0000000001029738: 4008000000000000 0000000000000000 +0x0000000001029748: 0000000000000000 0000000008a3cf60 +0x0000000001029758: 0000000002fb72be 0000000008a3cf00 +0x0000000001029768: 0000000000000001 4010000000000000 +0x0000000001029778: 0000000000000000 0000000000000000 +0x0000000001029788: 0000000002f8d1de 0000000000000000 +0x0000000001029798: 0000000008a3cf60 0000000000000001 +0x00000000010297a8: 000000001176d320 0000000009e522a0 +0x00000000010297b8: 000000000319bd9e 0000000008a3cf60 +0x00000000010297c8: 0000000000000020 0000000000000002 +0x00000000010297d8: 00000000013b7338 0000000008a3cf50 +0x00000000010297e8: 00000000359f17a0 000000003c19ca80 + +Instructions: (pc=0x0000000002e47250) +0x0000000002e47240: 89 11 c3 cc cc cc cc cc cc cc cc cc cc cc cc cc +0x0000000002e47250: 8b 01 c3 cc cc cc cc cc cc cc cc cc cc cc cc cc + + +Stack: [0x0000000000030000,0x0000000001030000), sp=0x00000000010296f8, free space=16357k +Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code) +C [libmwgui.dll+0x77250] + +Java frames: (J=compiled Java code, j=interpreted, Vv=VM code) +j com.mathworks.jmi.NativeMatlab.SendMatlabMessage(Ljava/lang/Object;)Ljava/lang/Object;+0 +j com.mathworks.jmi.NativeMatlab.sendMatlabMessage(Ljava/lang/Object;)Ljava/lang/Object;+22 +j com.mathworks.jmi.MatlabLooper.sendMatlabMessage(Lcom/mathworks/services/message/MWMessage;)Ljava/lang/Object;+20 +j com.mathworks.jmi.Matlab.mtFevalConsoleOutput(Ljava/lang/String;[Ljava/lang/Object;I)Ljava/lang/Object;+58 +j com.mathworks.mde.desk.MLDesktop$5.run()V+14 +j com.mathworks.jmi.NativeMatlab.dispatchMTRequests(Z)V+50 +v ~StubRoutines::call_stub + +--------------- P R O C E S S --------------- + +Java Threads: ( => current thread ) + 0x0000000011b68400 JavaThread "Thread-168" [_thread_blocked, id=3544] + 0x0000000011b68c00 JavaThread "Prefs Updater" [_thread_blocked, id=6864] + 0x0000000011b67000 JavaThread "Thread-8" [_thread_blocked, id=6900] + 0x0000000011b66800 JavaThread "Thread-7" [_thread_blocked, id=6792] + 0x0000000011b66000 JavaThread "Thread-6" [_thread_blocked, id=868] + 0x0000000011b65800 JavaThread "Thread-5" [_thread_blocked, id=6628] + 0x0000000030e0a000 JavaThread "Active Reference Queue Daemon" daemon [_thread_blocked, id=1428] + 0x0000000011b97800 JavaThread "Timer-2" daemon [_thread_blocked, id=3276] + 0x0000000030ded400 JavaThread "Timer-1" daemon [_thread_blocked, id=6912] + 0x0000000011a81000 JavaThread "TimerQueue" daemon [_thread_blocked, id=5220] + 0x00000000117fd400 JavaThread "AWT-EventQueue-0" [_thread_blocked, id=120] + 0x00000000114dec00 JavaThread "AWT-Windows" daemon [_thread_in_native, id=3212] + 0x00000000114de400 JavaThread "AWT-Shutdown" [_thread_blocked, id=6512] + 0x00000000114ddc00 JavaThread "Java2D Disposer" daemon [_thread_blocked, id=4896] + 0x0000000011244c00 JavaThread "Timer-0" [_thread_blocked, id=3172] + 0x000000000fb42400 JavaThread "Low Memory Detector" daemon [_thread_blocked, id=2312] + 0x000000000fb40000 JavaThread "CompilerThread1" daemon [_thread_blocked, id=3556] + 0x000000000fb3b800 JavaThread "CompilerThread0" daemon [_thread_blocked, id=2260] + 0x000000000fb37400 JavaThread "Attach Listener" daemon [_thread_blocked, id=6760] + 0x000000000fb1f400 JavaThread "Finalizer" daemon [_thread_blocked, id=5488] + 0x000000000fb19800 JavaThread "Reference Handler" daemon [_thread_blocked, id=6300] +=>0x0000000003d2fc00 JavaThread "main" [_thread_in_native, id=5820] + +Other Threads: + 0x000000000fb16000 VMThread [id=7068] + 0x000000000fb47800 WatcherThread [id=4288] + +VM state:not at safepoint (normal execution) + +VM Mutex/Monitor currently owned by a thread: None + +Heap + PSYoungGen total 7104K, used 6681K [0x00000000265a0000, 0x0000000026d80000, 0x00000000296a0000) + eden space 6400K, 97% used [0x00000000265a0000,0x0000000026bb6710,0x0000000026be0000) + from space 704K, 63% used [0x0000000026cd0000,0x0000000026d40000,0x0000000026d80000) + to space 832K, 0% used [0x0000000026be0000,0x0000000026be0000,0x0000000026cb0000) + PSOldGen total 47616K, used 41927K [0x000000001d2a0000, 0x0000000020120000, 0x00000000265a0000) + object space 47616K, 88% used [0x000000001d2a0000,0x000000001fb91f18,0x0000000020120000) + PSPermGen total 80384K, used 43275K [0x00000000152a0000, 0x000000001a120000, 0x000000001d2a0000) + object space 80384K, 53% used [0x00000000152a0000,0x0000000017ce2c78,0x000000001a120000) + +Dynamic libraries: +0x0000000140000000 - 0x0000000140138000 C:\Program Files\MATLAB\R2008a\bin\win64\MATLAB.exe +0x0000000077420000 - 0x00000000775c9000 C:\Windows\SYSTEM32\ntdll.dll +0x0000000077300000 - 0x000000007741f000 C:\Windows\system32\kernel32.dll +0x000007fefd440000 - 0x000007fefd4ab000 C:\Windows\system32\KERNELBASE.dll +0x0000000180000000 - 0x0000000180401000 C:\Program Files\MATLAB\R2008a\bin\win64\libut.dll +0x000007fefee00000 - 0x000007fefee17000 C:\Windows\system32\imagehlp.dll +0x000007fefd7c0000 - 0x000007fefd85f000 C:\Windows\system32\msvcrt.dll +0x00000000775f0000 - 0x00000000775f7000 C:\Windows\system32\PSAPI.DLL +0x00000000011e0000 - 0x0000000001208000 C:\Program Files\MATLAB\R2008a\bin\win64\LIBEXPAT.dll +0x0000000073a30000 - 0x0000000073af9000 C:\Windows\WinSxS\amd64_microsoft.vc80.crt_1fc8b3b9a1e18e3b_8.0.50727.5592_none_88e45feb2faab9ce\MSVCR80.dll +0x000000004a800000 - 0x000000004a917000 C:\Program Files\MATLAB\R2008a\bin\win64\icuuc36.dll +0x000007fefea70000 - 0x000007fefeb4b000 C:\Windows\system32\ADVAPI32.dll +0x000007feff180000 - 0x000007feff19f000 C:\Windows\SYSTEM32\sechost.dll +0x000007feff2d0000 - 0x000007feff3fd000 C:\Windows\system32\RPCRT4.dll +0x0000000001220000 - 0x0000000001223000 C:\Program Files\MATLAB\R2008a\bin\win64\icudt36.dll +0x000000004ab00000 - 0x000000004ab0f000 C:\Program Files\MATLAB\R2008a\bin\win64\icuio36.dll +0x0000000001250000 - 0x0000000001356000 C:\Program Files\MATLAB\R2008a\bin\win64\icuin36.dll +0x0000000072330000 - 0x0000000072439000 C:\Windows\WinSxS\amd64_microsoft.vc80.crt_1fc8b3b9a1e18e3b_8.0.50727.5592_none_88e45feb2faab9ce\MSVCP80.dll +0x0000000077200000 - 0x00000000772fa000 C:\Windows\system32\USER32.dll +0x000007fefd750000 - 0x000007fefd7b7000 C:\Windows\system32\GDI32.dll +0x000007fefea60000 - 0x000007fefea6e000 C:\Windows\system32\LPK.dll +0x000007feff030000 - 0x000007feff0f9000 C:\Windows\system32\USP10.dll +0x0000000001370000 - 0x00000000014e4000 C:\Program Files\MATLAB\R2008a\bin\win64\libmwservices.dll +0x0000000001500000 - 0x0000000001570000 C:\Program Files\MATLAB\R2008a\bin\win64\libmx.dll +0x0000000001580000 - 0x0000000001597000 C:\Program Files\MATLAB\R2008a\bin\win64\zlib1.dll +0x00000000015a0000 - 0x0000000001648000 C:\Program Files\MATLAB\R2008a\bin\win64\libmwmathutil.dll +0x0000000001660000 - 0x00000000016b5000 C:\Program Files\MATLAB\R2008a\bin\win64\mpath.dll +0x00000000016d0000 - 0x00000000016f1000 C:\Program Files\MATLAB\R2008a\bin\win64\mlutil.dll +0x000007fef9870000 - 0x000007fef9910000 C:\Windows\WinSxS\amd64_microsoft.windows.common-controls_6595b64144ccf1df_5.82.7601.17514_none_a4d6a923711520a9\COMCTL32.dll +0x000007fefec90000 - 0x000007fefed27000 C:\Windows\system32\comdlg32.dll +0x000007fefed80000 - 0x000007fefedf1000 C:\Windows\system32\SHLWAPI.dll +0x000007fefd970000 - 0x000007fefe6f8000 C:\Windows\system32\SHELL32.dll +0x000007fefc840000 - 0x000007fefc856000 C:\Windows\system32\NETAPI32.dll +0x000007fefc830000 - 0x000007fefc83c000 C:\Windows\system32\netutils.dll +0x000007fefcee0000 - 0x000007fefcf03000 C:\Windows\system32\srvcli.dll +0x000007fefc810000 - 0x000007fefc825000 C:\Windows\system32\wkscli.dll +0x000007fefed30000 - 0x000007fefed7d000 C:\Windows\system32\WS2_32.dll +0x000007fefd740000 - 0x000007fefd748000 C:\Windows\system32\NSI.dll +0x0000000001710000 - 0x0000000001765000 C:\Program Files\MATLAB\R2008a\bin\win64\mcr.dll +0x0000000001780000 - 0x00000000017a5000 C:\Program Files\MATLAB\R2008a\bin\win64\iqm.dll +0x00000000017c0000 - 0x00000000017e1000 C:\Program Files\MATLAB\R2008a\bin\win64\bridge.dll +0x0000000001800000 - 0x0000000001811000 C:\Program Files\MATLAB\R2008a\bin\win64\libmex.dll +0x0000000001830000 - 0x00000000018bc000 C:\Program Files\MATLAB\R2008a\bin\win64\m_dispatcher.dll +0x00000000018d0000 - 0x00000000018f5000 C:\Program Files\MATLAB\R2008a\bin\win64\datasvcs.dll +0x0000000012000000 - 0x0000000012295000 C:\Program Files\MATLAB\R2008a\bin\win64\xerces-c_2_7.dll +0x0000000001920000 - 0x00000000021b1000 C:\Program Files\MATLAB\R2008a\bin\win64\m_interpreter.dll +0x00000000021d0000 - 0x0000000002201000 C:\Program Files\MATLAB\R2008a\bin\win64\libmat.dll +0x0000000002220000 - 0x0000000002325000 C:\Program Files\MATLAB\R2008a\bin\win64\libhdf5.dll +0x0000000002330000 - 0x000000000239f000 C:\Program Files\MATLAB\R2008a\bin\win64\profiler.dll +0x00000000023b0000 - 0x00000000023ba000 C:\Program Files\MATLAB\R2008a\bin\win64\libmwmathrng.dll +0x00000000023d0000 - 0x00000000023ea000 C:\Program Files\MATLAB\R2008a\bin\win64\m_pcodeio.dll +0x0000000002400000 - 0x000000000244a000 C:\Program Files\MATLAB\R2008a\bin\win64\m_ir.dll +0x0000000002460000 - 0x0000000002a1b000 C:\Program Files\MATLAB\R2008a\bin\win64\m_parser.dll +0x0000000002a30000 - 0x0000000002a42000 C:\Program Files\MATLAB\R2008a\bin\win64\ir_xfmr.dll +0x0000000002a60000 - 0x0000000002c7b000 C:\Program Files\MATLAB\R2008a\bin\win64\mcos.dll +0x0000000002c90000 - 0x0000000002c9c000 C:\Program Files\MATLAB\R2008a\bin\win64\mtok.dll +0x0000000002cb0000 - 0x0000000002cd0000 C:\Program Files\MATLAB\R2008a\bin\win64\m_pcodegen.dll +0x000007fef4b20000 - 0x000007fef4c45000 C:\Windows\system32\dbghelp.dll +0x0000000002ce0000 - 0x0000000002cf0000 C:\Program Files\MATLAB\R2008a\bin\win64\boost_thread-vc80-mt-1_34_1.dll +0x0000000002d00000 - 0x0000000002dc0000 C:\Program Files\MATLAB\R2008a\bin\win64\udd.dll +0x0000000002dd0000 - 0x0000000002f12000 C:\Program Files\MATLAB\R2008a\bin\win64\libmwgui.dll +0x0000000002f30000 - 0x000000000316a000 C:\Program Files\MATLAB\R2008a\bin\win64\hg.dll +0x0000000003180000 - 0x00000000031d6000 C:\Program Files\MATLAB\R2008a\bin\win64\jmi.dll +0x00000000031f0000 - 0x000000000322e000 C:\Program Files\MATLAB\R2008a\bin\win64\libmwhardcopy.dll +0x0000000003240000 - 0x000000000329c000 C:\Program Files\MATLAB\R2008a\bin\win64\libuij.dll +0x00000000032b0000 - 0x000000000353c000 C:\Program Files\MATLAB\R2008a\bin\win64\numerics.dll +0x0000000003550000 - 0x000000000355c000 C:\Program Files\MATLAB\R2008a\bin\win64\libmwblas.dll +0x0000000003570000 - 0x000000000357f000 C:\Program Files\MATLAB\R2008a\bin\win64\libmwbinder.dll +0x0000000003590000 - 0x00000000035b4000 C:\Program Files\MATLAB\R2008a\bin\win64\libmwlapack.dll +0x00000000035d0000 - 0x00000000035db000 C:\Program Files\MATLAB\R2008a\bin\win64\libmwfftw.dll +0x00000000035f0000 - 0x0000000003625000 C:\Program Files\MATLAB\R2008a\bin\win64\libmwrookfastbp.dll +0x0000000003640000 - 0x000000000366e000 C:\Program Files\MATLAB\R2008a\bin\win64\libmwma57.dll +0x0000000010000000 - 0x00000000100d3000 C:\Program Files\MATLAB\R2008a\bin\win64\libifcoremd.dll +0x0000000003680000 - 0x000000000389d000 C:\Program Files\MATLAB\R2008a\bin\win64\libmmd.dll +0x00000000038a0000 - 0x00000000038a9000 C:\Program Files\MATLAB\R2008a\bin\win64\libmwcsparse.dll +0x00000000038c0000 - 0x000000000398a000 C:\Program Files\MATLAB\R2008a\bin\win64\libmwumfpack.dll +0x00000000039a0000 - 0x00000000039ad000 C:\Program Files\MATLAB\R2008a\bin\win64\libmwamd.dll +0x00000000039c0000 - 0x0000000003a52000 C:\Program Files\MATLAB\R2008a\bin\win64\libmwcholmod.dll +0x0000000003a70000 - 0x0000000003a7c000 C:\Program Files\MATLAB\R2008a\bin\win64\libmwcolamd.dll +0x0000000003a90000 - 0x0000000003b49000 C:\Program Files\MATLAB\R2008a\bin\win64\uiw.dll +0x0000000003b60000 - 0x0000000003b6a000 C:\Program Files\MATLAB\R2008a\bin\win64\uinone.dll +0x0000000068a70000 - 0x0000000068c0c000 C:\Windows\WinSxS\amd64_microsoft.vc80.mfc_1fc8b3b9a1e18e3b_8.0.50727.5592_none_8448f49f328da8c3\MFC80.DLL +0x000007fefb690000 - 0x000007fefb701000 C:\Windows\system32\WINSPOOL.DRV +0x000007fefee20000 - 0x000007feff023000 C:\Windows\system32\ole32.dll +0x000007fefebb0000 - 0x000007fefec87000 C:\Windows\system32\OLEAUT32.dll +0x0000000003b80000 - 0x0000000003c10000 C:\Program Files\MATLAB\R2008a\bin\win64\udd_mi.dll +0x0000000003c20000 - 0x0000000003c38000 C:\Program Files\MATLAB\R2008a\bin\win64\mwoles05.DLL +0x0000000003c50000 - 0x0000000003cb9000 C:\Program Files\MATLAB\R2008a\bin\win64\comcli.dll +0x0000000072310000 - 0x0000000072330000 C:\Windows\WinSxS\amd64_microsoft.vc80.atl_1fc8b3b9a1e18e3b_8.0.50727.5592_none_8a1e1b372ed7b012\ATL80.DLL +0x0000000003cd0000 - 0x0000000003cde000 C:\Program Files\MATLAB\R2008a\bin\win64\mlautoregister.dll +0x000007feff4a0000 - 0x000007feff4ce000 C:\Windows\system32\IMM32.DLL +0x000007fefd860000 - 0x000007fefd969000 C:\Windows\system32\MSCTF.dll +0x000000006fa00000 - 0x000000006fa3f000 C:\PROGRA~2\Sophos\SOPHOS~1\SOPHOS~2.DLL +0x00000000076c0000 - 0x000000000808e000 C:\Program Files\MATLAB\R2008a\bin\win64\mkl.dll +0x00000000068d0000 - 0x000000000691b000 C:\Program Files\MATLAB\R2008a\bin\win64\libguide40.dll +0x0000000003e70000 - 0x0000000003e78000 C:\Program Files\MATLAB\R2008a\bin\win64\mklcompat.dll +0x0000000008090000 - 0x0000000008637000 C:\Program Files\MATLAB\R2008a\bin\win64\mllapack.dll +0x00000000070b0000 - 0x00000000071a4000 C:\Program Files\MATLAB\R2008a\bin\win64\libfftw3i.dll +0x0000000007260000 - 0x000000000734e000 C:\Program Files\MATLAB\R2008a\bin\win64\libfftw3f.dll +0x000007fefd370000 - 0x000007fefd37f000 C:\Windows\system32\profapi.dll +0x000007fefd240000 - 0x000007fefd24f000 C:\Windows\system32\CRYPTBASE.dll +0x000007fefbe90000 - 0x000007fefc084000 C:\Windows\WinSxS\amd64_microsoft.windows.common-controls_6595b64144ccf1df_6.0.7601.17514_none_fa396087175ac9ac\comctl32.dll +0x000007fefe700000 - 0x000007fefe8d7000 C:\Windows\system32\SETUPAPI.dll +0x000007fefd4b0000 - 0x000007fefd4e6000 C:\Windows\system32\CFGMGR32.dll +0x000007fefd420000 - 0x000007fefd43a000 C:\Windows\system32\DEVOBJ.dll +0x000007feff400000 - 0x000007feff499000 C:\Windows\system32\CLBCatQ.DLL +0x000007fefb8f0000 - 0x000007fefba1c000 C:\Windows\system32\propsys.dll +0x000007fefaea0000 - 0x000007fefaecd000 C:\Windows\system32\ntmarta.dll +0x000007fefeb50000 - 0x000007fefeba2000 C:\Windows\system32\WLDAP32.dll +0x000007fefa500000 - 0x000007fefa527000 C:\Windows\system32\iphlpapi.dll +0x000007fefa4f0000 - 0x000007fefa4fb000 C:\Windows\system32\WINNSI.DLL +0x000007fefca60000 - 0x000007fefcabb000 C:\Windows\system32\DNSAPI.dll +0x000007fefa0b0000 - 0x000007fefa0c8000 C:\Windows\system32\dhcpcsvc.DLL +0x000007fefa0d0000 - 0x000007fefa0e1000 C:\Windows\system32\dhcpcsvc6.DLL +0x000007fefd210000 - 0x000007fefd235000 C:\Windows\system32\SspiCli.dll +0x0000000074aa0000 - 0x0000000074aa3000 C:\Windows\system32\icmp.Dll +0x000000000edf0000 - 0x000000000f341000 C:\Program Files\MATLAB\R2008a\sys\java\jre\win64\jre1.6.0\bin\server\jvm.dll +0x000007fefaed0000 - 0x000007fefaf0b000 C:\Windows\system32\WINMM.dll +0x0000000007450000 - 0x00000000074b5000 C:\Program Files\WIDCOMM\Bluetooth Software\btmmhook.dll +0x0000000007230000 - 0x000000000723a000 C:\Program Files\MATLAB\R2008a\sys\java\jre\win64\jre1.6.0\bin\hpi.dll +0x0000000008740000 - 0x000000000874e000 C:\Program Files\MATLAB\R2008a\sys\java\jre\win64\jre1.6.0\bin\verify.dll +0x0000000008750000 - 0x0000000008777000 C:\Program Files\MATLAB\R2008a\sys\java\jre\win64\jre1.6.0\bin\java.dll +0x0000000008780000 - 0x0000000008792000 C:\Program Files\MATLAB\R2008a\sys\java\jre\win64\jre1.6.0\bin\zip.dll +0x00000000087a0000 - 0x00000000087b6000 C:\Program Files\MATLAB\R2008a\bin\win64\nativejava.dll +0x00000000088a0000 - 0x00000000088b6000 C:\Program Files\MATLAB\R2008a\bin\win64\nativejmi.dll +0x000000000f850000 - 0x000000000f857000 C:\Program Files\MATLAB\R2008a\bin\win64\nativeservices.dll +0x0000000011ce0000 - 0x0000000011f30000 C:\Program Files\MATLAB\R2008a\sys\java\jre\win64\jre1.6.0\bin\awt.dll +0x00000000306a0000 - 0x0000000030709000 C:\Program Files\MATLAB\R2008a\sys\java\jre\win64\jre1.6.0\bin\fontmanager.dll + +VM Arguments: +jvm_args: -Xss512k -XX:PermSize=32M -Xms64m -XX:NewRatio=3 -XX:MaxPermSize=128M -Xmx196m -XX:MaxDirectMemorySize=2147400000 -Dsun.java2d.noddraw=true -Dsun.awt.nopixfmt=true -Xshare:off -Xrs -Djava.library.path=C:\Program Files\MATLAB\R2008a\bin\win64 vfprintf abort +java_command: +Launcher Type: generic + +Environment Variables: +CLASSPATH=.;C:\Program Files (x86)\Java\jre6\lib\ext\QTJava.zip +PATH=C:\Program Files (x86)\Nokia\PC Connectivity Solution\;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Program Files\Intel\WiFi\bin\;C:\Program Files\Common Files\Intel\WirelessCommon\;C:\Program Files\Intel\DMIX;C:\Program Files (x86)\NTRU Cryptosystems\NTRU TCG Software Stack\bin\;C:\Program Files\NTRU Cryptosystems\NTRU TCG Software Stack\bin\;C:\Program Files\Wave Systems Corp\Gemalto\Access Client\v5\;c:\Program Files\WIDCOMM\Bluetooth Software\;c:\Program Files\WIDCOMM\Bluetooth Software\syswow64;C:\Program Files (x86)\Common Files\Roxio Shared\DLLShared\;C:\Program Files (x86)\Common Files\Roxio Shared\10.0\DLLShared\;C:\Program Files (x86)\Common Files\Adobe\AGL;C:\Program Files\MATLAB\R2010b\bin;C:\Program Files\MATLAB\R2010a\bin;C:\Program Files\MATLAB\R2008a\bin;C:\Program Files\MATLAB\R2008a\bin\win64;C:\Program Files (x86)\QuickTime\QTSystem\;C:\Program Files\Microsoft Windows Performance Toolkit\ +USERNAME=rmeddis +OS=Windows_NT +PROCESSOR_IDENTIFIER=Intel64 Family 6 Model 37 Stepping 2, GenuineIntel + + + +--------------- S Y S T E M --------------- + +OS: Windows NT 6.1 Build 7601 Service Pack 1 + +CPU:total 4 em64t ht + +Memory: 4k page, physical 8181592k(6037968k free), swap 16361336k(14041736k free) + +vm_info: Java HotSpot(TM) 64-Bit Server VM (1.6.0-b105) for windows-amd64, built on Nov 29 2006 00:38:01 by "java_re" with unknown MS VC++:1400 + diff -r 000000000000 -r f233164f4c86 multithreshold 1.46/nextStimulus.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/multithreshold 1.46/nextStimulus.m Fri May 27 13:19:21 2011 +0100 @@ -0,0 +1,853 @@ +function errormsg=nextStimulus(handles) +% Handles everything concerned with the stimulus presentation +% called from startNewRun in subjGUI + +global experiment stimulusParameters withinRuns betweenRuns +experiment.status='presentingStimulus'; +errormsg=''; + +% interrupt by 'stop' button +if experiment.stop + disp('******** experiment manually stopped *****************') + experiment.status= 'waitingForStart'; + addToMsg('manually stopped',1) + return +end + +% -----------------------------------------choose catch trials at random +% catch trials are for subject threshold measurements only +% this is the only place where withinRuns.catchTrial is set +if experiment.allowCatchTrials + if withinRuns.trialNumber==1; + % first trial is never a catch trial + withinRuns.catchTrial=0; + withinRuns.catchTrialCount=0; % reset count on first trial + elseif withinRuns.trialNumber==2 ... + && withinRuns.catchTrialCount==0 + % second trial is always a catch trial + withinRuns.catchTrial=1; + withinRuns.catchTrialCount=1; % this must be the first + elseif withinRuns.thisIsRepeatTrial + % for requested repeats do not change catch trial status + withinRuns.thisIsRepeatTrial=0; % reset toggle + else + % choose whether or not to have a catch trial + R=rand; + if R upperLevel + errormsg=['Level(' num2str(max(maskerLevel,cueMaskerLevel)) ... + ') is too high ***']; + withinRuns.forceThreshold=upperLevel; + withinRuns.forceThreshold=NaN; + return + end + if max(maskerLevel, cueMaskerLevel)< lowerLevel + errormsg=['Level(' num2str(max(maskerLevel,cueMaskerLevel)) ... + ') is too low ***']; + withinRuns.forceThreshold=lowerLevel; + withinRuns.forceThreshold=NaN; + return + end + + if max(maskerLevel, cueMaskerLevel)> clippingLevel + errormsg=['Level(' num2str(max(maskerLevel,cueMaskerLevel)) ... + ') is clipping ***']; + withinRuns.forceThreshold=clippingLevel; + withinRuns.forceThreshold=NaN; + return + end + + case 'targetLevel' + upperLevel=stimulusParameters.WRVlimits(2); + lowerLevel=stimulusParameters.WRVlimits(1); + if ~withinRuns.catchTrial + if max(targetLevel, cueTargetLevel)> upperLevel + errormsg=['target level (' ... + num2str(max(targetLevel, cueTargetLevel)) ... + ') is too high ***']; + withinRuns.forceThreshold=upperLevel; + withinRuns.forceThreshold=NaN; + return + end + if max(targetLevel, cueTargetLevel)< lowerLevel + errormsg=['target level (' ... + num2str(max(targetLevel, cueTargetLevel)) ... + ') is too low ***']; + withinRuns.forceThreshold=lowerLevel; + withinRuns.forceThreshold=NaN; + return + end + if max(targetLevel, cueTargetLevel)> clippingLevel + errormsg=['target level (' ... + num2str(max(targetLevel, cueTargetLevel)) ... + ') is clipping ***']; + withinRuns.forceThreshold=upperLevel; + withinRuns.forceThreshold=NaN; + return + end + end + case 'maskerDuration' + % this is odd! but harmless + if max(maskerDuration, cueMaskerDuration)> ... + stimulusParameters.WRVlimits(2) + errormsg=['maskerDuration (' ... + num2str(max(maskerDuration, cueMaskerDuration))... + ') is too long ***']; + withinRuns.forceThreshold=stimulusParameters.WRVlimits(2); + withinRuns.forceThreshold=NaN; + return + end + + if min(maskerDuration, cueMaskerDuration)... + < stimulusParameters.WRVlimits(1) + errormsg=['maskerDuration (' num2str(maskerLevel) ... + ') too short ***']; + withinRuns.forceThreshold=stimulusParameters.WRVlimits(1); + withinRuns.forceThreshold=NaN; + return + end + + % legacy programming + case 'gapDuration' + if gapDuration<0 + errormsg=['gapDuration (' num2str(gapDuration) ... + ') is less than zero ***']; + return + end + + case 'maskerFrequency' + switch experiment.paradigm + case 'bandwidth' + frequency=maskerFrequency'; + if stimulusParameters.WRVstep<0 + lowerLevel=stimulusParameters.targetFrequency; + upperLevel=stimulusParameters.targetFrequency*2; + else + lowerLevel=stimulusParameters.targetFrequency/3; + upperLevel=stimulusParameters.targetFrequency; + end + + if frequency(1)>upperLevel || frequency(1)stimulusParameters.WRVlimits(2) + errormsg=['masker frequency (' ... + num2str(frequencyDifference) ... + ') is outside WRV limits ***']; + withinRuns.forceThreshold=stimulusParameters.WRVlimits(2) ; + return + end + +end + +% --------------------------------Ear ---------------------------------- +globalStimParams.ears='specified'; +% ear: 1=left, 2=right +switch experiment.ear + case 'left' + maskerEar=1; + targetEar=1; + case 'right' + maskerEar=2; + targetEar=2; + case 'dichoticLeft' + maskerEar=2; + targetEar=1; + case 'dichoticRight' + maskerEar=1; + targetEar=2; + case 'diotic' + maskerEar=1; + targetEar=1; + globalStimParams.ears='diotic'; + case {'MAPmodel', 'MAPmodelMultiCh', 'MAPmodelSingleCh', 'MAPmodelListen',... + 'statsModelLogistic', 'statsModelRareEvent'} + maskerEar=1; + targetEar=1; +end + +backgroundType=stimulusParameters.backgroundType; +switch stimulusParameters.backgroundType + case {'noiseDich', 'pinkNoiseDich'} +% case 'Dich' + % dich means put the background in the ear opposite to the target + backgroundType=backgroundType(1:end-4); + switch targetEar + case 1 + backgroundEar=2; + case 2 + backgroundEar=1; + end + otherwise +% case {'none','noise', 'pinkNoise', 'TEN','babble'} + backgroundEar=targetEar; +end + +% ------------------------------- Make Stimulus ------------------- +% single interval up/down plays cue then target stimulus +% 2IFC uses cue stimulus as interval with no target +globalStimParams.FS=stimulusParameters.sampleRate; +dt=1/stimulusParameters.sampleRate; +globalStimParams.dt=dt; +stimulusParameters.dt=dt; % for use later + +% calibration of sound output +correctiondB=stimulusParameters.calibrationdB; +globalStimParams.audioOutCorrection=10^(correctiondB/20); +% the output will be reduced by this amount in stimulusCreate +% i.e. audio=audio/globalStimParams.audioOutCorrection +% A 91 dB level will yield a peak amp of 1 for calibration=0 +% A 91 dB level will yield a peak amp of 0.4467 for calibration=7 +% A 98 dB level will yield a peak amp of 1 for calibration=7 + +precedingSilence=stimulusParameters.stimulusDelay; +% all stimuli have 20 ms terminal silence. +% this is clearance for modelling late-ringing targets +terminalSilence=.03; + +% Now compute overall duration of the stimulus +% note that all endsilence values are set to -1 +% so that they will fill with terminal silence as required to make +% components equal in length +% We need to find the longest possible duration +duration(1)=precedingSilence+maskerDuration+cueGapDuration... + +targetDuration+terminalSilence; +duration(2)=precedingSilence+maskerDuration+gapDuration... + +targetDuration+ terminalSilence; +% If the gap is negative we need to ignore it when estimating total length +duration(3)=precedingSilence+maskerDuration+ terminalSilence; +globalStimParams.overallDuration=max(duration); +globalStimParams.nSignalPoints=... + round(globalStimParams.overallDuration/globalStimParams.dt); + +% ----------------------------------------------cue stimulus +% cue masker +componentNo=1; +precedingSilence=stimulusParameters.stimulusDelay; +stimComponents(maskerEar,componentNo).type=maskerType; +stimComponents(maskerEar,componentNo).toneDuration=cueMaskerDuration; +stimComponents(maskerEar,componentNo).frequencies=cueMaskerFrequency; +stimComponents(maskerEar,componentNo).amplitudesdB=cueMaskerLevel; +stimComponents(maskerEar,componentNo).beginSilence=precedingSilence; +stimComponents(maskerEar,componentNo).endSilence=-1; +stimComponents(maskerEar,componentNo).AMfrequency=0; +stimComponents(maskerEar,componentNo).AMdepth=0; +if rampDuration0.5 % put test stimulus first + stimulusParameters.testTargetBegins=targetDelay ; + stimulusParameters.testTargetEnds= ... + targetDelay+targetDuration; + stimulusParameters.testNonTargetBegins=... + length(cueStimulus)*dt ... + + AFCsilenceDuration +targetDelay ; + stimulusParameters.testNonTargetEnds=... + length(cueStimulus)*dt ... + + AFCsilenceDuration+targetDelay+targetDuration; + + set(handles.pushbutton1,'backgroundcolor','r'), drawnow + y=audioplayer(targetStimulus, globalStimParams.FS, 24); + playblocking(y) + set(handles.pushbutton1,'backgroundcolor',... + get(0,'defaultUicontrolBackgroundColor')), drawnow + y=audioplayer(IAFCinterveningSilence, ... + globalStimParams.FS, 24); + playblocking(y) + set(handles.pushbutton2,'backgroundcolor','r'), drawnow + y=audioplayer(cueStimulus, globalStimParams.FS, 24); + playblocking(y) + set(handles.pushbutton2,'backgroundcolor',... + get(0,'defaultUicontrolBackgroundColor')), drawnow + withinRuns.stimulusOrder='targetFirst'; + audio= [targetStimulus; IAFCinterveningSilence; ... + cueStimulus]; % for plotting purposes later + + else % put test stimulus second + stimulusParameters.testTargetBegins=... + length(cueStimulus)*dt ... + + AFCsilenceDuration +targetDelay ; + stimulusParameters.testTargetEnds=... + length(cueStimulus)*dt ... + + AFCsilenceDuration+targetDelay+targetDuration; + stimulusParameters.testNonTargetBegins=targetDelay ; + stimulusParameters.testNonTargetEnds=... + targetDelay+targetDuration; + + set(handles.pushbutton1,'backgroundcolor','r'),drawnow + y=audioplayer(cueStimulus, globalStimParams.FS, 24); + playblocking(y) + set(handles.pushbutton1,'backgroundcolor',... + get(0,'defaultUicontrolBackgroundColor')), drawnow + y=audioplayer(IAFCinterveningSilence, ... + globalStimParams.FS, 24); + playblocking(y) + set(handles.pushbutton2,'backgroundcolor','r'), drawnow + y=audioplayer(targetStimulus, globalStimParams.FS, 24); + playblocking(y) + set(handles.pushbutton2,'backgroundcolor',... + get(0,'defaultUicontrolBackgroundColor')), drawnow + withinRuns.stimulusOrder='targetSecond'; + audio= [cueStimulus; IAFCinterveningSilence; ... + targetStimulus]; % for plotting purposes later + end + otherwise % singleInterval + if strcmp(experiment.ear,'MAPmodel') ... + || strcmp(experiment.ear,'MAPmodelMultiCh') ... + || strcmp(experiment.ear,'MAPmodelSingleCh') ... + ||strcmp(experiment.ear,'MAPmodelListen') + % don't play for MAPmodel + switch experiment.ear + % except on special request + case {'MAPmodelListen'} + y=audioplayer(audio, globalStimParams.FS, 24); + playblocking(y) % suspends operations until completed + end + else + y=audioplayer(audio, globalStimParams.FS, 24); + playblocking(y) + end % if experiment.ear + end % switch experiment.threshEstMethod +end % switch experiment.ear + + +% switch experiment.ear +% case {'MAPmodel', 'MAPmodelListen', 'MAPmodelMultiCh','MAPmodelSingleCh'} +% % save audio for later reference or for input to MAP model +% wavwrite(audio/max(audio), globalStimParams.FS,32,'stimulus') +% end + +% Panel 1 +% graphical presentation of the stimulus +% NB shown *after* the stimulus has been presented +axes(expGUIhandles.axes1), cla +% plot is HW rectified and plotted as dB re 28e-6 +% calibration is ignored +t=dt:dt:dt*length(audio); +plot(t,stimulusParameters.calibrationdB+20*log10((abs(audio)+1e-10)/28e-6)) +% set(gca,'xtick',[]) +ylim([-20 100]) +ylabel('stimulus (dB SPL)') +xlim([0 t(end)]) +grid on +header=[betweenRuns.variableName1 ': ' ... + num2str(betweenRuns.var1Sequence(betweenRuns.runNumber))]; +header=[header ' ' num2str(... + betweenRuns.var2Sequence(betweenRuns.runNumber)) ':' ... + betweenRuns.variableName2 ]; +title(header) + diff -r 000000000000 -r f233164f4c86 multithreshold 1.46/paradigms/paradigmList.mat Binary file multithreshold 1.46/paradigms/paradigmList.mat has changed diff -r 000000000000 -r f233164f4c86 multithreshold 1.46/paradigms/paradigm_GOM.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/multithreshold 1.46/paradigms/paradigm_GOM.m Fri May 27 13:19:21 2011 +0100 @@ -0,0 +1,45 @@ +function paradigm_GOM(handles) +global stimulusParameters experiment betweenRuns + +paradigm_training(handles) % default + +stimulusParameters.WRVname='maskerLevel'; +stimulusParameters.WRVstartValues=20; +stimulusParameters.WRVsteps= [-10 -2]; +stimulusParameters.WRVlimits=[-30 110]; + +% target variable: slope=1, start going down. +withinRuns.direction='up'; +experiment.psyFunSlope=-1; + +betweenRuns.variableName1='targetLevel'; +betweenRuns.variableList1=25: 5: 70; +betweenRuns.variableName2='maskerRelativeFrequency'; +betweenRuns.variableList2=[1 0.5]; +betweenRuns.randomizeSequence=1; % 'random sequence' + +stimulusParameters.maskerType='tone'; +stimulusParameters.maskerPhase='sin'; +stimulusParameters.maskerDuration=0.104; +stimulusParameters.maskerLevel=stimulusParameters.WRVstartValues(1); +stimulusParameters.maskerRelativeFrequency=betweenRuns.variableList2; + +stimulusParameters.gapDuration=0.0002; + +stimulusParameters.targetType='tone'; +stimulusParameters.targetPhase='sin'; +% retain current target frequency +x=str2num(get(handles.edittargetFrequency,'string')); +stimulusParameters.targetFrequency=x(1); + +stimulusParameters.targetDuration=0.004; +stimulusParameters.targetLevel=stimulusParameters.WRVstartValues(1); + +stimulusParameters.rampDuration=0.002; + +% instructions to user +% single interval up/down no cue +stimulusParameters.instructions{1}= [{'YES if you hear the tone clearly'}, { }, { 'NO if not (or you are uncertain'}]; +% single interval up/down with cue +stimulusParameters.instructions{2}= [{'count the tones you hear clearly'}, { }, { 'ignore indistinct tones'}]; + diff -r 000000000000 -r f233164f4c86 multithreshold 1.46/paradigms/paradigm_IFMC.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/multithreshold 1.46/paradigms/paradigm_IFMC.m Fri May 27 13:19:21 2011 +0100 @@ -0,0 +1,41 @@ +function paradigm_IFMC(handles) +global stimulusParameters experiment betweenRuns + +paradigm_training(handles) % default + +stimulusParameters.WRVname='maskerLevel'; +stimulusParameters.WRVstartValues=-10; +stimulusParameters.WRVsteps= [-10 -2]; +stimulusParameters.WRVlimits=[-30 110]; + +experiment.psyFunSlope = -1; +withinRuns.direction='up'; + +betweenRuns.variableName1='maskerRelativeFrequency'; +betweenRuns.variableList1=[1 0.5 1.6 .9 .7 1.1 1.3 ]; +betweenRuns.variableName2='targetFrequency'; +% keep old list of target frequencies +betweenRuns.variableList2=str2num(get(handles.edittargetFrequency,'string')); +betweenRuns.randomizeSequence=1; % 'random sequence' + +stimulusParameters.maskerDuration=0.108; +stimulusParameters.maskerLevel=stimulusParameters.WRVstartValues(1); +stimulusParameters.maskerRelativeFrequency=betweenRuns.variableList1; + +stimulusParameters.gapDuration=0.01; + +stimulusParameters.targetType='tone'; +stimulusParameters.targetPhase='sin'; +stimulusParameters.targetFrequency=betweenRuns.variableList2(1); +stimulusParameters.targetDuration=0.016; +stimulusParameters.targetLevel=NaN; + +stimulusParameters.rampDuration=0.004; + +% instructions to user +% single interval up/down no cue +stimulusParameters.instructions{1}=[{'YES if you hear the added click'}, { }, { 'NO if not (or you are uncertain'}]; +% single interval up/down with cue +stimulusParameters.instructions{2}=[{'count how many distinct clicks you hear'},{'ignore the tones'},{' '},... + {'The clicks must be **clearly distinct** to count'}]; + diff -r 000000000000 -r f233164f4c86 multithreshold 1.46/paradigms/paradigm_IFMC_16ms.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/multithreshold 1.46/paradigms/paradigm_IFMC_16ms.m Fri May 27 13:19:21 2011 +0100 @@ -0,0 +1,41 @@ +function paradigm_IFMC_8ms(handles) +global stimulusParameters experiment betweenRuns + +paradigm_training(handles) % default + +stimulusParameters.WRVname='maskerLevel'; +stimulusParameters.WRVstartValues=50; +stimulusParameters.WRVsteps= [-10 -2]; +stimulusParameters.WRVlimits=[-30 110]; + +experiment.psyFunSlope = -1; +withinRuns.direction='up'; + +betweenRuns.variableName1='maskerRelativeFrequency'; +betweenRuns.variableList1=[1 0.5 1.6 .9 .7 1.1 1.3 ]; +betweenRuns.variableName2='targetFrequency'; +% keep old list of target frequencies +betweenRuns.variableList2=str2num(get(handles.edittargetFrequency,'string')); +betweenRuns.randomizeSequence=1; % 'random sequence' + +stimulusParameters.maskerDuration=0.108; +stimulusParameters.maskerLevel=stimulusParameters.WRVstartValues(1); +stimulusParameters.maskerRelativeFrequency=betweenRuns.variableList1; + +stimulusParameters.gapDuration=0.01; + +stimulusParameters.targetType='tone'; +stimulusParameters.targetPhase='sin'; +stimulusParameters.targetFrequency=betweenRuns.variableList2(1); +stimulusParameters.targetDuration=0.016; +stimulusParameters.targetLevel=NaN; + +stimulusParameters.rampDuration=0.004; + +% instructions to user +% single interval up/down no cue +stimulusParameters.instructions{1}=[{'YES if you hear the added click'}, { }, { 'NO if not (or you are uncertain'}]; +% single interval up/down with cue +stimulusParameters.instructions{2}=[{'count how many distinct clicks you hear'},{'ignore the tones'},{' '},... + {'The clicks must be **clearly distinct** to count'}]; + diff -r 000000000000 -r f233164f4c86 multithreshold 1.46/paradigms/paradigm_SRT.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/multithreshold 1.46/paradigms/paradigm_SRT.m Fri May 27 13:19:21 2011 +0100 @@ -0,0 +1,72 @@ +function paradigm_SRT(handles) +global stimulusParameters experiment betweenRuns + +stimulusParameters.subjectSampleRate=44100; + +% assessment method +% {'oneIntervalUpDown', 'MaxLikelihood', '2I2AFC++', '2I2AFC+++'} +experiment.threshEstMethod='oneIntervalUpDown'; +% {'cued', 'noCue'}; +stimulusParameters.includeCue=0; +stimulusParameters.cueTestDifference=10; + +experiment.singleIntervalMaxTrials=10; +experiment.maxTrials=10; +experiment.allowCatchTrials= 0; + +% {'tone','noise', 'pinkNoise','whiteNoise','OHIO'} +stimulusParameters.WRVname='targetLevel'; +stimulusParameters.WRVstartValues=60 ; +stimulusParameters.WRVsteps=[5 2]; +stimulusParameters.WRVlimits=[-30 110]; + +% target variable: slope=1, start going down. +experiment.psyFunSlope=1; +withinRuns.direction='down'; + +betweenRuns.variableName1='targetFrequency'; +betweenRuns.variableList1=1000; +betweenRuns.variableName2='maskerDuration'; +betweenRuns.variableList2=0.1 ; +% 1='fixed sequence', 2='randomize within blocks', 3='randomize across +% blocks' +betweenRuns.randomizeSequence=1; % 'random sequence' + +% delay > masker > gap > target + +stimulusParameters.stimulusDelay=0.3; + +% maskerTypes={'tone','noise', 'pinkNoise','TEN','whiteNoise'}; +stimulusParameters.maskerType='tone'; +stimulusParameters.maskerPhase='sin'; +stimulusParameters.maskerDuration=0.0; +stimulusParameters.maskerLevel= -50; +stimulusParameters.maskerRelativeFrequency= 1 ; % not used + +stimulusParameters.gapDuration=0.0; + +% targetTypes={'tone','noise', 'pinkNoise','whiteNoise','OHIO'}; +stimulusParameters.targetType='digitStrings'; +stimulusParameters.targetPhase='sin'; +stimulusParameters.targetFrequency=1000; +stimulusParameters.targetDuration=2; +stimulusParameters.targetLevel=stimulusParameters.WRVstartValues(1); + +stimulusParameters.rampDuration=0.004; +stimulusParameters.stimulusDelay=1; + +% forced choice window interval +stimulusParameters.AFCsilenceDuration=0.5; + +% {'none','noise', 'pinkNoise', 'TEN','noiseDich', 'pinkNoiseDich','whiteNoise'} +stimulusParameters.backgroundType='24TalkerBabble'; +stimulusParameters.backgroundLevel= 60; + +% instructions to user +% single interval up/down no cue +stimulusParameters.instructions{1}= ... + [{'Type three digits in the box (top left)'}, { }, ... + {'then hit return'}]; + +stimulusParameters.numOHIOtones=1; + diff -r 000000000000 -r f233164f4c86 multithreshold 1.46/paradigms/paradigm_TENtest.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/multithreshold 1.46/paradigms/paradigm_TENtest.m Fri May 27 13:19:21 2011 +0100 @@ -0,0 +1,33 @@ +function paradigm_TENtest(handles) +global stimulusParameters experiment betweenRuns + +paradigm_training(handles) % default + +stimulusParameters.WRVname='targetLevel'; +stimulusParameters.WRVstartValues=40; +stimulusParameters.WRVsteps=[10 2]; +stimulusParameters.WRVlimits=[-30 110]; + +betweenRuns.variableName1='targetFrequency'; +betweenRuns.variableList1=[250 500 1000 2000 4000 8000 ]; +betweenRuns.variableName2='targetDuration'; +betweenRuns.variableList2= 0.25; +betweenRuns.randomizeSequence=1; % 'random sequence' + +stimulusParameters.targetType='tone'; +stimulusParameters.targetPhase='sin'; +stimulusParameters.targetFrequency=betweenRuns.variableList1; +stimulusParameters.targetDuration=0.5; +stimulusParameters.targetLevel=stimulusParameters.WRVstartValues(1); + +% {'none','noise', 'pinkNoise', 'TEN','noiseDich', 'pinkNoiseDich','whiteNoise'} +stimulusParameters.backgroundType='TEN'; +stimulusParameters.backgroundLevel=20; + +% instructions to user +% single interval up/down no cue +stimulusParameters.instructions{1}=[{'YES if you hear the added click'}, { }, { 'NO if not (or you are uncertain'}]; +% single interval up/down with cue +stimulusParameters.instructions{2}=[{'count how many distinct clicks you hear'},{'ignore the tones'},{' '},... + {'The clicks must be **clearly distinct** to count'}]; + diff -r 000000000000 -r f233164f4c86 multithreshold 1.46/paradigms/paradigm_TMC.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/multithreshold 1.46/paradigms/paradigm_TMC.m Fri May 27 13:19:21 2011 +0100 @@ -0,0 +1,44 @@ +function paradigm_TMC(handles) +global stimulusParameters experiment betweenRuns + +paradigm_training(handles) % default + +stimulusParameters.WRVname='maskerLevel'; +stimulusParameters.WRVstartValues=-10; +stimulusParameters.WRVsteps= [-10 -4]; +stimulusParameters.WRVlimits=[-30 110]; + +stimulusParameters.cueTestDifference = 10; +experiment.psyFunSlope = -1; +withinRuns.direction='up'; + +betweenRuns.variableName1='gapDuration'; +betweenRuns.variableList1=[.05 .08 .02 .06 .04 ]; +betweenRuns.variableName2='targetFrequency'; +% retain existing targetFrequencies +betweenRuns.variableList2=str2num(get(handles.edittargetFrequency,'string')); +betweenRuns.randomizeSequence=1; % 'random sequence' + +stimulusParameters.maskerType='tone'; +stimulusParameters.maskerPhase='sin'; +stimulusParameters.maskerDuration=0.108; +stimulusParameters.maskerLevel=stimulusParameters.WRVstartValues(1); +stimulusParameters.maskerRelativeFrequency=1; + +stimulusParameters.gapDuration=betweenRuns.variableList1; + +stimulusParameters.targetType='tone'; +stimulusParameters.targetPhase='sin'; +stimulusParameters.targetFrequency=betweenRuns.variableList2(1); +stimulusParameters.targetDuration=0.016; +stimulusParameters.targetLevel=NaN; + +stimulusParameters.rampDuration=0.004; + +% instructions to user +% single interval up/down no cue +stimulusParameters.instructions{1}=[{'YES if you hear the added click'}, { }, { 'NO if not (or you are uncertain'}]; +% single interval up/down with cue +stimulusParameters.instructions{2}=[{'count how many distinct clicks you hear'},{'ignore the tones'},{' '},... + {'The clicks must be **clearly distinct** to count'}]; + diff -r 000000000000 -r f233164f4c86 multithreshold 1.46/paradigms/paradigm_TMC_16ms.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/multithreshold 1.46/paradigms/paradigm_TMC_16ms.m Fri May 27 13:19:21 2011 +0100 @@ -0,0 +1,46 @@ +function paradigm_TMC_16ms(handles) +global stimulusParameters experiment betweenRuns + +paradigm_training(handles) % default + +experiment.singleIntervalMaxTrials=20; + +stimulusParameters.WRVname='maskerLevel'; +stimulusParameters.WRVstartValues=50; +stimulusParameters.WRVsteps= [-10 -4]; +stimulusParameters.WRVlimits=[-30 110]; + +stimulusParameters.cueTestDifference = 10; +experiment.psyFunSlope = -1; +withinRuns.direction='up'; + +betweenRuns.variableName1='gapDuration'; +betweenRuns.variableList1=[.01 .09 .03 .05 .07]; +betweenRuns.variableName2='targetFrequency'; +% retain existing targetFrequencies +betweenRuns.variableList2=str2num(get(handles.edittargetFrequency,'string')); +betweenRuns.randomizeSequence=1; % 'random sequence' + +stimulusParameters.maskerType='tone'; +stimulusParameters.maskerPhase='sin'; +stimulusParameters.maskerDuration=0.108; +stimulusParameters.maskerLevel=stimulusParameters.WRVstartValues(1); +stimulusParameters.maskerRelativeFrequency=1; + +stimulusParameters.gapDuration=betweenRuns.variableList1; + +stimulusParameters.targetType='tone'; +stimulusParameters.targetPhase='sin'; +stimulusParameters.targetFrequency=betweenRuns.variableList2(1); +stimulusParameters.targetDuration=0.016; +stimulusParameters.targetLevel=NaN; + +stimulusParameters.rampDuration=0.004; + +% instructions to user +% single interval up/down no cue +stimulusParameters.instructions{1}=[{'YES if you hear the added click'}, { }, { 'NO if not (or you are uncertain'}]; +% single interval up/down with cue +stimulusParameters.instructions{2}=[{'count how many distinct clicks you hear'},{'ignore the tones'},{' '},... + {'The clicks must be **clearly distinct** to count'}]; + diff -r 000000000000 -r f233164f4c86 multithreshold 1.46/paradigms/paradigm_TMCmodel.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/multithreshold 1.46/paradigms/paradigm_TMCmodel.m Fri May 27 13:19:21 2011 +0100 @@ -0,0 +1,45 @@ +function paradigm_TMCmodel(handles) +global stimulusParameters experiment betweenRuns + +paradigm_training(handles) % default + +stimulusParameters.WRVname='maskerLevel'; +stimulusParameters.WRVstartValues=30; +stimulusParameters.WRVsteps= [-10 -4]; +stimulusParameters.WRVlimits=[-30 110]; + +stimulusParameters.cueTestDifference = 10; +experiment.psyFunSlope = -1; +withinRuns.direction='up'; + +betweenRuns.variableName1='gapDuration'; +betweenRuns.variableList1=[ 0.09 0.01:0.02:0.07 0.02:0.02:.08 0.005]; +betweenRuns.variableName2='targetFrequency'; +% retain existing targetFrequencies +betweenRuns.variableList2=str2num(get(handles.edittargetFrequency,'string')); +betweenRuns.randomizeSequence=1; % 'random sequence' + +stimulusParameters.maskerType='tone'; +stimulusParameters.maskerPhase='sin'; +stimulusParameters.maskerDuration=0.108; +stimulusParameters.maskerLevel=stimulusParameters.WRVstartValues(1); +stimulusParameters.maskerRelativeFrequency=1; +experiment.singleIntervalMaxTrials=10; + +stimulusParameters.gapDuration=betweenRuns.variableList1; + +stimulusParameters.targetType='tone'; +stimulusParameters.targetPhase='sin'; +stimulusParameters.targetFrequency=betweenRuns.variableList2(1); +stimulusParameters.targetDuration=0.016; +stimulusParameters.targetLevel=NaN; + +stimulusParameters.rampDuration=0.004; + +% instructions to user +% single interval up/down no cue +stimulusParameters.instructions{1}=[{'YES if you hear the added click'}, { }, { 'NO if not (or you are uncertain'}]; +% single interval up/down with cue +stimulusParameters.instructions{2}=[{'count how many distinct clicks you hear'},{'ignore the tones'},{' '},... + {'The clicks must be **clearly distinct** to count'}]; + diff -r 000000000000 -r f233164f4c86 multithreshold 1.46/paradigms/paradigm_absThreshold.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/multithreshold 1.46/paradigms/paradigm_absThreshold.m Fri May 27 13:19:21 2011 +0100 @@ -0,0 +1,29 @@ +function paradigm_absThreshold(handles) +global stimulusParameters experiment betweenRuns + +paradigm_training(handles) % default + +betweenRuns.variableName1='targetFrequency'; +betweenRuns.variableList1=[250 500 1000 2000 4000 8000 ]; +betweenRuns.variableName2='targetDuration'; +betweenRuns.variableList2= 0.25; + +stimulusParameters.targetFrequency=betweenRuns.variableList1; +stimulusParameters.targetDuration=betweenRuns.variableList2; +stimulusParameters.targetLevel=stimulusParameters.WRVstartValues(1); + +stimulusParameters.WRVstartValues=30; + + +% forced choice window interval +stimulusParameters.AFCsilenceDuration=0.5; + + +% instructions to user +% single interval up/down no cue +stimulusParameters.instructions{1}=[{'YES if you hear the added click'}, { }, { 'NO if not (or you are uncertain'}]; +% single interval up/down with cue +stimulusParameters.instructions{2}=[{'count how many distinct clicks you hear'},{'ignore the tones'},{' '},... + {'The clicks must be **clearly distinct** to count'}]; + + diff -r 000000000000 -r f233164f4c86 multithreshold 1.46/paradigms/paradigm_absThreshold_16.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/multithreshold 1.46/paradigms/paradigm_absThreshold_16.m Fri May 27 13:19:21 2011 +0100 @@ -0,0 +1,36 @@ +function paradigm_absThreshold16(handles) +global stimulusParameters experiment betweenRuns + +paradigm_training(handles) % default + +betweenRuns.variableName1='targetFrequency'; +betweenRuns.variableList1=1000; +betweenRuns.variableList1=str2num(get(handles.edittargetFrequency,'string')); +betweenRuns.variableName2='targetDuration'; +betweenRuns.variableList2=0.016; +betweenRuns.randomizeSequence=1; % 'random sequence' + +% delay > masker > gap > target + + +stimulusParameters.targetType='tone'; +stimulusParameters.targetPhase='sin'; +stimulusParameters.targetFrequency=1000; +stimulusParameters.targetDuration=0.016; +stimulusParameters.targetLevel=stimulusParameters.WRVstartValues(1); + +stimulusParameters.rampDuration=0.004; + +experiment.stopCriteria2IFC=[75 3 5]; +experiment.singleIntervalMaxTrials=[20]; + + +% forced choice window interval +stimulusParameters.AFCsilenceDuration=0.5; + +% instructions to user +% single interval up/down no cue +stimulusParameters.instructions{1}= [{'YES if you hear the tone clearly'}, { }, { 'NO if not (or you are uncertain'}]; +% single interval up/down with cue +stimulusParameters.instructions{2}= [{'count the tones you hear clearly'}, { }, { 'ignore indistinct tones'}]; + diff -r 000000000000 -r f233164f4c86 multithreshold 1.46/paradigms/paradigm_absThreshold_8.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/multithreshold 1.46/paradigms/paradigm_absThreshold_8.m Fri May 27 13:19:21 2011 +0100 @@ -0,0 +1,32 @@ +function paradigm_absThreshold_8(handles) +global stimulusParameters experiment betweenRuns + +paradigm_training(handles) % default + +betweenRuns.variableName1='targetFrequency'; +betweenRuns.variableList1=1000; +betweenRuns.variableList1=str2num(get(handles.edittargetFrequency,'string')); +betweenRuns.variableName2='targetDuration'; +betweenRuns.variableList2=0.008 ; +betweenRuns.randomizeSequence=1; % 'random sequence' + +% delay > masker > gap > target + + +stimulusParameters.targetType='tone'; +stimulusParameters.targetPhase='sin'; +stimulusParameters.targetFrequency=1000; +stimulusParameters.targetDuration=0.008; +stimulusParameters.targetLevel=stimulusParameters.WRVstartValues(1); + +stimulusParameters.rampDuration=0.004; + +% forced choice window interval +stimulusParameters.AFCsilenceDuration=0.5; + +% instructions to user +% single interval up/down no cue +stimulusParameters.instructions{1}= [{'YES if you hear the tone clearly'}, { }, { 'NO if not (or you are uncertain'}]; +% single interval up/down with cue +stimulusParameters.instructions{2}= [{'count the tones you hear clearly'}, { }, { 'ignore indistinct tones'}]; + diff -r 000000000000 -r f233164f4c86 multithreshold 1.46/paradigms/paradigm_discomfort.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/multithreshold 1.46/paradigms/paradigm_discomfort.m Fri May 27 13:19:21 2011 +0100 @@ -0,0 +1,28 @@ +function paradigm_discomfort(handles) +global stimulusParameters experiment betweenRuns + +paradigm_training(handles) % default + +stimulusParameters.WRVname='targetLevel'; +stimulusParameters.WRVstartValues=75 ; +stimulusParameters.WRVsteps=[3 3]; +stimulusParameters.WRVlimits=[-30 110]; + +betweenRuns.variableName1='targetFrequency'; +betweenRuns.variableList1=[1000]; +betweenRuns.variableName2='targetDuration'; +betweenRuns.variableList2=0.5 ; +betweenRuns.randomizeSequence=2; % 'fixed sequence' + +stimulusParameters.stimulusDelay=0; + +stimulusParameters.targetType='tone'; +stimulusParameters.targetPhase='sin'; +stimulusParameters.targetFrequency=1000; +stimulusParameters.targetDuration=0.5; +stimulusParameters.targetLevel=stimulusParameters.WRVstartValues(1); + +stimulusParameters.instructions{1}= ['Is the tone ''comfortable'', ''loud'' or ''uncomfortable''?']; +% single interval up/down with cue +stimulusParameters.instructions{2}= []; + diff -r 000000000000 -r f233164f4c86 multithreshold 1.46/paradigms/paradigm_forwardMasking.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/multithreshold 1.46/paradigms/paradigm_forwardMasking.m Fri May 27 13:19:21 2011 +0100 @@ -0,0 +1,44 @@ +function paradigm_forwardMasking(handles) +global stimulusParameters experiment betweenRuns + +paradigm_training(handles) % default + +stimulusParameters.WRVname='targetLevel'; +stimulusParameters.WRVstartValues=50; +stimulusParameters.WRVsteps= [10 2]; +stimulusParameters.WRVlimits=[-30 110]; + +betweenRuns.variableName1='gapDuration'; +betweenRuns.variableList1=[.005 0.01 0.02 0.04]; +betweenRuns.variableName2='maskerLevel'; +betweenRuns.variableList2=[20 40 60 80]; +betweenRuns.randomizeSequence=1; % 'random sequence' + +stimulusParameters.maskerType='tone'; +stimulusParameters.maskerPhase='sin'; +stimulusParameters.maskerDuration=0.108; +stimulusParameters.maskerLevel=betweenRuns.variableList2; +stimulusParameters.maskerRelativeFrequency=1; + +stimulusParameters.gapDuration=betweenRuns.variableList1; + +stimulusParameters.targetType='tone'; +stimulusParameters.targetPhase='sin'; +stimulusParameters.targetFrequency=1000; +stimulusParameters.targetDuration=0.02; +stimulusParameters.targetLevel=-stimulusParameters.WRVstartValues(1); + +stimulusParameters.rampDuration=0.01; + +% instructions to user +% single interval up/down no cue +stimulusParameters.instructions{1}=[{'YES if you hear the added click'}, { }, { 'NO if not (or you are uncertain'}]; +% single interval up/down with cue +stimulusParameters.instructions{2}=[{'count how many distinct clicks you hear'},{'ignore the tones'},{' '},... + {'The clicks must be **clearly distinct** to count'}]; + +experiment.maxTrials=10; +% catchTrials +experiment.allowCatchTrials= 1; + + diff -r 000000000000 -r f233164f4c86 multithreshold 1.46/paradigms/paradigm_overShoot.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/multithreshold 1.46/paradigms/paradigm_overShoot.m Fri May 27 13:19:21 2011 +0100 @@ -0,0 +1,44 @@ +function paradigm_overShoot(handles) +global stimulusParameters betweenRuns + +paradigm_training(handles) % default + +stimulusParameters.WRVname='targetLevel'; +stimulusParameters.WRVstartValues=50; +stimulusParameters.WRVsteps= [10 2]; +stimulusParameters.WRVlimits=[-30 110]; + +betweenRuns.variableName1='gapDuration'; +betweenRuns.variableList1=[-.399 -.2]; +% betweenRuns.variableList1=[-.288 -.218 -.2 -.190 -.170 -.130 -.070 -.030 -.010 .005 .020 .080]; +% betweenRuns.variableList1=[-.350 -.238 -.213 -.180 -.160 -.100 -.040 -.020 0 .010 .040 .140]; +betweenRuns.variableName2='maskerLevel'; +betweenRuns.variableList2=50; +betweenRuns.randomizeSequence=1; % 'random sequence' + +% delay > masker > gap > target +stimulusParameters.stimulusDelay=0.3; + +stimulusParameters.maskerType='tone'; +stimulusParameters.maskerPhase='sin'; +stimulusParameters.maskerDuration=0.4; +stimulusParameters.maskerLevel=betweenRuns.variableList2; +stimulusParameters.maskerRelativeFrequency=1; + +stimulusParameters.gapDuration=betweenRuns.variableList1; + +stimulusParameters.targetType='tone'; +stimulusParameters.targetPhase='sin'; +stimulusParameters.targetFrequency=1000; +stimulusParameters.targetDuration=0.01; +stimulusParameters.targetLevel=-stimulusParameters.WRVstartValues(1); + +stimulusParameters.rampDuration=0.005; + +% instructions to user +% single interval up/down no cue +stimulusParameters.instructions{1}=[{'YES if you hear the added click'}, { }, { 'NO if not (or you are uncertain'}]; +% single interval up/down with cue +stimulusParameters.instructions{2}=[{'count how many distinct clicks you hear'},{'ignore the tones'},{' '},... + {'The clicks must be **clearly distinct** to count'}]; + diff -r 000000000000 -r f233164f4c86 multithreshold 1.46/paradigms/paradigm_psychometric.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/multithreshold 1.46/paradigms/paradigm_psychometric.m Fri May 27 13:19:21 2011 +0100 @@ -0,0 +1,32 @@ +function paradigm_psychometric(handles) +global stimulusParameters experiment betweenRuns + +paradigm_training(handles) % default + +experiment.printTracks=1; +experiment.maxTrials=30; + +stimulusParameters.WRVname='targetLevel'; +stimulusParameters.WRVstartValues=30 ; +stimulusParameters.WRVsteps=[10 2]; +stimulusParameters.WRVlimits=[-30 110]; + +betweenRuns.variableName1='targetFrequency'; +betweenRuns.variableList1=1000.01:0.01:1000.05; +betweenRuns.variableName2='targetDuration'; +betweenRuns.variableList2=0.1 ; +betweenRuns.randomizeSequence=1; % 'random sequence' + +stimulusParameters.targetType='tone'; +stimulusParameters.targetPhase='sin'; +stimulusParameters.targetFrequency=1000; +stimulusParameters.targetDuration=0.1; +stimulusParameters.targetLevel=stimulusParameters.WRVstartValues(1); + +% instructions to user +% single interval up/down no cue +stimulusParameters.instructions{1}= [{'YES if you hear the tone clearly'}, { }, { 'NO if not (or you are uncertain'}]; +% single interval up/down with cue +stimulusParameters.instructions{2}= [{'count the tones you hear clearly'}, { }, { 'ignore indistinct tones'}]; + + diff -r 000000000000 -r f233164f4c86 multithreshold 1.46/paradigms/paradigm_threshold_duration.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/multithreshold 1.46/paradigms/paradigm_threshold_duration.m Fri May 27 13:19:21 2011 +0100 @@ -0,0 +1,33 @@ +function paradigm_threshold_duration(handles) +global stimulusParameters experiment betweenRuns + +paradigm_training(handles) % default + +stimulusParameters.WRVname='targetLevel'; +stimulusParameters.WRVstartValues=40; +stimulusParameters.WRVsteps=[10 2]; +stimulusParameters.WRVlimits=[-30 110]; + +betweenRuns.variableName1='targetDuration'; +betweenRuns.variableList1=[ .016 .032 .064 .128 .256 .512]; +betweenRuns.variableName2='targetFrequency'; +betweenRuns.variableList2=1000; +betweenRuns.randomizeSequence=1; % 'random sequence' + +stimulusParameters.targetType='tone'; +stimulusParameters.targetPhase='sin'; +% retain current target frequency +x=str2num(get(handles.edittargetFrequency,'string')); +stimulusParameters.targetFrequency=x(1); +stimulusParameters.targetDuration=betweenRuns.variableList2; +stimulusParameters.targetLevel=stimulusParameters.WRVstartValues(1); + +stimulusParameters.rampDuration=0.004; + +% instructions to user +% single interval up/down no cue +stimulusParameters.instructions{1}=[{'YES if you hear the added click'}, { }, { 'NO if not (or you are uncertain'}]; +% single interval up/down with cue +stimulusParameters.instructions{2}=[{'count how many distinct clicks you hear'},{'ignore the tones'},{' '},... + {'The clicks must be **clearly distinct** to count'}]; + diff -r 000000000000 -r f233164f4c86 multithreshold 1.46/paradigms/paradigm_training.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/multithreshold 1.46/paradigms/paradigm_training.m Fri May 27 13:19:21 2011 +0100 @@ -0,0 +1,72 @@ +function paradigm_training(handles) +global stimulusParameters experiment betweenRuns + +stimulusParameters.subjectSampleRate=44100; % compatible with file input +stimulusParameters.subjectSampleRate=50000; % compatible with file input + +% assessment method +% {'oneIntervalUpDown', 'MaxLikelihood', '2I2AFC++', '2I2AFC+++'} +experiment.threshEstMethod='oneIntervalUpDown'; +% {'cued', 'noCue'}; +stimulusParameters.includeCue=1; +stimulusParameters.cueTestDifference=10; + +experiment.singleIntervalMaxTrials=10; +experiment.maxTrials=10; +experiment.allowCatchTrials= 1; + +% {'tone','noise', 'pinkNoise','whiteNoise','OHIO'} +stimulusParameters.WRVname='targetLevel'; +stimulusParameters.WRVstartValues=20 ; +stimulusParameters.WRVsteps=[10 2]; +stimulusParameters.WRVlimits=[-30 110]; + +% target variable: slope=1, start going down. +experiment.psyFunSlope=1; +withinRuns.direction='down'; + +betweenRuns.variableName1='targetFrequency'; +betweenRuns.variableList1=1000; +betweenRuns.variableName2='targetDuration'; +betweenRuns.variableList2=0.1 ; +% 1='fixed sequence', 2='randomize within blocks', 3='randomize across +% blocks' +betweenRuns.randomizeSequence=1; % 'random sequence' + +% delay > masker > gap > target + +stimulusParameters.stimulusDelay=0.3; + +% maskerTypes={'tone','noise', 'pinkNoise','TEN','whiteNoise'}; +stimulusParameters.maskerType='tone'; +stimulusParameters.maskerPhase='sin'; +stimulusParameters.maskerDuration=0.0; +stimulusParameters.maskerLevel= -50; +stimulusParameters.maskerRelativeFrequency= 1 ; % not used + +stimulusParameters.gapDuration=0.0; + +% targetTypes={'tone','noise', 'pinkNoise','whiteNoise','OHIO'}; +stimulusParameters.targetType='tone'; +stimulusParameters.targetPhase='sin'; +stimulusParameters.targetFrequency=1000; +stimulusParameters.targetDuration=0.1; +stimulusParameters.targetLevel=stimulusParameters.WRVstartValues(1); + +stimulusParameters.rampDuration=0.004; + +% forced choice window interval +stimulusParameters.AFCsilenceDuration=0.5; + +% {'none','noise', 'pinkNoise', 'TEN','noiseDich', 'pinkNoiseDich','whiteNoise'} +stimulusParameters.backgroundType='none'; +stimulusParameters.backgroundLevel=-100; + +% instructions to user +% single interval up/down no cue +stimulusParameters.instructions{1}= [{'YES if you hear the tone clearly'}, { }, { 'NO if not (or you are uncertain'}]; +% single interval up/down with cue +stimulusParameters.instructions{2}= [{'count the tones you hear clearly'}, { }, { 'ignore indistinct tones'}]; + +stimulusParameters.numOHIOtones=1; + diff -r 000000000000 -r f233164f4c86 multithreshold 1.46/paradigms/paradigm_trainingIFMC.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/multithreshold 1.46/paradigms/paradigm_trainingIFMC.m Fri May 27 13:19:21 2011 +0100 @@ -0,0 +1,43 @@ +function paradigm_trainingIFMC(handles) +global stimulusParameters experiment betweenRuns + +paradigm_training(handles) % default + +stimulusParameters.WRVname='maskerLevel'; +stimulusParameters.WRVstartValues=-10; +stimulusParameters.WRVsteps= [-10 -2]; +stimulusParameters.WRVlimits=[-30 110]; + +stimulusParameters.cueTestDifference = 10; +experiment.psyFunSlope = -1; +withinRuns.direction='up'; + +betweenRuns.variableName1='maskerRelativeFrequency'; +betweenRuns.variableList1=[ 0.5 .9 .7 1.3 ]; +betweenRuns.variableName2='targetFrequency'; +% keep old list of target frequencies +betweenRuns.variableList2=str2num(get(handles.edittargetFrequency,'string')); +betweenRuns.randomizeSequence=1; % 'random sequence' + +stimulusParameters.maskerType='tone'; +stimulusParameters.maskerPhase='sin'; +stimulusParameters.maskerDuration=0.108; +stimulusParameters.maskerLevel=stimulusParameters.WRVstartValues(1); +stimulusParameters.maskerRelativeFrequency=betweenRuns.variableList1; + +stimulusParameters.gapDuration=0.03; + +stimulusParameters.targetType='tone'; +stimulusParameters.targetPhase='sin'; +stimulusParameters.targetFrequency=betweenRuns.variableList2(1); +stimulusParameters.targetDuration=0.016; +stimulusParameters.targetLevel= 30; + +stimulusParameters.rampDuration=0.004; + +% instructions to user +% single interval up/down no cue +stimulusParameters.instructions{1}=[{'YES if you hear the added click'}, { }, { 'NO if not (or you are uncertain'}]; +% single interval up/down with cue +stimulusParameters.instructions{2}=[{'count how many distinct clicks you hear'},{'ignore the tones'},{' '},... + {'The clicks must be **clearly distinct** to count'}]; diff -r 000000000000 -r f233164f4c86 multithreshold 1.46/paradigms/reserve team/OHIOthresholds.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/multithreshold 1.46/paradigms/reserve team/OHIOthresholds.m Fri May 27 13:19:21 2011 +0100 @@ -0,0 +1,7 @@ +function experiment=OHIOthresholds(experiment) + +experiment.OHIOfrequencies=[494, 663, 870, 1125, 1442, 1838, 2338, 2957, 3725, 4680, 5866, 7334]; %Hz. +% User must specify abs thresholds (dB SPL) of each tone frequency +experiment.OHIOthresholds= [ + 9.1 8.6 8.1 7.9 9.8 10.5 13.5 15.0 17.4 19.4 22.6 25.2 +]; \ No newline at end of file diff -r 000000000000 -r f233164f4c86 multithreshold 1.46/paradigms/reserve team/paradigm_OHIOabs.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/multithreshold 1.46/paradigms/reserve team/paradigm_OHIOabs.m Fri May 27 13:19:21 2011 +0100 @@ -0,0 +1,47 @@ +function paradigm_OHIOabs(handles) +global stimulusParameters experiment betweenRuns + +paradigm_training(handles) % default + +% find the threshold for a tonecomplex consisting of a sequence of 10-ms tones +% whose frequencies are chosen at random from a list (OHIOfrequencies) +% All tones are presented at the same level (SL) computed using absolute +% threshols specified in OHIOthresholds; +% The duration of the complex is increased across runs and the number of tones is +% controlled by OHIOdurations, (for each 20 ms a further tone is added. +% The frequency of the tones is changed on each trial + +experiment.OHIOfrequencies=[494, 663, 870, 1125, 1442, 1838, 2338, 2957, 3725, 4680, 5866, 7334]; %Hz. +% User must specify abs thresholds (dB SPL) of each tone frequency +% experiment.OHIOthresholds= [18 16 16 19 20 22 24 26 27 30 32 35]; + +% assessment method +% {'oneIntervalUpDown', 'MaxLikelihood', '2I2AFC++', '2I2AFC+++'} +experiment.threshEstMethod='oneIntervalUpDown'; +% {'cued', 'noCue'}; + +stimulusParameters.WRVname='targetLevel'; +stimulusParameters.WRVstartValues=20 ; +stimulusParameters.WRVsteps=[10 2]; +stimulusParameters.WRVlimits=[-30 110]; + +betweenRuns.variableName1='numOHIOtones'; +betweenRuns.variableList1= 1:12; % i.e. the frequency to be used +betweenRuns.variableName2='stimulusDelay'; +betweenRuns.variableList2=0.05; +betweenRuns.randomizeSequence=2; % not random sequence + +stimulusParameters.targetType='OHIO'; +stimulusParameters.targetPhase='sin'; +stimulusParameters.targetFrequency=experiment.OHIOfrequencies; +stimulusParameters.targetDuration=0.01; % overruled by OHIO program +stimulusParameters.targetLevel=stimulusParameters.WRVstartValues(1); + +stimulusParameters.rampDuration=0.005; + +% instructions to user +% single interval up/down no cue +stimulusParameters.instructions{1}= [{'YES if you hear the tone clearly'}, { }, { 'NO if not (or you are uncertain'}]; +% single interval up/down with cue +stimulusParameters.instructions{2}= [{'count the tones you hear clearly'}, { }, { 'ignore indistinct tones'}]; + diff -r 000000000000 -r f233164f4c86 multithreshold 1.46/paradigms/reserve team/paradigm_OHIOrand.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/multithreshold 1.46/paradigms/reserve team/paradigm_OHIOrand.m Fri May 27 13:19:21 2011 +0100 @@ -0,0 +1,41 @@ +function paradigm_OHIOrand(handles) +global stimulusParameters experiment betweenRuns + +paradigm_training(handles) % default + +% find the threshold for a tonecomplex consisting of a sequence of 10-ms tones +% whose frequencies are chosen at random from a list (OHIOfrequencies) +% All tones are presented at the same level (SL) computed using absolute +% threshols specified in OHIOthresholds; +% The duration of the complex is increased across runs and the number of tones is +% controlled by OHIOdurations, (for each 20 ms a further tone is added. +% The frequency of the tones is changed on each trial + +% fetch thresholds and frequencies +experiment=OHIOthresholds(experiment); + +stimulusParameters.WRVname='targetLevel'; +stimulusParameters.WRVstartValues=0 ; +stimulusParameters.WRVsteps=[10 2]; +stimulusParameters.WRVlimits=[-30 110]; + +betweenRuns.variableName1='numOHIOtones'; +betweenRuns.variableList1= [1 2 4 8 12]; +betweenRuns.variableName2='stimulusDelay'; +betweenRuns.variableList2=0.1; +betweenRuns.randomizeSequence=2; % not random sequence + +stimulusParameters.targetType='OHIO'; +stimulusParameters.targetPhase='sin'; +stimulusParameters.targetFrequency=experiment.OHIOfrequencies; +stimulusParameters.targetDuration=betweenRuns.variableList2; +stimulusParameters.targetLevel=stimulusParameters.WRVstartValues(1); + +stimulusParameters.rampDuration=0.005; + +% instructions to user +% single interval up/down no cue +stimulusParameters.instructions{1}= [{'YES if you hear the tone clearly'}, { }, { 'NO if not (or you are uncertain'}]; +% single interval up/down with cue +stimulusParameters.instructions{2}= [{'count the tones you hear clearly'}, { }, { 'ignore indistinct tones'}]; + diff -r 000000000000 -r f233164f4c86 multithreshold 1.46/paradigms/reserve team/paradigm_OHIOspect.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/multithreshold 1.46/paradigms/reserve team/paradigm_OHIOspect.m Fri May 27 13:19:21 2011 +0100 @@ -0,0 +1,41 @@ +function paradigm_OHIOspect(handles) +global stimulusParameters experiment betweenRuns + +paradigm_training(handles) % default + +% find the threshold for a tonecomplex consisting of a sequence of 10-ms tones +% whose frequencies are chosen at random from a list (OHIOfrequencies) +% All tones are presented at the same level (SL) computed using absolute +% threshols specified in OHIOthresholds; +% The duration of the complex is increased across runs and the number of tones is +% controlled by OHIOdurations, (for each 20 ms a further tone is added. +% The frequency of the tones is changed on each trial + +% fetch thresholds and frequencies +experiment=OHIOthresholds(experiment); + +stimulusParameters.WRVname='targetLevel'; +stimulusParameters.WRVstartValues=0 ; +stimulusParameters.WRVsteps=[10 2]; +stimulusParameters.WRVlimits=[-30 110]; + +betweenRuns.variableName1='numOHIOtones'; +betweenRuns.variableList1= [1 2 4 8 12]; +betweenRuns.variableName2='stimulusDelay'; +betweenRuns.variableList2=0.1; +betweenRuns.randomizeSequence=2; % not random sequence + +stimulusParameters.targetType='OHIO'; +stimulusParameters.targetPhase='sin'; +stimulusParameters.targetFrequency=experiment.OHIOfrequencies; +stimulusParameters.targetDuration=betweenRuns.variableList2; +stimulusParameters.targetLevel=stimulusParameters.WRVstartValues(1); + +stimulusParameters.rampDuration=0.005; + +% instructions to user +% single interval up/down no cue +stimulusParameters.instructions{1}= [{'YES if you hear the tone clearly'}, { }, { 'NO if not (or you are uncertain'}]; +% single interval up/down with cue +stimulusParameters.instructions{2}= [{'count the tones you hear clearly'}, { }, { 'ignore indistinct tones'}]; + diff -r 000000000000 -r f233164f4c86 multithreshold 1.46/paradigms/reserve team/paradigm_OHIOspectemp.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/multithreshold 1.46/paradigms/reserve team/paradigm_OHIOspectemp.m Fri May 27 13:19:21 2011 +0100 @@ -0,0 +1,40 @@ +function paradigm_OHIOspectemp(handles) +global stimulusParameters experiment betweenRuns + +paradigm_training(handles) % default + +% find the threshold for a tonecomplex consisting of a sequence of 10-ms tones +% whose frequencies are chosen at random from a list (OHIOfrequencies) +% All tones are presented at the same level (SL) computed using absolute +% threshols specified in OHIOthresholds; +% The duration of the complex is increased across runs and the number of tones is +% controlled by OHIOdurations, (for each 20 ms a further tone is added. +% The frequency of the tones is changed on each trial + +% fetch thresholds and frequencies +experiment=OHIOthresholds(experiment); + +stimulusParameters.WRVname='targetLevel'; +stimulusParameters.WRVstartValues=0 ; +stimulusParameters.WRVsteps=[10 2]; +stimulusParameters.WRVlimits=[-30 110]; + +betweenRuns.variableName1='numOHIOtones'; +betweenRuns.variableList1= [1 2 4 8 12]; +betweenRuns.variableName2='stimulusDelay'; +betweenRuns.variableList2=0.1; +betweenRuns.randomizeSequence=2; % not random sequence + +stimulusParameters.targetType='OHIO'; +stimulusParameters.targetPhase='sin'; +stimulusParameters.targetFrequency=experiment.OHIOfrequencies; +stimulusParameters.targetDuration=betweenRuns.variableList2; +stimulusParameters.targetLevel=stimulusParameters.WRVstartValues(1); + +stimulusParameters.rampDuration=0.005; + +% instructions to user +% single interval up/down no cue +stimulusParameters.instructions{1}= [{'YES if you hear the tone clearly'}, { }, { 'NO if not (or you are uncertain'}]; +% single interval up/down with cue +stimulusParameters.instructions{2}= [{'count the tones you hear clearly'}, { }, { 'ignore indistinct tones'}]; diff -r 000000000000 -r f233164f4c86 multithreshold 1.46/paradigms/reserve team/paradigm_OHIOtemp.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/multithreshold 1.46/paradigms/reserve team/paradigm_OHIOtemp.m Fri May 27 13:19:21 2011 +0100 @@ -0,0 +1,44 @@ +function paradigm_OHIOtemp(handles) +global stimulusParameters experiment betweenRuns + +paradigm_training(handles) % default + +% find the threshold for a tonecomplex consisting of a sequence of 10-ms tones +% whose frequencies are chosen at random from a list (OHIOfrequencies) +% All tones are presented at the same level (SL) computed using absolute +% threshols specified in OHIOthresholds; +% The duration of the complex is increased across runs and the number of tones is +% controlled by OHIOdurations, (for each 20 ms a further tone is added. +% The frequency of the tones is changed on each trial + +% fetch thresholds and frequencies +experiment=OHIOthresholds(experiment); + +stimulusParameters.WRVname='targetLevel'; +stimulusParameters.WRVstartValues=0 ; +stimulusParameters.WRVsteps=[10 2]; +stimulusParameters.WRVlimits=[-30 110]; +% target variable: slope=1, start going down. +stimulusParameters.cueTestDifference=10; +experiment.psyFunSlope= 1; +withinRuns.direction='down'; + +betweenRuns.variableName1='numOHIOtones'; +betweenRuns.variableList1= [1 2 4 8 12]; +betweenRuns.variableName2='stimulusDelay'; +betweenRuns.variableList2=0.1; +betweenRuns.randomizeSequence=2; % not random sequence + +stimulusParameters.targetType='OHIO'; +stimulusParameters.targetPhase='sin'; +stimulusParameters.targetFrequency=experiment.OHIOfrequencies; +stimulusParameters.targetDuration=betweenRuns.variableList2; +stimulusParameters.targetLevel=stimulusParameters.WRVstartValues(1); + +stimulusParameters.rampDuration=0.005; + +% instructions to user +% single interval up/down no cue +stimulusParameters.instructions{1}= [{'YES if you hear the tone clearly'}, { }, { 'NO if not (or you are uncertain'}]; +% single interval up/down with cue +stimulusParameters.instructions{2}= [{'count the tones you hear clearly'}, { }, { 'ignore indistinct tones'}]; diff -r 000000000000 -r f233164f4c86 multithreshold 1.46/paradigms/stimulus.wav Binary file multithreshold 1.46/paradigms/stimulus.wav has changed diff -r 000000000000 -r f233164f4c86 multithreshold 1.46/printReport.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/multithreshold 1.46/printReport.m Fri May 27 13:19:21 2011 +0100 @@ -0,0 +1,319 @@ +function printReport(fileName, printTracks) + +% End of run report (no args) +% *or* +% reprint previous report from file + +global experiment stimulusParameters betweenRuns withinRuns statsModel audio +global LevittControl expGUIhandles + + +global inputStimulusParams OMEParams DRNLParams +global IHC_VResp_VivoParams IHCpreSynapseParams AN_IHCsynapseParams +global MacGregorParams MacGregorMultiParams filteredSACFParams +global experiment % used by calls from multiThreshold only +global IHC_cilia_RPParams + + +printReportGuide.structures=1; +printReportGuide.showPsychometric=0; +printReportGuide.HorizontalTracks=1; + +if nargin==0 + % print new report + printReportGuide.showTracks=experiment.printTracks; + printReportGuide.fileName=[]; + if experiment.saveData + saveFileName=['savedData/' experiment.name '_' experiment.date '_' experiment.paradigm]; + else + % overwrite existing file just in case + saveFileName=['savedData/mostRecentResults']; + end + experiment.minElapsed=etime(clock, betweenRuns.timeNow)/60; + save(saveFileName, 'experiment', 'stimulusParameters', 'betweenRuns', 'withinRuns', 'statsModel', 'expGUIhandles') + disp(['data saved as: ' saveFileName]); + +else + % reprint request + printReportGuide.fileName=fileName; + load(printReportGuide.fileName) + saveFileName=printReportGuide.fileName; + if nargin>1 + printReportGuide.showTracks=printTracks; + else + printReportGuide.showTracks=experiment.printTracks; + end +end + +fprintf('******** multithreshold ') +x=pwd; disp(['version ' x(end-3:end)]) +fprintf('\nName:\t%s ', experiment.name) +fprintf('\nparadigm:\t%s ', experiment.paradigm) +fprintf('\nEar:\t%s ', experiment.ear) +method=experiment.threshEstMethod; +if stimulusParameters.includeCue && ~strcmp(method(1:6),'2I2AFC') + method=[method '/ withCue']; +end +fprintf('\nmethod:\t%s ', method) +fprintf('\ndate:\t%s ', experiment.date) + +fprintf('\n\n') + +if isempty(betweenRuns.thresholds) + disp('no thresholds found') +end + +% prepare results as matrices ready to print +[idx1, idx2, var1values, var2values]=... + sortVariables(betweenRuns.variableList1, betweenRuns.variableList2, betweenRuns.var1Sequence, betweenRuns.var2Sequence); + +% if strcmp(betweenRuns.variableName2, 'none') +% betweenRuns.variableName2=' '; +% end +header1=betweenRuns.variableName1; +header2=betweenRuns.variableName2; +header1 = strrep(header1, 'none', ' '); % none is not a useful header +header2 = strrep(header2, 'none', ' '); % none is not a useful header +headers=strvcat([header1 '/'], header2); + +disp('thresholds') +msg=printTabTable(sortTablesForPrinting(idx1,idx2,var1values,var2values, betweenRuns.thresholds), headers); +addToMsg(msg,0) +fprintf('\n') + +% sort tracks into the same order +betweenRuns.levelTracks=betweenRuns.levelTracks(idx1); +betweenRuns.responseTracks=betweenRuns.responseTracks(idx1); +betweenRuns.bestThresholdTracks=betweenRuns.bestThresholdTracks(idx1); + +betweenRuns.levelTracks=betweenRuns.levelTracks(idx2); +betweenRuns.responseTracks=betweenRuns.responseTracks(idx2); +betweenRuns.bestThresholdTracks=betweenRuns.bestThresholdTracks(idx2); + +if printReportGuide.structures + maxNoArrayValues=30; + showStructureSummary(stimulusParameters, 'stimulusParameters', maxNoArrayValues) + showStructureSummary(experiment, 'experiment',maxNoArrayValues) + showStructureSummary(betweenRuns, 'betweenRuns',maxNoArrayValues) + showStructureSummary(withinRuns, 'withinRuns') + + switch experiment.threshEstMethod + case {'2I2AFC++', '2I2AFC+++'} + showStructureSummary(LevittControl, 'LevittControl', maxNoArrayValues) + end + + switch experiment.ear + case {'statsModelLogistic','statsModelRareEvent'} + showStructureSummary(statsModel, 'statsModel', maxNoArrayValues) + end +end + +if printReportGuide.showTracks + % NB this procedure can only be used if all the tracks are present and + % of equal length + bigTable=[]; header=[]; + disp(' '); disp('Leveltracks starting from 1 response before the first reversal') + for i=1:length(betweenRuns.levelTracks) + if printReportGuide.HorizontalTracks + printTabTable(betweenRuns.levelTracks{i}); + end + header=strvcat(header, 'level'); + end + + disp(' '); disp('Response tracks starting from 1 response before the first reversal') + for i=1:length(betweenRuns.responseTracks) + if printReportGuide.HorizontalTracks + printTabTable(betweenRuns.responseTracks{i}); + end + header=strvcat(header, 'resp'); + end + + disp(' '); disp('threshold tracks starting from the first reversal') + for i=1:length(betweenRuns.bestThresholdTracks) + if printReportGuide.HorizontalTracks + end + printTabTable(betweenRuns.bestThresholdTracks{i}); + header=strvcat(header, 'mean'); + end + + disp(' '); disp('threshold (mean) tracks starting from the first reversal') + for i=1:length(betweenRuns.bestThresholdTracks) + if printReportGuide.HorizontalTracks + end + printTabTable(betweenRuns.bestThresholdMeanTracks{i}); + header=strvcat(header, 'mean'); + end + disp(' '); disp('threshold tracks (median) starting from the first reversal') + for i=1:length(betweenRuns.bestThresholdMedianTracks) + if printReportGuide.HorizontalTracks + end + printTabTable(betweenRuns.bestThresholdTracks{i}); + header=strvcat(header, 'mean'); + end + +end + +switch experiment.ear + case {'MAPmodelMultiCh', 'MAPmodelSingleCh'} + % show all parameters but do not compute the model + nm=UTIL_paramsList(whos); + for i=1:length(nm) + try + eval(['UTIL_showStruct(' nm{i} ', ''' nm{i} ''')']) + catch + end + end +end + +if experiment.saveData + fprintf('\n') + disp('To reprint this report with tracks use:') + disp([ 'printReport(''' saveFileName ''',1)']) +end + +% print final summary (repeat of above) +fprintf('\n') +fprintf('\n') +disp('thresholds') +msg=printTabTable(sortTablesForPrinting(idx1,idx2,var1values,var2values, betweenRuns.thresholds), headers); +addToMsg(msg,0) +fprintf('\n') + +if length(var1values)==1 && length(var2values)==1 && experiment.maxTrials>49 + [psy, levelsBinVector, binFrequencies, nNo, nYes]= ... + psychometricFunction(withinRuns.levelsPhaseTwo,withinRuns.responsesPhaseTwo, experiment.psyBinWidth); + disp('Psychometric function') + fprintf(' level \tfreq\tprob\n') + fprintf('%6.0f\t%6.2f\t%6.0f\n', [levelsBinVector; binFrequencies; psy]) + fprintf('\n') + fprintf('k \t %6.2f\n',logistic.bestK) + fprintf('g \t%7.5f\n',rareEvent.bestGain) + fprintf('\n') + +end +% resultsSoFar=[betweenRuns.var1Sequence(betweenRuns.runNumber)'... +% betweenRuns.var2Sequence(betweenRuns.runNumber)'... +% betweenRuns.thresholds(betweenRuns.runNumber)' ]; +% fprintf('%10.3f \t%10.3f \t%10.1f \n', resultsSoFar') + +% ------------------------------------------------------- sortTablesForPrinting +function table= sortTablesForPrinting(idx1,idx2, var1values,var2values, x) +% table converts a vector to a table +% after sorting according to idx1 and idx2 +% the table is completed by adding row and column values +x=x(idx1); +x=x(idx2); +xMatrix=reshape(x,length(var1values),length(var2values)); + +table=[[-1000 var2values]; [var1values' xMatrix]]; + +% ------------------------------------------------------- showStructureSummary +function showStructureSummary(structure, name, maxNoArrayValues) +% showStructureSummary prints out the values of a single structure +% The header is the structure name and each row is a field +% e.g. showStructureSummary(params,'params') +% This not the same as 'UTIL_showstruct' + + +if nargin<3 + maxNoArrayValues=20; +end + +fprintf('\n%s:', name) + +fields=fieldnames(eval('structure')); +% for each field in the structure +for i=1:length(fields) + y=eval([ 'structure.' fields{i}]); + if isstr(y), + % strings + fprintf('\n%s=\t''%s''', fields{i},y) + elseif isnumeric(y) + % arrays + if length(y)>1 + % vectors + [r c]=size(y); + if r>c, y=y'; end + + [r c]=size(y); + if r>1 + % fprintf('\n%s.%s=\t%g x %g matrix',name, fields{i}, r, c) + fprintf('\n%s=\t%g x %g matrix',fields{i}, r, c) + + elseif c1 + [r c]=size(headers); + for no=1:r + % print all headers in a row + fprintf('%s\t',headers(no,:)) + strings{stringCount}=sprintf('%s\t',headers(no,:)); stringCount=stringCount+1; + end + fprintf('\n') +end + +[r c]=size(M); + +for row=1:r + string=[]; + for col=1:c + if row==1 & col==1 & M(1,1)==-1000 + % Print nothing (tab follows below) + else + fprintf('%s',num2str(M(row,col))) + string=[string ' ' sprintf('%s',num2str(M(row,col)))]; + end + if col0); + predictions(idx)= 1-exp(-duration*(gP_Vmin(idx))); + predictions(~idx)=0; + + error=(predictions - responses).^2; + error=mean(error(~isnan(error))); + if error1 & bestVminCount0); % isolate 'yes' +y=levels(idx1); +nYes=hist(y, levelsBinVector); + +if sum(nNo)==0 | sum(nYes)==0 + psy=[]; levelsBinVector=[]; + return % yesses and nos required for a function +end + +binFrequencies=nNo+nYes; + +warning off MATLAB:divideByZero +psy=nYes./binFrequencies; % psy is the proportion of 'yes' responses +warning on MATLAB:divideByZero +lastwarn(''); + +idx=~isnan(psy); %remove empty bins +idx=(nYes>0) |(nNo>0); %remove empty bins +psy=psy(idx); +levelsBinVector=levelsBinVector(idx); +binFrequencies=binFrequencies(idx); +nNo=nNo(idx); +nYes=nYes(idx); + +% [nNo' nYes'] +% [levelsBinVector' psy'] +% plot(levelsBinVector,psy,['o']) \ No newline at end of file diff -r 000000000000 -r f233164f4c86 multithreshold 1.46/savedData/mostRecentResults.mat Binary file multithreshold 1.46/savedData/mostRecentResults.mat has changed diff -r 000000000000 -r f233164f4c86 multithreshold 1.46/speech.wav Binary file multithreshold 1.46/speech.wav has changed diff -r 000000000000 -r f233164f4c86 multithreshold 1.46/stimulus.wav Binary file multithreshold 1.46/stimulus.wav has changed diff -r 000000000000 -r f233164f4c86 multithreshold 1.46/subjGUI_MT.fig Binary file multithreshold 1.46/subjGUI_MT.fig has changed diff -r 000000000000 -r f233164f4c86 multithreshold 1.46/subjGUI_MT.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/multithreshold 1.46/subjGUI_MT.m Fri May 27 13:19:21 2011 +0100 @@ -0,0 +1,1741 @@ +function varargout = subjGUI_MT(varargin) + +% Begin initialization code - DO NOT EDIT +gui_Singleton = 1; +gui_State = struct('gui_Name', mfilename, ... + 'gui_Singleton', gui_Singleton, ... + 'gui_OpeningFcn', @subjGUI_MT_OpeningFcn, ... + 'gui_OutputFcn', @subjGUI_MT_OutputFcn, ... + 'gui_LayoutFcn', [] , ... + 'gui_Callback', []); +if nargin && isstr(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 subjGUI_MT is made visible. +function subjGUI_MT_OpeningFcn(hObject, eventdata, handles, varargin) + +% Choose default command line output for subjGUI_MT +handles.output = hObject; +initializeGUI(handles) +guidata(hObject, handles); + +function varargout = subjGUI_MT_OutputFcn(hObject, eventdata, handles) +% Get default command line output from handles structure +varargout{1} = handles.output; + +% -----------------------------------------------------initializeGUI +function initializeGUI(handles) +global experiment +global subjectGUIHandles expGUIhandles + addpath (['..' filesep 'MAP'], ['..' filesep 'utilities'], ... + ['..' filesep 'parameterStore'], ['..' filesep 'wavFileStore'],... + ['..' filesep 'testPrograms']) + +dbstop if error + +% subjectGUI size and location % [left bottom width height] +scrnsize=get(0,'screensize'); +set(0, 'units','pixels') +switch experiment.ear + % use default size unless... + case {'MAPmodel', 'MAPmodelMultich', 'MAPmodelSingleCh', ... + 'statsModelLogistic','statsModelRareEvent'} + % subjectGUI not needed for modelling so minimize subject GUI + set(gcf, 'units','pixels') + y=[0*scrnsize(3) 0.8*scrnsize(4) 0.1*scrnsize(3) 0.2*scrnsize(4)]; + set(gcf,'position',y, 'color',[.871 .961 .996]) + + + + case 'MAPmodelListen', + % subjectGUI is needed for display purposes. Make it large + set(gcf, 'units','pixels') + y=[.665*scrnsize(3) 0.02*scrnsize(4) ... + 0.33*scrnsize(3) 0.5*scrnsize(4)]; % alongside + set(gcf,'position',y, 'color',[.871 .961 .996]) +end + +switch experiment.ear + case{'left', 'right','diotic', 'dichoticLeft','dichoticRight'} + % Look to see if the button box exists and, if so, initialise it + buttonBoxIntitialize % harmless if no button box attached +end + +% function varargout = subjGUI_MT(varargin) +% +% % Begin initialization code - DO NOT EDIT +% gui_Singleton = 1; +% gui_State = struct('gui_Name', mfilename, ... +% 'gui_Singleton', gui_Singleton, ... +% 'gui_OpeningFcn', @subjGUI_MT_OpeningFcn, ... +% 'gui_OutputFcn', @subjGUI_MT_OutputFcn, ... +% 'gui_LayoutFcn', [] , ... +% 'gui_Callback', []); +% if nargin && isstr(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 subjGUI_MT is made visible. +% function subjGUI_MT_OpeningFcn(hObject, eventdata, handles, varargin) +% +% % Choose default command line output for subjGUI_MT +% handles.output = hObject; +% initializeGUI(handles) +% guidata(hObject, handles); +% +% function varargout = subjGUI_MT_OutputFcn(hObject, eventdata, handles) +% % Get default command line output from handles structure +% varargout{1} = handles.output; +% +% % -----------------------------------------------------initializeGUI +% function initializeGUI(handles) +% global experiment +% global subjectGUIHandles expGUIhandles +% +% dbstop if error +% +% % subjectGUI size and location % [left bottom width height] +% scrnsize=get(0,'screensize'); +% set(0, 'units','pixels') +% switch experiment.ear +% % use default size unless... +% case {'MAPmodel', 'MAPmodelMultiCh','MAPmodelSingleCh', ... +% 'statsModelLogistic','statsModelRareEvent'} +% % subjectGUI not needed for modelling so minimize subject GUI +% set(gcf, 'units','pixels') +% y=[0*scrnsize(3) 0.8*scrnsize(4) 0.1*scrnsize(3) 0.2*scrnsize(4)]; +% set(gcf,'position',y, 'color',[.871 .961 .996]) +% +% case 'MAPmodelListen', +% % subjectGUI is needed for display purposes. Make it large +% set(gcf, 'units','pixels') +% y=[.665*scrnsize(3) 0.02*scrnsize(4) ... +% 0.33*scrnsize(3) 0.5*scrnsize(4)]; % alongside +% set(gcf,'position',y, 'color',[.871 .961 .996]) +% end +% +% switch experiment.ear +% case{'left', 'right','diotic', 'dichoticLeft','dichoticRight'} +% % Look to see if the button box exists and, if so, initialise it +% buttonBoxIntitialize % harmless if no button box attached +% end + +% clear display of previous mean values. This is a new measurement series +axes(expGUIhandles.axes4), cla +reset (expGUIhandles.axes4) + +% handles needed in non-callback routines below +subjectGUIHandles=handles; + +% start immediately +startNewExperiment(handles, expGUIhandles) +% This is the end of the experiment. Exit here and return to ExpGUI. + +% ----------------------------------------------------- startNewExperiment +function startNewExperiment(handles, expGUIhandles) +% An experiment consists of a series of 'runs'. +% Resets all relevant variables at the beginning of a new experiment. +global experiment stimulusParameters betweenRuns + +% 'start new experiment' button is the only valid action now +experiment.status='waitingForStart'; + +switch experiment.threshEstMethod + % add appropriate labels to subject GUI buttons + case {'2I2AFC++', '2I2AFC+++'} + set(handles.pushbutton3,'string','') + set(handles.pushbutton2,'string','2') + set(handles.pushbutton1,'string','1') + set(handles.pushbutton0,'string','0') + case {'MaxLikelihood', 'oneIntervalUpDown'} + if stimulusParameters.includeCue + set(handles.pushbutton3,'string','') + set(handles.pushbutton2,'string','2') + set(handles.pushbutton1,'string','1') + set(handles.pushbutton0,'string','0') + else + set(handles.pushbutton3,'string','') + set(handles.pushbutton2,'string','YES') + set(handles.pushbutton1,'string','NO') + set(handles.pushbutton0,'string','') + end +end + +switch experiment.paradigm + case 'discomfort' + set(handles.pushbutton3,'string','') + set(handles.pushbutton2,'string','uncomfortable') + set(handles.pushbutton1,'string','loud') + set(handles.pushbutton0,'string','comfortable') + experiment.allowCatchTrials=0; +end + +% experiment.subjGUIfontSize is set on expGUI +set(handles.pushbutton3,'FontSize',experiment.subjGUIfontSize) +set(handles.pushbutton2,'FontSize',experiment.subjGUIfontSize) +set(handles.pushbutton1,'FontSize',experiment.subjGUIfontSize) +set(handles.pushbutton0,'FontSize',experiment.subjGUIfontSize) +set(handles.pushbuttoNotSure,'FontSize',experiment.subjGUIfontSize) +set(handles.pushbuttonGO,'FontSize',experiment.subjGUIfontSize) +set(handles.textMSG,'FontSize',experiment.subjGUIfontSize) + +set(handles.pushbutton19,'visible','off') % unused button + +% start command window summary of progress +fprintf(' \n ----------- NEW MEASUREMENTS\n') +disp(['paradigm: ' experiment.paradigm]) +cla(expGUIhandles.axes1) +cla(expGUIhandles.axes2) +cla(expGUIhandles.axes4) +cla(expGUIhandles.axes5) + +experiment.stop=0; % status of 'stop' button +experiment.pleaseRepeat=0; % status of 'repeat' button +experiment.buttonBoxStatus='not busy'; + +% date and time and replace ':' with '_' +date=datestr(now);idx=findstr(':',date);date(idx)='_'; +experiment.date=date; +timeNow=clock; betweenRuns.timeNow= timeNow; +experiment.timeAtStart=[num2str(timeNow(4)) ':' num2str(timeNow(5))]; +experiment.minElapsed=0; + +% unpack catch trial rates. The rate declines from the start rate +% to the base rate using a time constant. +stimulusParameters.catchTrialRate=stimulusParameters.catchTrialRates(1); +stimulusParameters.catchTrialBaseRate=... + stimulusParameters.catchTrialRates(2); +stimulusParameters.catchTrialTimeConstant=... + stimulusParameters.catchTrialRates(3); +if stimulusParameters.catchTrialBaseRate==0 + stimulusParameters.catchTrialRate=0; +end + +% for human measurements only, identify the start catch trial rate +switch experiment.ear + case{'left', 'right','diotic', 'dichoticLeft','dichoticRight'} + fprintf('stimulusParameters.catchTrialRate= %6.3f\n', ... + stimulusParameters.catchTrialRate) +end + +% Reset betweenRuns parameters. this occurs only at experiment start +% withinRuns values are reset in 'startNewRun' +% this approach creates a more readable structure summary printout. +betweenRuns.thresholds=[]; +betweenRuns.thresholds_mean=[]; +betweenRuns.thresholds_median=[]; +betweenRuns.forceThresholds=[]; +betweenRuns.observationCount=[]; +betweenRuns.catchTrials=[]; +betweenRuns.timesOfFirstReversals=[]; +betweenRuns.bestThresholdTracks=[]; +betweenRuns.bestThresholdMeanTracks=[]; +betweenRuns.bestThresholdMedianTracks=[]; +betweenRuns.levelTracks=[]; +betweenRuns.responseTracks=[]; +betweenRuns.slopeKTracks=[]; +betweenRuns.gainTracks=[]; +betweenRuns.VminTracks=[]; +betweenRuns.bestGain=[]; +betweenRuns.bestVMin=[]; +betweenRuns.bestPaMin=[]; +betweenRuns.bestLogisticM=[]; +betweenRuns.bestLogisticK=[]; +betweenRuns.resets=0; +betweenRuns.runNumber=0; + +% Up to two parameters can be changed between runs +% Find the variable parameters and randomize them +% e.g. 'variableList1 = stimulusParameters.targetFrequency;' +eval(['variableList1=stimulusParameters.' betweenRuns.variableName1 ';']); +eval(['variableList2=stimulusParameters.' betweenRuns.variableName2 ';']); +nVar1=length(variableList1); +nVar2=length(variableList2); + +% Create two sequence vectors to represent the sequence of var1 and var2 +% values. 'var1' changes most rapidly. +switch betweenRuns.randomizeSequence + case 'fixed sequence' + var1Sequence=repmat(betweenRuns.variableList1, 1,nVar2); + var2Sequence=reshape(repmat(betweenRuns.variableList2, ... + nVar1,1),1,nVar1*nVar2); + case 'randomize within blocks' + % the blocks are not randomized + var1Sequence=betweenRuns.variableList1; + ranNums=rand(1, length(var1Sequence)); [x idx]=sort(ranNums); + var1Sequence=var1Sequence(idx); + betweenRuns.variableList1=variableList1(idx); + var1Sequence=repmat(var1Sequence, 1,nVar2); + var2Sequence=reshape(repmat(betweenRuns.variableList2, nVar1,1)... + ,1,nVar1*nVar2); + case 'randomize across blocks' + var1Sequence=repmat(betweenRuns.variableList1, 1,nVar2); + var2Sequence=reshape(repmat(betweenRuns.variableList2, nVar1,1),... + 1,nVar1*nVar2); + ranNums=rand(1, nVar1*nVar2); + [x idx]=sort(ranNums); + var1Sequence=var1Sequence(idx); + var2Sequence=var2Sequence(idx); + % there should be one start value for every combination + % of var1/ var2. In principle this allows these values to be + % programmed. Not currently in use. + stimulusParameters.WRVstartValues=... + stimulusParameters.WRVstartValues(idx); +end +betweenRuns.var1Sequence=var1Sequence; +betweenRuns.var2Sequence=var2Sequence; + +% caught out vector needs to be linked to the length of the whole sequence +betweenRuns.caughtOut=zeros(1,length(var1Sequence)); + +disp('planned sequence:') +if min(var1Sequence)>1 + % use decidaml places only if necessary +disp([betweenRuns.variableName1 ': ' num2str(var1Sequence,'%6.0f') ]) +else +disp([betweenRuns.variableName1 ': ' num2str(var1Sequence,'%8.3f') ]) +end +if min(var1Sequence)>1 +disp([betweenRuns.variableName2 ': ' num2str(var2Sequence,'%6.0f') ]) +else +disp([betweenRuns.variableName2 ': ' num2str(var2Sequence,'%8.3f') ]) +end + +fprintf('\nvariable1 \t variable2\t \n') +fprintf('%s \t %s\t Threshold \n',betweenRuns.variableName1,... + betweenRuns.variableName2) + +% Light up 'GO' on subjGUI and advise. +set(handles.editdigitInput,'visible','off') +switch experiment.ear + case {'statsModelLogistic', 'statsModelRareEvent',... + 'MAPmodel', 'MAPmodelMultiCh','MAPmodelSingleCh'} + % no changes required if model used + otherwise + set(handles.pushbuttonGO,'backgroundcolor','y') + set(handles.pushbuttonGO,'visible','on') + set(handles.frame1,'visible','off') + set(handles.textMSG,'backgroundcolor', 'w') + msg=[{'Ready to start new Experiment'}, {' '}, {'Please, click on the GO button'}]; + set(handles.textMSG,'string', msg) + + set(handles.pushbuttoNotSure,'visible','off') + set(handles.pushbuttonWrongButton,'visible','off') + set(handles.pushbutton3,'visible','off') + set(handles.pushbutton2,'visible','off') + set(handles.pushbutton1,'visible','off') + set(handles.pushbutton0,'visible','off') + pause(.1) % to allow display to be drawn +end + +% Selecting the 'GO' button is the only valid operation action now +experiment.status='waitingForGO'; % i.e. waiting for new run + +% control is now either manual, model (MAP) or randomization +switch experiment.ear + case {'MAPmodel','MAPmodelMultiCh','MAPmodelSingleCh','MAPmodelListen'} % MAP model is now the subject + stimulusParameters.calibrationdB=0; % Pascals required! + MAPmodelRunsGUI(handles) + % model is now the subject + case {'statsModelLogistic', 'statsModelRareEvent'} + % no catch trials for the statistical model + stimulusParameters.catchTrialBaseRate=0; + stimulusParameters.catchTrialRate=0; + statsModelRunsGUI(handles) + otherwise + %manual operation; wait for user to click on 'GO' +end + +% Experiment complete (after MAP or randomization) +% return to 'initializeGUI' and then back to expGUI +% Manual control finds its own way home. Program control assumed when +% the user hits the GO button + +% ----------------------------------------------------------------- startNewRun +function startNewRun(handles) +% There are many ways to arrive here. +% Under manual control this is achieved by hitting the GO button +% either via the button box or a mouse click +% MAP and randomization methods call this too + +global experiment stimulusParameters betweenRuns withinRuns expGUIhandles +global LevittControl rareEvent + +figure(handles.figure1) % guarantee subject GUI visibility + +% ignore call if program is not ready +if ~strcmp(experiment.status,'waitingForGO'), return, end + +set(handles.pushbuttonGO,'visible','off') + +% append message to expGUI message box to alert experimenter that the user +% is active +addToMsg('Starting new trial',0) + +cla(expGUIhandles.axes1), title(''); % stimulus +cla(expGUIhandles.axes2), title(''); % WRV track +drawnow + +betweenRuns.runNumber=betweenRuns.runNumber + 1; + +withinRuns.trialNumber=1; +withinRuns.variableValue=... + stimulusParameters.WRVstartValues(betweenRuns.runNumber); +% add random jitter to start level +if ~experiment.singleShot + % SS or single shot allows the user to precisely set the WRV + withinRuns.variableValue=withinRuns.variableValue +... + (rand-0.5)*stimulusParameters.jitterStartdB; +end + +withinRuns.peaks=[]; +withinRuns.troughs=[]; +withinRuns.levelList=[]; +withinRuns.meanEstTrack=[]; +withinRuns.bestSlopeK=[]; +withinRuns.bestGain=[]; +withinRuns.bestVMin=[]; +withinRuns.forceThreshold=NaN; +withinRuns.responseList=[]; +withinRuns.caughtOut=0; +withinRuns.wrongButton=0; +withinRuns.catchTrialCount=0; +withinRuns.thresholdEstimateTrack=[]; + +withinRuns.beginningOfPhase2=0; +withinRuns.nowInPhase2=0; +withinRuns.thisIsRepeatTrial=0; + +rareEvent.Euclid=NaN; +rareEvent.bestGain=NaN; +rareEvent.bestVMin=NaN; +rareEvent.thresholddB=0; +rareEvent.bestPaMindB=NaN; +rareEvent.predictionLevels=[]; +rareEvent.predictionsRE=[]; + +LevittControl.sequence=[]; + +% on-screen count of number of runs still to complete +trialsToGo=length(betweenRuns.var1Sequence)-betweenRuns.runNumber; +set(handles.toGoCounter,'string', trialsToGo); + +switch experiment.threshEstMethod + case {'2I2AFC++', '2I2AFC+++'} + % For 2I2AFC the buttons need to be on the screen ab initio + Levitt2 % inititalize Levitt2 procedure +end + +switch experiment.ear + case{'left', 'right','diotic', 'dichoticLeft','dichoticRight'} + % allow subject time to recover from 'go' press + pause(experiment.clickToStimulusPause) +end + +errormsg=nextStimulus(handles); % get the show on the road + +% switch experiment.paradigm +% case 'SRT' +% set(handles.editdigitInput,'visible','on') +% uicontrol(handles.editdigitInput) +% end + +% terminate if there is any kind of problem +if ~isempty(errormsg) + % e.g. limits exceeded, clipping + disp(errormsg) + runCompleted(handles) + return +end + +% return route is variable (see intro to this function) + +% -----------------------------------------------------buttonBox_callback +function buttonBox_callback(obj, info) +global experiment +global serobj +global subjectGUIHandles + +% do not accept callback if one is already in process +if strcmp(experiment.buttonBoxStatus,'busy') + disp(' ignored button press') + return +end +experiment.buttonBoxStatus='busy'; +% fclose(serobj) + +% identify the code of the button pressed +buttonPressedNo = fscanf(serobj,'%c',1); + +% This is the map from the button to the Cedrus codes +switch experiment.buttonBoxType + case 'horizontal' + pbGo='7'; pb0='1'; + pb1='2'; pb2='3'; + pbRepeat='4'; pbWrong='6'; pbBlank='5'; + case 'square' + pbGo='7'; pb0='1'; + pb1='3'; pb2='4'; + pbRepeat='8'; pbWrong='6'; pbBlank='5'; +end + +% decide what to do +switch experiment.status + case {'presentingStimulus', 'waitingForStart', 'trialcompleted', ... + 'endOfExperiment'} + disp(' ignored button press') + + case 'waitingForGO' + % i.e. waiting for new run + if strcmp(buttonPressedNo,pbGo) % only GO button accepted + startNewRun(subjectGUIHandles) + else + disp(' ignored button press') + end + + case 'waitingForResponse' + % response to stimuli + switch buttonPressedNo + case pb0 % button 0 (top left) + switch experiment.threshEstMethod + case {'2I2AFC++', '2I2AFC+++'} + disp(' ignored button press') + otherwise + set(subjectGUIHandles.pushbutton0,... + 'backgroundcolor','r') + pause(.1) + set(subjectGUIHandles.pushbutton0,... + 'backgroundcolor',get(0,... + 'defaultUicontrolBackgroundColor')) + userSelects0or1(subjectGUIHandles) + end + + case pb1 % button 1 (bottom left) + switch experiment.threshEstMethod + case {'2I2AFC++', '2I2AFC+++'} + userSelects0or1(subjectGUIHandles) + otherwise + set(subjectGUIHandles.pushbutton1,... + 'backgroundcolor','r') + pause(.1) + set(subjectGUIHandles.pushbutton1,... + 'backgroundcolor',get(0,... + 'defaultUicontrolBackgroundColor')) + userSelects0or1(subjectGUIHandles) + end + + case pb2 % button 2 (bottom right) + switch experiment.threshEstMethod + case {'2I2AFC++', '2I2AFC+++'} + userSelects2 (subjectGUIHandles) + otherwise + set(subjectGUIHandles.pushbutton2,... + 'backgroundcolor','r') + pause(.1) + set(subjectGUIHandles.pushbutton2,... + 'backgroundcolor',get(0,... + 'defaultUicontrolBackgroundColor')) + userSelects2 (subjectGUIHandles) + end + + case pbRepeat % extreme right button + switch experiment.threshEstMethod + case {'2I2AFC++', '2I2AFC+++'} + disp(' ignored button press') + otherwise + + set(subjectGUIHandles.pushbuttoNotSure,... + 'backgroundcolor','r') + pause(.1) + set(subjectGUIHandles.pushbuttoNotSure,... + 'backgroundcolor',get(0,... + 'defaultUicontrolBackgroundColor')) + userSelectsPleaseRepeat (subjectGUIHandles) + end + + case {pbWrong, pbBlank} + disp(' ignored button press') + + otherwise % unrecognised button + disp('ignored button press') + end % end (button press number) + otherwise + disp('ignored button press') +end % experiment status + +% All processing returns through here. +% fopen(serobj); % flushes the input buffer + +% buttonPressedNo = fscanf(serobj,'%c',1); + +% button box remains 'busy' until after the stimulus has been presented +experiment.buttonBoxStatus='not busy'; + +% -------------------------------------------------- pushbuttonGO_Callback +function pushbuttonGO_Callback(hObject, eventdata, handles) +% This is a mouse click path +% GO function is also called directly from button box +% and from MAP model and stats model + +set(handles.pushbuttonGO,'visible','off') +startNewRun(handles) + +% ---------------------------------------------------pushbutton0_Callback +function pushbutton0_Callback(hObject, eventdata, handles) +global experiment +% This is a mouse click path + +% ignore 0 button if 2I2AFC used +if findstr(experiment.threshEstMethod,'2I2AFC'), return, end + +% userDoesNotHearTarget(handles) % only possible interpretation +userDecides(handles, false) + +% -------------------------------------------------- pushbutton1_Callback +function pushbutton1_Callback(hObject, eventdata, handles) +userSelects0or1(handles) % also called from buttonBox + +% ---------------------------------------------------pushbutton2_Callback +function pushbutton2_Callback(hObject, eventdata, handles) +userSelects2(handles) % also called from buttonBox + +% --------------------------------------------- pushbuttoNotSure_Callback +function pushbuttoNotSure_Callback(hObject, eventdata, handles) +userSelectsPleaseRepeat(handles) % also called from buttonBox + +% -------------------------------------------------- pushbutton3_Callback +function pushbutton3_Callback(hObject, eventdata, handles) + +% ------------------------------------------------- pushbutton19_Callback +function pushbutton19_Callback(hObject, eventdata, handles) +% should be invisible (ignore) + +% --------------------------------------- pushbuttonWrongButton_Callback +function pushbuttonWrongButton_Callback(hObject, eventdata, handles) +userSelectsWrongButton(handles) + +% --------------------------------------- editdigitInput_Callback +function editdigitInput_Callback(hObject, eventdata, handles) +userSelects0or1(handles) % after digit string input + + + +% ----------------------------------------------------- userSelects0or1 +function userSelects0or1(handles) +global experiment withinRuns + +switch experiment.threshEstMethod + case {'2I2AFC++', '2I2AFC+++'} + switch withinRuns.stimulusOrder + case 'targetFirst'; + % userHearsTarget(handles) + userDecides(handles, true) + otherwise + % userDoesNotHearTarget(handles) + userDecides(handles, false) + end + otherwise + % single interval + % 0 or 1 are treated as equivalent (i.e. target is not heard) + userDecides(handles, false) +end +% return to pushButton1 callback + +% ----------------------------------------------------- userSelects2 +function userSelects2(handles) +global experiment withinRuns +switch experiment.threshEstMethod + case {'2I2AFC++', '2I2AFC+++'} + switch withinRuns.stimulusOrder + case 'targetSecond'; + % userDoesNotHearTarget(handles) + userDecides(handles, true) + otherwise + % userHearsTarget(handles) + userDecides(handles, false) + end + otherwise + % single interval (2 targets heard) + userDecides(handles, true) +end +% return to pushButton2 callback + +% ----------------------------------------------------- ---- userDecides +function userDecides(handles, saidYes) +global experiment stimulusParameters betweenRuns withinRuns +global rareEvent logistic psy levelsBinVector + +if experiment.singleShot + return +end + +% ignore click if not 'waitingForResponse' +if ~strcmp(experiment.status,'waitingForResponse') + disp('ignored click') + return +end + +% speech reception threshold +if strcmp(stimulusParameters.targetType,'digitStrings') + digitsInput=get(handles.editdigitInput,'string'); + % must be three digits + if ~(length(digitsInput)==3) + addToMsg(['error message: Wrong no of digits'], 0, 1) + set(handles.textMSG,'string', 'Wrong no of digits', ... + 'BackgroundColor','r', 'ForegroundColor', 'w') + set(handles.editdigitInput,'string','') + + return + end + % obtain correct answer from file name + x=stimulusParameters.digitString; + idx=find(x=='O'); x(idx)='0'; % replace 'oh' with zero + + disp([x ' ' digitsInput]) + + if x==digitsInput + saidYes=1; + else + saidYes=0; + end +set(handles.editdigitInput,'string','') +set(handles.editdigitInput,'visible','off') +pause(0.1) +end + + + +% no button presses accepted while processing +experiment.status='processingResponse'; + +% catch trials. Restart trial if caught +if withinRuns.catchTrial + if saidYes + disp('catch trial - caught out') + withinRuns.caughtOut=withinRuns.caughtOut+1; + + % special: estimate caught out rate by allowing the trial + % to continue after catch + if stimulusParameters.catchTrialBaseRate==0.5 + % To use this facility, set the catchTrialRate and the + % catchTrialBaseRate both to 0.5 + % update false positive rate + betweenRuns.caughtOut(betweenRuns.runNumber)=... + withinRuns.caughtOut; + plotProgressThisTrial(handles) + nextStimulus(handles); + return + end + + % Punishment: restart the trial + set(handles.frame1,'backgroundColor','r') + set(handles.pushbuttonGO, ... + 'visible','on', 'backgroundcolor','y') % and go again + msg=[{'Start again: catch trial error'}, {' '},... + {'Please,click on the GO button'}]; + set(handles.textMSG,'string',msg) + [y,fs]=wavread('ding.wav'); + wavplay(y/100,fs) + + % raise catch trial rate temporarily. + % this is normally reduced on each new trial (see GO) + stimulusParameters.catchTrialRate=... + stimulusParameters.catchTrialRate+0.1; + if stimulusParameters.catchTrialRate>0.5 + stimulusParameters.catchTrialRate=0.5; + end + fprintf('stimulusParameters.catchTrialRate= %6.3f\n', ... + stimulusParameters.catchTrialRate) + + betweenRuns.caughtOut(betweenRuns.runNumber)=... + 1+betweenRuns.caughtOut(betweenRuns.runNumber); + betweenRuns.runNumber=betweenRuns.runNumber-1; + experiment.status='waitingForGO'; + return % unwind and wait for button press + else % (said No) + % user claims not to have heard target. fortunate as it was not + % present. So, repeat the stimulus (possibly with target) + % and behave as if the last trial did not occur + errormsg=nextStimulus(handles); + + % terminate if there is any kind of problem + if ~isempty(errormsg) + % e.g. limits exceeded, clipping + disp(['Error nextStimulus: ' errormsg]) + runCompleted(handles) + return + end + return % no further action - next trial + end +end + +% This section analyses the responses, makes tracks and defines next stim. + +% Define response and update response list +if saidYes + % target was heard, so response=1; + withinRuns.responseList=[withinRuns.responseList 1]; % 'heard it!' +else + % target was not hear heard, so response=0; + withinRuns.responseList=[withinRuns.responseList 0]; +end +withinRuns.levelList=[withinRuns.levelList withinRuns.variableValue]; +trialNumber=length(withinRuns.responseList); + +% keep track of peaks and troughs; +% identify direction of change during initial period +if saidYes + % default step size before first reversal + WRVinitialStep=-stimulusParameters.WRVinitialStep; + WRVsmallStep=-stimulusParameters.WRVsmallStep; + % if the previous direction was 'less difficult', this must be a peak + if strcmp(withinRuns.direction,'less difficult') ... + && length(withinRuns.levelList)>1 + withinRuns.peaks=[withinRuns.peaks withinRuns.variableValue]; + end + withinRuns.direction='more difficult'; + +else + % said 'no' + % default step size before first reversal + WRVinitialStep=stimulusParameters.WRVinitialStep; + WRVsmallStep=stimulusParameters.WRVsmallStep; + + % if the previous direction was 'up', this must be a peak + if strcmp(withinRuns.direction,'more difficult') ... + && length(withinRuns.levelList)>1 + withinRuns.troughs=[withinRuns.troughs withinRuns.variableValue]; + end + withinRuns.direction='less difficult'; +end + +% phase 2 is all the levels after and incuding the first reversal +% plus the level before that +if ~withinRuns.nowInPhase2 && length(withinRuns.peaks)+ ... + length(withinRuns.troughs)>0 +% if ~withinRuns.nowInPhase2 && (~isempty(withinRuns.peaks) ... +% || ~isempty(withinRuns.troughs)) + % define phase 2 + withinRuns.beginningOfPhase2=trialNumber-1; + withinRuns.nowInPhase2=1; + WRVsmallStep=WRVinitialStep/2; +end + +if withinRuns.nowInPhase2 + % keep a record of all levels and responses in phase 2 only + withinRuns.levelsPhaseTwo=... + withinRuns.levelList(withinRuns.beginningOfPhase2:end); + withinRuns.responsesPhaseTwo=... + withinRuns.responseList(withinRuns.beginningOfPhase2:end); +else + withinRuns.levelsPhaseTwo=[]; +end + + +% get (or substitute) threshold estimate +switch experiment.threshEstMethod + case {'2I2AFC++', '2I2AFC+++'} + % for plotting psychometric function only + if withinRuns.beginningOfPhase2>0 + [psy, levelsBinVector, logistic, rareEvent]= ... + bestFitPsychometicFunctions... + (withinRuns.levelsPhaseTwo, withinRuns.responsesPhaseTwo); + end + + if ~isempty(withinRuns.peaks) && ~isempty(withinRuns.troughs) + thresholdEstimate= ... + mean([mean(withinRuns.peaks) mean(withinRuns.troughs)]); + else + thresholdEstimate=NaN; + end + otherwise + % single interval methods + try + % using the s trial after the first reversal + [psy, levelsBinVector, logistic, rareEvent]= ... + bestFitPsychometicFunctions(withinRuns.levelsPhaseTwo,... + withinRuns.responsesPhaseTwo); + catch + logistic.bestThreshold=NaN; + end +end + +if withinRuns.nowInPhase2 + % save tracks of threshold estimates for plotting andprinting + switch experiment.functionEstMethod + case {'logisticLS', 'logisticML'} + if withinRuns.nowInPhase2 + withinRuns.meanEstTrack=... + [withinRuns.meanEstTrack ... + mean(withinRuns.levelsPhaseTwo)]; + withinRuns.thresholdEstimateTrack=... + [withinRuns.thresholdEstimateTrack ... + logistic.bestThreshold]; + end + case 'rareEvent' + withinRuns.meanEstTrack=... + [withinRuns.meanEstTrack rareEvent.thresholddB]; + withinRuns.thresholdEstimateTrack=... + [withinRuns.thresholdEstimateTrack logistic.bestThreshold]; + case 'peaksAndTroughs' + withinRuns.meanEstTrack=... + [withinRuns.meanEstTrack thresholdEstimate]; + withinRuns.thresholdEstimateTrack=... + [withinRuns.thresholdEstimateTrack thresholdEstimate]; + end +end + +% special discomfort condition +% run is completed when subject hits '2' button +switch experiment.paradigm + case 'discomfort' + if saidYes + runCompleted(handles) + return + end +end + +% choose the next level for the stimulus +switch experiment.threshEstMethod + case {'2I2AFC++', '2I2AFC+++'} + if saidYes + [WRVinitialStep, msg]=Levitt2('hit', withinRuns.variableValue); + else + [WRVinitialStep, msg]=Levitt2('miss',withinRuns.variableValue); + end + + % empty message means continue as normal + if ~isempty(msg) + runCompleted(handles) + return + end + newWRVvalue=withinRuns.variableValue-WRVinitialStep; + + case {'MaxLikelihood', 'oneIntervalUpDown'} + % run completed by virtue of number of trials + % or restart because listener is in trouble + if length(withinRuns.levelsPhaseTwo)== experiment.maxTrials + % Use bonomial test to decide if there is an imbalance in the + % number of 'yes'es and 'no's + yesCount=sum(withinRuns.responseList); + noCount=length(withinRuns.responseList)-yesCount; + z=abs(yesCount-noCount)/(yesCount+noCount)^0.5; + if z>1.96 + betweenRuns.resets=betweenRuns.resets+1; + disp([ 'reset / z= ' num2str( z) ... + ' Nresets= ' num2str( betweenRuns.resets) ] ) + withinRuns.peaks=[]; + withinRuns.troughs=[]; + withinRuns.levelList=withinRuns.levelList(end); + withinRuns.meanEstTrack=withinRuns.meanEstTrack(end); + withinRuns.forceThreshold=NaN; + withinRuns.responseList=withinRuns.responseList(end); + withinRuns.beginningOfPhase2=0; + withinRuns.nowInPhase2=0; + withinRuns.thresholdEstimateTrack=... + withinRuns.thresholdEstimateTrack(end); + else + runCompleted(handles) + return + end + end + + % set new value for WRV + if withinRuns.nowInPhase2 + % phase 2 + currentMeanEst=withinRuns.thresholdEstimateTrack(end); + switch experiment.threshEstMethod + case 'MaxLikelihood' + newWRVvalue=currentMeanEst; + case {'oneIntervalUpDown'} + newWRVvalue=withinRuns.variableValue+WRVsmallStep; + end + else + % phase 1 + if withinRuns.variableValue+2*WRVinitialStep>... + stimulusParameters.WRVlimits(2) + % use smaller steps when close to maximum + WRVinitialStep=WRVinitialStep/2; + end + newWRVvalue=withinRuns.variableValue+WRVinitialStep; + end + otherwise + error( 'assessment method not recognised') +end + +switch experiment.paradigm + % prevent unrealistic gap durations 'gapDetection' tasks. + % Note that the gap begins when the ramp ends not when stimulus ends + case 'gapDetection' + if newWRVvalue<-2*stimulusParameters.rampDuration + newWRVvalue=-2*stimulusParameters.rampDuration; + addToMsg('gap duration fixed at - 2 * ramp!',1, 1) + end +end + +withinRuns.variableValue=newWRVvalue; +withinRuns.trialNumber=withinRuns.trialNumber+1; + +% Trial continues +plotProgressThisTrial(handles) + +% next stimulus and so the cycle continues +errormsg=nextStimulus(handles); +% after the stimulus is presented, control returns here and the system +% waits for user action. + +% terminate if there is any kind of problem +if ~isempty(errormsg) + % e.g. limits exceeded, clipping + disp(['Error nextStimulus: ' errormsg]) + runCompleted(handles) + return +end + +% ------------------------------------------------ userSelectsPleaseRepeat +function userSelectsPleaseRepeat(handles) +global experiment withinRuns +% ignore click if not 'waitingForResponse' +if ~strcmp(experiment.status,'waitingForResponse') + disp('ignored click') + return +end +% Take no action other than to make a +% tally of repeat requests +experiment.pleaseRepeat=experiment.pleaseRepeat+1; +withinRuns.thisIsRepeatTrial=1; +nextStimulus(handles); + +% ------------------------------------------------ userSelectsWrongButton +function userSelectsWrongButton(handles) +global withinRuns experiment +% restart is the simplest solution for a 'wrong button' request +withinRuns.wrongButton=withinRuns.wrongButton+1; +set(handles.pushbuttonGO, 'visible','on', 'backgroundcolor','y') +msg=[{'Start again: wrong button pressed'}, {' '},... + {'Please,click on the GO button'}]; +set(handles.textMSG,'string',msg) +experiment.status='waitingForGO'; + +% ------------------------------------------------- plotProgressThisTrial +function plotProgressThisTrial(handles) + +% used for all responses +global experiment stimulusParameters betweenRuns withinRuns expGUIhandles +global psy levelsBinVector binFrequencies rareEvent logistic statsModel + + +% plot the levelTrack and the threshold track + +% Panel 2 +% plot the levelList +axes(expGUIhandles.axes2); cla +plot( withinRuns.levelList,'o','markerFaceColor','k'), hold on +% plot the best threshold estimate tracks +if length(withinRuns.meanEstTrack)>=1 + % The length of the levelList is 2 greater than number of thresholds + ptr=withinRuns.beginningOfPhase2+1; + plot(ptr: ptr+length(withinRuns.meanEstTrack)-1, ... + withinRuns.meanEstTrack, 'r') + plot( ptr: ptr+length(withinRuns.thresholdEstimateTrack)-1, ... + withinRuns.thresholdEstimateTrack, 'g') + hold off + estThresh=withinRuns.thresholdEstimateTrack(end); + switch experiment.threshEstMethod + % add appropriate labels to subject GUI buttons + case {'2I2AFC++', '2I2AFC+++'} + title([stimulusParameters.WRVname ' = ' ... + num2str(withinRuns.variableValue, '%5.1f')]) + otherwise + title([stimulusParameters.WRVname ' = ' ... + num2str(withinRuns.variableValue, '%5.1f') ... + '; TH= ' num2str(estThresh, '%5.1f')]) + end +end +xlim([0 experiment.maxTrials+withinRuns.beginningOfPhase2]); +ylim(stimulusParameters.WRVlimits) +grid on + +% Panel 4: Summary of threshold estimates (not used here) +% Earlier estimates are set in 'runCompleted' +% However, title shows runs/trials remaining + +axes(expGUIhandles.axes4) +runsToGo=length(betweenRuns.var1Sequence)-betweenRuns.runNumber; +if withinRuns.beginningOfPhase2>0 + trialsToGo= experiment.singleIntervalMaxTrials(1) ... + + withinRuns.beginningOfPhase2- withinRuns.trialNumber; + title(['trials remaining = ' num2str(trialsToGo) ... + ': runs to go= ' num2str(runsToGo)]) +end + +% plot psychometric function - panel 5 +axes(expGUIhandles.axes5), cla +plot(withinRuns.levelList, withinRuns.responseList,'b.'), hold on +ylim([0 1]) +title('') + +switch experiment.threshEstMethod + case {'MaxLikelihood', 'oneIntervalUpDown'} + if withinRuns.beginningOfPhase2>0 + % display only when in phase 2. + withinRuns.levelsPhaseTwo=... + withinRuns.levelList(withinRuns.beginningOfPhase2:end); + withinRuns.responsesPhaseTwo=... + withinRuns.responseList(withinRuns.beginningOfPhase2:end); + + % organise data as psychometric function + [psy, levelsBinVector, binFrequencies]= ... + psychometricFunction(withinRuns.levelsPhaseTwo,... + withinRuns.responsesPhaseTwo, experiment.psyBinWidth); + + % Plot the function + % point by point with circles of appropiate weighted size + hold on, + for i=1:length(psy) + plot(levelsBinVector(i), psy(i), 'ro', ... + 'markersize', 50*binFrequencies(i)/sum(binFrequencies)) + end + % save info for later + betweenRuns.psychometicFunction{betweenRuns.runNumber}=... + [levelsBinVector; psy]; + + % fitPsychometric functions is computed in 'userDecides' + % plot(rareEvent.predictionLevels, rareEvent.predictionsRE,'k') + plot(logistic.predictionLevels, logistic.predictionsLOG, 'r') + plot(rareEvent.predictionLevels, rareEvent.predictionsRE, 'k') + if ~isnan(logistic.bestThreshold ) +% xlim([ (logistic.bestThreshold -20) ... +% (logistic.bestThreshold +20) ]) + xlim([ 0 100 ]) +% if logistic.bestK< max(experiment.possLogSlopes) + title(['k= ' num2str(logistic.bestK, '%6.2f') ' g= '... + num2str(rareEvent.bestGain,'%6.3f') ' A=' ... + num2str(rareEvent.bestVMin,'%8.1f')]) +% title('') +% end + else + title(' ') + end + + switch experiment.ear + %plot green line for statsModel a priori model + case 'statsModelLogistic' + % plot proTem logistic (green) used by stats model + p= 1./(1+exp(-statsModel.logisticSlope... + *(levelsBinVector-logistic.bestThreshold))); + if experiment.psyFunSlope<0, p=1-p;end + titleText=[ ', statsModel: logistic']; + hold on, plot(levelsBinVector, p,'g') + case 'statsModelRareEvent' + pressure=28*10.^(levelsBinVector/20); + p=1-exp(-stimulusParameters.targetDuration... + *(statsModel.rareEvenGain... + * pressure-statsModel.rareEventVmin)); + p(p<0)=0; + if experiment.psyFunSlope<0, p=1-p;end + hold on, plot(levelsBinVector, p,'g') + end %(estMethod) + end + otherwise % 2A2IFC + + message3= ... + ([ 'peaks=' num2str(withinRuns.peaks) ... + 'troughs=' num2str(withinRuns.troughs)]); + ylimRM([-0.1 1.1]) % 0=no / 1=yes + set(gca,'ytick',[0 1], 'yTickLabel', {'no';'yes'}) + ylabel('psychometric function'), xlabel('target level') + if length(levelsBinVector)>1 + xlim([ min(levelsBinVector) max(levelsBinVector)]) + xlim([ 0 100]) + end +end + +% command window summary +% Accumulate things to say in the message window +message1= (['responses: ' num2str(withinRuns.responseList,'%9.0f')]); +switch experiment.paradigm + % more decimal places needed on GUI + case { 'gapDetection', 'frequencyDiscrimination', 'forwardMaskingD'} + message2= ([stimulusParameters.WRVname ... + ': ' num2str(withinRuns.levelList,'%7.3f')]); + message3= (['Thresh (logistic mean): ' ... + num2str(withinRuns.thresholdEstimateTrack,'%7.3f')]); + otherwise + message2= ([stimulusParameters.WRVname ': ' ... + num2str(withinRuns.levelList,'%7.1f')]); + message3= (['Thresh (logistic mean): ' ... + num2str(withinRuns.thresholdEstimateTrack,'%7.1f')]); +end + +addToMsg(str2mat(message1, message2, message3), 0) + +% -----------------------------------------------------runCompleted +function runCompleted(handles) +% Used at the end of each run +global experiment stimulusParameters betweenRuns withinRuns +global rareEvent expGUIhandles +% disp('run completed') + +experiment.status='runCompleted'; + +plotProgressThisTrial(handles) + +switch experiment.ear + case {'statsModelLogistic', 'statsModelRareEvent','MAPmodel', ... + 'MAPmodelMultiCh','MAPmodelSingleCh', 'MAPmodelListen'} + % no changes required if model used + otherwise + set(handles.frame1,'visible','off') + set(handles.pushbuttoNotSure,'visible','off') + set(handles.pushbuttonWrongButton,'visible','off') + set(handles.pushbutton3,'visible','off') + set(handles.pushbutton2,'visible','off') + set(handles.pushbutton1,'visible','off') + set(handles.pushbutton0,'visible','off') + set(handles.pushbuttonGO,'visible','off') +end + +if isnan(withinRuns.forceThreshold) + % the experiment has been aborted for some reason + threshold=withinRuns.forceThreshold; + stdev=NaN; + logistic.bestK=NaN; + logistic.bestThreshold=NaN; + medianThreshold=NaN; + meanThreshold=NaN; +else + % use only phase 2 levels and responses for calculating thresholds + withinRuns.levelsPhaseTwo=... + withinRuns.levelList(withinRuns.beginningOfPhase2:end); + withinRuns.responsesPhaseTwo=... + withinRuns.responseList(withinRuns.beginningOfPhase2:end); + [psy, levelsPhaseTwoBinVector, logistic, rareEvent]= ... + bestFitPsychometicFunctions... + (withinRuns.levelsPhaseTwo, withinRuns.responsesPhaseTwo); + + % plot final psychometric function + axes(expGUIhandles.axes5),cla + hold on, plot(rareEvent.predictionLevels, rareEvent.predictionsRE, 'k') + hold on, plot(logistic.predictionLevels, logistic.predictionsLOG, 'r') + % organise data as psychometric function + [psy, levelsBinVector, binFrequencies]= ... + psychometricFunction(withinRuns.levelsPhaseTwo,... + withinRuns.responsesPhaseTwo, experiment.psyBinWidth); + % point by point with circles of appropiate weighted size + hold on, + for i=1:length(psy) + plot(levelsBinVector(i), psy(i), 'ro', ... + 'markersize', 50*binFrequencies(i)/sum(binFrequencies)) + end + + + % experimental + medianThreshold=median(withinRuns.levelsPhaseTwo); + warning off + meanThreshold=mean(withinRuns.levelsPhaseTwo); + + % identify the current threshold estimate + switch experiment.paradigm + case 'discomfort' + % most recent value (not truely a mean value) + threshold=withinRuns.levelList(end); + stdev=NaN; + otherwise + switch experiment.threshEstMethod + case {'MaxLikelihood', 'oneIntervalUpDown'} + % last value in the list + threshold=withinRuns.meanEstTrack(end); + threshold=withinRuns.thresholdEstimateTrack(end); + stdev=NaN; + + case {'2I2AFC++', '2I2AFC+++'} + % use peaks and troughs + try % there may not be enough values to use + peaksUsed=experiment.peaksUsed; + threshold=... + mean(... + [withinRuns.peaks(end-peaksUsed+1:end) ... + withinRuns.troughs(end-peaksUsed+1:end)]); + stdev=... + std([withinRuns.peaks(end-peaksUsed +1:end) ... + withinRuns.troughs(end-peaksUsed:end)]); + catch + threshold=NaN; + stdev=NaN; + end + end + end +end + +% Store thresholds +betweenRuns.thresholds=[betweenRuns.thresholds threshold]; +betweenRuns.thresholds_mean=[betweenRuns.thresholds_mean meanThreshold]; +betweenRuns.thresholds_median=... + [betweenRuns.thresholds_median medianThreshold]; +betweenRuns.forceThresholds=... + [betweenRuns.forceThresholds withinRuns.forceThreshold]; + +% count observations after the startup phase for record keeping +betweenRuns.observationCount=... + [betweenRuns.observationCount length(withinRuns.levelList)]; +betweenRuns.timesOfFirstReversals=... + [betweenRuns.timesOfFirstReversals withinRuns.beginningOfPhase2]; +betweenRuns.catchTrials=... + [betweenRuns.catchTrials withinRuns.catchTrialCount]; + +% add variable length tracks to cell arrays +if withinRuns.beginningOfPhase2>0 + betweenRuns.bestThresholdTracks{length(betweenRuns.thresholds)}=... + withinRuns.thresholdEstimateTrack; + betweenRuns.bestThresholdMeanTracks... + {length(betweenRuns.thresholds_mean)}=... + withinRuns.thresholdEstimateTrack; + betweenRuns.bestThresholdMedianTracks... + {length(betweenRuns.thresholds_median)}=... + withinRuns.thresholdEstimateTrack; + + betweenRuns.levelTracks{length(betweenRuns.thresholds)}=... + withinRuns.levelList(withinRuns.beginningOfPhase2:end); + betweenRuns.responseTracks{length(betweenRuns.thresholds)}=... + withinRuns.responseList(withinRuns.beginningOfPhase2:end); +else + betweenRuns.bestThresholdTracks{length(betweenRuns.thresholds)}=[]; + betweenRuns.bestThresholdMeanTracks{length(betweenRuns.thresholds)}=[]; + betweenRuns.bestThresholdMedianTracks{length(betweenRuns.thresholds)}=... + []; + betweenRuns.levelTracks{length(betweenRuns.thresholds)}=[]; + betweenRuns.responseTracks{length(betweenRuns.thresholds)}=[]; +end + +betweenRuns.bestGain=[betweenRuns.bestGain rareEvent.bestGain]; +betweenRuns.bestVMin=[betweenRuns.bestVMin rareEvent.bestVMin]; +betweenRuns.bestPaMin=[betweenRuns.bestPaMin rareEvent.bestPaMindB]; +betweenRuns.bestLogisticM=... + [betweenRuns.bestLogisticM logistic.bestThreshold]; +betweenRuns.bestLogisticK=[betweenRuns.bestLogisticK logistic.bestK]; + +resultsSoFar=[betweenRuns.var1Sequence(betweenRuns.runNumber)'... + betweenRuns.var2Sequence(betweenRuns.runNumber)'... + betweenRuns.thresholds(betweenRuns.runNumber)' + ]; + +fprintf('%10.3f \t%10.3f \t%10.1f \n', resultsSoFar') + +switch experiment.ear + case {'left', 'right', 'diotic', 'dichoticLeft','dichoticRight'} + disp(['caught out= ' num2str(betweenRuns.caughtOut)]) +end + +% plot history of thresholds in panel 4 +axes(expGUIhandles.axes4), cla +plotColors='rgbmckywrgbmckyw'; +for i=1:length(betweenRuns.thresholds) + faceColor=plotColors(floor(i/length(betweenRuns.variableList1)-.01)+1); + switch betweenRuns.variableName1 + case {'targetFrequency', 'maskerRelativeFrequency'} + if min(betweenRuns.var1Sequence)>0 + % semilogx(betweenRuns.var1Sequence(1:betweenRuns.runNumber), ... + % betweenRuns.thresholds, 'o', ... + % 'markerSize', 5,'markerFaceColor',faceColor) + semilogx(betweenRuns.var1Sequence(i), ... + betweenRuns.thresholds(i), 'o', ... + 'markerSize', 5,'markerFaceColor',faceColor) + else + plot(betweenRuns.var1Sequence(1:betweenRuns.runNumber), ... + betweenRuns.thresholds, 'o', ... + 'markerSize', 5,'markerFaceColor',faceColor) + plot(betweenRuns.var1Sequence(i), ... + betweenRuns.thresholds(i), 'o', ... + 'markerSize', 5,'markerFaceColor',faceColor) + end + otherwise + % plot(betweenRuns.var1Sequence(1:betweenRuns.runNumber), ... + % betweenRuns.thresholds, 'o', 'markerSize', 5,... + % 'markerFaceColor',faceColor) + plot(betweenRuns.var1Sequence(i), ... + betweenRuns.thresholds(i), 'o', 'markerSize', 5,... + 'markerFaceColor',faceColor) + end + hold on +end +xlimRM([ min(betweenRuns.variableList1) max(betweenRuns.variableList1) ]) +ylim(stimulusParameters.WRVlimits) +ylabel('thresholds') +xlabel(betweenRuns.variableName1) +set(gca,'ytick', [0 20 40 60 80 100]) +try + % problems if only one x value + set(gca,'XTick', sort(betweenRuns.variableList1)) +catch +end +grid on, set(gca,'XMinorGrid', 'off') + +% If comparison data is available in pearmeter file, plot it now +if ~isempty (experiment.comparisonData) + comparisonData=experiment.comparisonData(:,1:end-1); % ignore final BF + [x, ncols]=size(comparisonData); + if length(betweenRuns.variableList1)==ncols + hold on + plot (sort(betweenRuns.variableList1), comparisonData, 'r') + hold off + end +end + +% End of the Experiment also? +if betweenRuns.runNumber==length(betweenRuns.var1Sequence) + % yes, end of experiment + fileName=['savedData/' experiment.name experiment.date ... + experiment.paradigm]; + % save (fileName, 'experiment', 'stimulusParameters', 'betweenRuns', 'withinRuns', 'variableNames', 'paradigmNames', 'LevittControl') + disp('Experiment completed') + + % update subject GUI to acknowledge end of run + subjGUImsg=[{'Experiment completed'}, {' '}, {'Thank you!'}]; + set(handles.textMSG,'string', subjGUImsg ) + % play 'Tada' + [y,fs,nbits]=wavread('TADA.wav'); + musicGain=10^(stimulusParameters.musicLeveldB/20); + y=y*musicGain; + wavplay(y/100,fs, 'async') + + % update experimenter GUI + addToMsg('Experiment completed.',1) + + printReport + experiment.status='endOfExperiment'; + return +else + % No, hang on. + switch experiment.ear + case {'statsModelLogistic', 'statsModelRareEvent','MAPmodel', ... + 'MAPmodelMultiCh','MAPmodelSingleCh', 'MAPmodelListen'} + % no changes required if model used + otherwise + % decrement catchTrialRate towards baseRate + stimulusParameters.catchTrialRate=... + stimulusParameters.catchTrialBaseRate + ... + (stimulusParameters.catchTrialRate... + -stimulusParameters.catchTrialBaseRate)... + *(1-exp(-stimulusParameters.catchTrialTimeConstant)); + fprintf('stimulusParameters.catchTrialRate= %6.3f\n', ... + stimulusParameters.catchTrialRate) + + % and go again + set(handles.pushbuttonGO,'backgroundcolor','y') + set(handles.frame1,'visible','off') + set(handles.pushbuttonGO,'visible','on') + msg=[{'Ready to start new trial'}, {' '},... + {'Please,click on the GO button'}]; + set(handles.textMSG,'string',msg) + end + experiment.status='waitingForGO'; + % fprintf('\n') + + [y,fs,nbits]=wavread('CHIMES.wav'); + musicGain=10^(stimulusParameters.musicLeveldB/20); + y=y*musicGain; + wavplay(y/100,fs,'async') +end + +% -----------------------------------------------------MAPmodelRunsGUI +% The computer presses the buttons +function MAPmodelRunsGUI(handles) +global experiment stimulusParameters method expGUIhandles +global AN_IHCsynapseParams +method=[]; + +while strcmp(experiment.status,'waitingForGO') + % no catch trials for MAP model + experiment.allowCatchTrials=0; + + % initiates run and plays first stimulus and it returns + % without waiting for button press + startNewRun(handles) + + if sum(strcmp(experiment.ear,... + {'MAPmodelMultiCh', 'MAPmodelListen'})) + % use BFlist specified in MAPparams file + BFlist= -1; + else + BFlist=stimulusParameters.targetFrequency; + end + showParams=0; + % find model parameters using the 'name' box (e.g. CTa ->MAPparamsCTa) + paramFunctionName=['method=MAPparams' experiment.name ... + '(BFlist, stimulusParameters.sampleRate, showParams);']; + eval(paramFunctionName) % go and fetch the parameters + + + % show sample Rate on GUI; it must be set in MAPparams + set(expGUIhandles.textsampleRate,'string',... + num2str(stimulusParameters.sampleRate)) + + if experiment.singleShot +% AN_IHCsynapseParams.showSummaryStatistics=1; + method.showSummaryStatistics=1; + AN_IHCsynapseParams.plotSynapseContents=1; + else + method.showSummaryStatistics=0; + AN_IHCsynapseParams.plotSynapseContents=0; + end + + if strcmp(experiment.ear, 'MAPmodelSingleCh') + method.MGmembranePotentialSave=1; + end + + % continuous loop until the program stops itself + while strcmp(experiment.status,'waitingForResponse') + % NB at this point the stimulus has been played + pause(0.1) % to allow interrupt with CTRL/C + + switch experiment.ear + case { 'MAPmodelListen'} + set(handles.pushbutton1,'backgroundcolor','y','visible','on') + set(handles.pushbutton2,'backgroundcolor','y','visible','on') + end + +AN_IHCsynapseParams.mode= 'spikes'; + +% Analayse the current stimulus using MAP + [modelResponse earObject]= MAPmodel( experiment.MAPplot, method); + + if experiment.stop || experiment.singleShot + % trap for single trial or user interrupt using 'stop' button. + experiment.status= 'waitingForStart'; + experiment.stop=0; + addToMsg('manually stopped',1); + return + end + + switch modelResponse + case 1 + % userDoesNotHearTarget(handles) + switch experiment.ear + case {'MAPmodelListen'} + % illuminate appropriate button + set(handles.pushbutton1,... + 'backgroundcolor','r','visible','on') + set(handles.pushbutton2,'backgroundcolor','y') + end + userDecides(handles, false) + if experiment.singleShot, return, end + + case 2 + % userHearsTarget(handles) + switch experiment.ear + case {'MAPmodelListen'} + % illuminate appropriate button (DEMO only) + set(handles.pushbutton2,'backgroundcolor',... + 'r','visible','on') + set(handles.pushbutton1,'backgroundcolor','y') + end + + switch experiment.paradigm + case 'discomfort' + % always treat discomfort as 'not heard' + userDecides(handles, false) + otherwise + userDecides(handles, true) + end + otherwise + % probably an abort + return + end + end +end + + +% -----------------------------------------------------statsModelRunsGUI +% The computer presses the buttons +function statsModelRunsGUI(handles) +% Decision are made at random using a prescribe statistical function +% to set probabilities as a function of signal level. +global experiment + +experiment.allowCatchTrials=0; + +while strcmp(experiment.status,'waitingForGO') + % i.e. waiting for new run + if experiment.stop + % user has requested an abort + experiment.status= 'waitingForStart'; + addToMsg('manually stopped',1) + return + end + + % initiates run and plays first stimulus and it returns + % without waiting for button press + % NB stimulus is not actually generated (for speed) + startNewRun(handles) + + while strcmp(experiment.status,'waitingForResponse') + % create artificial response here + modelResponse=statsModelGetResponse; + switch modelResponse + case 1 + % userDoesNotHearTarget(handles) + userDecides(handles, false) + case 2 + % userHearsTarget(handles) + userDecides(handles, true) + end + end +end + +% -----------------------------------------------------statsModelGetResponse +function modelResponse=statsModelGetResponse(handles) +global experiment withinRuns statsModel stimulusParameters +% use the generating function to decide if a detection occurs or not + +% pause(0.1) % to allow stopping with CTRL/C but slows things down + +% first compute the probability that a detection occurs +switch experiment.ear + case {'statsModelLogistic'} + prob= 1./(1+exp(-statsModel.logisticSlope.*(withinRuns.variableValue-statsModel.logisticMean))); + % if experiment.psyFunSlope<0, + % prob=1-prob; + % end + + case 'statsModelRareEvent' + if experiment.psyFunSlope<0 + addToMsg('statsModelRareEvent cannot be used with negative slope',0) + error('statsModelRareEvent cannot be used with negative slope') + end + + % standard formula is prob = 1 – exp(-d (g P – A)) + % here A->A; To find Pmin use A/gain + pressure=28*10^(withinRuns.variableValue/20); + gain=statsModel.rareEvenGain; + A=statsModel.rareEventVmin; + d=stimulusParameters.targetDuration; + gP_Vmin=gain*pressure-A; + if gP_Vmin>0 + prob=1-exp(-d*(gP_Vmin)); + else + prob=0; + end +end + +% Use the probability to choose whether or not a detection has occurred +switch experiment.threshEstMethod + case {'MaxLikelihood', 'oneIntervalUpDown'} + if rand1 + [r c]=size(headers); + for no=1:r + fprintf('%s\t',headers(no,:)) + end + fprintf('\n') +end + +[r c]=size(M); + +for row=1:r + for col=1:c + if row==1 && col==1 && M(1,1)==-1000 + % Print nothing (tab follows below) + else + fprintf('%s',num2str(M(row,col))) + end + if col1,xlim([min(levels) max(levels)]), end + ylabel(['dB re:' num2str(refBMdisplacement,'%6.1e') 'm']) + ylim([-20 50]) + set(gca,'ytick',[-10 0 10 20 40]) + grid on + % legend({num2str(stimulusFrequencies')}, 'location', 'EastOutside') + UTIL_printTabTable([levels' peakAmpBMdB], ... + num2str([0 stimulusFrequencies]','%5.0f'), '%5.0f') + finalSummary=[finalSummary peakAmpBMdB]; + + % Tuning curve + if length(relativeFrequencies)>2 + figure(3), subplot(3,nBFs, nBFs+BFno) + % contour(stimulusFrequencies,levels,peakAmpBM,... + % [refBMdisplacement refBMdisplacement],'r') + contour(stimulusFrequencies,levels,peakAmpBM,... + refBMdisplacement.*[1 5 10 50 100]) + title(['tuning curve at ' num2str(refBMdisplacement) 'm']); + ylabel('level (dB) at reference') + xlim([100 10000]) + grid on + hold on + set(gca,'xscale','log') + end + + + % MOC contribution + figure(3) + subplot(3,nBFs,2*nBFs+BFno), cla + plot(levels,20*log10(peakEfferent), 'linewidth',2) + ylabel('MOC (dB attenuation)'), xlabel('level') + title(['peak MOC: model= ' AN_spikesOrProbability]) + grid on + if length(levels)>1, xlim([min(levels) max(levels)]), end + + % AR contribution + hold on + plot(levels,20*log10(peakAREfferent), 'r') + hold off + +end % best frequency + +UTIL_showStructureSummary(DRNLParams, 'DRNLParams', 10) + + UTIL_printTabTable([levels' finalSummary], ... + num2str([0 stimulusFrequencies]','%5.0f'), '%5.0f') + +path(savePath); \ No newline at end of file diff -r 000000000000 -r f233164f4c86 multithreshold 1.46/testFM.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/multithreshold 1.46/testFM.m Fri May 27 13:19:21 2011 +0100 @@ -0,0 +1,247 @@ +function testFM(showPSTHs) +% specify whether you want AN 'probability' or 'spikes' +% spikes is more realistic but takes longer +% refractory effect is included only for spikes +% + +% specify the AN ANresponse bin width (normally 1 ms). +% This can influence the measure of the AN onset rate based on the +% largest bin in the ANresponse +% +% Demonstration is based on Harris and Dallos + +global experiment stimulusParameters +global inputStimulusParams outerMiddleEarParams DRNLParams +global IHC_VResp_VivoParams IHCpreSynapseParams AN_IHCsynapseParams + +dbstop if error +% masker and probe levels are relative to this threshold +thresholdAtCF=10; % dB SPL +thresholdAtCF=5; % dB SPL + +if nargin<1, showPSTHs=1;end + +sampleRate=50000; + +% fetch BF from GUI: use only the first target frequency +BFlist=stimulusParameters.targetFrequency(1); +maskerFrequency=BFlist; +maskerDuration=.1; + +targetFrequency=maskerFrequency; +probeLeveldB=20+thresholdAtCF; % H&D use 20 dB SL/ TMC uses 10 dB SL +probeDuration=0.008; % HD use 15 ms probe (fig 3). +probeDuration=0.015; % HD use 15 ms probe (fig 3). + +rampDuration=.001; % HD use 1 ms linear ramp +initialSilenceDuration=0.02; +finalSilenceDuration=0.05; % useful for showing recovery + +maskerLevels=[-80 10 20 30 40 60 ] + thresholdAtCF; +% maskerLevels=[-80 40 60 ] + thresholdAtCF; + +dt=1/sampleRate; + +figure(7), clf +set(gcf,'position',[613 36 360 247]) +set(gcf,'name', ['forward masking: thresholdAtCF=' num2str(thresholdAtCF)]) + +if showPSTHs + figure(8), clf + set(gcf,'name', 'Harris and Dallos simulation') + set(gcf,'position',[980 36 380 249]) +end + +% Plot Harris and Dallos result for comparison +gapDurations=[0.001 0.002 0.005 0.01 0.02 0.05 0.1 0.3]; +HDmaskerLevels=[+10 +20 +30 +40 +60]; +HDresponse=[ + 1 1 1 1 1 1 1 1; + 0.8 0.82 0.81 0.83 0.87 0.95 1 1; + 0.48 0.5 0.54 0.58 0.7 0.85 0.95 1; + 0.3 0.31 0.35 0.4 0.5 0.68 0.82 0.94; + 0.2 0.27 0.27 0.29 0.42 0.64 0.75 0.92; + 0.15 0.17 0.18 0.23 0.3 0.5 0.6 0.82]; + +figure(7) +semilogx(gapDurations,HDresponse,'o'), hold on +legend(strvcat(num2str(maskerLevels')),'location','southeast') +title([ 'masker dB: ' num2str(HDmaskerLevels)]) + +%% Run the trials +maxProbeResponse=0; +levelNo=0; +resultsMatrix=zeros(length(maskerLevels), length(gapDurations)); +summaryFiringRates=[]; + +% initial silence +time=dt: dt: initialSilenceDuration; +initialSilence=zeros(1,length(time)); + +% probe +time=dt: dt: probeDuration; +amp=28e-6*10^(probeLeveldB/20); +probe=amp*sin(2*pi.*targetFrequency*time); +% ramps +% catch rampTime error +if rampDuration>0.5*probeDuration, rampDuration=probeDuration/2; end +rampTime=dt:dt:rampDuration; +% raised cosine ramp +ramp=[0.5*(1+cos(2*pi*rampTime/(2*rampDuration)+pi)) ... + ones(1,length(time)-length(rampTime))]; +% onset ramp +probe=probe.*ramp; +% offset ramp makes complete ramp for probe +ramp=fliplr(ramp); +% apply ramp mask to probe. Probe does not change below +probe=probe.*ramp; + +% final silence +time=dt: dt: finalSilenceDuration; +finalSilence=zeros(1,length(time)); + +PSTHplotCount=0; +longestSignalDuration=initialSilenceDuration + maskerDuration +... + max(gapDurations) + probeDuration + finalSilenceDuration ; +for maskerLeveldB=maskerLevels + levelNo=levelNo+1; + allDurations=[]; + allFiringRates=[]; + + %masker + time=dt: dt: maskerDuration; + masker=sin(2*pi.*maskerFrequency*time); + % masker ramps + if rampDuration>0.5*maskerDuration + % catch ramp duration error + rampDuration=maskerDuration/2; + end + % NB masker ramp (not probe ramp) + rampTime=dt:dt:rampDuration; + % raised cosine ramp + ramp=[0.5*(1+cos(2*pi*rampTime/(2*rampDuration)+pi))... + ones(1,length(time)-length(rampTime))]; + % onset ramp + masker=masker.*ramp; + % offset ramp + ramp=fliplr(ramp); + % apply ramp + masker=masker.*ramp; + amp=28e-6*10^(maskerLeveldB/20); + maskerPa=amp*masker; + + for gapDuration=gapDurations + time=dt: dt: gapDuration; + gap=zeros(1,length(time)); + + inputSignal=... + [initialSilence maskerPa gap probe finalSilence]; + + % ********************************** run MAP model + + global ANprobRateOutput tauCas ... + + MAPparamsName=experiment.name; + showPlotsAndDetails=0; + +AN_spikesOrProbability='probability'; + +MAP1_14(inputSignal, 1/dt, targetFrequency, ... + MAPparamsName, AN_spikesOrProbability); + + [nFibers c]=size(ANprobRateOutput); + nLSRfibers=nFibers/length(tauCas); + ANresponse=ANprobRateOutput(end-nLSRfibers:end,:); + ANresponse=sum(ANresponse)/nLSRfibers; + + % analyse results + probeStart=initialSilenceDuration+maskerDuration+gapDuration; + PSTHbinWidth=dt; + responseDelay=0.005; + probeTimes=probeStart+responseDelay:... + PSTHbinWidth:probeStart+probeDuration+responseDelay; + probeIDX=round(probeTimes/PSTHbinWidth); + probePSTH=ANresponse(probeIDX); + firingRate=mean(probePSTH); + % NB this only works if you start with the lowest level masker + maxProbeResponse=max([maxProbeResponse firingRate]); + allDurations=[allDurations gapDuration]; + allFiringRates=[allFiringRates firingRate]; + + %% show PSTHs + if showPSTHs + nLevels=length(maskerLevels); + nDurations=length(gapDurations); + figure(8) + PSTHbinWidth=1e-3; + PSTH=UTIL_PSTHmaker(ANresponse, dt, PSTHbinWidth); + PSTH=PSTH*dt/PSTHbinWidth; + PSTHplotCount=PSTHplotCount+1; + subplot(nLevels,nDurations,PSTHplotCount) + probeTime=PSTHbinWidth:PSTHbinWidth:... + PSTHbinWidth*length(PSTH); + bar(probeTime, PSTH) + if strcmp(AN_spikesOrProbability, 'spikes') + ylim([0 500]) + else + ylim([0 500]) + end + xlim([0 longestSignalDuration]) + grid on + + if PSTHplotCount< (nLevels-1) * nDurations+1 + set(gca,'xticklabel',[]) + end + + if ~isequal(mod(PSTHplotCount,nDurations),1) + set(gca,'yticklabel',[]) + else + ylabel([num2str(maskerLevels... + (round(PSTHplotCount/nDurations) +1))]) + end + + if PSTHplotCount<=nDurations + title([num2str(1000*gapDurations(PSTHplotCount)) 'ms']) + end + end % showPSTHs + + end % gapDurations duration + summaryFiringRates=[summaryFiringRates allFiringRates']; + + figure(7), hold on + semilogx(allDurations, allFiringRates/maxProbeResponse) + ylim([0 1]), hold on + ylim([0 inf]), xlim([min(gapDurations) max(gapDurations)]) + xlim([0.001 1]) + pause(0.1) % to allow for CTRL/C interrupts + resultsMatrix(levelNo,:)=allFiringRates; +end % maskerLevel + +disp('delay/ rates') +disp(num2str(round( [1000*allDurations' summaryFiringRates]))) + +% replot with best adjustment +% figure(34), clf% use for separate plot +figure(7), clf +peakProbe=max(max(resultsMatrix)); +resultsMatrix=resultsMatrix/peakProbe; +semilogx(gapDurations,HDresponse,'o'), hold on +title(['FrMsk: probe ' num2str(probeLeveldB)... + 'dB SL: peakProbe=' num2str(peakProbe,'%5.0f') ' sp/s']) +xlabel('gap duration (s)'), ylabel ('probe response') +semilogx(allDurations, resultsMatrix'), ylim([0 1]) +ylim([0 inf]), +xlim([0.001 1]) +legend(strvcat(num2str(maskerLevels'-thresholdAtCF)), -1) + +% ------------------------------------------------- display parameters +disp(['parameter file was: ' experiment.name]) +fprintf('\n') +% UTIL_showStruct(inputStimulusParams, 'inputStimulusParams') +% UTIL_showStruct(outerMiddleEarParams, 'outerMiddleEarParams') +% UTIL_showStruct(DRNLParams, 'DRNLParams') +% UTIL_showStruct(IHC_VResp_VivoParams, 'IHC_VResp_VivoParams') +UTIL_showStruct(IHCpreSynapseParams, 'IHCpreSynapseParams') +UTIL_showStruct(AN_IHCsynapseParams, 'AN_IHCsynapseParams') + + diff -r 000000000000 -r f233164f4c86 multithreshold 1.46/testOME.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/multithreshold 1.46/testOME.m Fri May 27 13:19:21 2011 +0100 @@ -0,0 +1,85 @@ +function testOME + +global experiment +savePath=path; +addpath (['..' filesep 'utilities'],['..' filesep 'MAP']) + +sampleRate=50000; + +dt=1/sampleRate; +leveldBSPL=80; % dB SPL as used by Huber (may trigger AR) +amp=10^(leveldBSPL/20)*28e-6; +duration=.05; +time=dt: dt: duration; + +%% Comparison data (human) +% These data are taken directly from Huber 2001 (Fig. 4) +HuberFrequencies=[600 800 1000 2000 3000 4000 6000 8000]; +HuberDisplacementAt80dBSPL=[1.5E-9 1.5E-09 1.5E-09 1.0E-09 7.0E-10 ... + 3.0E-10 2.0E-10 1.0E-10]; % m; +% HuberVelocityAt80dBSPL= 2*pi*HuberFrequencies.*HuberDisplacementAt80dBSPL; + +figure(2), clf, subplot(2,1,1) +set(2,'position',[5 349 268 327]) +semilogx(HuberFrequencies, 20*log10(HuberDisplacementAt80dBSPL/1e-10),... + 'ko', 'MarkerFaceColor','k', 'Marker','o', 'markerSize',6) +% Generate test stimulus ................................................................. + +%% independent test using discrete frequencies +peakResponses=[]; +peakTMpressure=[]; +frequencies=[200 400 HuberFrequencies 10000]; +for toneFrequency=frequencies + inputSignal=amp*sin(2*pi*toneFrequency*time); + + MAPparamsName=experiment.name; + showPlotsAndDetails=0; + AN_spikesOrProbability='probability'; + % switch off AR & MOC (Huber's patients were deaf) + paramChanges{1}='OMEParams.rateToAttenuationFactorProb=0;'; + paramChanges{2}='DRNLParams.rateToAttenuationFactorProb = 0;'; + + global OMEoutput OMEextEarPressure TMoutput ARAttenuation + % BF is irrelevant + MAP1_14(inputSignal, sampleRate, -1, ... + MAPparamsName, AN_spikesOrProbability, paramChanges); + + peakDisplacement=max(OMEoutput(floor(end/2):end)); + peakResponses=[peakResponses peakDisplacement]; + + peakTMpressure=[peakTMpressure max(OMEextEarPressure)]; + disp([' greatest AR attenuation: ' num2str(min(ARAttenuation))]) +end + +%% Report +disp('frequency displacement(m)') +% disp(num2str([frequencies' peakResponses'])) +fprintf('%6.0f \t%10.3e\n',[frequencies' peakResponses']') + +% stapes peak displacement +figure(2), subplot(2,1,1), hold on +semilogx(frequencies, 20*log10(peakResponses/1e-10), 'r', 'linewidth',4) +% ylim([1e-11 1e-8]) +xlim([100 10000]), ylim([0 30]) +grid on +title(['stapes at ' num2str(leveldBSPL) ' (NB deaf)']) +ylabel('disp: dB re 1e-10m') +xlabel('stimulus frequency (Hz)') +legend({'Huber et al','model'},'location','southWest') +set(gcf,'name','OME') + +% external ear resonance +figure(2), subplot(2,1,2),hold off +semilogx(frequencies, 20*log10(peakTMpressure/28e-6)-leveldBSPL,... + 'k', 'linewidth',2) +xlim([100 10000]) %, ylim([-10 30]) +grid on +title(['External ear resonances' ]) +ylabel('dB') +xlabel('frequency') +set(gcf,'name','OME: external resonances') +% ---------------------------------------------------------- display parameters +disp(['parameter file was: ' experiment.name]) +fprintf('\n') + +path(savePath); \ No newline at end of file diff -r 000000000000 -r f233164f4c86 multithreshold 1.46/testPeriphery.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/multithreshold 1.46/testPeriphery.m Fri May 27 13:19:21 2011 +0100 @@ -0,0 +1,161 @@ +function testPeriphery (BMlocations, paramsName) +% testBM generates input output functions for DRNL model for any number +% of locations. +% Computations are bast on a single channel model (channelBFs=BF) +% peak displacement (peakAmp) is measured. +% if DRNLParams.useMOC is chosen, the full model is run (slow) +% otherwise only DRNL is computed. +% Tuning curves are generated based on a range of frequencies reletove to +% the BF of the location. +% + +global DRNLParams + +savePath=path; + +addpath (['..' filesep 'utilities'],['..' filesep 'MAP']) + +levels=-10:10:90; nLevels=length(levels); +% levels= 50; nLevels=length(levels); + +% relativeFrequencies=[0.25 .5 .75 1 1.25 1.5 2]; +relativeFrequencies=1; + +% refBMdisplacement is the displacement of the BM at threshold +% 1 nm disp at threshold (9 kHz, Ruggero) +refBMdisplacement= 1e-8; % adjusted for 10 nm at 1 kHz + +toneDuration=.200; +rampDuration=0.01; +silenceDuration=0.01; + +sampleRate=30000; + +dbstop if error +figure(3), clf +% set(gcf,'position',[276 33 331 645]) +set(gcf,'name','DRNL - BM') + +finalSummary=[]; +nBFs=length(BMlocations); +BFno=0; plotCount=0; +for BF=BMlocations + BFno=BFno+1; + plotCount=plotCount+nBFs; + stimulusFrequencies=BF* relativeFrequencies; + nFrequencies=length(stimulusFrequencies); + + peakAmpBM=zeros(nLevels,nFrequencies); + peakAmpBMdB=NaN(nLevels,nFrequencies); + peakEfferent=NaN(nLevels,nFrequencies); + peakAREfferent=NaN(nLevels,nFrequencies); + + + levelNo=0; + for leveldB=levels + disp(['level= ' num2str(leveldB)]) + levelNo=levelNo+1; + + freqNo=0; + for frequency=stimulusFrequencies + freqNo=freqNo+1; + + % Generate stimuli + globalStimParams.FS=sampleRate; + globalStimParams.overallDuration=... + toneDuration+silenceDuration; % s + stim.type='tone'; + stim.phases='sin'; + stim.toneDuration=toneDuration; + stim.frequencies=frequency; + stim.amplitudesdB=leveldB; + stim.beginSilence=silenceDuration; + stim.rampOnDur=rampDuration; + stim.rampOffDur=rampDuration; + doPlot=0; + inputSignal=stimulusCreate(globalStimParams, stim, doPlot); + inputSignal=inputSignal(:,1)'; + + %% run the model + MAPparamsName=paramsName; + AN_spikesOrProbability='probability'; + % spikes are slow but can be used to study MOC using IC units + % AN_spikesOrProbability='spikes'; + + global DRNLoutput MOCattenuation ARattenuation IHCoutput + MAP1_14(inputSignal, sampleRate, BF, ... + MAPparamsName, AN_spikesOrProbability); + + DRNLresponse=IHCoutput; + peakAmp=max(max(... + DRNLresponse(:, end-round(length(DRNLresponse)/2):end))); + peakAmpBM(levelNo,freqNo)=peakAmp; + if peakAmp>0 + peakAmpBMdB(levelNo,freqNo)=... + 20*log10(peakAmp/refBMdisplacement); + else + peakAmpBMdB(levelNo,freqNo)=peakAmp; + end + peakEfferent(levelNo,freqNo)=min(min(MOCattenuation)); + peakAREfferent(levelNo,freqNo)=min(min(ARattenuation)); + + end % tone frequency + end % level + + %% analyses results and plot + + % BM I/O plot (top panel) + figure(3) + subplot(3,nBFs,BFno), cla + plot(levels,peakAmpBMdB, 'linewidth',2) + hold on, plot(levels, repmat(refBMdisplacement,1,length(levels))) + hold off + title(['BF=' num2str(BF,'%5.0f') ' - ' paramsName]) + xlabel('level') + % set(gca,'xtick',levels), grid on + if length(levels)>1,xlim([min(levels) max(levels)]), end + ylabel(['dB re:' num2str(refBMdisplacement,'%6.1e') 'm']) + ylim([-20 50]) + set(gca,'ytick',[-10 0 10 20 40]) + % legend({num2str(stimulusFrequencies')}, 'location', 'EastOutside') + UTIL_printTabTable([levels' peakAmpBMdB], ... + num2str([0 stimulusFrequencies]','%5.0f'), '%5.0f') + finalSummary=[finalSummary peakAmpBMdB]; + + % Tuning curve + if length(relativeFrequencies)>2 + figure(3), subplot(3,nBFs, nBFs+BFno) + % contour(stimulusFrequencies,levels,peakAmpBM,... + % [refBMdisplacement refBMdisplacement],'r') + contour(stimulusFrequencies,levels,peakAmpBM,... + refBMdisplacement.*[1 5 10 50 100]) + title(['tuning curve at ' num2str(refBMdisplacement) 'm']); + ylabel('level (dB) at reference') + xlim([100 10000]) + hold on + set(gca,'xscale','log') + end + + + % MOC contribution + figure(3) + subplot(3,nBFs,2*nBFs+BFno), cla + plot(levels,20*log10(peakEfferent), 'linewidth',2) + ylabel('MOC (dB attenuation)'), xlabel('level') + title(['peak MOC: model= ' AN_spikesOrProbability]) + grid on + if length(levels)>1, xlim([min(levels) max(levels)]), end + + % AR contribution + hold on + plot(levels,20*log10(peakAREfferent), 'r') + hold off + +end % best frequency + +UTIL_showStructureSummary(DRNLParams, 'DRNLParams', 10) + + UTIL_printTabTable([levels' finalSummary], ... + num2str([0 stimulusFrequencies]','%5.0f'), '%5.0f') + +path(savePath); \ No newline at end of file diff -r 000000000000 -r f233164f4c86 multithreshold 1.46/testRF.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/multithreshold 1.46/testRF.m Fri May 27 13:19:21 2011 +0100 @@ -0,0 +1,295 @@ +function testRF +% testIHC used either for IHC I/O function or receptive field (doReceptiveFields=1) + +global experiment method stimulusParameters expGUIhandles +global inputStimulusParams IHC_ciliaParams +global IHC_VResp_VivoParams IHCpreSynapseParams AN_IHCsynapseParams +dbstop if error +% set(expGUIhandles.pushbuttonStop, 'backgroundColor', [.941 .941 .941]) + +addpath (['..' filesep 'MAP'], ['..' filesep 'utilities'], ... + ['..' filesep 'parameterStore'], ['..' filesep 'wavFileStore'],... + ['..' filesep 'testPrograms']) + +targetFrequency=stimulusParameters.targetFrequency(1); + +sampleRate=50000; +doReceptiveFields=1; + +toneDuration=.05; +rampDuration=0.004; +silenceDuration=.02; + +nRepeats=100; % no. of AN fibers + +plotGraphsForIHC=1; +% number of MacGregor units is set in the parameter file. + +if doReceptiveFields + % show all receptive field + frequencies=targetFrequency* [ 0.5 0.7 0.9 1 1.1 1.3 1.6]; + levels=0:20:80; nLevels=length(levels); + figure(14), clf + figure(15), clf +else + % show only I/O function at BF + frequencies=targetFrequency; + levels=-20:10:90; + % levels=10:.25:13; + % levels=-20:1:-15 + nLevels=length(levels); +% figure(13), clf, +% set (gcf, 'name', ['IHC/AN input/output' num2str(AN_IHCsynapseParams.numFibers) ' repeats']) +% drawnow +end +nFrequencies=length(frequencies); + +IHC_RP_peak=zeros(nLevels,nFrequencies); +IHC_RP_min=zeros(nLevels,nFrequencies); +IHC_RP_dc=zeros(nLevels,nFrequencies); +AN_HSRonset=zeros(nLevels,nFrequencies); +AN_HSRsaturated=zeros(nLevels,nFrequencies); +AN_LSRonset=zeros(nLevels,nFrequencies); +AN_LSRsaturated=zeros(nLevels,nFrequencies); +CNLSRsaturated=zeros(nLevels,nFrequencies); +CNHSRsaturated=zeros(nLevels,nFrequencies); +ICHSRsaturated=zeros(nLevels,nFrequencies); +ICLSRsaturated=zeros(nLevels,nFrequencies); + + +levelNo=0; PSTHplotCount=0; +for leveldB=levels + fprintf('%4.0f\t', leveldB) + levelNo=levelNo+1; + amp=28e-6*10^(leveldB/20); + + freqNo=0; + for frequency=frequencies + + paramFunctionName=['method=MAPparams' experiment.name ... + '(' num2str(targetFrequency) ');' ]; + eval(paramFunctionName); % read parameters afresh each pass + + dt=method.dt; + time=dt:dt:toneDuration; + rampTime=dt:dt:rampDuration; + ramp=[0.5*(1+cos(2*pi*rampTime/(2*rampDuration)+pi)) ones(1,length(time)-length(rampTime))]; + ramp=ramp.*fliplr(ramp); + + silence=zeros(1,round(silenceDuration/dt)); + + toneStartptr=length(silence)+1; + toneMidptr=toneStartptr+round(toneDuration/(2*dt)) -1; + toneEndptr=toneStartptr+round(toneDuration/dt) -1; + + % create signal (leveldB/ frequency) + freqNo=freqNo+1; + inputSignal=amp*sin(2*pi*frequency'*time); + inputSignal= ramp.*inputSignal; + inputSignal=[silence inputSignal silence]; + + if doReceptiveFields % receptive field + method.plotGraphs= 0; % plot only PSTHs + else + method.plotGraphs= plotGraphsForIHC; % show progress + end + + targetChannelNo=1; + + % force parameters + % the number of AN fibers at each BF + AN_IHCsynapseParams.numFibers= nRepeats; + AN_IHCsynapseParams. mode= 'spikes'; + AN_IHCsynapseParams.plotSynapseContents=0; + AN_IHCsynapseParams.PSTHbinWidth=.001; + + method.DRNLSave=1; + method.IHC_cilia_RPSave=1; + method.PSTHbinWidth=1e-3; % useful 1-ms default for all PSTHs + method.AN_IHCsynapseSave=1; + method.MacGregorMultiSave=1; + method.MacGregorSave=1; + method.dt=dt; + + moduleSequence=[1:8]; + + global ANdt ARAttenuation TMoutput OMEoutput ... + DRNLoutput IHC_cilia_output IHCrestingCiliaCond IHCrestingV... + IHCoutput ANprobRateOutput ANoutput savePavailable tauCas ... + CNoutput ICoutput ICmembraneOutput ICfiberTypeRates MOCattenuation + +AN_spikesOrProbability='spikes'; +AN_spikesOrProbability='probability'; +MAPparamsName='Normal'; + +MAP1_14(inputSignal, 1/dt, targetFrequency, ... + MAPparamsName, AN_spikesOrProbability); + + % RP + IHC_RPData=IHC_cilia_output; + IHC_RPData=IHCoutput(targetChannelNo,:); + IHC_RP_peak(levelNo,freqNo)=max(IHC_RPData(toneStartptr:toneEndptr)); + IHC_RP_min(levelNo,freqNo)=min(IHC_RPData(toneStartptr:toneEndptr)); + IHC_RP_dc(levelNo,freqNo)=mean(IHC_RPData(toneStartptr:toneEndptr)); + + % AN next + AN_IHCsynapseAllData=ANoutput; + method.PSTHbinWidth=0.001; + + nTaus=length(tauCas); + numANfibers=size(ANoutput,1); + numLSRfibers=numANfibers/nTaus; + + %LSR (same as HSR if no LSR fibers present) + channelPtr1=(targetChannelNo-1)*numANfibers+1; + channelPtr2=channelPtr1+numANfibers-1; + LSRspikes=AN_IHCsynapseAllData(channelPtr1:channelPtr2,:); + method.dt=method.AN_IHCsynapsedt; + PSTH=UTIL_PSTHmaker(LSRspikes, method); + PSTH=sum(PSTH,1); % sum across fibers (HSR only) + PSTHStartptr=round(silenceDuration/method.PSTHbinWidth)+1; + PSTHMidptr=PSTHStartptr+round(toneDuration/(2*method.PSTHbinWidth)) -1; + PSTHEndptr=PSTHStartptr+round(toneDuration/method.PSTHbinWidth) -1; + AN_LSRonset(levelNo,freqNo)=max(max(PSTH))/(method.PSTHbinWidth*method.numANfibers); + AN_LSRsaturated(levelNo,freqNo)=sum(PSTH(PSTHMidptr:PSTHEndptr))/(method.numANfibers*toneDuration/2); + + % HSR + channelPtr1=numLSRfibers+(targetChannelNo-1)*method.numANfibers+1; + channelPtr2=channelPtr1+method.numANfibers-1; + HSRspikes=AN_IHCsynapseAllData(channelPtr1:channelPtr2,:); + method.dt=method.AN_IHCsynapsedt; + PSTH=UTIL_PSTHmaker(HSRspikes, method); + PSTH=sum(PSTH,1); % sum across fibers (HSR only) + PSTHStartptr=round(silenceDuration/method.PSTHbinWidth)+1; + PSTHMidptr=PSTHStartptr+round(toneDuration/(2*method.PSTHbinWidth)) -1; + PSTHEndptr=PSTHStartptr+round(toneDuration/method.PSTHbinWidth) -1; + AN_HSRonset(levelNo,freqNo)=max(max(PSTH))/(method.PSTHbinWidth*method.numANfibers); + AN_HSRsaturated(levelNo,freqNo)=sum(PSTH(PSTHMidptr:PSTHEndptr))/(method.numANfibers*toneDuration/2); + [cvANHSR, cvTimes, allTimeStamps, allISIs]= UTIL_CV(HSRspikes, method.AN_IHCsynapsedt); + + PSTHplotCount=PSTHplotCount+1; + if doReceptiveFields % receptive field for HSR only + figure(14), set(gcf,'name','AN') + plotReceptiveFields(method, PSTH, PSTHplotCount, levels, frequencies) + ylim([0 method.numANfibers]) + xlabel(['CV= ' num2str(max(cvANHSR),'%4.2f')],'fontsize',8) + end % doReceptiveFields + + % CN + MacGregorMultiAllData=method.MacGregorMultiData; + numLSRfibers=method.McGMultinNeuronsPerBF*length(method.nonlinCF)* (nTaus-1); + + %LSR (same as HSR if no LSR fibers present) + channelPtr1=(targetChannelNo-1)*method.McGMultinNeuronsPerBF+1; + channelPtr2=channelPtr1+method.McGMultinNeuronsPerBF-1; + MacGregorMultiLSRspikes=MacGregorMultiAllData(channelPtr1:channelPtr2,:); + method.dt=method.MacGregorMultidt; + PSTH=UTIL_PSTHmaker(MacGregorMultiLSRspikes, method); + PSTH=sum(PSTH,1); % sum across fibers (HSR only) + PSTHStartptr=round(silenceDuration/method.PSTHbinWidth)+1; + PSTHMidptr=PSTHStartptr+round(toneDuration/(2*method.PSTHbinWidth)) -1; + PSTHEndptr=PSTHStartptr+round(toneDuration/method.PSTHbinWidth) -1; + CNLSRsaturated(levelNo,freqNo)=sum(PSTH(PSTHMidptr:PSTHEndptr)); + CNLSRsaturated(levelNo,freqNo)=CNLSRsaturated(levelNo,freqNo)... + /((toneDuration/2)*method.McGMultinNeuronsPerBF); + + %HSR + channelPtr1=numLSRfibers+(targetChannelNo-1)*method.McGMultinNeuronsPerBF+1; + channelPtr2=channelPtr1+method.McGMultinNeuronsPerBF-1; + MacGregorMultiHSRspikes=MacGregorMultiAllData(channelPtr1:channelPtr2,:); + method.dt=method.MacGregorMultidt; + PSTH=UTIL_PSTHmaker(MacGregorMultiHSRspikes, method); + PSTH=sum(PSTH,1); % sum across fibers (HSR only) + PSTHStartptr=round(silenceDuration/method.PSTHbinWidth)+1; + PSTHMidptr=PSTHStartptr+round(toneDuration/(2*method.PSTHbinWidth)) -1; + PSTHEndptr=PSTHStartptr+round(toneDuration/method.PSTHbinWidth) -1; + CNHSRsaturated(levelNo,freqNo)=sum(PSTH(PSTHMidptr:PSTHEndptr)); + CNHSRsaturated(levelNo,freqNo)=CNHSRsaturated(levelNo,freqNo)... + /((toneDuration/2)*method.McGMultinNeuronsPerBF); + [cvMMHSR, cvTimes, allTimeStamps, allISIs]= UTIL_CV(MacGregorMultiHSRspikes, method.MacGregorMultidt); + + if doReceptiveFields % receptive field + figure(15), set(gcf,'name','CN HSR input') + plotReceptiveFields(method, PSTH, PSTHplotCount, levels, frequencies) + ylim([0 method.McGMultinNeuronsPerBF]) + xlabel(['CV= ' num2str(max(cvMMHSR),'%4.2f')],'fontsize',8) + end + + MacGregorAllData=method.MacGregorData; + numLSRfibers=length(method.nonlinCF)* (nTaus-1); + + %LSR (same as HSR if no LSR fibers present) + channelPtr1=targetChannelNo; + MacGregorLSR=MacGregorAllData(channelPtr1,:); + method.dt=method.MacGregordt; + PSTH=UTIL_PSTHmaker(MacGregorLSR, method); + PSTHStartptr=round(silenceDuration/method.PSTHbinWidth)+1; + PSTHMidptr=PSTHStartptr+round(toneDuration/(2*method.PSTHbinWidth)) -1; + PSTHEndptr=PSTHStartptr+round(toneDuration/method.PSTHbinWidth) -1; + ICLSRsaturated(levelNo,freqNo)=sum(PSTH(PSTHMidptr:PSTHEndptr)); + ICLSRsaturated(levelNo,freqNo)=ICLSRsaturated(levelNo,freqNo)/(toneDuration/2); + + %LSR (same as HSR if no LSR fibers present) + channelPtr1=numLSRfibers+targetChannelNo; + MacGregorHSR=MacGregorAllData(channelPtr1,:); + method.dt=method.MacGregordt; + PSTH=UTIL_PSTHmaker(MacGregorHSR, method); + PSTHStartptr=round(silenceDuration/method.PSTHbinWidth)+1; + PSTHMidptr=PSTHStartptr+round(toneDuration/(2*method.PSTHbinWidth)) -1; + PSTHEndptr=PSTHStartptr+round(toneDuration/method.PSTHbinWidth) -1; + ICHSRsaturated(levelNo,freqNo)=sum(PSTH(PSTHMidptr:PSTHEndptr)); + ICHSRsaturated(levelNo,freqNo)=ICHSRsaturated(levelNo,freqNo)/(toneDuration/2); + [cvICHSR, cvTimes, allTimeStamps, allISIs]= UTIL_CV(MacGregorHSR, method.MacGregordt); + +% if doReceptiveFields % receptive field +% figure(16), set(gcf,'name','IC HSR input') +% plotReceptiveFields(method, PSTH, PSTHplotCount, levels, frequencies) +% ylim([0 method.McGMultinNeuronsPerBF]) +% xlabel(['CV= ' num2str(max(cvICHSR),'%4.2f')],'fontsize',8) +% end + end % frequency +end % level +fprintf('\n') +toneDuration=2; +rampDuration=0.004; +silenceDuration=.02; +nRepeats=200; % no. of AN fibers +fprintf('toneDuration %6.3f\n', toneDuration) +fprintf(' %6.0f AN fibers (repeats)\n', nRepeats) +fprintf('levels') +fprintf('%6.2f\t', levels) +fprintf('\n') + + +% ---------------------------------------------------------- display parameters +disp(['parameter file was: ' experiment.name]) +fprintf('\n') +UTIL_showStruct(IHC_VResp_VivoParams, 'IHC_cilia_RPParams') +UTIL_showStruct(IHCpreSynapseParams, 'IHCpreSynapseParams') +UTIL_showStruct(AN_IHCsynapseParams, 'AN_IHCsynapseParams') + + + +function plotReceptiveFields(method, PSTH, PSTHplotCount, levels, frequencies) + +% show PSTH for each level/frequency combination +nLevels=length(levels); +nFrequencies=length(frequencies); + +PSTHtime=method.PSTHbinWidth:method.PSTHbinWidth:method.PSTHbinWidth*length(PSTH); +subplot(nLevels,nFrequencies,PSTHplotCount) +bar(PSTHtime, PSTH) +xlim([0 max(PSTHtime)]) +% write axis labels only at left and bottom +if PSTHplotCount< (nLevels-1) * nFrequencies+1 + set(gca,'xticklabel',[]) +end +if ~isequal(mod(PSTHplotCount,nFrequencies),1) + set(gca,'yticklabel',[]) +else + ylabel([num2str(levels(round(PSTHplotCount/nFrequencies) +1)) ' dB']) +end +% add titles only on top row +if PSTHplotCount<=nFrequencies + title([num2str(frequencies(PSTHplotCount)) ' Hz']) +end diff -r 000000000000 -r f233164f4c86 multithreshold 1.46/testRP.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/multithreshold 1.46/testRP.m Fri May 27 13:19:21 2011 +0100 @@ -0,0 +1,208 @@ +function testRP(BFs,MAPparamsName,paramChanges) +% testIHC used for IHC I/O function + +global experiment method inputStimulusParams +global stimulusParameters IHC_VResp_VivoParams IHC_cilia_RPParams +savePath=path; +addpath (['..' filesep 'utilities'],['..' filesep 'MAP']) +dbstop if error + +figure(4), clf, +set (gcf, 'name', ['IHC']) +% set(gcf,'position',[613 354 360 322]) +drawColors='rgbkmcy'; +drawnow + +if nargin<3, paramChanges=[]; end + +levels=-20:10:100; +nLevels=length(levels); +toneDuration=.05; +silenceDuration=.01; +sampleRate=50000; +dt=1/sampleRate; + +allIHC_RP_peak=[]; +allIHC_RP_dc=[]; + +changes{1}=[]; +% changes{1}='IHC_cilia_RPParams.Et= 0.100;'; +% changes{2}='IHC_cilia_RPParams.Et= 0.070;'; + +for changeNo=1:length(changes) + if isempty(changes{1}) + paramChanges=[]; + else + paramChanges{1}=changes{changeNo}; + end +for BFno=1:length(BFs) + BF=BFs(BFno); + targetFrequency=BF; + % OR + %Patuzzi and Sellick test (see ELP & AEM, 2006) + % targetFrequency=100; + + IHC_RP_peak=zeros(nLevels,1); + IHC_RP_min=zeros(nLevels,1); + IHC_RP_dc=zeros(nLevels,1); + + time=dt:dt:toneDuration; + + rampDuration=0.004; + rampTime=dt:dt:rampDuration; + ramp=[0.5*(1+cos(2*pi*rampTime/(2*rampDuration)+pi)) ... + ones(1,length(time)-length(rampTime))]; + ramp=ramp.*fliplr(ramp); + + silence=zeros(1,round(silenceDuration/dt)); + + toneStartptr=length(silence)+1; + toneMidptr=toneStartptr+round(toneDuration/(2*dt)) -1; + toneEndptr=toneStartptr+round(toneDuration/dt) -1; + + levelNo=0; + for leveldB=levels + levelNo=levelNo+1; + % replicate at all levels + amp=28e-6*10^(leveldB/20); + + %% create signal (leveldB/ frequency) + inputSignal=amp*sin(2*pi*targetFrequency'*time); + inputSignal= ramp.*inputSignal; + inputSignal=[silence inputSignal silence]; + inputStimulusParams.sampleRate=1/dt; +% global IHC_ciliaParams + + %% disable efferent for fast processing + method.DRNLSave=1; + method.IHC_cilia_RPSave=1; + method.IHCpreSynapseSave=1; + method.IHC_cilia_RPSave=1; + method.segmentDuration=-1; + moduleSequence=1:4; + + %% run the model + global DRNLoutput IHC_cilia_output IHCrestingCiliaCond IHCrestingV... + IHCoutput + AN_spikesOrProbability='probability'; + + MAP1_14(inputSignal, sampleRate, BF, ... + MAPparamsName, AN_spikesOrProbability, paramChanges); + + % DRNL + DRNLoutput=DRNLoutput; + DRNL_peak(levelNo,1)=max(DRNLoutput(toneMidptr:toneEndptr)); + DRNL_min(levelNo,1)=min(DRNLoutput(toneMidptr:toneEndptr)); + DRNL_dc(levelNo,1)=mean(DRNLoutput(toneMidptr:toneEndptr)); + + % cilia + IHC_ciliaData=IHC_cilia_output; + IHC_ciliaData=IHC_ciliaData; + IHC_cilia_peak(levelNo,1)=... + max(IHC_ciliaData(toneMidptr:toneEndptr)); + IHC_cilia_min(levelNo,1)=... + min(IHC_ciliaData(toneMidptr:toneEndptr)); + IHC_cilia_dc(levelNo,1)=... + mean(IHC_ciliaData(toneMidptr:toneEndptr)); + + % RP + IHC_RPData=IHCoutput; + IHC_RPData=IHC_RPData; + IHC_RP_peak(levelNo,1)=... + max(IHC_RPData(toneMidptr:toneEndptr)); + IHC_RP_min(levelNo,1)=... + min(IHC_RPData(toneMidptr:toneEndptr)); + IHC_RP_dc(levelNo,1)=... + mean(IHC_RPData(toneMidptr:toneEndptr)); + + end % level + + + disp(['parameter file was: ' MAPparamsName]) + fprintf('\n') + + %% plot DRNL + subplot(2,2,1) +% referenceDisp= 9e-9*1000/targetFrequency; +% plot(levels,20*log10(DRNL_peak/referenceDisp), drawColors(BFno), ... +% 'linewidth',2), hold on + referenceDisp=10e-9; + plot(levels,20*log10(DRNL_peak/referenceDisp), drawColors(BFno), ... + 'linewidth',2), hold on + title([' DRNL peak: ' num2str(BFs) ' Hz']) + ylabel ('log10DRNL(m)'), xlabel('dB SPL') + xlim([min(levels) max(levels)]), ylim([-10 50]) + grid on + + %% plot cilia displacement + figure(4) + subplot(2,2,2) + restingIHC_cilia=IHCrestingCiliaCond; + plot(levels, IHC_cilia_peak,'k', 'linewidth',2), hold on + plot(levels, IHC_cilia_min,'r', 'linewidth',2) + hold on, + plot([min(levels) max(levels)], ... + [restingIHC_cilia restingIHC_cilia], 'g') + title(' IHC apical cond.') + ylabel ('IHCcilia(conductance)'), xlabel('dB SPL') + xlim([min(levels) max(levels)]) + grid on + + %% plot receptor potentials + figure(4) + subplot(2,2,3) + % RP I/O function min and max + restingRP=IHC_RP_peak(1); + restingRP=IHCrestingV; + toPlot= [fliplr(IHC_RP_min(:,1)') IHC_RP_peak(:,1)']; + microPa= 28e-6*10.^(levels/20); + microPa=[-fliplr(microPa) microPa]; + plot(microPa,toPlot, drawColors(BFno), 'linewidth',2) + % ylim([0 300]) + + %% Dallos and Harris data + dallosx=[-0.9 -0.1 -0.001 0.001 0.01 0.9]; + dallosy=[-8 -7.8 -6.5 11 16.5 22]/1000 + restingRP; + hold on, plot(dallosx,dallosy, 'o') + plot([-1 1], [restingRP restingRP], 'r') + title(' Dallos(86) data at 800 Hz') + ylabel ('receptor potential(V)'), xlabel('Pa') + ylim([-0.08 -0.02]), xlim([-1 1]) + grid on + + %% RP I/O function min and max + figure(4) + subplot(2,2,4) + restingRP=IHC_RP_peak(1); + peakRP=max(IHC_RP_peak); + plot(levels, IHC_RP_peak,drawColors(BFno), 'linewidth',2) + hold on + plot(levels, IHC_RP_dc, [drawColors(BFno) ':'], 'linewidth',2) + hold on, + plot([min(levels) max(levels)], [restingRP restingRP], 'r') + xlim([min(levels) max(levels)]) + grid on + title(['Et= ' num2str(IHC_cilia_RPParams.Et) ': RP (AC- / DC:']) + ylabel ('RP(V)'), xlabel('dB SPL') + ylim([-0.08 -0.02]) + allIHC_RP_peak=[allIHC_RP_peak IHC_RP_peak]; + allIHC_RP_dc=[allIHC_RP_dc IHC_RP_dc]; + + fprintf('level\t peak\t DC\n') + UTIL_printTabTable([levels' IHC_RP_peak IHC_RP_dc]) + % disp(['restingIHC_cilia= ' num2str(restingIHC_cilia)]) + fprintf('peakRP= \t%6.3f', peakRP) + fprintf('\nrestingRP= \t%6.3f', restingRP) + fprintf('\ndifference= \t%6.3f\n', (peakRP-restingRP)) + drawnow +end +end +% UTIL_showStruct(IHC_VResp_VivoParams, 'IHC_VResp_VivoParams') +UTIL_showStruct(IHC_cilia_RPParams, 'IHC_cilia_RPParams') + fprintf('level\t peak\n') + UTIL_printTabTable([levels' allIHC_RP_peak]) + fprintf('level\t DC\n') + UTIL_printTabTable([levels' allIHC_RP_dc]) + +path(savePath); +disp(paramChanges) \ No newline at end of file diff -r 000000000000 -r f233164f4c86 multithreshold 1.46/testSynapse.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/multithreshold 1.46/testSynapse.m Fri May 27 13:19:21 2011 +0100 @@ -0,0 +1,88 @@ +function testSynapse +% testSynapse tracks the quantity of available transmitter vesicles +% the computations are single channel using the first frequency +% in the targetFrequency box of the expGUI. +% For, speed this function uses only probability and HSR fibers. +% This cannot be changed because of the way AN_IHCsynapse is coded.This). + +global experiment method IHCpreSynapseParams +global AN_IHCsynapseParams stimulusParameters +savePath=path; +addpath (['..' filesep 'utilities'],['..' filesep 'MAP']) + +figure(6),clf +plotColors='rbgkrbgkrbgkrbgkrbgkrbgk'; +set(gcf,'position',[5 32 264 243]) + +sampleRate=5e4; dt=1/sampleRate; + +maskerLevels=-0:10:100; + +BFlist=stimulusParameters.targetFrequency(1); +targetFrequency=stimulusParameters.targetFrequency; +targetFrequency=targetFrequency(1); % only one frequency used + +showParams=0; +useEfferent=0; % no efferent + +silenceDuration=0.005; +maskerDuration=0.1; +recoveryDuration=0.15; +rampDuration=0.004; + +maskerTime=dt:dt:maskerDuration; + +rampTime=dt:dt:rampDuration; +ramp=[0.5*(1+cos(2*pi*rampTime/(2*rampDuration)+pi)) ... + ones(1,length(maskerTime)-length(rampTime))]; +ramp=ramp.*fliplr(ramp); + +initialSilence=zeros(1,round(silenceDuration/dt)); +recoverySilence=zeros(1,round(recoveryDuration/dt)); + +signal=sin(2*pi*targetFrequency'*maskerTime); +signal= ramp.*signal; +signal=[initialSilence signal recoverySilence]; + +levelCount=0; +qtMatrix=[]; +for leveldB=maskerLevels + levelCount=levelCount+1; + + amp=28e-6*10^(leveldB/20); + inputSignal=amp*signal; + + AN_spikesOrProbability='probability'; + MAPparamsName=experiment.name; + showPlotsAndDetails=0; + + global savePavailable + + MAP1_14(inputSignal, 1/dt, targetFrequency, ... + MAPparamsName, AN_spikesOrProbability); + + % ignore LSR channels (if any) at the top of the matrix + qt=savePavailable(end, :); + + synapsedt=dt; + time=synapsedt:synapsedt:synapsedt*length(qt); + + figure(6) + qtMatrix=[qtMatrix; qt]; + plot(time,qt, plotColors(levelCount)) + hold on + xlim([0 max(time)]) + ylim([0 AN_IHCsynapseParams.M]) +end + +set(gcf,'name','pre-synaptic available transmitter') +title(['q - available vesicles:' num2str(BFlist) ' Hz']) +legend(strvcat(num2str(maskerLevels')),'location','southeast') +legend boxoff +grid on + +figure(88), [c,H]=contour(time, maskerLevels,qtMatrix); clabel(c, H); +set(gcf,'position',[ 276 31 264 243]) +xlabel('time'), ylabel('maskerLevels') + +path(savePath); diff -r 000000000000 -r f233164f4c86 parameterStore/MAPparamsNormal.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/parameterStore/MAPparamsNormal.m Fri May 27 13:19:21 2011 +0100 @@ -0,0 +1,345 @@ +function method=MAPparamsNormal ... + (BFlist, sampleRate, showParams) +% MAPparams<> establishes a complete set of MAP parameters +% Parameter file names must be of the form +% +% input arguments +% BFlist (optional) specifies the desired list of channel BFs +% otherwise defaults set below +% sampleRate (optional), default is 50000. +% showParams (optional) =1 prints out the complete set of parameters +% output argument +% method passes a miscelleny of values + +global inputStimulusParams OMEParams DRNLParams +global IHC_VResp_VivoParams IHCpreSynapseParams AN_IHCsynapseParams +global MacGregorParams MacGregorMultiParams filteredSACFParams +global experiment % used by calls from multiThreshold only +global IHC_cilia_RPParams + +currentFile=mfilename; % i.e. the name of this mfile +method.parameterSource=currentFile(10:end); % for the record + +switchOffEfferent=0; +efferentDelay=0.010; +method.segmentDuration=efferentDelay; + +if nargin<3, showParams=0; end +if nargin<2, sampleRate=50000; end +if nargin<1 || BFlist(1)<0 % if BFlist= -1, set BFlist to default + lowestBF=250; highestBF= 8000; numChannels=21; + % 21 chs (250-8k)includes BFs at 250 500 1000 2000 4000 8000 + BFlist=round(logspace(log10(lowestBF),log10(highestBF),numChannels)); +end +% BFlist=1000; + +% preserve for backward campatibility +method.nonlinCF=BFlist; +method.dt=1/sampleRate; + +%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% set model parameters +%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% #1 inputStimulus +inputStimulusParams=[]; +inputStimulusParams.sampleRate= sampleRate; + +%% #2 outerMiddleEar +OMEParams=[]; % clear the structure first +% outer ear resonances band pass filter [gain lp order hp] +OMEParams.externalResonanceFilters= [ 10 1 1000 4000]; + +% highpass stapes filter +% Huber gives 2e-9 m at 80 dB and 1 kHz (2e-13 at 0 dB SPL) +OMEParams.OMEstapesLPcutoff= 1000; +OMEParams.stapesScalar= 45e-9; + +% Acoustic reflex: maximum attenuation should be around 25 dB Price (1966) +% i.e. a minimum ratio of 0.056. +if ~switchOffEfferent + % 'spikes' model: AR based on brainstem spiking activity (LSR) + OMEParams.rateToAttenuationFactor=0.003; % * N(all ICspikes) +% OMEParams.rateToAttenuationFactor=0; % * N(all ICspikes) + % 'probability model': Ar based on An firing probabilities (LSR) + OMEParams.rateToAttenuationFactorProb=0.005;% * N(all ANrates) +% OMEParams.rateToAttenuationFactorProb=0;% * N(all ANrates) +else + OMEParams.rateToAttenuationFactor=0; % 0= off + OMEParams.rateToAttenuationFactorProb=0; % 0= off +end +% asymptote should be around 100-200 ms +OMEParams.ARtau=.05; % AR smoothing function +% delay must be longer than the segment length +OMEParams.ARdelay=efferentDelay; %Moss gives 8.5 ms latency +OMEParams.ARrateThreshold=0; + +%% #3 DRNL +DRNLParams=[]; % clear the structure first +DRNLParams.BFlist=BFlist; + +% DRNL nonlinear path +DRNLParams.a=3e4; % nonlinear path gain (below compression threshold) +% DRNLParams.a=0; % DRNL.a=0 means no OHCs (no nonlinear path) + +DRNLParams.b=8e-6; % *compression threshold raised compression +% DRNLParams.b=1; % b=1 means no compression + +DRNLParams.c=0.2; % compression exponent +% nonlinear filters +DRNLParams.nonlinCFs=BFlist; +DRNLParams.nonlinOrder= 3; % order of nonlinear gammatone filters +p=0.2895; q=170; % human (% p=0.14; q=366; % cat) +DRNLParams.nlBWs= p * BFlist + q; +DRNLParams.p=p; DRNLParams.q=q; % save p and q for printing only + +% DRNL linear path: +DRNLParams.g=100; % linear path gain factor +% linCF is not necessarily the same as nonlinCF +minLinCF=153.13; coeffLinCF=0.7341; % linCF>nonlinBF for BF < 1 kHz +DRNLParams.linCFs=minLinCF+coeffLinCF*BFlist; +DRNLParams.linOrder= 3; % order of linear gammatone filters +minLinBW=100; coeffLinBW=0.6531; +DRNLParams.linBWs=minLinBW + coeffLinBW*BFlist; % bandwidths of linear filters + +% DRNL MOC efferents +DRNLParams.MOCdelay = efferentDelay; % must be < segment length! +if ~switchOffEfferent + % 'spikes' model: MOC based on brainstem spiking activity (HSR) + DRNLParams.rateToAttenuationFactor = .009; % strength of MOC + DRNLParams.rateToAttenuationFactor = .009; % strength of MOC +% DRNLParams.rateToAttenuationFactor = 0; % strength of MOC + + % 'spikes' model: MOC based on brainstem spiking activity (HSR) + DRNLParams.rateToAttenuationFactorProb = .002; % strength of MOC +else + DRNLParams.rateToAttenuationFactor = 0; % 0 = MOC off (probability) + DRNLParams.rateToAttenuationFactorProb = 0; % 0 = MOC off (spikes) +end +DRNLParams.MOCtau =.03; % smoothing for MOC +DRNLParams.MOCrateThreshold =50; % set to AN rate threshold + + +%% #4 IHC_cilia_RPParams + +IHC_cilia_RPParams.tc= 0.0003; % 0.0003 filter time simulates viscocity +% IHC_cilia_RPParams.tc= 0.0005; % 0.0003 filter time simulates viscocity +IHC_cilia_RPParams.C= 0.05; % 0.1 scalar (C_cilia ) +IHC_cilia_RPParams.u0= 5e-9; +IHC_cilia_RPParams.s0= 30e-9; +IHC_cilia_RPParams.u1= 1e-9; +IHC_cilia_RPParams.s1= 1e-9; + +IHC_cilia_RPParams.Gmax= 5e-9; % 2.5e-9 maximum conductance (Siemens) +IHC_cilia_RPParams.Gu0= 1e-9; % 4.3e-9 fixed apical membrane conductance + +% #5 IHC_RP +IHC_cilia_RPParams.Cab= 4e-012; % IHC capacitance (F) +IHC_cilia_RPParams.Et= 0.100; % endocochlear potential (V) +% IHC_cilia_RPParams.Et= 0.070; % endocochlear potential (V) + +IHC_cilia_RPParams.Gk= 2e-008; % 1e-8 potassium conductance (S) +IHC_cilia_RPParams.Ek= -0.08; % -0.084 K equilibrium potential +IHC_cilia_RPParams.Rpc= 0.04; % combined resistances + + + +%% #5 IHCpreSynapse +IHCpreSynapseParams=[]; +IHCpreSynapseParams.GmaxCa= 14e-9;% maximum calcium conductance +IHCpreSynapseParams.GmaxCa= 13e-9;% maximum calcium conductance +IHCpreSynapseParams.ECa= 0.066; % calcium equilibrium potential +IHCpreSynapseParams.beta= 400; % determine Ca channel opening +IHCpreSynapseParams.gamma= 100; % determine Ca channel opening +IHCpreSynapseParams.tauM= 0.00005; % membrane time constant ?0.1ms +IHCpreSynapseParams.power= 3; +% reminder: changing z has a strong effect on HF thresholds (like Et) +IHCpreSynapseParams.z= 2e42; % scalar Ca -> vesicle release rate + +LSRtauCa=50e-6; HSRtauCa=85e-6; % seconds +% LSRtauCa=35e-6; HSRtauCa=70e-6; % seconds +IHCpreSynapseParams.tauCa= [LSRtauCa HSRtauCa]; %LSR and HSR fiber + +%% #6 AN_IHCsynapse +% c=kym/(y(l+r)+kl) (spontaneous rate) +% c=(approx) ym/l (saturated rate) +AN_IHCsynapseParams=[]; % clear the structure first +AN_IHCsynapseParams.M= 12; % maximum vesicles at synapse +AN_IHCsynapseParams.y= 4; % depleted vesicle replacement rate +AN_IHCsynapseParams.y= 6; % depleted vesicle replacement rate + +AN_IHCsynapseParams.x= 30; % replenishment from re-uptake store +AN_IHCsynapseParams.x= 60; % replenishment from re-uptake store + +% reduce l to increase saturated rate +AN_IHCsynapseParams.l= 100; % *loss rate of vesicles from the cleft +AN_IHCsynapseParams.l= 250; % *loss rate of vesicles from the cleft + +AN_IHCsynapseParams.r= 500; % *reuptake rate from cleft into cell +% AN_IHCsynapseParams.r= 300; % *reuptake rate from cleft into cell + +AN_IHCsynapseParams.refractory_period= 0.00075; +% number of AN fibers at each BF (used only for spike generation) +AN_IHCsynapseParams.numFibers= 100; +AN_IHCsynapseParams.TWdelay=0.004; % ?delay before stimulus first spike + +%% #7 MacGregorMulti (first order brainstem neurons) +MacGregorMultiParams=[]; +MacGregorMultiType='chopper'; % MacGregorMultiType='primary-like'; %choose +switch MacGregorMultiType + case 'primary-like' + MacGregorMultiParams.nNeuronsPerBF= 10; % N neurons per BF + MacGregorMultiParams.type = 'primary-like cell'; + MacGregorMultiParams.fibersPerNeuron=4; % N input fibers + MacGregorMultiParams.dendriteLPfreq=200; % dendritic filter + MacGregorMultiParams.currentPerSpike=0.11e-6; % (A) per spike + MacGregorMultiParams.Cap=4.55e-9; % cell capacitance (Siemens) + MacGregorMultiParams.tauM=5e-4; % membrane time constant (s) + MacGregorMultiParams.Ek=-0.01; % K+ eq. potential (V) + MacGregorMultiParams.dGkSpike=3.64e-5; % K+ cond.shift on spike,S + MacGregorMultiParams.tauGk= 0.0012; % K+ conductance tau (s) + MacGregorMultiParams.Th0= 0.01; % equilibrium threshold (V) + MacGregorMultiParams.c= 0.01; % threshold shift on spike, (V) + MacGregorMultiParams.tauTh= 0.015; % variable threshold tau + MacGregorMultiParams.Er=-0.06; % resting potential (V) + MacGregorMultiParams.Eb=0.06; % spike height (V) + + case 'chopper' + MacGregorMultiParams.nNeuronsPerBF= 10; % N neurons per BF + MacGregorMultiParams.type = 'chopper cell'; + MacGregorMultiParams.fibersPerNeuron=10; % N input fibers + MacGregorMultiParams.fibersPerNeuron=6; % N input fibers + + MacGregorMultiParams.dendriteLPfreq=50; % dendritic filter + MacGregorMultiParams.currentPerSpike=39e-9; % *per spike +% MacGregorMultiParams.currentPerSpike=45e-9; % *per spike + + MacGregorMultiParams.Cap=1.67e-8; % ??cell capacitance (Siemens) + MacGregorMultiParams.tauM=0.002; % membrane time constant (s) + MacGregorMultiParams.Ek=-0.01; % K+ eq. potential (V) + MacGregorMultiParams.dGkSpike=1.33e-4; % K+ cond.shift on spike,S + MacGregorMultiParams.tauGk= 0.0001;% K+ conductance tau (s) + MacGregorMultiParams.Th0= 0.01; % equilibrium threshold (V) + MacGregorMultiParams.c= 0; % threshold shift on spike, (V) + MacGregorMultiParams.tauTh= 0.02; % variable threshold tau + MacGregorMultiParams.Er=-0.06; % resting potential (V) + MacGregorMultiParams.Eb=0.06; % spike height (V) + MacGregorMultiParams.PSTHbinWidth= 1e-4; +end + +%% #8 MacGregor (second-order neuron). Only one per channel +MacGregorParams=[]; % clear the structure first +MacGregorParams.type = 'chopper cell'; +MacGregorParams.fibersPerNeuron=10; % N input fibers +MacGregorParams.dendriteLPfreq=100; % dendritic filter +MacGregorParams.currentPerSpike=120e-9;% *(A) per spike + +MacGregorParams.Cap=16.7e-9; % cell capacitance (Siemens) +MacGregorParams.tauM=0.002; % membrane time constant (s) +MacGregorParams.Ek=-0.01; % K+ eq. potential (V) +MacGregorParams.dGkSpike=1.33e-4; % K+ cond.shift on spike,S +MacGregorParams.tauGk= 0.0003; % K+ conductance tau (s) +MacGregorParams.Th0= 0.01; % equilibrium threshold (V) +MacGregorParams.c= 0; % threshold shift on spike, (V) +MacGregorParams.tauTh= 0.02; % variable threshold tau +MacGregorParams.Er=-0.06; % resting potential (V) +MacGregorParams.Eb=0.06; % spike height (V) +MacGregorParams.debugging=0; % (special) +% wideband accepts input from all channels (of same fiber type) +% use wideband to create inhibitory units +MacGregorParams.wideband=0; % special for wideband units +% MacGregorParams.saveAllData=0; + +%% #9 filteredSACF +minPitch= 300; maxPitch= 3000; numPitches=60; % specify lags +pitches=100*log10(logspace(minPitch/100, maxPitch/100, numPitches)); +filteredSACFParams.lags=1./pitches; % autocorrelation lags vector +filteredSACFParams.acfTau= .003; % time constant of running ACF +filteredSACFParams.lambda= 0.12; % slower filter to smooth ACF +filteredSACFParams.plotFilteredSACF=1; % 0 plots unfiltered ACFs +filteredSACFParams.plotACFs=0; % special plot (see code) +% filteredSACFParams.usePressnitzer=0; % attenuates ACF at long lags +filteredSACFParams.lagsProcedure= 'useAllLags'; +% filteredSACFParams.lagsProcedure= 'useBernsteinLagWeights'; +% filteredSACFParams.lagsProcedure= 'omitShortLags'; +filteredSACFParams.criterionForOmittingLags=3; + +% checks +if AN_IHCsynapseParams.numFibers file in 'parameterStore' folder + % and print out all parameters + cmd=['MAPparams' saveMAPparamsName ... + '(-1, 1/dt, 1);']; + eval(cmd); +end + +if options.printFiringRates + %% print summary firing rates + fprintf('\n\n') + disp('summary') + disp(['AR: ' num2str(min(ARattenuation))]) + disp(['MOC: ' num2str(min(min(MOCattenuation)))]) + nANfiberTypes=length(tauCas); + if strcmp(saveAN_spikesOrProbability, 'spikes') + nANfibers=size(ANoutput,1); + nHSRfibers=nANfibers/nANfiberTypes; + duration=size(TMoutput,2)*dt; + disp(['AN: ' num2str(sum(sum(ANoutput(end-nHSRfibers+1:end,:)))/... + (nHSRfibers*duration))]) + + nCNneurons=size(CNoutput,1); + nHSRCNneuronss=nCNneurons/nANfiberTypes; + disp(['CN: ' num2str(sum(sum(CNoutput(end-nHSRCNneuronss+1:end,:)))... + /(nHSRCNneuronss*duration))]) + disp(['IC: ' num2str(sum(sum(ICoutput)))]) + disp(['IC by type: ' num2str(mean(ICfiberTypeRates,2)')]) + else + disp(['AN: ' num2str(mean(mean(ANprobRateOutput)))]) + end +end + + +%% figure (99) summarises main model output +if options.showModelOutput + plotInstructions.figureNo=99; + signalRMS=mean(savedInputSignal.^2)^0.5; + signalRMSdb=20*log10(signalRMS/20e-6); + + % plot signal (1) + plotInstructions.displaydt=dt; + plotInstructions.numPlots=6; + plotInstructions.subPlotNo=1; + plotInstructions.title=... + ['stimulus: ' num2str(signalRMSdb, '%4.0f') ' dB SPL']; + r=size(savedInputSignal,1); + if r==1, savedInputSignal=savedInputSignal'; end + UTIL_plotMatrix(savedInputSignal', plotInstructions); + + % stapes (2) + plotInstructions.subPlotNo=2; + plotInstructions.title= ['stapes displacement']; + UTIL_plotMatrix(OMEoutput, plotInstructions); + + % DRNL (3) + plotInstructions.subPlotNo=3; + plotInstructions.title= ['BM displacement']; + plotInstructions.yValues= savedBFlist; + UTIL_plotMatrix(DRNLoutput, plotInstructions); + + switch saveAN_spikesOrProbability + case 'spikes' + % AN (4) + plotInstructions.displaydt=ANdt; + plotInstructions.title='AN'; + plotInstructions.subPlotNo=4; + plotInstructions.yLabel='BF'; + plotInstructions.yValues= savedBFlist; + plotInstructions.rasterDotSize=1; + plotInstructions.plotDivider=1; + if sum(sum(ANoutput))<100 + plotInstructions.rasterDotSize=3; + end + UTIL_plotMatrix(ANoutput, plotInstructions); + + % CN (5) + plotInstructions.displaydt=ANdt; + plotInstructions.subPlotNo=5; + plotInstructions.title='CN spikes'; + if sum(sum(CNoutput))<100 + plotInstructions.rasterDotSize=3; + end + UTIL_plotMatrix(CNoutput, plotInstructions); + + % IC (6) + plotInstructions.displaydt=ANdt; + plotInstructions.subPlotNo=6; + plotInstructions.title='IC'; + if size(ICoutput,1)>3 + if sum(sum(ICoutput))<100 + plotInstructions.rasterDotSize=3; + end + UTIL_plotMatrix(ICoutput, plotInstructions); + else + plotInstructions.title='IC (HSR) membrane potential'; + plotInstructions.displaydt=dt; + plotInstructions.yLabel='V'; + plotInstructions.zValuesRange= [-.1 0]; + UTIL_plotMatrix(ICmembraneOutput, plotInstructions); + end + + otherwise % probability (4-6) + plotInstructions.displaydt=dt; + plotInstructions.numPlots=2; + plotInstructions.subPlotNo=2; + plotInstructions.yLabel='BF'; + if nANfiberTypes>1, + plotInstructions.yLabel='LSR HSR'; + plotInstructions.plotDivider=1; + end + plotInstructions.title='AN - spike probability'; + UTIL_plotMatrix(ANprobRateOutput, plotInstructions); + end +end + +%% plot efferent control values as dB +if options.showEfferent + plotInstructions=[]; + plotInstructions.figureNo=98; + figure(98), clf + plotInstructions.displaydt=dt; + plotInstructions.numPlots=2; + plotInstructions.subPlotNo=1; + plotInstructions.zValuesRange=[ -25 0]; + plotInstructions.title= ['AR strength. Signal level= ' ... + num2str(signalRMSdb,'%4.0f') ' dB SPL']; + UTIL_plotMatrix(20*log10(ARattenuation), plotInstructions); + + plotInstructions.subPlotNo=2; + plotInstructions.yValues= savedBFlist; + plotInstructions.yLabel= 'BF'; + plotInstructions.title= ['MOC strength']; + plotInstructions.zValuesRange=[ -25 0]; + subplot(2,1,2) + % imagesc(MOCattenuation) + UTIL_plotMatrix(20*log10(MOCattenuation), plotInstructions); + colorbar +end + + +%% ACF plot if required +if options.showACF + tic + method.dt=dt; + method.segmentNo=1; + method.nonlinCF=savedBFlist; + + minPitch= 80; maxPitch= 4000; numPitches=100; % specify lags + pitches=10.^ linspace(log10(minPitch), log10(maxPitch),numPitches); + pitches=fliplr(pitches); + filteredSACFParams.lags=1./pitches; % autocorrelation lags vector + filteredSACFParams.acfTau= .003; % time constant of running ACF + filteredSACFParams.lambda= 0.12; % slower filter to smooth ACF + filteredSACFParams.lambda= 0.01; % slower filter to smooth ACF + + filteredSACFParams.plotACFs=0; % special plot (see code) + filteredSACFParams.plotFilteredSACF=0; % 0 plots unfiltered ACFs + filteredSACFParams.plotMoviePauses=.3; % special plot (see code) + + filteredSACFParams.usePressnitzer=0; % attenuates ACF at long lags + filteredSACFParams.lagsProcedure= 'useAllLags'; + % filteredSACFParams.lagsProcedure= 'useBernsteinLagWeights'; + % filteredSACFParams.lagsProcedure= 'omitShortLags'; + filteredSACFParams.criterionForOmittingLags=3; + filteredSACFParams.plotACFsInterval=200; + + if filteredSACFParams.plotACFs + % plot original waveform on ACF plot + figure(13), clf + subplot(4,1,1) + t=dt*(1:length(savedInputSignal)); + plot(t,savedInputSignal) + xlim([0 t(end)]) + title(['stimulus: ' num2str(signalRMSdb, '%4.0f') ' dB SPL']); + end + + % plot original waveform on summary/smoothed ACF plot + figure(97), clf + subplot(2,1,1) + t=dt*(1:length(savedInputSignal)); + plot(t,savedInputSignal) + xlim([0 t(end)]) + title(['stimulus: ' num2str(signalRMSdb, '%4.0f') ' dB SPL']); + + + % compute ACF + switch saveAN_spikesOrProbability + case 'probability' + inputToACF=ANprobRateOutput.^0.5; + otherwise + inputToACF=ANoutput; + end + + disp ('computing ACF...') + [P, BFlist, sacf, boundaryValue] = ... + filteredSACF(inputToACF, method, filteredSACFParams); + disp(' ACF done.') + + % SACF + subplot(2,1,2) + imagesc(P) + ylabel('periodicities (Hz)') + xlabel('time (s)') + title(['running smoothed (root) SACF. ' saveAN_spikesOrProbability ' input']) + pt=[1 get(gca,'ytick')]; % force top xtick to show + set(gca,'ytick',pt) + set(gca,'ytickLabel', round(pitches(pt))) + tt=get(gca,'xtick'); + set(gca,'xtickLabel', round(100*t(tt))/100) +end + +path(restorePath) \ No newline at end of file diff -r 000000000000 -r f233164f4c86 testPrograms/test_MAP1_14.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/testPrograms/test_MAP1_14.m Fri May 27 13:19:21 2011 +0100 @@ -0,0 +1,128 @@ +function test_MAP1_14 + +% MAPdemo runs the MATLAB auditory periphery model (MAP1_14) as far as +% the AN (probabilities) or IC (spikes) with graphical output + +% Things you might want to change; #1 - #5 + +%% #1 parameter file name +MAPparamsName='Normal'; + + +%% #2 probability (fast) or spikes (slow) representation +AN_spikesOrProbability='spikes'; +% or +AN_spikesOrProbability='probability'; + + +%% #3 pure tone, harmonic sequence or speech file input +signalType= 'tones'; +duration=0.100; % seconds +sampleRate= 100000; +% toneFrequency= 250:250:8000; % harmonic sequence (Hz) +toneFrequency= 1000; % or a pure tone (Hz8 + +rampDuration=.005; % seconds + +% or +signalType= 'file'; +fileName='twister_44kHz'; +% fileName='new-da-44khz'; + + +%% #4 rms level +% signal details +leveldBSPL=70; % dB SPL + + +%% #5 number of channels in the model +% 21-channel model (log spacing) +numChannels=21; +lowestBF=250; highestBF= 8000; +BFlist=round(logspace(log10(lowestBF), log10(highestBF), numChannels)); + +% or specify your own channel BFs +% BFlist=1000; + + +%% #6 change model parameters +paramChanges=[]; + +% or +% Parameter changes can be used to change one or more model parameters +% *after* the MAPparams file has been read +% This example declares only one fiber type with a calcium clearance time +% constant of 80e-6 s (HSR fiber) when the probability option is selected. +switch AN_spikesOrProbability + case 'probability' + paramChanges={'IHCpreSynapseParams.tauCa=80e-6;'}; + otherwise + paramChanges=[]; +end + +%% delare showMap options +showMapOptions=[]; % use defaults + +% or (example: show everything including an smoothed SACF output + showMapOptions.showModelParameters=1; + showMapOptions.showModelOutput=1; + showMapOptions.printFiringRates=1; + showMapOptions.showACF=1; + showMapOptions.showEfferent=1; + +%% Generate stimuli + +dbstop if error +restorePath=path; +addpath (['..' filesep 'MAP'], ['..' filesep 'wavFileStore']) +switch signalType + case 'tones' + inputSignal=createMultiTone(sampleRate, toneFrequency, ... + leveldBSPL, duration, rampDuration); + + case 'file' + [inputSignal sampleRate]=wavread(fileName); + inputSignal(:,1); + targetRMS=20e-6*10^(leveldBSPL/20); + rms=(mean(inputSignal.^2))^0.5; + amp=targetRMS/rms; + inputSignal=inputSignal*amp; +end + + +%% run the model +tic + +MAP1_14(inputSignal, sampleRate, BFlist, ... + MAPparamsName, AN_spikesOrProbability, paramChanges); +toc + +% the model run is now complete. Now display the results +showMAP(showMapOptions) + +path(restorePath) + + +function inputSignal=createMultiTone(sampleRate, toneFrequency, ... + leveldBSPL, duration, rampDuration) +% Create pure tone stimulus +dt=1/sampleRate; % seconds +time=dt: dt: duration; +inputSignal=sum(sin(2*pi*toneFrequency'*time), 1); +amp=10^(leveldBSPL/20)*28e-6; % converts to Pascals (peak) +inputSignal=amp*inputSignal; + +% apply ramps +% catch rampTime error +if rampDuration>0.5*duration, rampDuration=duration/2; end +rampTime=dt:dt:rampDuration; +ramp=[0.5*(1+cos(2*pi*rampTime/(2*rampDuration)+pi)) ... + ones(1,length(time)-length(rampTime))]; +inputSignal=inputSignal.*ramp; +ramp=fliplr(ramp); +inputSignal=inputSignal.*ramp; + +% add 10 ms silence +silence= zeros(1,round(0.03/dt)); +inputSignal= [silence inputSignal silence]; + diff -r 000000000000 -r f233164f4c86 utilities/UTIL_CV.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/utilities/UTIL_CV.m Fri May 27 13:19:21 2011 +0100 @@ -0,0 +1,35 @@ +function [cv, cvTimes, allTimeStamps, allISIs]= UTIL_CV(earObject, dt, timeStep) +% UTIL_CV computes coefficient of variation for multiple spike trains +% earObject must be logical 0/1. Each row is a separate run +% CV is computed for successive time regions specified by timeStep + +if ~islogical(earObject),error('UTIL_CV: input is not logical/ spikes'), end + +[rows cols]=size(earObject); +totalDuration=cols*dt; + +if nargin<3, timeStep=totalDuration/5; end + +% identify all intervals +allISIs=[]; allTimeStamps=[]; +for i=1:rows + temp=find(earObject(i,:))*dt; % find spikes + isi{i}=diff(temp); % find ISIs + timeStamps{i}=temp(2:end); % time of isi is time of second spike + allISIs=[allISIs isi{i}]; + allTimeStamps=[allTimeStamps timeStamps{i}]; +end + +count=0; +cvTimes=0: timeStep:totalDuration-timeStep; % bin edges +for t= cvTimes + % sort ISIs according to when they happened + idx=find(allTimeStamps>t & allTimeStamps<=t+timeStep); + count=count+1; + if ~isempty(allISIs(idx)) + cv(count)=std(allISIs(idx))/mean(allISIs(idx)); + else + cv(count)=0; + end +end + diff -r 000000000000 -r f233164f4c86 utilities/UTIL_PSTHmaker.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/utilities/UTIL_PSTHmaker.m Fri May 27 13:19:21 2011 +0100 @@ -0,0 +1,40 @@ +function [PSTH dt]=UTIL_PSTHmaker(inputData, dt, PSTHbinWidth) +% UTIL_PSTHmaker accumulates values into bins. +% No corrections are applied +% usage: +% PSTH=UTIL_PSTHmaker(inputData, method) +% +% arguments +% inputData is a channel x time matrix +% PSTH is the reduced matrix, the sum of all elements in the bin +% +% mandatory fileds: +% method.dt +% method.PSTHbinWidth +[numChannels numDataPoints]= size(inputData); + +% Multiple fibers is the same as repeat trials +% Consolidate data into a histogram +dataPointsPerBin=round(PSTHbinWidth/dt); +if dataPointsPerBin<=1; +% Too few data points + PSTH=inputData; + return +end + +numBins=floor(numDataPoints/dataPointsPerBin); +PSTH=zeros(numChannels,numBins); + +% take care that signal length is an integer multiple of bin size +% by dropping the last unuseable values +useableDataLength=numBins*dataPointsPerBin; +inputData=inputData(:,1:useableDataLength); + +for ch=1:numChannels + % Convert each channel into a matrix where each column represents + % the content of a single PSTH bin + PSTH2D=reshape (inputData(ch,:), dataPointsPerBin, numBins ); + % and sum within each bin (across the rows + PSTH(ch,:)=sum (PSTH2D,1); +end + diff -r 000000000000 -r f233164f4c86 utilities/UTIL_makePSTH.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/utilities/UTIL_makePSTH.m Fri May 27 13:19:21 2011 +0100 @@ -0,0 +1,38 @@ +function PSTH =UTIL_makePSTH(inputData, dt, PSTHbinWidth) +% UTIL_PSTHmaker accumulates values into bins. +% No corrections are applied +% usage: +% PSTH=UTIL_makePSTH(inputData, dt, PSTHbinWidth) +% +% arguments +% inputData is a channel x time matrix +% PSTH is the reduced matrix, the sum of all elements in the bin +% + +[numChannels numDataPoints]= size(inputData); + +% Multiple fibers is the same as repeat trials +% Consolidate data into a histogram +dataPointsPerBin=round(PSTHbinWidth/dt); +if dataPointsPerBin<=1; +% Too few data points + PSTH=inputData; + return +end + +numBins=floor(numDataPoints/dataPointsPerBin); +PSTH=zeros(numChannels,numBins); + +% take care that signal length is an integer multiple of bin size +% by dropping the last unuseable values +useableDataLength=numBins*dataPointsPerBin; +inputData=inputData(:,1:useableDataLength); + +for ch=1:numChannels + % Convert each channel into a matrix where each column represents + % the content of a single PSTH bin + PSTH2D=reshape (inputData(ch,:), dataPointsPerBin, numBins ); + % and sum within each bin (across the rows + PSTH(ch,:)=sum (PSTH2D,1); +end + diff -r 000000000000 -r f233164f4c86 utilities/UTIL_paramsList.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/utilities/UTIL_paramsList.m Fri May 27 13:19:21 2011 +0100 @@ -0,0 +1,40 @@ +function paramsFound=UTIL_paramsList(myWhos) +% UTIL_paramsList looks for structures with names ending in Params. +% nm=UTIL_paramsList(whos); +% for i=1:length(nm), eval(['showStruct(' nm{i} ', ''' nm{i} ''')']),end + +% find structures ending with params +paramsUsedCount=0; +for i=1:length(myWhos) + var=myWhos(i).name; + if length(var)>5 + tag=var(end-5:end); + if strcmp(tag,'Params') + paramsUsedCount=paramsUsedCount+1; + paramsUsed{paramsUsedCount}=var; + end + end +end + + + +orderedList={'controlParams', 'globalStimParams', 'inputStimulusParams',... + 'OMEParams', 'DRNLParams', ... + 'IHC_cilia_RPParams', 'IHCpreSynapseParams', 'AN_IHCsynapseParams', ... + 'MacGregorMultiParams', 'MacGregorParams'}; + + +% check that they belong to the approved list +paramsFoundcount=0; +for i=1:length(orderedList) + for j=1:length(paramsUsed) + usedName=paramsUsed{j}; + if strcmp(orderedList{i},paramsUsed{j}) + paramsFoundcount=paramsFoundcount+1; + paramsFound{paramsFoundcount}=usedName; + end + end +end + +% return the list of names + diff -r 000000000000 -r f233164f4c86 utilities/UTIL_periodHistogram.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/utilities/UTIL_periodHistogram.m Fri May 27 13:19:21 2011 +0100 @@ -0,0 +1,49 @@ +function [PH, binTimes]=UTIL_periodHistogram(A, dt, frequency) +% UTIL_makePeriodHistogram converts a time sequence into a period histogram +%********************* +% The period is 1/frequency. +% +% usage: +% PH=UTIL_periodHistogram(A, dt, frequency) +% +% Input: +% A is a channel x time matrix of spikes (or other stuff) +% frequency determines the period of the histogram +% +% Output +% PH is a channel by periodhistogram matrix +% bintimes is useful for plotting the output +% + +periodInSeconds=1/frequency; +[numChannels signalNpoints]=size(A); + +% retrict data array to a multiple of the period. +pointsPerPeriod= round(periodInSeconds/dt); +NcompletePeriods=floor(signalNpoints/pointsPerPeriod); +totalPointsUsed=NcompletePeriods*pointsPerPeriod; + +% check that the period is a whole number of epochs +aliasing=NcompletePeriods*(periodInSeconds/dt-pointsPerPeriod); + +if aliasing>.1 + error('UTIL_periodHistogram: irregular period length') +end + +if NcompletePeriods<1 + error('UTIL_periodHistogram: too few datapoints') +end + +% transpose data so that time is down a column +A=A(:,1:totalPointsUsed)'; + +% knock it into shape +A=reshape(A,pointsPerPeriod, NcompletePeriods, numChannels); +% each period is a separate column +% imagesc(squeeze(A)) % should have horizontal stipe + +% channels are now the third dimension. +PH=squeeze(sum(A,2))'; +% PH=PH/NcompletePeriods; + +binTimes=dt:dt:pointsPerPeriod*dt; diff -r 000000000000 -r f233164f4c86 utilities/UTIL_plotMatrix.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/utilities/UTIL_plotMatrix.m Fri May 27 13:19:21 2011 +0100 @@ -0,0 +1,350 @@ +function UTIL_plotMatrix(toPlot, method) +% UTIL_plotMatrix general purpose plotting utility for plotting the results +% of the MAP auditory model. +% All plots are placed in subplots of a figure (default figure 1). +% Input arguments: +% 'toPlot' is matrix (either numeric or logical) +% 'method' is a structure containing plot instructions +% +% surface plots have log z-axis when all values are >1 +% +% when calling this function, always increment the subPlotNo in method +% method.subPlotNo=method.subPlotNo+1; +% method.subPlotNo=method.subPlotNo; +% +% mandatory parameters: +% method.displaydt xValues spacing between data points +% method.numPlots total number of subPlots in the figure +% method.subPlotNo number of this plot +% method.yValues mandatory only for 3D plots +% +% optional +% method.figureNo normally figure(1) +% method.zValuesRange [min max] value pair to define yaxis limits +% method.zValuesRange [min max] CLIMS for 3-D plot +% method.yLabel (string) y-axis label +% method.xLabel (string) x-axis label +% method.title (string) subplot title +% method.bar =1, to force bar histogram (single channel only) +% method.view 3D plot 'view' settings e.g. [-6 40] +% method.axes (handle) used for writing to GUIs (specifies panel) +% method.maxPixels maximum number of pixels (used to speed plotting) +% method.blackOnWhite =1; % NB inverts display for 2D plots +% method.forceLog positive values are put on log z-scale +% method.rasterDotSize min value is 1 +% method.defaultFontSize +% method.timeStart default=dt +% method.defaultTextColor default ='w' +% method.defaultAxesColor default = 'w' +% method.nCols default=1 +% method.nRows default=method.numPlots +% +% useful paste for calling program +% method.numPlots=method.numPlots; +% method.subPlotNo=method.subPlotNo+1; +% method.subPlotNo=method.subPlotNo; +% dt=dt; +% method.yValues=method.nonlinCF; % for 3D plots only +% +% method.figureNo=1; +% method.yLabel='useThisLabel'; +% method.xLabel='use this label'; +% method.title='myTitle'; +% +% UTIL_plotMatrix(toPlot, method) + +dt=method.displaydt; +if ~isfield(method,'figureNo') || isempty(method.figureNo) + method.figureNo=99; +end +% if ~isfield(method,'zValuesRange') || isempty(method.zValuesRange) +% method.zValuesRange=[-inf inf]; +% end + +% set some defaults +if ~isfield( method,'plotDivider') || isempty(method.plotDivider) + method.plotDivider=0; +end +if ~isfield( method,'blackOnWhite') || isempty(method.blackOnWhite) + method.blackOnWhite=0; +end +if ~isfield(method,'timeStart')|| isempty(method.timeStart) + method.timeStart=dt; +end +if ~isfield(method,'objectDuration') || isempty(method.objectDuration) + [nRows nCols]=size(toPlot); method.objectDuration=dt*nCols; +end +if ~isfield(method,'defaultFontSize') || isempty(method.defaultFontSize) + method.defaultFontSize=12; +end +if ~isfield(method,'defaultTextColor') || isempty(method.defaultTextColor) + method.defaultTextColor='k'; + defaultTextColor=method.defaultTextColor; +else + defaultTextColor='k'; +end +if ~isfield( method,'defaultAxesColor') || isempty(method.defaultAxesColor) + method.defaultAxesColor=defaultTextColor; +end +defaultAxesColor=method.defaultAxesColor; + +% arrangement of plots in rows and columns +if ~isfield(method,'nCols') || isempty(method.nRows) + method.nCols=1; +end +if ~isfield(method,'nRows') || isempty(method.nRows) + method.nRows= method.numPlots; +end + +if ~isfield(method,'rasterDotSize') || isempty(method.rasterDotSize) + rasterDotSize=1; +else + rasterDotSize=method.rasterDotSize; +end + +% user can specify either an independent axis +% or a subplot of the current figure +% if both are specified, 'axes' takes priority +figure(method.figureNo) +if isfield(method,'axes') && ~isempty(method.axes) + % select an axis in some location other than 'figure' + h=axes(method.axes); +else + % now using a regular figure + if method.subPlotNo>method.numPlots; + error('UTIL_plotMatrix: not enough subplots allocated in figure 1. Check method.numPlots') + end + % choose subplot + subplot(method.nRows,method.nCols,method.subPlotNo), % cla + + if isfield(method,'segmentNumber') && ~isempty(method.segmentNumber)... + && method.segmentNumber>1 + % in multi-segment mode do not clear the image + % from the previous segment + hold on + else + % otherwise a fresh image will be plotted + hold off + cla + end +end + +[numYvalues numXvalues]=size(toPlot); +xValues=method.timeStart:dt:method.timeStart+dt*(numXvalues-1); + +if isfield(method,'yValues') && ~isempty(method.yValues) + % yValues is normally a vector specifying channel BF + yValues=method.yValues; +else + yValues=1:numYvalues; +end + +% Now start the plot. +% 3D plotting for 4 or more channels +% otherwise special cases for fewer channels + +if ~islogical(toPlot) + % continuous variables + switch numYvalues + case 1 % single vector (black) + if isfield(method,'bar') && ~isempty(method.bar) + % histogram + bar(xValues, toPlot,'k') + method.bar=[]; % avoid carry over between modules + else + % waveform + plot(xValues, toPlot,'k') + end + xlim([0 method.objectDuration]) + if isfield(method,'zValuesRange') ... + && ~isempty(method.zValuesRange) + ylim(method.zValuesRange) + method.zValuesRange=[]; % avoid carry over between modules + end + if isfield(method,'yLabel') && ~isempty(method.yLabel) + ylabel(method.yLabel, 'color', defaultTextColor) + method.yLabel=[]; % avoid carry over between modules + end + + case 2 % 2 x N vector (black and red) + plot(xValues, toPlot(1,:),'k'), % hold on + plot(xValues, toPlot(2,:),'r'), % hold off + xlim([0 method.objectDuration]) + if isfield(method,'zValuesRange') ... + && ~isempty(method.zValuesRange) + ylim(method.zValuesRange) + method.zValuesRange=[]; % avoid carry over between modules + end + if isfield(method,'yLabel')&& ~isempty(method.yLabel) + ylabel(method.yLabel, 'color', defaultTextColor) + method.yLabel=[]; % avoid carry over between modules + end + + case 3 % 3 x N vector (black red and green) + % this is used for 1 channel DRNL output + plot(xValues, toPlot(1,:),'k'), hold on + plot(xValues, toPlot(2,:),'r'), hold on + plot(xValues, toPlot(3,:),'g'), hold off + xlim([0 method.objectDuration]) + if isfield(method,'zValuesRange') ... + && ~isempty(method.zValuesRange) + ylim(method.zValuesRange) + end + if isfield(method,'yLabel') && ~isempty(method.yLabel) + ylabel(method.yLabel, 'color', defaultTextColor) + end + + otherwise % >3 channels: surface plot + % add white line to separate HSR and LSR + if method.plotDivider && size(toPlot,1) > 2 + [r c]=size(toPlot); +% if isempty(method.zValuesRange), method.zValuesRange=0; end +% mm=method.zValuesRange(2); + emptyLine=max(max(toPlot))*ones(2,c); + halfway=round(r/2); + toPlot=[toPlot(1:halfway,:); emptyLine; toPlot(halfway+1:end,:)]; + end + + % invert data for black on white matrix plotting + if method.blackOnWhite + toPlot=-toPlot; + end + + % matrix (analogue) plot + if isfield(method,'forceLog') && ~isempty(method.forceLog) + % positive values are put on log z-scale + toPlot=toPlot+min(min(toPlot))+1; + toPlot=log(toPlot); + if isfield(method,'title') + method.title=[method.title ' (log scale)']; + else + method.title= '(log scale)'; + end + end + + % zValuesRange + if isfield(method,'zValuesRange') ... + && ~isempty(method.zValuesRange) + % zValuesRange gives the max and min values +% a=method.zValuesRange(1); +% b=method.zValuesRange(2); +% toPlot=(toPlot-a)/(b-a); +% clims=[0 1]; + clims=(method.zValuesRange); + imagesc(xValues, yValues, toPlot, clims), axis xy; %NB assumes equally spaced y-values + else + % automatically scaled + imagesc(xValues, yValues, toPlot), axis xy; %NB assumes equally spaced y-values + + % if ~isfield(method,'zValuesRange') + % method.zValuesRange=[-inf inf]; + % end + % + % if method.blackOnWhite + % % NB plotted values have negative sign for black on white + % caxis([-method.zValuesRange(2) -method.zValuesRange(1)]) + % else + % caxis(method.zValuesRange) + % end + + if ~isfield(method,'zValuesRange')... + || isempty(method.zValuesRange) + method.zValuesRange=[-inf inf]; + end + + if method.blackOnWhite + % NB plotted values have negative sign for black on white + caxis([-method.zValuesRange(2) -method.zValuesRange(1)]) + else + caxis(method.zValuesRange) + end + end + + % xaxis + % NB segmentation may shorten signal duration + [r c]=size(toPlot); + imageDuration=c*method.displaydt; + xlim([0 imageDuration]) +% xlim([0 method.objectDuration]) + + % yaxis + if isfield(method,'minyMaxy') && ~isempty(method.minyMaxy) + ylim(method.minyMaxy) + else + if max(yValues)>min(yValues) + ylim([min(yValues) max(yValues)]) + end + end + if min(yValues)>1 % put channel array on a log scale + tickValues=[min(yValues) max(yValues)]; + set(gca,'ytick',tickValues) + set(gca,'ytickLabel', strvcat(num2str(tickValues'))) + set(gca,'FontSize', method.defaultFontSize) + end + + end + +else % is logical + + % logical implies spike array. Use raster plot + [y,x]=find(toPlot); %locate all spikes: y is fiber number ie row + x=x*dt+method.timeStart; % x is time + plot(x,y, 'o', 'MarkerSize', rasterDotSize, 'color', 'k') + if numYvalues>1 + set(gca,'yScale','linear') + set(gca,'ytick', [1 numYvalues],'FontSize', method.defaultFontSize) + % show lowest and highest BF value only + set(gca,'ytickLabel', [min(yValues) max(yValues) ],'FontSize', method.defaultFontSize) + if method.plotDivider + % or use labels to identify fiber type + set(gca,'ytickLabel', {'LSR', 'HSR'},'FontSize', method.defaultFontSize) + end + ylim([0 numYvalues+1]) + end + xlim([0 method.objectDuration]) + if isfield(method,'yLabel') && ~isempty(method.yLabel) + ylabel(method.yLabel,'FontSize', method.defaultFontSize, 'color', defaultTextColor) + end + + % add line to separate HSR and LSR + if method.plotDivider + [r c]=size(toPlot); + halfWayUp=round(r/2); + hold on + plot([0 c*method.displaydt],[halfWayUp halfWayUp], 'b') + hold off + end +end + +set(gca, 'xcolor', defaultAxesColor) +set(gca, 'ycolor', defaultAxesColor) + +% add title +if isfield(method,'title') && ~isempty(method.title) + title(method.title, 'FontSize', method.defaultFontSize, 'color', defaultTextColor) +end + +% label axes +if ~isfield(method,'axes') || isempty(method.axes) + % annotate the x-axis only if it is the last plot on a figure created by this utility + set(gca,'xtick',[],'FontSize', method.defaultFontSize) + if method.subPlotNo==method.numPlots + if isfield(method,'xLabel') && ~isempty(method.xLabel) +% set(gca,'ActivePositionProperty','outerposition') + % xlabel(method.xLabel) + xlabel(method.xLabel, 'FontSize', method.defaultFontSize, 'color', defaultTextColor) + end + set(gca,'xtickmode','auto') % add timescale to the lowest graph + end +end + +% add user labels to the y-axis if requested +if isfield(method,'yLabel') && ~isempty(method.yLabel) + ylabel(method.yLabel, 'color', defaultTextColor) +end + +% define color +if method.blackOnWhite, colormap bone, else colormap jet +end + +% drawnow diff -r 000000000000 -r f233164f4c86 utilities/UTIL_printTabTable.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/utilities/UTIL_printTabTable.m Fri May 27 13:19:21 2011 +0100 @@ -0,0 +1,30 @@ +function UTIL_printTabTable(M, headers, format) +% printTabTable prints a matrix as a table with tabs +%headers are optional +%headers=strvcat('firstname', 'secondname') +% printTabTable([1 2; 3 4],strvcat('a1','a2')); + +if nargin<3 + format='%g'; +end + +if nargin>1 + [r c]=size(headers); + for no=1:r + fprintf('%s\t',headers(no,:)) + end + fprintf('\n') +end + +[r c]=size(M); + +for row=1:r + for col=1:c + fprintf('%s',num2str(M(row,col),format)) + if col '.' ' = ' +% e.g. +% showStruct(params,'params') % standard usage +%showStruct(params,'params', 0, ';') % adds final comma +%showStruct(params,'params', 1) % omits structure and field names + +if nargin<3, valuesOnly=0; end +if nargin<4, terminator=[]; end + +fields=fieldnames(eval('structure')); +for i=1:length(fields) + % y is the contents of this field + y=eval([ 'structure.' fields{i}]); + if ischar(y), + % strings + if valuesOnly + fprintf('\n%s', y) + else + fprintf('\n%s.%s=\t''%s%s''', name, fields{i},y,terminator) + end + elseif isnumeric(y) + % arrays + if length(y)>1 + % matrices and vectors + [r c]=size(y); + if r>c, y=y'; end % make row vector from column vector + [r c]=size(y); + + if r>10 + % large matrix + fprintf('\n%s.%s=\t%g x %g matrix',name, fields{i}, r, c) + + elseif r>1 + % small matrix + for row=1:r + fprintf('\n%s.%s(%1.0f)=\t%s;', name, fields{i},row, num2str(y(row,:))) + end + + elseif c>20 + % long row vector + fprintf('\n%s.%s=\t %g... [%g element array]%s',name, fields{i}, y(1),c, terminator) + + else + fprintf('\n%s.%s=\t[%s]%s', name, fields{i},num2str(y),terminator) + end + else + % single valued arrays + if valuesOnly + fprintf('\n%s%s', num2str(y), terminator) + else + fprintf('\n%s.%s=\t%s%s', name, fields{i},num2str(y), terminator) + end + + end % length (y) + elseif iscell(y) + fprintf('\n%s.%s=\t cell array', name, fields{i}) + + elseif isstruct(y) + fprintf('\n%s.%s=\t structure', name, fields{i}) + end % isstr/ numeric + +end % field +fprintf('\n') \ No newline at end of file diff -r 000000000000 -r f233164f4c86 utilities/UTIL_showStructureSummary.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/utilities/UTIL_showStructureSummary.m Fri May 27 13:19:21 2011 +0100 @@ -0,0 +1,55 @@ +function UTIL_showStructureSummary(structure, name, maxNoArrayValues) +% showStructureSummary prints out the values of a single structure +% The header is the structure name and each row is a field +% e.g. showStructureSummary(params,'params') +% This not the same as 'UTIL_showstruct' + + +if nargin<3 + maxNoArrayValues=20; +end + +fprintf('\n%s:', name) + +fields=fieldnames(eval('structure')); +% for each field in the structure +for i=1:length(fields) + y=eval([ 'structure.' fields{i}]); + if isstr(y), + % strings + fprintf('\n%s=\t''%s''', fields{i},y) + elseif isnumeric(y) + % arrays + if length(y)>1 + % vectors + [r c]=size(y); + if r>c, y=y'; end + + [r c]=size(y); + if r>1 + % fprintf('\n%s.%s=\t%g x %g matrix',name, fields{i}, r, c) + fprintf('\n%s=\t%g x %g matrix',fields{i}, r, c) + + elseif c2, + globalStimParams.doPlot=doPlot; +end + +% stimComponents(1,1).endSilence=-1; % end silence is always computed + +% perform checks and set defaults +[globalStimParams, stimComponents]=checkDescriptors(globalStimParams, stimComponents); + + +% create empty stereo audio of appropriate length +audio=zeros(globalStimParams.nSignalPoints, 2); +% signal=zeros(globalStimParams.nSignalPoints, 1); +dt=globalStimParams.dt; + +[Nears nComponentSounds]=size(stimComponents); +for ear=1:Nears % left/ right + % combinedSignal is the sum of all sounds in one ear + % it is a column vector + combinedSignal=zeros(globalStimParams.nSignalPoints,1); + + % find valid components + % if a component is empty, it is not a validComponent and is ignored + validStimComponents=[]; + for i=1:nComponentSounds + if ~isempty(stimComponents(ear,i).type) + validStimComponents=[validStimComponents i]; + end + end + + for componentNo=validStimComponents + % compute individual components before adding + stim=stimComponents(ear,componentNo); + switch stim.type + case 'tone' + stimulus=maketone(globalStimParams, stim); + + case 'fmTone' + stimulus=makeFMtone(globalStimParams, stim); + + case 'OHIO' + stim.beginSilence=0; + stimulus=makeOHIOtones(globalStimParams, stim); + + case 'transposedStimulus' + stim.beginSilence=0; % necessary because of recursion + stimulus=makeTransposedStimulus(globalStimParams, stim); + + case { 'noise', 'pinkNoise'} + stimulus=makeNoise(globalStimParams, stim); + + case { 'whiteNoise'} + stimulus=makeWhiteNoise(globalStimParams, stim); + + case {'IRN', 'irn'} + stimulus=makeIRN(globalStimParams, stim); + + case {'RPN'} + stimulus=makeRPN(globalStimParams, stim); + + case 'clicks' + stimulus=makeClicks(globalStimParams, stim); + + case 'PressnitzerClicks' + % kxx clicks + % k is 1/clickRepeatFrequency + stimulus=makePressnitzerClicks(globalStimParams, stimComponents); + + case 'PressnitzerABxClicks' + % kxx clicks + % k is 1/clickRepeatFrequency + stimulus=makePressnitzerABxClicks(globalStimParams, stimComponents); + + case 'ABxClicks' + % A=rand*k, B=k-A, x=rand*k. + stimulus=makeABxClicks(globalStimParams, stimComponents); + + case 'YostClicks' + % kxx clicks + % k is 1/clickRepeatFrequency + stimulus=makeYostClicks(globalStimParams, stimComponents); + + case 'kxxClicks' + % kxx clicks + % k is 1/clickRepeatFrequency + stimulus=makeKxxClicks(globalStimParams, stimComponents); + + +% case 'babble' +% % NB random start in a long file +% [stimulus sampleRate]= wavread('babble'); +% nPoints=round(sampleRate*... +% stimComponents(ear,componentNo).toneDuration); +% start=round(rand(1,1)*(length(stimulus)-nPoints)); +% stimulus=stimulus(start:start+nPoints-1); +% rms= 20*log10((mean(stimulus.^2).^0.5)/20e-6); +% dBSPLrms=stimComponents(ear,componentNo).amplitudesdB; +% gain=10.^((dBSPLrms-rms)/20); +% stimulus=stimulus'*gain; + + case 'speech' + [stimulus sampleRate]= wavread('speech'); + stimulus=stimulus'; + nPoints=sampleRate*stimComponents(ear,componentNo).toneDuration; + if nPoints > length(stimulus) + initialSilence=zeros(1,nPoints-length(stimulus)); + else + initialSilence=[]; + start=round(rand(1,1)*(length(stimulus)-nPoints)); + stimulus=stimulus(start:start+nPoints-1); + end + rms= 20*log10((mean(stimulus.^2).^0.5)/20e-6); + dBSPLrms=stimComponents(ear,componentNo).amplitudesdB; + gain=10.^((dBSPLrms-rms)/20); + stimulus=stimulus*gain; + stimulus=[stimulus initialSilence ]; + + + case 'file' + % component already read from file and stored in stimulus. Insert it here + % additional code for establishing signal rms level + % NB signal is always mono at this stage + + stimulus=stim.stimulus; + dBSPL=stim.amplitudesdB; + + nPoints=round(stim.toneDuration/dt); + [r c]=size(stimulus); + if r>c, stimulus=stimulus'; end % secure horizontal vector + stimulus=stimulus(1,1:nPoints); % only mono taken from file + + try + % dB rms + rms= 20*log10((mean(stimulus.^2).^0.5)/20e-6); + % special request to set fixed rms for stimulus + dBSPLrms=stimComponents(ear,componentNo).amplitudesdBrms; + if ~(dBSPLrms==-1) + gain=10.^((dBSPLrms-rms)/20); + stimulus=stimulus*gain; + end + catch + % If no request for rms level is made + % set dB as peak amp + [stimulus gain]= normalize(stimulus); + dBSPL=stimComponents(ear,componentNo).amplitudesdB; + if ~(dBSPL==-1) + amplitude=28e-6*10.^(dBSPL/20); + stimulus=stimulus*amplitude; + end + end + + case 'none' + % no stimulus + stimulus=zeros(1,round(stim.toneDuration/dt)); + + case 'digitStrings' + % select a digit string at random anduse as target + files=dir(['..' filesep '..' filesep 'multithresholdResources\digitStrings']); + files=files(3:end); + nFiles=length(files); + fileNo=ceil(nFiles*rand); + fileData=files(fileNo); + fileName=['..\..\multithresholdResources\digitStrings\' fileData.name]; + [stimulus sampleRate]=wavread(fileName); + stimulus=stimulus(:,1)'; % make into a row vector + % estimate the extend of endsilence padding + nPoints=sampleRate*... + stimComponents(ear,componentNo).toneDuration; + if nPoints > length(stimulus) + endSilence=zeros(1,nPoints-length(stimulus)); + else + % or truncate the file + endSilence=[]; + stimulus=stimulus(1:nPoints); + end + % compute rms before adding silence + rms= 20*log10((mean(stimulus.^2).^0.5)/20e-6); + dBSPLrms=stimComponents(ear,componentNo).amplitudesdB; + gain=10.^((dBSPLrms-rms)/20); + stimulus=stimulus*gain; + stimulus=[stimulus endSilence]; + global stimulusParameters + stimulusParameters.digitString=fileName(end-7:end-5); + + otherwise + switch stim.type(end-5:end) + % any file name with 'Babble' at the end is a + % multiThreshold file + case 'Babble' + % one of the many babbles is selected. + % NB random start in a long file + % stim.type should contain the name of the babble file + fileName=['..' filesep '..' filesep ... + 'multithresholdResources' filesep ... + 'backgrounds and maskers'... + filesep stim.type]; + + [stimulus sampleRate]= wavread(fileName); + if ~isequal(sampleRate, globalStimParams.FS) + % NB the file will read but will disagree with + % tone stimuli or other files read + msg= ['error: file sample rate disagrees ' ... + 'with sample rate requested in paradigm'... + ' file (' ... + num2str(globalStimParams.FS) ').']; + error(msg); + end + nPoints=round(sampleRate*... + stimComponents(ear,componentNo).toneDuration); + start=round(rand(1,1)*(length(stimulus)-nPoints)); + stimulus=stimulus(start:start+nPoints-1); + rms= 20*log10((mean(stimulus.^2).^0.5)/20e-6); + dBSPLrms=stimComponents(ear,componentNo).amplitudesdB; + gain=10.^((dBSPLrms-rms)/20); + stimulus=stimulus'*gain; + + otherwise + % stim.type may be the name of a file to be read + % play from beginning for stimulus duration + try + [stimulus sampleRate]= wavread([stim.type '.wav']); + catch + error(['stimulusCreate: unrecognised stimulus type -> '... + stim.type]) + end + if ~isequal(sampleRate, globalStimParams.FS) + % NB the file will read but will disagree with + % tone stimuli or other files read + msg= ['error: file sample rate disagrees ' ... + 'with sample rate requested in paradigm'... + ' file (' ... + num2str(globalStimParams.FS) ').']; + error(msg); + end + stimulus=stimulus'; % make into a row vector + % estimate the extend of endsilence padding + nPoints=sampleRate*... + stimComponents(ear,componentNo).toneDuration; + if nPoints > length(stimulus) + endSilence=zeros(1,nPoints-length(stimulus)); + else + % or truncate the file + endSilence=[]; + stimulus=stimulus(1:nPoints); + end + % compute rms before adding silence + rms= 20*log10((mean(stimulus.^2).^0.5)/20e-6); + dBSPLrms=stimComponents(ear,componentNo).amplitudesdB; + gain=10.^((dBSPLrms-rms)/20); + stimulus=stimulus*gain; + stimulus=[stimulus endSilence]; + end + end + + % NB stimulus is a row vector now! + % audio and combinedSignal were column vectors + % signal will be a row vector + + % filter stimulus + try + % if filter field is present, [lower upper order] + if stim.filter(1)>0 % 0 means don't filter + stimulus=Butterworth (stimulus, dt, stim.filter(1), ... + stim.filter(2), stim.filter(3)); + + end + catch + end + + + % apply amplitude modulation + if isfield(stim,'AMfrequency') & isfield(stim,'AMdepth') + if stim.AMfrequency>0 & stim.AMdepth>0 + time=dt:dt:dt*length(stimulus); + modulator=sin(2*pi*stim.AMfrequency*time); + modulator=modulator*stim.AMdepth/100 + 1; % depth is percent + stimulus=stimulus.*modulator/2; + end + end + + % Basic stimulus is now created. + % Add trappings, ramps, silences to main stimulus + rampOnTime=0; %ramp starts at the beginning of the stimulus + rampOffTime=stim.toneDuration-stim.rampOffDur; + if stim.rampOnDur>0.0001 + stimulus=applyRampOn(stimulus, stim.rampOnDur, rampOnTime, 1/dt); + stimulus=applyRampOff(stimulus, stim.rampOffDur, rampOffTime, 1/dt); + end + if stim.rampOnDur<-0.0001 % apply Gaussian ramp + stimulus=applyGaussianRamps(stimulus, -stim.rampOnDur, 1/dt); + end + + % Initial silence + % start with a signal of the right length consisting of zeros + signal=zeros(1, globalStimParams.nSignalPoints); + % identify start of stimulus + insertStimulusAt=round(stim.beginSilence/dt)+1; + % add stimulus + endOfStimulus=insertStimulusAt+length(stimulus)-1; + if endOfStimulus<=globalStimParams.nSignalPoints + signal(1, insertStimulusAt: endOfStimulus)=stimulus; + else + error('stimulusCreate: tone too long to fit into the overall duration') + end + + % time signature + time=dt:dt:dt*length(signal); + % figure(22), plot(signal), title([num2str(ear) ' - ' num2str(componentNo)]),pause (1) + + try + % create a column vector and trap if no signal has been created + signal=signal'; + % also traps if signals are not the same length + combinedSignal=combinedSignal+signal; + % figure(21), plot(combinedSignal), title([num2str(ear) ' - ' num2str(componentNo)]),pause (1) + catch + % dump everything because there is a problem + globalStimParams + [ear componentNo] + stim + size(combinedSignal) + size(signal) + [ size(initialSilence) size(signal) size(endSilence)] + [ ear componentNo... + round(globalStimParams.overallDuration*globalStimParams.FS)... + round(stim.beginSilence*globalStimParams.FS)... + round(stim.toneDuration*globalStimParams.FS) ... + round(stim.endSilence*globalStimParams.FS)... + ( round(globalStimParams.overallDuration*globalStimParams.FS)... + -round(stim.beginSilence*globalStimParams.FS)... + -round(stim.toneDuration*globalStimParams.FS) ... + -round(stim.endSilence*globalStimParams.FS))... + ] + error(' trouble in stimulusCreate: signals are the wrong length ') + end + + end % component no + + audio(:,ear)= combinedSignal; + + % FFT + try + if globalStimParams.FFT + showFFT (audio, dt) + end + catch + end + + +end % ear + +switch globalStimParams.ears + % normally the signals are created in appropriate ears but .ears can + % overide this to produce a mono signal. + case 'monoticL'; + % combine left and right ears to make a mono signal in the left ear + audio(:,1)=audio(:,1)+audio(:,2); + audio(:,2)=zeros(globalStimParams.nSignalPoints, 1); + + case 'monoticR'; + % combine left and right ears to make a mono signal in the right ear + audio(:,2)=audio(:,1)+audio(:,2); + audio(:,1)=zeros(globalStimParams.nSignalPoints, 1); + + case 'diotic'; + % combine left and right ears to make a mono signal in both ears + bothEarsCombined=audio(:,1)+audio(:,2); + audio(:,2)=bothEarsCombined; + audio(:,1)=bothEarsCombined; + + otherwise + % Any other denomination produces no effect here +end + +% Plotting as required +if globalStimParams.doPlot + figure(9), clf + plot(time,audio(:,1)'), hold on, + if Nears>1 + offSet=(max(audio(:,1))+max(audio(:,2)))/10; + offSet=2*offSet+max(audio(:,1))+max(audio(:,2)); + plot(time,audio(:,2)'+offSet,'r'), hold off + end + ylabel('left right') +end + +% Calibration +% all signals are divided by this correction factor +% peakAmp=globalStimParams.audioOutCorrection; % microPascals = 100 dB SPL + +audio=audio/globalStimParams.audioOutCorrection; + +if globalStimParams.doPlay + wavplay(audio,globalStimParams.FS) +end +% all Done +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + +%---------------------------------------------------- maketone +function tone=maketone(globalStimParams, stimComponents) +% maketone generates a stimComponents tone +% tone=maketone(dt, frequencies, toneDuration, dBSPL, phases) +% tone is returned in Pascals +% frequencies is a list of frequencies +% phase is list of phases or 'sin', 'cos', 'alt' +% +% defaults: +% phase = sin +% dBSPL=56 dB SPL + +dt=globalStimParams.dt; +frequencies=stimComponents.frequencies; +toneDuration=stimComponents.toneDuration; +dBSPL=stimComponents.amplitudesdB; +phases=stimComponents.phases; + +if ischar(phases) + switch phases + case 'sin' + phases= zeros(1,length(frequencies)); + case 'cos' + phases= pi/2*ones(1,length(frequencies)); + case 'alt' + phases= repmat([0 pi/2], 1, floor(length(frequencies)/2)); + if length(phases)1 + msg= 'click times must be <= than 1 (period)'; + return +end + +if clickWidth>=1/stimComponents.clickRepeatFrequency + msg= 'click width is too great for frequency'; + return +end + +duration=stimComponents.toneDuration; +totalLength=round(stimComponents.toneDuration/dt); +F0=stimComponents.clickRepeatFrequency; +F0=round(F0/dt)*dt; +if F0==-1 % single click required + F0=1/duration; + repetitions=1; + clickStartTimes=1; %clicktimes are fractions of a period +else + repetitions=round(F0*duration)-1; + duration=repetitions/F0; + clickStartTimes=clickTimes; +end +% if a clickTime=1 (end of duty period) set it to the beginning +clickStartTimes(clickStartTimes==1)=0; + +period=1/F0; +time=dt:dt:period; +nPoints=length(time); +signal=zeros(1,nPoints); +dBSPL=stimComponents.amplitudesdB; + +% compute click train for a single cycle +clickWidthNpoints=round(clickWidth*FS); +for i=1:length(clickStartTimes) + % if clickStartTimes(i)totalLength + clickTrain=clickTrain(1:totalLength); +elseif length(clickTrain)signalLength, break,end + intervalCount=intervalCount+1; + intervals(intervalCount)=kInterval; + + % repeat x intervals as required + if nXs>0 + for nX=1:nXs + xInterval=round(rand*twoK/dt); + timeIdx=timeIdx+xInterval; + if timeIdx>signalLength, break,end + intervalCount=intervalCount+1; + intervals(intervalCount)=xInterval; + end + end + if timeIdx>signalLength, break,end +end + +% shuffle intervals +if shuffled + randomNumbers=rand(1,length(intervals)); + [randomNumbers idx]=sort(randomNumbers); + intervals=intervals(idx); + idx=intervals>0; + intervals=intervals(idx); +end + +intervalCount=length(intervals); +signal(1)=clickHeight; +clickTime=0; +for i=1:intervalCount + clickTime=clickTime+intervals(i); + signal(clickTime:clickTime+clickWidthNpoints)=clickHeight; +end +signal=signal(1:signalLength); +% figure(1), plot(dt:dt:duration,signal) + +%--------------------------------------------------------------------makeKxxClicks +function signal=makeKxxClicks(globalStimParams, stimComponents) +% Click train consists of kkxxx.. sequences +% k is the duration of a fixed interval (seconds) +% random intervals are distributed 0 : 2* k (NB not like Pressnitzer clicks) +% nKs is the number of successive 'k' intervals +% nXs is the number of random intervals between k sequences +% sequences of 3 x intervals > k are replaced with new sequences +% shuffled causes all intervals to be reordered randomly +% NB 1/k is the mean click rate + +FS=globalStimParams.FS; % sample rate +dt=1/FS; + +try + k=stimComponents.k; % duration (s) of fixed intervals +catch + error('makeYostClicks: field ''k'' is missing from stimComponents') +end + +try + duration=stimComponents.toneDuration; +catch + error('makeYostClicks: field ''duration'' is missing from stimComponents') +end + +if isfield(stimComponents,'clickWidth') + clickWidth=stimComponents.clickWidth; +else + clickWidth=dt; +end + +if isfield(stimComponents,'clickHeight') + clickHeight=stimComponents.clickHeight; +else + clickHeight=28e-6 * 10^(stimComponents.amplitudesdB/20); +end + + +if isfield(stimComponents,'order') + order=stimComponents.order; +else + order=1; +end + +if isfield(stimComponents,'nKs') + nKs=stimComponents.nKs; +else + nKs=1; +end + +if isfield(stimComponents,'nXs') + nXs=stimComponents.nXs; +else + nXs=1; +end + +if isfield(stimComponents,'shuffled') + shuffled=stimComponents.shuffled; +else + shuffled=1; +end + +kLength=round(k/dt); % fixed interval +xLength=2*kLength; % maximum random interval +requiredSignalLength=round(duration/dt); +intervalsPerCycle=(nKs+nXs); +cycleLength=nKs*kLength+nXs*xLength; +% more cycles to allow for uncertainty +nCycles=5*round(requiredSignalLength/cycleLength); +nIntervals=nCycles*intervalsPerCycle; + +% random intervals +if nXs>0 + xIntervals=floor(rand(1,nIntervals)*2*kLength); + % weed out triple intervals > 2*k + rogues=1; + while sum(rogues) + y=(xIntervals>kLength); + rogues=(sum([y(1:end-2)' y(2:end-1)' y(3:end)'],2)>2); + xIntervals(rogues)=floor(rand*2*kLength); + end + xIntervals=reshape(xIntervals,nCycles,intervalsPerCycle); +else + xIntervals=[]; +end + +% insert constrained (k) intervals +if nKs>0 + switch order + case 1 + kIntervals=floor(ones(nCycles,nKs)*kLength); + case 2 + nKs=1; % force this + kIntervals=floor(rand(nCycles,1)*kLength); + kIntervals=[kIntervals kLength-kIntervals]; + end +else + kIntervals=[]; +end + +% combine fixed and random +intervals=[kIntervals xIntervals(:,nKs+1:end)]; +% make a single array; +[r c]=size(intervals); +intervals=reshape(intervals',1,r*c); + +% shuffle intervals +if shuffled + randomNumbers=rand(1,length(intervals)); + [randomNumbers idx]=sort(randomNumbers); + intervals=intervals(idx); + idx=intervals>0; + intervals=intervals(idx); +end + +% convert intervals to clicks +clickTimes=cumsum(intervals); +signal(clickTimes)=clickHeight; +signal=signal(1:requiredSignalLength); +% figure(1), clf, plot(signal) + + + +%--------------------------------------------------------------------makeNoise +function noise=makeNoise(globalStimParams, stimComponents) +% FS in Hz, noiseDuration in s, delay in s; +% noise is returned with overall level dB(rms) = amplitudesdB +% +% % You need +% +% stim.type='noise'; % or 'IRN', or 'pinkNoise' +% stim.toneDuration=.05; +% stim.amplitudesdB=50; +% stim.beginSilence=.01; +% stim.endSilence=-1; +% stim.rampOnDur=.002; +% stim.rampOffDur=-1; +% +% % Mandatory structure fields +% globalStimParams.FS=100000; +% globalStimParams.overallDuration=.1; % s +% globalStimParams.doPlot=1; +% globalStimParams.doPlay=1; +% +% [audio, msg]=stimulusCreate(globalStimParams, stim, ); +% +% % local +% stim.type='noise'; % or 'IRN' +% +FS=globalStimParams.FS; +noiseDuration= stimComponents.toneDuration; +npts=round(noiseDuration*FS); +noise=randn(1,npts); % NB randn (normally distributed) + +switch stimComponents.type + case 'pinkNoise' + % noise=UTIL_lowpassFilterFreq(noise, 100, 1/FS); + noise=UTIL_bandPassFilter(noise, 1, 100, 200, 1/FS,[]); +end + +rms=(mean(noise.^2)^.5); %should be 20 microPascals for 0 dB SPL +adjust=20e-6/rms; +noise=noise*adjust; +rms=(mean(noise.^2)^.5); +amplitude=10.^(stimComponents.amplitudesdB/20); +noise=amplitude*noise; +% rms=(mean(noise.^2)^.5); +% dBnoise=20*log10(rms/20e-6) + + +%--------------------------------------------------------------------makeWhiteNoise +function noise=makeWhiteNoise(globalStimParams, stimComponents) +% FS in Hz, noiseDuration in s, delay in s; +% noise is bandpass filtered between 100 and 10000 Hz +% spectrum level (dB/Hz) is 40 dB below nominal level. +% noise is returned with dB(rms) = amplitudesdB +% +% % You need +% +% stim.type='noise'; % or 'IRN', or 'pinkNoise' +% stim.toneDuration=.05; +% stim.amplitudesdB=50; +% stim.beginSilence=.01; +% stim.endSilence=-1; +% stim.rampOnDur=.002; +% stim.rampOffDur=-1; +% +% % Mandatory structure fields +% globalStimParams.FS=100000; +% globalStimParams.overallDuration=.1; % s +% globalStimParams.doPlot=1; +% globalStimParams.doPlay=1; +% +% [audio, msg]=stimulusCreate(globalStimParams, stim, ); +% +% % local +% stim.type='noise'; % or 'IRN' +% +FS=globalStimParams.FS; +noiseDuration= stimComponents.toneDuration; +npts=round(noiseDuration*FS); +noise=randn(1,npts); + +noise=UTIL_bandPassFilter (noise, 6, 100, 10000, 1/FS, []); + +rms=(mean(noise.^2)^.5); %should be 20 microPascals for 0 dB SPL +adjust=20e-6/rms; +noise=noise*adjust; +rms=(mean(noise.^2)^.5); +amplitude=10.^(stimComponents.amplitudesdB/20); +noise=amplitude*noise; +% rms=(mean(noise.^2)^.5); +% dBnoise=20*log10(rms/20e-6) + + +%-----------------------------------------------------------------makeIRN +function noise=makeIRN(globalStimParams, stimComponents) +% FS in Hz, noiseDuration in s, delay in s; +% noise is returned with dB(rms) = amplitudesdB +% +% % You need +% +% stim.type='noise'; % or 'IRN', or 'pinkNoise' +% stim.toneDuration=.05; +% stim.amplitudesdB=50; +% stim.beginSilence=.01; +% stim.endSilence=-1; +% stim.rampOnDur=.002; +% stim.rampOffDur=-1; +% +% % Mandatory structure fields +% globalStimParams.FS=100000; +% globalStimParams.overallDuration=.1; % s +% globalStimParams.doPlot=1; +% globalStimParams.doPlay=1; +% +% [audio, msg]=stimulusCreate(globalStimParams, stim, ); +% +% % local +% stim.type='noise'; % or 'IRN' +% % for IRN only +% stim.niterations = 8; %0 for white noise +% stim.delay = 1/150; +% stim.irnGain = 1; +% +FS=globalStimParams.FS; +noiseDuration= stimComponents.toneDuration; + +nIterations=stimComponents.niterations; +if nIterations==0 + % white noise is specified as nIterations=1 + nIterations=1; + IRNgain=0; + delay=0.01; % dummy +else + % IRN + delay=stimComponents.delay; + IRNgain=stimComponents.irnGain; +end + +npts=round(noiseDuration*FS); +dels=round(delay*FS); +noise=randn(1,npts); + +%fringe=nIterations*dels; +%npts=npts+fringe; + +for i=1:nIterations, + dnoise=[noise(dels+1:npts) noise(1:dels)]; + dnoise=dnoise.*IRNgain; + noise=noise+dnoise; +end; + +switch stimComponents.type + case 'pinkNoise' + noise=UTIL_lowpassFilterFreq(noise, 10000, 1/FS); +end + +rms=(mean(noise.^2)^.5); %should be 20 microPascals for 0 dB SPL +adjust=20e-6/rms; +noise=noise*adjust; +rms=(mean(noise.^2)^.5); +amplitude=10.^(stimComponents.amplitudesdB/20); +noise=amplitude*noise; +% rms=(mean(noise.^2)^.5); +% dBnoise=20*log10(rms/20e-6) + +%------------------------------------------------------------------ makeRPN +function RPN=makeRPN(globalStimParams, stim) +% 'period' is a collection of samples - AAABCD +% you need +% +% stim.type='RPN'; +% stim.toneDuration=.2; +% stim.amplitudesdB=50; +% stim.beginSilence=.01; +% stim.rampOnDur=.002; +% stim.rampOffDur=-1; +% +% stim.sampleDuration=.005; %200 Hz pitch +% stim.nSimilarSamples=5; % pitch strength +% stim.nIndependentSamples=1% dilutes strength +% +% % Mandatory structure fields +% globalStimParams.FS=44100; +% globalStimParams.overallDuration=.21; % s +% +% globalStimParams.doPlot=1; +% globalStimParams.doPlay=1; +% [audio, msg]=stimulusCreate(globalStimParams, stim); + +FS=globalStimParams.FS; +ptsPerSample=floor(stim.sampleDuration*FS); + +samplesPerPeriod=stim.nSimilarSamples+stim.nIndependentSamples; +periodDuration=samplesPerPeriod*stim.sampleDuration; + +totalNumPeriods=2*floor(stim.toneDuration/periodDuration); % longer than necessary +if totalNumPeriods<1 + error('stimulusCreate: RPN, stimulus duration needs to be longer') +end + +RPN=[]; +for j=1:totalNumPeriods + noise=randn(1,ptsPerSample); + for i=1:stim.nSimilarSamples + RPN=[RPN noise]; + end + + for i=1:stim.nIndependentSamples + noise=randn(1,ptsPerSample); + RPN=[RPN noise]; + end +end + +targetStimulusLength=round(stim.toneDuration/FS); +RPN=RPN(1:floor(stim.toneDuration*FS)); % take enough for stimulus + +rms=(mean(RPN.^2)^.5); %should be 20 microPascals for 0 dB SPL +adjust=20e-6/rms; +RPN=RPN*adjust; +rms=(mean(RPN.^2)^.5); +amplitude=10.^(stim.amplitudesdB/20); +RPN=amplitude*RPN; +% rms=(mean(noise.^2)^.5); +% dBnoise=20*log10(rms/20e-6) + +%--------------------------------------------------------------------applyRampOn +function signal=applyRampOn(signal, rampDur, rampOnTime, sampleRate) +%applyRampOn applies raised cosine ramp +%rampOntime is the time at which the ramp begins +%At all other times the mask has a value of 1 +%signal=applyRampOn(signal, rampDur, rampOnTime, sampleRate) + +rampDurPoints=round(rampDur*sampleRate); +rampOn= (1+cos(pi:pi/(rampDurPoints-1): 2*pi))/2'; + +sigDurPoints=length(signal); +mask(1:sigDurPoints)=1; +rampOnStartIndex=round(rampOnTime*sampleRate+1); +mask(rampOnStartIndex: rampOnStartIndex+ rampDurPoints-1)=rampOn; +signal=signal.*mask; +%plot(mask) + +%--------------------------------------------------------------------applyRampOff +function signal=applyRampOff(signal, rampDur, rampOffTime, sampleRate) +%applyRampOn applies raised cosine squared ramp +%rampOffTime is the time at which the ramp begins +%At all other times the mask has a value of 1 +% signal=applyRampOff(signal, rampDur, rampOffTime, sampleRate) + +rampDurPoints=round(rampDur*sampleRate); +rampOff= (1+cos(0:pi/(rampDurPoints-1): pi))/2'; + +sigDurPoints=length(signal); +mask=ones(1,sigDurPoints); +rampOffStartIndex=round(rampOffTime*sampleRate+1); +mask(rampOffStartIndex: round(rampOffStartIndex+ rampDurPoints-1))=rampOff; +if length(mask)>sigDurPoints, mask=mask(1:sigDurPoints); end +signal=signal.*mask; +%plot(mask) + +function signal=applyGaussianRamps(signal, sigma, sampleRate) +dt=1/sampleRate; +time=dt:dt:dt*length(signal); +ramp=1-exp(-time.^2/(2*sigma^2)); +% apply onset ramp +signal=signal.*ramp; +% apply offset ramp +ramp=fliplr(ramp); +signal=signal.*ramp; + + + +%--------------------------------------------------------------------checkDescriptors +function [globalStimParams, stimComponents]=checkDescriptors(globalStimParams, stimComponents); + +try + % if FS exists, it takes priority + globalStimParams.dt=1/globalStimParams.FS; +catch + % otherwise set FS using dt + globalStimParams.FS=1/globalStimParams.dt; +end + +globalStimParams.nSignalPoints=round(globalStimParams.overallDuration/globalStimParams.dt); + +% optional field (ears) +try + globalStimParams.ears; +catch + % default: dichotic. + globalStimParams.ears='dichotic'; +end + +% audioOutCorrection is optional +% audioOutCorrection is a scalar for reducing the sound +try + globalStimParams.audioOutCorrection; +catch + % set to 1 if omitted + globalStimParams.audioOutCorrection=1; +end + +try + globalStimParams.doPlay; +catch + % default plays sound only if explicitly requested + globalStimParams.doPlay=0; +end + +try + globalStimParams.doPlot; +catch + % no plotting unless explicitly requested + globalStimParams.doPlot=0; +end + + + +[ears nComponentSounds]=size(stimComponents); + +for ear=1:2 % 1=left/ 2=right + + % create a list of components whose type is specified + % if no type is specified assume that it is an empty specification + % this is allowed + validStimComponents=[]; + for i=1:nComponentSounds + try + if ~isempty(stimComponents(ear,i).type) + validStimComponents=[validStimComponents i]; + end + catch + end + end + + for componentNo=validStimComponents + % If no AM filed is present, create it for completeness + if ~isfield(stimComponents(ear,componentNo),'AMfrequency') |... + ~isfield(stimComponents(ear,componentNo),'AMdepth') + stimComponents(ear,componentNo).AMfrequency=0; + stimComponents(ear,componentNo).AMdepth=0; + end + + % all signals must have durations, amplitudes and ramps + if ... + isempty(stimComponents(ear,componentNo).type) |... + isempty(stimComponents(ear,componentNo).toneDuration) |... + isempty(stimComponents(ear,componentNo).amplitudesdB) |... + isempty(stimComponents(ear,componentNo).rampOnDur) + descriptorError( 'missing stimComponent descriptor', stimComponents, ear, componentNo) + end + + try, stimComponents(ear,componentNo).endSilence; catch, stimComponents(ear,componentNo).endSilence=-1; end + + % ramp checks do not apply to file input + if ~strcmp(stimComponents(ear,componentNo).type, 'file') + % match offset ramp to onset if not explicitly specified + if stimComponents(ear,componentNo).rampOffDur==-1, + stimComponents(ear,componentNo).rampOffDur=stimComponents(ear,componentNo).rampOnDur; + end + % ramps must be shorter than the stimulus + if stimComponents(ear,componentNo).rampOffDur> stimComponents(ear,componentNo).toneDuration | ... + stimComponents(ear,componentNo).rampOnDur> stimComponents(ear,componentNo).toneDuration + descriptorError( 'ramp longer than sound component', stimComponents, ear, componentNo) + end + end + + % end silence is measured to fit into the global duration + if stimComponents(ear,componentNo).endSilence==-1, + endSilenceNpoints=... + globalStimParams.nSignalPoints ... + -round(stimComponents(ear,componentNo).beginSilence*globalStimParams.FS)... + -round(stimComponents(ear,componentNo).toneDuration*globalStimParams.FS); + stimComponents(ear,componentNo).endSilence=endSilenceNpoints/globalStimParams.FS; + % if endSilence < 0, we have a problem + if stimComponents(ear,componentNo).endSilence<0 + globalStimParams + descriptorError( 'component durations greater than overallDuration', stimComponents, ear, componentNo) + end + end + + % check overall duration of this component against global duration + totalDuration= ... + stimComponents(ear,componentNo).beginSilence+... + stimComponents(ear,componentNo).toneDuration+... + stimComponents(ear,componentNo).endSilence; + + % avoid annoying error message for single stimulus component + if ears==1 && nComponentSounds==1 + globalStimParams.overallDuration= totalDuration; + end + + + if round(totalDuration*globalStimParams.FS)>round(globalStimParams.overallDuration*globalStimParams.FS) + globalStimParams + descriptorError( 'Component durations greater than overallDuration', stimComponents, ear, componentNo) + end + + % check total duration + totalSignalPoints= round((stimComponents(ear,componentNo).beginSilence+ stimComponents(ear,componentNo).toneDuration+... + stimComponents(ear,componentNo).endSilence)/globalStimParams.dt); + if totalSignalPoints >globalStimParams.nSignalPoints + descriptorError( 'Signal component duration does not match overall duration ', stimComponents, ear, componentNo) + end + + % no ramps for clicks please! + % if strcmp(stimComponents(ear,componentNo).type, 'clicks') & stimComponents(ear,componentNo).clickRepeatFrequency==-1 + % if strcmp(stimComponents(ear,componentNo).type, 'clicks') + % stimComponents(ear,componentNo).rampOnDur=0; + % stimComponents(ear,componentNo).rampOffDur=0; + % end + + if isfield(stimComponents(ear,componentNo), 'filter') + if ~isequal(length(stimComponents(ear,componentNo).filter), 3) + descriptorError( 'Filter parameter must have three elements ', stimComponents, ear, componentNo) + end + end + end % component + % ?? + if strcmp(globalStimParams.ears,'monoticL') | strcmp(globalStimParams.ears, 'monoticR'), break, end +end % ear + + +%-------------------------------------------------------------------- descriptorError +function descriptorError( msg, stimComponents, ear, componentNo) +stimComponents(ear, componentNo) + +disp(' *********** **************** ************') +disp([ '...Error in stimComponents description: ']) +disp([msg ]) +disp(['Ear = ' num2str(ear) ' component No ' num2str(componentNo)]) +disp(' *********** **************** ************') +error('myError ') + + +%-------------------------------------------------------------------- normalize +function [normalizedSignal, gain]= normalize(signal) +% normalize (signal) +maxSignal=max(max(signal)); +minSignal=min(min(signal)); +if -minSignal>maxSignal, normalizingFactor=-minSignal; else normalizingFactor=maxSignal; end +normalizingFactor=1.01*normalizingFactor; +gain= 20*log10(normalizingFactor); +normalizedSignal=signal/normalizingFactor; + + +%--------------------------------------------------------------------Butterworth +function y=Butterworth (x, dt, fl, fu, order) +% Butterworth (x, dt, fu, fl, order) +% Taken from Yuel and beauchamp page 261 +% NB error in their table for K (see their text) +% x is original signal +% fu, fl upper and lower cutoff +% order is the number of times the filter is applied + +q=(pi*dt*(fu-fl)); +J=1/(1+ cot(q)); +K= (2*cos(pi*dt*(fu+fl)))/(1+tan(q)*cos(q)); +L= (tan(q)-1)/(tan(q)+1); +b=[J -J]; +a=[1 -K -L]; +for i=1:order + y=filter(b, a, x); + x=y; +end + + +% -------------------------------------------------------- UTIL_amp2dB +function [y] = UTIL_amp2dB (x, ref) +% Calculates a dB (ref. ref) value 'y' from a peak amplitude number 'x'. +% if ref omitted treat as dB +% Check the number of arguments that are passed in. +if (nargin < 2) + ref=1; +end +if (nargin > 2) + error ('Too many arguments'); +end + +% Check arguments. +if x < 0.0 + error ('Can not calculate the log10 of a negative number'); +elseif x == 0.0 + warning ('log10 of zero. The result is set to -1000.0'); + y = -1000.0; +else + % Do calculations. + y = 20.0 * log10(x/(sqrt(2)*ref)); + +end + +%-------------------------------------------------------------------- FFT +function showFFT (getFFTsignal, dt) +color='r'; +figure(2), clf, +hold off + +% trim initial silence +idx=find(getFFTsignal>0); +if ~isempty(idx) + getFFTsignal=getFFTsignal(idx(1):end); +end +%trim final silence +getFFTsignal=getFFTsignal(end:-1:1); +idx=find(getFFTsignal>0); +if ~isempty(idx) + getFFTsignal=getFFTsignal(idx(1):end); + getFFTsignal=getFFTsignal(end:-1:1); +end + +% Analyse make stimComponents length a power of 2 +x=length(getFFTsignal); +squareLength=2; +while squareLength<=x + squareLength=squareLength*2; +end +squareLength=round(squareLength/2); +getFFTsignal=getFFTsignal(1:squareLength); +n=length(getFFTsignal); + +minf=100; maxf=20000; + +fft_result = fft(getFFTsignal, n); % Compute FFT of the input signal. +fft_power = fft_result .* conj(fft_result);% / n; % Compute power spectrum. Dividing by 'n' we get the power spectral density. +fft_phase = angle(fft_result); % Compute the phase spectrum. + +frequencies = (1/dt)*(1:n/2)/n; +fft_power=fft_power(1:length(fft_power)/2); % remove mirror frequencies +fft_phase=fft_phase(1:length(fft_phase)/2); % remove mirror frequencies +fft_powerdB = UTIL_amp2dB (fft_power, max(fft_power)); % convert to dB +% jags=find(diff(fft_phase)>0); % unwrap phase +% for i=jags, fft_phase(i+1:end)=fft_phase(i+1:end)-2*pi; end + +xlim([minf maxf]) +semilogx(frequencies, fft_powerdB-max(fft_powerdB), color) +ylim([ -20 5]) + + + +function y=UTIL_lowpassFilterFreq(x, cutOffFrequency, dt) +% UTIL_lowpassFilterFreq multi-channel filter +% +% Usage: +% output=UTIL_lowpassFilterFreq(input, cutOffFrequency, dt) +% +% cutoff should be around 100 Hz for audio work +% dt should be <1/50000 s for audio work +% +% Attenuation is - 6 dB per octave above cutoff. + + +sampleRate=1/dt; + +if 4*cutOffFrequency>sampleRate + warning(['UTIL_lowpassFilterFreq: sample rate ' num2str(1/dt) ' is too low for this BF. Sampling rate should be >' num2str(4*cutOffFrequency) 'or cutoff (' num2str(4*cutOffFrequency) ') should be lower' ]) + cutOffFrequency=sampleRate/4; +end + +tau=1/(2*pi*cutOffFrequency); + +y=zeros(size(x)); +[numChannels numPoints]=size(x); +for i=1:numChannels + y(i,:)=filter([dt/tau], [1 -(1-dt/tau)], x(i,:)); +end + + diff -r 000000000000 -r f233164f4c86 wavFileStore/new-ba-44khz.wav Binary file wavFileStore/new-ba-44khz.wav has changed diff -r 000000000000 -r f233164f4c86 wavFileStore/new-da-44khz.wav Binary file wavFileStore/new-da-44khz.wav has changed diff -r 000000000000 -r f233164f4c86 wavFileStore/new-da-44khz_olde.wav Binary file wavFileStore/new-da-44khz_olde.wav has changed diff -r 000000000000 -r f233164f4c86 wavFileStore/twister_44kHz.wav Binary file wavFileStore/twister_44kHz.wav has changed diff -r 000000000000 -r f233164f4c86 ~$P1_14 quick reference.doc Binary file ~$P1_14 quick reference.doc has changed