function  P = PLExp2_params(level)

%PLEXP2_PARAMS -- Parameters for the Perceptual Learning Experiment 2
%
%  P = PLExp2_params()
%  P = PLExp2_params(level)
%
%  Master parameter structure for the main program PLEXP2 and its
%  subfunctions MAKE_PLE2_STIM, MAKE_PLE2_BACKGR, etc.
%
%  LEVEL 1 (default): as used in the main PLEXP2 (except 'movieStruct')
%  LEVEL 0: omit fields 'sounds', 'LUT', 'fixation', and 'keys'
%
%  See also PLEXP2, MAKE_PLE2_STIM, PLEXP1_PARAMS.

%  Original coding by Alexander Petrov, UC Irvine.
%  $Revision: 1.1 $  $Date: 2003/08/06 19:05 $

if (nargin < 1)  level = 1 ;   end   % default


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%   EQUIPMENT CHARACTERISTICS   %%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% NANAO Technology FlexScan 6600 paperwhite monitor with a P4 phosphor.
% Driven by the internal videocard of a Power Macintosh 7300/200.
% A special circuit combines two 8-bit output channels of the video-
% card to produce 24*256=6144 distinct gray levels (see MAKE_LINEAR_LUT).

viewing_dist = 720 ;  % milimeters, +/-10%
mm_pix = 0.5655 ;     % miliimeters/pixel [resol. 640x480, 19" monitor]
deg_pix = mm_pix/viewing_dist * 180/pi ;   % 0.045 degree/pixel, +/-10%

GAMMA = 1.50 ;        % voltage-to-luminance function of the monitor
%GAMMA = 1.95 ;       % value used in PLExp1
 % 10-30-01:  GAMMA = 1.91
 % 12-12-01:  GAMMA = 1.99
 % 11-06-02:  GAMMA = 1.74, max luminance = 29.6 cd/m^2
 % 07-30-03:  GAMMA = 1.50, max luminance = 21.6 cd/m^2
BRstep = 24 ;         % hardwired in the special circuit

msec_frame = 1000/120 ; % must be 8.3 msec/frame (120 Hz)



%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%   PARAMETER DEFINITIONS   %%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%-- Main parameters. Determined via pilot studies (see PILOT2.M).
% 64 pixels = 2.88 degrees of visual angle viewed from approx 720 mm.
P.size = [64 64] ;       % pixels, this scales everything else
P.duration = 75 ;        % msec, must be a multiple of MSEC_FRAME
P.Gabor_orient = [-10 +10] .* pi/180 ;
P.noise_orient = [-15 +15] .* pi/180 ;   % max power around +/-15 deg
P.noise_Cpeak = 0.66667 ;                % peak contrast of the noise
P.Gabor_Cpeak = [0.23 0.15 0.10 0.50] ;  % 3 difficulty levels + 1 demo
  % The peak contrasts 0.23, 0.15, and 0.10 were shown to yield approx.
  % 80%, 70%, and 60% correct for novice observers (see PILOT2.M).
  % The last value in the list is for demo trials only.

%-- Gabor parameters. See functions GABOR and GABOR_PARAMS for details
P.Gabor_params.phase = pi/2 ;
P.Gabor_params.freq = 2*deg_pix ;    % 2 cycles/deg --> 1/11.1 cycles/pix
P.Gabor_params.sigma = 0.4/deg_pix ; % 0.4 degrees --> 8.89 pixels

%-- Filtered noise parameters. See function MAKE_PLE2_BACKGR.
P.noise_params.sigma = 0.15 ;   % Gaussian with mean 0 and std.dev. SIGMA
P.noise_params.cutoff = 0.20 ;  % see BUTTERWORTH2 for details
P.noise_params.outcut = 4.0 ;   % FILTNOISE outlier cutoff

%-- CD-ROM containing the cached noise patches. See CACHE_PLE2_BACKGR.
NCache_params.N = 300 ;          % size(NOISE_CACHE) = [64,64,N]
if (strcmp(filesep,':'))         % Macintosh:  separator character = ':'
   NCache_params.path = 'PLE2_CACHE01' ;   % should be a valid alias
else       % assume it is Windows: separator character = '\'
   pathstr = fileparts(which('PLExp2_params'));  % 'C:\work\PLExp2\programs'
   idx = find(pathstr==filesep) ;                %     ^    ^      ^
   cutoff = idx(end)   ;                         %                 ^
   pathstr(cutoff:end) = [] ;                    % 'C:\work\PLExp2'
   NCache_params.path = fullfile(pathstr,'cache') ;
   %NCache_params.path = 'E:\' ;  % should point to the CD drive
end
NCache_params.fname = {'L01_%03d.mat','R01_%03d.mat'} ;  % L01_099.mat
P.NCache_params = NCache_params ;

%-- Lookup table parameters. See IMAGE/LUT_PARAMS and IMAGE/MAKE_SPLIT_LUT.
LUT_params.gamma = GAMMA ;
LUT_params.BRstep = BRstep ;
LUT_params.contrast = 1.0 ;     % use the full dynamic range of the monitor
LUT_params.domain = [0 255] ;
P.LUT_params = LUT_params ;

%-- Scaling parameters
P.viewing_dist = viewing_dist ;
P.mm_pix = mm_pix ;
P.deg_pix = deg_pix ;

%-- Convert time intervals from milliseconds to video frames
P.msec_frame = msec_frame ;
P.N_frames = round(P.duration / msec_frame) ;

%-- Trial parameters
dy = round(5.0/deg_pix) ;         % 5.0 degrees --> 111 pixels
P.position = {[0 -dy],[0 +dy]} ;  % dx=0, dy=+/-111 pixels off fixation
P.times.fix_onset = 0.500 ;     % fixation appears approx 500 msec before
P.times.alert_onset = 0.250 ;   % sound alert approx 250 msec before stim
P.times.fix2alert = P.times.fix_onset - P.times.alert_onset ;
P.times.ITI = 0.750 ;           % inter-trial interval, seconds
P.times.target_play = (P.N_frames+1)* msec_frame/1000 ; % + 1 blank frame
if (level>0)
  P.keys = {'sdfecSDFEC','jklimJKLIM'} ;   % {negKeys,posKeys}
end


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%   REUSABLE DATA STRUCTS   %%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%-- Everything happens in the following oval window
Xmin = -floor(P.size(1)/2) ; Ymin = -floor(P.size(2)/2) ;
[X,Y] = meshgrid([1:P.size(1)]+Xmin,[1:P.size(2)]+Ymin) ;
oval = (X.^2)./(Xmin.^2) + (Y.^2)./(Ymin.^2) ;
P.mask_idx = find(oval > 1) ;

%-- Calibrate GABOR_PARAMS so that the peak amplitude is 1.0
params = P.Gabor_params ;
params.amplit = 1.0 ;
params.orient = P.Gabor_orient(1) ;  % just for calibration
A = gabor(X,Y,params) ;
Cpeak = max(abs(A(:))) ;             % Cpeak < 1.0  because PHASE=pi/2
P.Gabor_params.amplit = params.amplit / Cpeak ;   % augment P
params.amplit = P.Gabor_params.amplit ;           % 1.0639

%-- Now make one Gabor patch for each orientation and difficulty level
P.Gabor = zeros([P.size length(P.Gabor_orient) length(P.Gabor_Cpeak)]) ;
for k = 1:length(P.Gabor_orient)
   params.orient = P.Gabor_orient(k) ;
   A = gabor(X,Y,params) ;
   for l = 1:length(P.Gabor_Cpeak)
      P.Gabor(:,:,k,l) = A .* P.Gabor_Cpeak(l) ;
   end
end
%-  Index of the pixel where each Gabor reaches maximum
A = P.Gabor(:,:,1) ;
[k,P.Gabor_argmax] = max(A(:)) ;      % = 1824 = (32,29)
% It should hold that  A(P.Gabor_argmax)==P.Gabor_Cpeak(1)

%-- Prepare filters for later calls to FILTNOISE
[Fx,Fy] = fftmesh(P.size) ;   % filter the noise patch
P.Filter = zeros([P.size length(P.noise_orient)]) ;
for k = 1:length(P.noise_orient)
   theta = P.noise_orient(k) + pi/2 ;     % orientation in Fourier space
   P.Filter(:,:,k) = butterworth2(Fx,Fy,theta,P.noise_params.cutoff) ;
end

%-- Lookup table (constructed here, installed later)
[LUT,gray] = make_linear_LUT(P.LUT_params) ;
if (level>0)  P.LUT = LUT ; end
% It should hold that LUMINANCE should be linear:
%    voltage = P.LUT(:,3) + P.LUT(:,1) ./ P.LUT_params.BRstep ;
%    luminance = voltage .^ P.LUT_params.gamma ; plot(luminance) ;
P.colors.black = P.LUT_params.domain(1) ;
P.colors.gray = gray ;
P.colors.white = P.LUT_params.domain(2) ;
P.LUT_params.span = min(gray-P.colors.black,P.colors.white-gray) ;

%-- Sounds
if (level>0)
  Rate = 2.2255e+004 ;   % Default sound sampling rate = Snd('DefaultRate')
  P.sounds.alert  = MakeBeep(500,0.100,Rate) ;  % 500 Hz, 100 msec
  P.sounds.badkey = MakeBeep(300,0.150,Rate) ;  % 300 Hz, 150 msec
  P.sounds.wrong  = P.sounds.badkey ;           % feedback on demo trials
end

%-- Fixation crosshair
if (level>0)
  P.fixation = repmat(gray,9,9) ;
  P.fixation(:,[4:6]) = P.colors.black ;
  P.fixation([4:6],:) = P.colors.black ;
  P.blank = repmat(gray,P.size) ;         % used to clear screen
end


%--- Return P
%%%%% End of file PLEXP2_PARAMS.M
