function q=QuestCreate(tGuess,tGuessSd,pThreshold,beta,delta,gamma,grain,range)
% q=QuestCreate(tGuess,tGuessSd,pThreshold,beta,delta,gamma,[grain],[range])
% Create a struct q with all the information necessary to measure
% threshold. Threshold "t" is measured on an abstract "intensity"
% scale, which usually corresponds to log10 contrast.
% 
% QuestCreate saves in struct q the parameters for a Weibull psychometric function:
% p2=delta*gamma+(1-delta)*(1-(1-gamma)*exp(-10.^(beta*(x2+xThreshold))));
% where x represents log10 contrast relative to threshold. The Weibull
% function itself appears only in QuestRecompute, which uses the
% specified parameter values in q to compute a psychometric function
% and store it in q. All the other Quest functions simply use the
% psychometric function stored in "q". QuestRecompute is called solely
% by QuestCreate and QuestBetaAnalysis (and possibly by a few user
% programs). Thus, if you prefer to use a different kind of
% psychometric function, called Foo, you need only create your own
% QuestCreateFoo, QuestRecomputeFoo, and (if you need it)
% QuestBetaAnalysisFoo, based on QuestCreate, QuestRecompute, and
% QuestBetaAnalysis, and you can use them with the rest of the Quest
% package unchanged. You would only be changing a few lines of code,
% so it would quite easy to do.
% 
% tGuess is your prior threshold estimate.
% tGuessSd is the standard deviation you assign to that guess.
% pThreshold is your threshold criterion expressed as probability of 
%	response==1. An intensity offset is introduced into the psychometric 
%	function so that threshold (i.e. the midpoint of the table) yields 
%	pThreshold.
% beta, delta, and gamma are the parameters of a Weibull psychometric function.
% beta controls the steepness of the psychometric function. Typically 3.5.
% delta is the fraction of trials on which the observer presses blindly. 
%	Typically 0.01.
% gamma is the fraction of trials that will generate response 1 when 
%	intensity==-inf.
% grain is the quantization of the internal table. E.g. 0.01.
% range is the intensity difference between the largest and smallest 
%	intensity that the internal table can store. E.g. 5. This interval will
% 	be centered on the initial guess tGuess, i.e. [tGuess-range/2, tGuess+range/2].
% 	QUEST assumes that intensities outside of this interval
% 	have zero prior probability, i.e. they are impossible.
% 
% See QuestCreate, QuestUpdate, QuestQuantile, QuestMean, QuestMode,
% QuestSd, and QuestSimulate.

% 6/8/96   dgp  Wrote it.
% 6/11/96  dgp  Optimized the order of stuffing for faster unstuffing.
% 11/10/96 dhb  Added warning about correctness after DGP told me.
% 3/1/97   dgp  Fixed error in sign of xThreshold in formula for p2.
% 3/1/97   dgp  Updated to use Matlab 5 structs.
% 3/3/97   dhb  Added missing semi-colon to first struct eval.
% 3/5/97   dgp  Fixed sd: use exp instead of 10^.
% 3/5/97   dgp  Added some explanation of the psychometric function.
% 6/24/97   dgp  For simulations, now allow specification of grain and dim.
% 9/30/98	dgp	Added "dim" fix from Richard Murray.
% 4/12/99 dgp dropped support for Matlab 4.
% 5/6/99 dgp Simplified "dim" calculation; just round up to even integer.
% 8/15/99   dgp  Explain how to use other kind of psychometric function.
% 2/10/02   dgp  Document grain and range.
% 
% Copyright (c) 1996-1999 Denis Pelli
if nargin<6 | nargin>8
	error('Usage: q=QuestCreate(tGuess,tGuessSd,pThreshold,beta,delta,gamma,[grain],[range])')
end
if nargin<7
	grain=0.01;
end
if nargin<8
	dim=500;
else
	if range<=0
		error('"range" must be greater than zero.')
	end
	dim=range/grain;
	dim=2*ceil(dim/2);	% round up to an even integer
end
q.updatePdf=1; % boolean, 1 for yes
q.warnPdf=1; % boolean, 1 for yes
q.normalizePdf=0;
q.tGuess=tGuess;
q.tGuessSd=tGuessSd;
q.pThreshold=pThreshold;
q.beta=beta;
q.delta=delta;
q.gamma=gamma;
q.grain=grain;
q.dim=dim;
q=QuestRecompute(q);

% THIS CODE WAS IN THE OLD VERSION. I'VE PASTED "q." INTO THE OBVIOUS PLACES.
% THIS IS RETAINED SOLELY TO HELP DEBUG ANY BUGS IN THE NEW CODE.
% % prepare all the arrays
% q.i=-dim/2:dim/2;
% q.x=i*grain;
% q.pdf=exp(-0.5*(q.x/tGuessSd).^2);
% q.pdf=q.pdf/sum(q.pdf);			% normalize the pdf 
% i2=-dim:dim;
% q.x2=i2*q.grain;
% q.p2=delta*gamma+(1-delta)*(1-(1-gamma)*exp(-10.^(beta*q.x2)));
% index=find(diff(q.p2)); 		% subset that is strictly monotonic
% q.xThreshold=interp1(q.p2(index),q.x2(index),q.pThreshold);
% q.p2=delta*gamma+(1-delta)*(1-(1-gamma)*exp(-10.^(beta*(q.x2+q.xThreshold))));
% q.s2=fliplr([1-q.p2;q.p2]);
% 
% % Best quantileOrder depends only on min and max of psychometric function.
% % For 2-interval forced choice, if pL=0.5 and pH=1 then best quantileOrder=0.60
% % We write x*log(x+eps) in place of x*log(x) to get zero instead of NAN when x is zero.
% pL=q.p2(1);
% pH=q.p2(end);
% pE=pH*log(pH+eps)-pL*log(pL+eps)+(1-pH+eps)*log(1-pH+eps)-(1-pL+eps)*log(1-pL+eps);
% pE=1/(1+exp(pE/(pL-pH)));
% q.quantileOrder=(pE-pL)/(pH-pL);
