annotate utilities/stimulusCreate.m @ 0:f233164f4c86

first commit
author Ray Meddis <rmeddis@essex.ac.uk>
date Fri, 27 May 2011 13:19:21 +0100
parents
children 1a502830d462
rev   line source
rmeddis@0 1 function [audio, msg, time]=stimulusCreate(globalStimParams,...
rmeddis@0 2 stimComponents, doPlot)
rmeddis@0 3 % updated June 2007
rmeddis@0 4 % the only authorised version of stimulus create is the version to be found
rmeddis@0 5 % in MAP1_6. Other versions are copies!!
rmeddis@0 6 %
rmeddis@0 7 % for a simple tone you need
rmeddis@0 8 %
rmeddis@0 9 % % Mandatory structure fields
rmeddis@0 10 % globalStimParams.FS=100000;
rmeddis@0 11 % globalStimParams.overallDuration=.1; % s
rmeddis@0 12 % doPlot=1;
rmeddis@0 13 %
rmeddis@0 14 % stim.type='tone';
rmeddis@0 15 % stim.phases='sin';
rmeddis@0 16 % stim.toneDuration=.05;;
rmeddis@0 17 % stim.frequencies=500;
rmeddis@0 18 % stim.amplitudesdB=50;
rmeddis@0 19 % stim.beginSilence=.01;
rmeddis@0 20 % stim.endSilence=-1;
rmeddis@0 21 % stim.rampOnDur=.002;
rmeddis@0 22 % stim.rampOffDur=-1;
rmeddis@0 23 % [audio, msg]=stimulusCreate(globalStimParams, stim, doPlot);
rmeddis@0 24 %
rmeddis@0 25 % % or for multi-component stimuli
rmeddis@0 26 % % Mandatory structure fields
rmeddis@0 27 % globalStimParams.FS=100000;
rmeddis@0 28 % globalStimParams.overallDuration=.1; % s
rmeddis@0 29 % ear=1;
rmeddis@0 30 % componentNo=1;
rmeddis@0 31 %
rmeddis@0 32 % stimComponents(ear, componentNo).type='tone';
rmeddis@0 33 % stimComponents(ear, componentNo).phases='sin';
rmeddis@0 34 % stimComponents(ear, componentNo).toneDuration=.05;;
rmeddis@0 35 % stimComponents(ear, componentNo).frequencies=500;
rmeddis@0 36 % stimComponents(ear, componentNo).amplitudesdB=50;
rmeddis@0 37 % stimComponents(ear, componentNo).beginSilence=.01;
rmeddis@0 38 % stimComponents(ear, componentNo).endSilence=-1;
rmeddis@0 39 % stimComponents(ear, componentNo).rampOnDur=.002;
rmeddis@0 40 % stimComponents(ear, componentNo).rampOffDur=-1;
rmeddis@0 41 %
rmeddis@0 42 % % All components are forced to have the same overall duration and sample rate
rmeddis@0 43 %
rmeddis@0 44 %
rmeddis@0 45 % [audio, msg]=stimulusCreate(globalStimParams, stimComponents);
rmeddis@0 46 %
rmeddis@0 47 % Optional fields
rmeddis@0 48 % .ears overides ear setting by component
rmeddis@0 49 % globalStimParams.ears='monoticL'; % 'monoticL', 'monoticR', 'diotic', 'dichotic'
rmeddis@0 50 %
rmeddis@0 51 % globalStimParams.filter = [leftfl leftfu rightfl right fu]
rmeddis@0 52 % filter is applied separately to left and right combined sounds
rmeddis@0 53 %
rmeddis@0 54 % correction factor is applied to all signals to compensate for differences in output devices.
rmeddis@0 55 % audioOutCorrection is a scalar
rmeddis@0 56 % globalStimParams.audioOutCorrection=2;
rmeddis@0 57 %
rmeddis@0 58 % globalStimParams.FFT= 1; % {0, 1}
rmeddis@0 59 % globalStimParams.doPlot=1; % {0, 1}
rmeddis@0 60 % globalStimParams.doPlay=1; % {0, 1}
rmeddis@0 61 %
rmeddis@0 62 % stimComponents(ear, componentNo).filter=[100 10000 2] % [lower, upper, order] applies to an
rmeddis@0 63 % individual component
rmeddis@0 64 %
rmeddis@0 65 % Output arguments:
rmeddis@0 66 % audio is a stereo signal, a 2-column vector
rmeddis@0 67 %
rmeddis@0 68 %
rmeddis@0 69 % stim.type='noise'; % {'IRN', 'irn', 'noise', 'pinkNoise'}
rmeddis@0 70 % stim.toneDuration=.05;;
rmeddis@0 71 % stim.amplitudesdB=50;
rmeddis@0 72 % stim.beginSilence=.01;
rmeddis@0 73 % stim.endSilence=-1;
rmeddis@0 74 % stim.rampOnDur=.002;
rmeddis@0 75 % stim.rampOffDur=-1;
rmeddis@0 76 % [audio, msg]=stimulusCreate(globalStimParams, stim);
rmeddis@0 77 %
rmeddis@0 78 % % for IRN only
rmeddis@0 79 % stim.type='IRN';
rmeddis@0 80 % stim.toneDuration=.05;;
rmeddis@0 81 % stim.amplitudesdB=50;
rmeddis@0 82 % stim.beginSilence=.01;
rmeddis@0 83 % stim.endSilence=-1;
rmeddis@0 84 % stim.rampOnDur=.002;
rmeddis@0 85 % stim.rampOffDur=-1;
rmeddis@0 86 % stim.niterations = 8; %0 for white noise
rmeddis@0 87 % stim.delay = 1/150;
rmeddis@0 88 % stim.irnGain = 1;
rmeddis@0 89 % [audio, msg]=stimulusCreate(globalStimParams, stim);stimComponents.clickWidth;
rmeddis@0 90 %
rmeddis@0 91 % stim.type='clicks'; % uses frequencies for duty cycle
rmeddis@0 92 % stim.toneDuration=.05;;
rmeddis@0 93 % stim.frequencies=500;
rmeddis@0 94 % stim.amplitudesdB=50;
rmeddis@0 95 % stim.beginSilence=.01;
rmeddis@0 96 % stim.endSilence=-1;
rmeddis@0 97 % stim.rampOnDur=.002;
rmeddis@0 98 % stim.rampOffDur=-1;
rmeddis@0 99 % [audio, msg]=stimulusCreate(globalStimParams, stim);
rmeddis@0 100 % stimComponents.clickWidth=.0001; % default= dt
rmeddis@0 101 % stimComponents.clickHeight= 20e-6; % default= 28e-6 * 10^(stimComponents.amplitudesdB/20);
rmeddis@0 102 % stim.clickTimes=[.4 .6]; % times in cylce when clicks occur, default = 1
rmeddis@0 103 %
rmeddis@0 104 %
rmeddis@0 105
rmeddis@0 106 msg=''; %error messages; no message is a good message
rmeddis@0 107
rmeddis@0 108 % plotting can be set as a separate argument or as a globalstimParams
rmeddis@0 109 % variable. this is for backwards compatibility only
rmeddis@0 110 if nargin>2,
rmeddis@0 111 globalStimParams.doPlot=doPlot;
rmeddis@0 112 end
rmeddis@0 113
rmeddis@0 114 % stimComponents(1,1).endSilence=-1; % end silence is always computed
rmeddis@0 115
rmeddis@0 116 % perform checks and set defaults
rmeddis@0 117 [globalStimParams, stimComponents]=checkDescriptors(globalStimParams, stimComponents);
rmeddis@0 118
rmeddis@0 119
rmeddis@0 120 % create empty stereo audio of appropriate length
rmeddis@0 121 audio=zeros(globalStimParams.nSignalPoints, 2);
rmeddis@0 122 % signal=zeros(globalStimParams.nSignalPoints, 1);
rmeddis@0 123 dt=globalStimParams.dt;
rmeddis@0 124
rmeddis@0 125 [Nears nComponentSounds]=size(stimComponents);
rmeddis@0 126 for ear=1:Nears % left/ right
rmeddis@0 127 % combinedSignal is the sum of all sounds in one ear
rmeddis@0 128 % it is a column vector
rmeddis@0 129 combinedSignal=zeros(globalStimParams.nSignalPoints,1);
rmeddis@0 130
rmeddis@0 131 % find valid components
rmeddis@0 132 % if a component is empty, it is not a validComponent and is ignored
rmeddis@0 133 validStimComponents=[];
rmeddis@0 134 for i=1:nComponentSounds
rmeddis@0 135 if ~isempty(stimComponents(ear,i).type)
rmeddis@0 136 validStimComponents=[validStimComponents i];
rmeddis@0 137 end
rmeddis@0 138 end
rmeddis@0 139
rmeddis@0 140 for componentNo=validStimComponents
rmeddis@0 141 % compute individual components before adding
rmeddis@0 142 stim=stimComponents(ear,componentNo);
rmeddis@0 143 switch stim.type
rmeddis@0 144 case 'tone'
rmeddis@0 145 stimulus=maketone(globalStimParams, stim);
rmeddis@0 146
rmeddis@0 147 case 'fmTone'
rmeddis@0 148 stimulus=makeFMtone(globalStimParams, stim);
rmeddis@0 149
rmeddis@0 150 case 'OHIO'
rmeddis@0 151 stim.beginSilence=0;
rmeddis@0 152 stimulus=makeOHIOtones(globalStimParams, stim);
rmeddis@0 153
rmeddis@0 154 case 'transposedStimulus'
rmeddis@0 155 stim.beginSilence=0; % necessary because of recursion
rmeddis@0 156 stimulus=makeTransposedStimulus(globalStimParams, stim);
rmeddis@0 157
rmeddis@0 158 case { 'noise', 'pinkNoise'}
rmeddis@0 159 stimulus=makeNoise(globalStimParams, stim);
rmeddis@0 160
rmeddis@0 161 case { 'whiteNoise'}
rmeddis@0 162 stimulus=makeWhiteNoise(globalStimParams, stim);
rmeddis@0 163
rmeddis@0 164 case {'IRN', 'irn'}
rmeddis@0 165 stimulus=makeIRN(globalStimParams, stim);
rmeddis@0 166
rmeddis@0 167 case {'RPN'}
rmeddis@0 168 stimulus=makeRPN(globalStimParams, stim);
rmeddis@0 169
rmeddis@0 170 case 'clicks'
rmeddis@0 171 stimulus=makeClicks(globalStimParams, stim);
rmeddis@0 172
rmeddis@0 173 case 'PressnitzerClicks'
rmeddis@0 174 % kxx clicks
rmeddis@0 175 % k is 1/clickRepeatFrequency
rmeddis@0 176 stimulus=makePressnitzerClicks(globalStimParams, stimComponents);
rmeddis@0 177
rmeddis@0 178 case 'PressnitzerABxClicks'
rmeddis@0 179 % kxx clicks
rmeddis@0 180 % k is 1/clickRepeatFrequency
rmeddis@0 181 stimulus=makePressnitzerABxClicks(globalStimParams, stimComponents);
rmeddis@0 182
rmeddis@0 183 case 'ABxClicks'
rmeddis@0 184 % A=rand*k, B=k-A, x=rand*k.
rmeddis@0 185 stimulus=makeABxClicks(globalStimParams, stimComponents);
rmeddis@0 186
rmeddis@0 187 case 'YostClicks'
rmeddis@0 188 % kxx clicks
rmeddis@0 189 % k is 1/clickRepeatFrequency
rmeddis@0 190 stimulus=makeYostClicks(globalStimParams, stimComponents);
rmeddis@0 191
rmeddis@0 192 case 'kxxClicks'
rmeddis@0 193 % kxx clicks
rmeddis@0 194 % k is 1/clickRepeatFrequency
rmeddis@0 195 stimulus=makeKxxClicks(globalStimParams, stimComponents);
rmeddis@0 196
rmeddis@0 197
rmeddis@0 198 % case 'babble'
rmeddis@0 199 % % NB random start in a long file
rmeddis@0 200 % [stimulus sampleRate]= wavread('babble');
rmeddis@0 201 % nPoints=round(sampleRate*...
rmeddis@0 202 % stimComponents(ear,componentNo).toneDuration);
rmeddis@0 203 % start=round(rand(1,1)*(length(stimulus)-nPoints));
rmeddis@0 204 % stimulus=stimulus(start:start+nPoints-1);
rmeddis@0 205 % rms= 20*log10((mean(stimulus.^2).^0.5)/20e-6);
rmeddis@0 206 % dBSPLrms=stimComponents(ear,componentNo).amplitudesdB;
rmeddis@0 207 % gain=10.^((dBSPLrms-rms)/20);
rmeddis@0 208 % stimulus=stimulus'*gain;
rmeddis@0 209
rmeddis@0 210 case 'speech'
rmeddis@0 211 [stimulus sampleRate]= wavread('speech');
rmeddis@0 212 stimulus=stimulus';
rmeddis@0 213 nPoints=sampleRate*stimComponents(ear,componentNo).toneDuration;
rmeddis@0 214 if nPoints > length(stimulus)
rmeddis@0 215 initialSilence=zeros(1,nPoints-length(stimulus));
rmeddis@0 216 else
rmeddis@0 217 initialSilence=[];
rmeddis@0 218 start=round(rand(1,1)*(length(stimulus)-nPoints));
rmeddis@0 219 stimulus=stimulus(start:start+nPoints-1);
rmeddis@0 220 end
rmeddis@0 221 rms= 20*log10((mean(stimulus.^2).^0.5)/20e-6);
rmeddis@0 222 dBSPLrms=stimComponents(ear,componentNo).amplitudesdB;
rmeddis@0 223 gain=10.^((dBSPLrms-rms)/20);
rmeddis@0 224 stimulus=stimulus*gain;
rmeddis@0 225 stimulus=[stimulus initialSilence ];
rmeddis@0 226
rmeddis@0 227
rmeddis@0 228 case 'file'
rmeddis@0 229 % component already read from file and stored in stimulus. Insert it here
rmeddis@0 230 % additional code for establishing signal rms level
rmeddis@0 231 % NB signal is always mono at this stage
rmeddis@0 232
rmeddis@0 233 stimulus=stim.stimulus;
rmeddis@0 234 dBSPL=stim.amplitudesdB;
rmeddis@0 235
rmeddis@0 236 nPoints=round(stim.toneDuration/dt);
rmeddis@0 237 [r c]=size(stimulus);
rmeddis@0 238 if r>c, stimulus=stimulus'; end % secure horizontal vector
rmeddis@0 239 stimulus=stimulus(1,1:nPoints); % only mono taken from file
rmeddis@0 240
rmeddis@0 241 try
rmeddis@0 242 % dB rms
rmeddis@0 243 rms= 20*log10((mean(stimulus.^2).^0.5)/20e-6);
rmeddis@0 244 % special request to set fixed rms for stimulus
rmeddis@0 245 dBSPLrms=stimComponents(ear,componentNo).amplitudesdBrms;
rmeddis@0 246 if ~(dBSPLrms==-1)
rmeddis@0 247 gain=10.^((dBSPLrms-rms)/20);
rmeddis@0 248 stimulus=stimulus*gain;
rmeddis@0 249 end
rmeddis@0 250 catch
rmeddis@0 251 % If no request for rms level is made
rmeddis@0 252 % set dB as peak amp
rmeddis@0 253 [stimulus gain]= normalize(stimulus);
rmeddis@0 254 dBSPL=stimComponents(ear,componentNo).amplitudesdB;
rmeddis@0 255 if ~(dBSPL==-1)
rmeddis@0 256 amplitude=28e-6*10.^(dBSPL/20);
rmeddis@0 257 stimulus=stimulus*amplitude;
rmeddis@0 258 end
rmeddis@0 259 end
rmeddis@0 260
rmeddis@0 261 case 'none'
rmeddis@0 262 % no stimulus
rmeddis@0 263 stimulus=zeros(1,round(stim.toneDuration/dt));
rmeddis@0 264
rmeddis@0 265 case 'digitStrings'
rmeddis@0 266 % select a digit string at random anduse as target
rmeddis@0 267 files=dir(['..' filesep '..' filesep 'multithresholdResources\digitStrings']);
rmeddis@0 268 files=files(3:end);
rmeddis@0 269 nFiles=length(files);
rmeddis@0 270 fileNo=ceil(nFiles*rand);
rmeddis@0 271 fileData=files(fileNo);
rmeddis@0 272 fileName=['..\..\multithresholdResources\digitStrings\' fileData.name];
rmeddis@0 273 [stimulus sampleRate]=wavread(fileName);
rmeddis@0 274 stimulus=stimulus(:,1)'; % make into a row vector
rmeddis@0 275 % estimate the extend of endsilence padding
rmeddis@0 276 nPoints=sampleRate*...
rmeddis@0 277 stimComponents(ear,componentNo).toneDuration;
rmeddis@0 278 if nPoints > length(stimulus)
rmeddis@0 279 endSilence=zeros(1,nPoints-length(stimulus));
rmeddis@0 280 else
rmeddis@0 281 % or truncate the file
rmeddis@0 282 endSilence=[];
rmeddis@0 283 stimulus=stimulus(1:nPoints);
rmeddis@0 284 end
rmeddis@0 285 % compute rms before adding silence
rmeddis@0 286 rms= 20*log10((mean(stimulus.^2).^0.5)/20e-6);
rmeddis@0 287 dBSPLrms=stimComponents(ear,componentNo).amplitudesdB;
rmeddis@0 288 gain=10.^((dBSPLrms-rms)/20);
rmeddis@0 289 stimulus=stimulus*gain;
rmeddis@0 290 stimulus=[stimulus endSilence];
rmeddis@0 291 global stimulusParameters
rmeddis@0 292 stimulusParameters.digitString=fileName(end-7:end-5);
rmeddis@0 293
rmeddis@0 294 otherwise
rmeddis@0 295 switch stim.type(end-5:end)
rmeddis@0 296 % any file name with 'Babble' at the end is a
rmeddis@0 297 % multiThreshold file
rmeddis@0 298 case 'Babble'
rmeddis@0 299 % one of the many babbles is selected.
rmeddis@0 300 % NB random start in a long file
rmeddis@0 301 % stim.type should contain the name of the babble file
rmeddis@0 302 fileName=['..' filesep '..' filesep ...
rmeddis@0 303 'multithresholdResources' filesep ...
rmeddis@0 304 'backgrounds and maskers'...
rmeddis@0 305 filesep stim.type];
rmeddis@0 306
rmeddis@0 307 [stimulus sampleRate]= wavread(fileName);
rmeddis@0 308 if ~isequal(sampleRate, globalStimParams.FS)
rmeddis@0 309 % NB the file will read but will disagree with
rmeddis@0 310 % tone stimuli or other files read
rmeddis@0 311 msg= ['error: file sample rate disagrees ' ...
rmeddis@0 312 'with sample rate requested in paradigm'...
rmeddis@0 313 ' file (' ...
rmeddis@0 314 num2str(globalStimParams.FS) ').'];
rmeddis@0 315 error(msg);
rmeddis@0 316 end
rmeddis@0 317 nPoints=round(sampleRate*...
rmeddis@0 318 stimComponents(ear,componentNo).toneDuration);
rmeddis@0 319 start=round(rand(1,1)*(length(stimulus)-nPoints));
rmeddis@0 320 stimulus=stimulus(start:start+nPoints-1);
rmeddis@0 321 rms= 20*log10((mean(stimulus.^2).^0.5)/20e-6);
rmeddis@0 322 dBSPLrms=stimComponents(ear,componentNo).amplitudesdB;
rmeddis@0 323 gain=10.^((dBSPLrms-rms)/20);
rmeddis@0 324 stimulus=stimulus'*gain;
rmeddis@0 325
rmeddis@0 326 otherwise
rmeddis@0 327 % stim.type may be the name of a file to be read
rmeddis@0 328 % play from beginning for stimulus duration
rmeddis@0 329 try
rmeddis@0 330 [stimulus sampleRate]= wavread([stim.type '.wav']);
rmeddis@0 331 catch
rmeddis@0 332 error(['stimulusCreate: unrecognised stimulus type -> '...
rmeddis@0 333 stim.type])
rmeddis@0 334 end
rmeddis@0 335 if ~isequal(sampleRate, globalStimParams.FS)
rmeddis@0 336 % NB the file will read but will disagree with
rmeddis@0 337 % tone stimuli or other files read
rmeddis@0 338 msg= ['error: file sample rate disagrees ' ...
rmeddis@0 339 'with sample rate requested in paradigm'...
rmeddis@0 340 ' file (' ...
rmeddis@0 341 num2str(globalStimParams.FS) ').'];
rmeddis@0 342 error(msg);
rmeddis@0 343 end
rmeddis@0 344 stimulus=stimulus'; % make into a row vector
rmeddis@0 345 % estimate the extend of endsilence padding
rmeddis@0 346 nPoints=sampleRate*...
rmeddis@0 347 stimComponents(ear,componentNo).toneDuration;
rmeddis@0 348 if nPoints > length(stimulus)
rmeddis@0 349 endSilence=zeros(1,nPoints-length(stimulus));
rmeddis@0 350 else
rmeddis@0 351 % or truncate the file
rmeddis@0 352 endSilence=[];
rmeddis@0 353 stimulus=stimulus(1:nPoints);
rmeddis@0 354 end
rmeddis@0 355 % compute rms before adding silence
rmeddis@0 356 rms= 20*log10((mean(stimulus.^2).^0.5)/20e-6);
rmeddis@0 357 dBSPLrms=stimComponents(ear,componentNo).amplitudesdB;
rmeddis@0 358 gain=10.^((dBSPLrms-rms)/20);
rmeddis@0 359 stimulus=stimulus*gain;
rmeddis@0 360 stimulus=[stimulus endSilence];
rmeddis@0 361 end
rmeddis@0 362 end
rmeddis@0 363
rmeddis@0 364 % NB stimulus is a row vector now!
rmeddis@0 365 % audio and combinedSignal were column vectors
rmeddis@0 366 % signal will be a row vector
rmeddis@0 367
rmeddis@0 368 % filter stimulus
rmeddis@0 369 try
rmeddis@0 370 % if filter field is present, [lower upper order]
rmeddis@0 371 if stim.filter(1)>0 % 0 means don't filter
rmeddis@0 372 stimulus=Butterworth (stimulus, dt, stim.filter(1), ...
rmeddis@0 373 stim.filter(2), stim.filter(3));
rmeddis@0 374
rmeddis@0 375 end
rmeddis@0 376 catch
rmeddis@0 377 end
rmeddis@0 378
rmeddis@0 379
rmeddis@0 380 % apply amplitude modulation
rmeddis@0 381 if isfield(stim,'AMfrequency') & isfield(stim,'AMdepth')
rmeddis@0 382 if stim.AMfrequency>0 & stim.AMdepth>0
rmeddis@0 383 time=dt:dt:dt*length(stimulus);
rmeddis@0 384 modulator=sin(2*pi*stim.AMfrequency*time);
rmeddis@0 385 modulator=modulator*stim.AMdepth/100 + 1; % depth is percent
rmeddis@0 386 stimulus=stimulus.*modulator/2;
rmeddis@0 387 end
rmeddis@0 388 end
rmeddis@0 389
rmeddis@0 390 % Basic stimulus is now created.
rmeddis@0 391 % Add trappings, ramps, silences to main stimulus
rmeddis@0 392 rampOnTime=0; %ramp starts at the beginning of the stimulus
rmeddis@0 393 rampOffTime=stim.toneDuration-stim.rampOffDur;
rmeddis@0 394 if stim.rampOnDur>0.0001
rmeddis@0 395 stimulus=applyRampOn(stimulus, stim.rampOnDur, rampOnTime, 1/dt);
rmeddis@0 396 stimulus=applyRampOff(stimulus, stim.rampOffDur, rampOffTime, 1/dt);
rmeddis@0 397 end
rmeddis@0 398 if stim.rampOnDur<-0.0001 % apply Gaussian ramp
rmeddis@0 399 stimulus=applyGaussianRamps(stimulus, -stim.rampOnDur, 1/dt);
rmeddis@0 400 end
rmeddis@0 401
rmeddis@0 402 % Initial silence
rmeddis@0 403 % start with a signal of the right length consisting of zeros
rmeddis@0 404 signal=zeros(1, globalStimParams.nSignalPoints);
rmeddis@0 405 % identify start of stimulus
rmeddis@0 406 insertStimulusAt=round(stim.beginSilence/dt)+1;
rmeddis@0 407 % add stimulus
rmeddis@0 408 endOfStimulus=insertStimulusAt+length(stimulus)-1;
rmeddis@0 409 if endOfStimulus<=globalStimParams.nSignalPoints
rmeddis@0 410 signal(1, insertStimulusAt: endOfStimulus)=stimulus;
rmeddis@0 411 else
rmeddis@0 412 error('stimulusCreate: tone too long to fit into the overall duration')
rmeddis@0 413 end
rmeddis@0 414
rmeddis@0 415 % time signature
rmeddis@0 416 time=dt:dt:dt*length(signal);
rmeddis@0 417 % figure(22), plot(signal), title([num2str(ear) ' - ' num2str(componentNo)]),pause (1)
rmeddis@0 418
rmeddis@0 419 try
rmeddis@0 420 % create a column vector and trap if no signal has been created
rmeddis@0 421 signal=signal';
rmeddis@0 422 % also traps if signals are not the same length
rmeddis@0 423 combinedSignal=combinedSignal+signal;
rmeddis@0 424 % figure(21), plot(combinedSignal), title([num2str(ear) ' - ' num2str(componentNo)]),pause (1)
rmeddis@0 425 catch
rmeddis@0 426 % dump everything because there is a problem
rmeddis@0 427 globalStimParams
rmeddis@0 428 [ear componentNo]
rmeddis@0 429 stim
rmeddis@0 430 size(combinedSignal)
rmeddis@0 431 size(signal)
rmeddis@0 432 [ size(initialSilence) size(signal) size(endSilence)]
rmeddis@0 433 [ ear componentNo...
rmeddis@0 434 round(globalStimParams.overallDuration*globalStimParams.FS)...
rmeddis@0 435 round(stim.beginSilence*globalStimParams.FS)...
rmeddis@0 436 round(stim.toneDuration*globalStimParams.FS) ...
rmeddis@0 437 round(stim.endSilence*globalStimParams.FS)...
rmeddis@0 438 ( round(globalStimParams.overallDuration*globalStimParams.FS)...
rmeddis@0 439 -round(stim.beginSilence*globalStimParams.FS)...
rmeddis@0 440 -round(stim.toneDuration*globalStimParams.FS) ...
rmeddis@0 441 -round(stim.endSilence*globalStimParams.FS))...
rmeddis@0 442 ]
rmeddis@0 443 error(' trouble in stimulusCreate: signals are the wrong length ')
rmeddis@0 444 end
rmeddis@0 445
rmeddis@0 446 end % component no
rmeddis@0 447
rmeddis@0 448 audio(:,ear)= combinedSignal;
rmeddis@0 449
rmeddis@0 450 % FFT
rmeddis@0 451 try
rmeddis@0 452 if globalStimParams.FFT
rmeddis@0 453 showFFT (audio, dt)
rmeddis@0 454 end
rmeddis@0 455 catch
rmeddis@0 456 end
rmeddis@0 457
rmeddis@0 458
rmeddis@0 459 end % ear
rmeddis@0 460
rmeddis@0 461 switch globalStimParams.ears
rmeddis@0 462 % normally the signals are created in appropriate ears but .ears can
rmeddis@0 463 % overide this to produce a mono signal.
rmeddis@0 464 case 'monoticL';
rmeddis@0 465 % combine left and right ears to make a mono signal in the left ear
rmeddis@0 466 audio(:,1)=audio(:,1)+audio(:,2);
rmeddis@0 467 audio(:,2)=zeros(globalStimParams.nSignalPoints, 1);
rmeddis@0 468
rmeddis@0 469 case 'monoticR';
rmeddis@0 470 % combine left and right ears to make a mono signal in the right ear
rmeddis@0 471 audio(:,2)=audio(:,1)+audio(:,2);
rmeddis@0 472 audio(:,1)=zeros(globalStimParams.nSignalPoints, 1);
rmeddis@0 473
rmeddis@0 474 case 'diotic';
rmeddis@0 475 % combine left and right ears to make a mono signal in both ears
rmeddis@0 476 bothEarsCombined=audio(:,1)+audio(:,2);
rmeddis@0 477 audio(:,2)=bothEarsCombined;
rmeddis@0 478 audio(:,1)=bothEarsCombined;
rmeddis@0 479
rmeddis@0 480 otherwise
rmeddis@0 481 % Any other denomination produces no effect here
rmeddis@0 482 end
rmeddis@0 483
rmeddis@0 484 % Plotting as required
rmeddis@0 485 if globalStimParams.doPlot
rmeddis@0 486 figure(9), clf
rmeddis@0 487 plot(time,audio(:,1)'), hold on,
rmeddis@0 488 if Nears>1
rmeddis@0 489 offSet=(max(audio(:,1))+max(audio(:,2)))/10;
rmeddis@0 490 offSet=2*offSet+max(audio(:,1))+max(audio(:,2));
rmeddis@0 491 plot(time,audio(:,2)'+offSet,'r'), hold off
rmeddis@0 492 end
rmeddis@0 493 ylabel('left right')
rmeddis@0 494 end
rmeddis@0 495
rmeddis@0 496 % Calibration
rmeddis@0 497 % all signals are divided by this correction factor
rmeddis@0 498 % peakAmp=globalStimParams.audioOutCorrection; % microPascals = 100 dB SPL
rmeddis@0 499
rmeddis@0 500 audio=audio/globalStimParams.audioOutCorrection;
rmeddis@0 501
rmeddis@0 502 if globalStimParams.doPlay
rmeddis@0 503 wavplay(audio,globalStimParams.FS)
rmeddis@0 504 end
rmeddis@0 505 % all Done
rmeddis@0 506 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
rmeddis@0 507
rmeddis@0 508
rmeddis@0 509
rmeddis@0 510 %---------------------------------------------------- maketone
rmeddis@0 511 function tone=maketone(globalStimParams, stimComponents)
rmeddis@0 512 % maketone generates a stimComponents tone
rmeddis@0 513 % tone=maketone(dt, frequencies, toneDuration, dBSPL, phases)
rmeddis@0 514 % tone is returned in Pascals
rmeddis@0 515 % frequencies is a list of frequencies
rmeddis@0 516 % phase is list of phases or 'sin', 'cos', 'alt'
rmeddis@0 517 %
rmeddis@0 518 % defaults:
rmeddis@0 519 % phase = sin
rmeddis@0 520 % dBSPL=56 dB SPL
rmeddis@0 521
rmeddis@0 522 dt=globalStimParams.dt;
rmeddis@0 523 frequencies=stimComponents.frequencies;
rmeddis@0 524 toneDuration=stimComponents.toneDuration;
rmeddis@0 525 dBSPL=stimComponents.amplitudesdB;
rmeddis@0 526 phases=stimComponents.phases;
rmeddis@0 527
rmeddis@0 528 if ischar(phases)
rmeddis@0 529 switch phases
rmeddis@0 530 case 'sin'
rmeddis@0 531 phases= zeros(1,length(frequencies));
rmeddis@0 532 case 'cos'
rmeddis@0 533 phases= pi/2*ones(1,length(frequencies));
rmeddis@0 534 case 'alt'
rmeddis@0 535 phases= repmat([0 pi/2], 1, floor(length(frequencies)/2));
rmeddis@0 536 if length(phases)<length(frequencies)
rmeddis@0 537 phases=[phases 0];
rmeddis@0 538 end
rmeddis@0 539 case {'ran', 'rand'}
rmeddis@0 540 phases= 2*pi*rand(1,length(frequencies));
rmeddis@0 541 end
rmeddis@0 542 end
rmeddis@0 543
rmeddis@0 544 if length(phases)==1, phases=repmat(phases(1), 1, length(frequencies)); end
rmeddis@0 545 if length(phases)<length(frequencies)
rmeddis@0 546 error('makeTone:phase specification must have the same length as frequencies')
rmeddis@0 547 end
rmeddis@0 548
rmeddis@0 549 if length(dBSPL)==1, dBSPL=repmat(dBSPL(1), 1, length(frequencies)); end
rmeddis@0 550 if length(dBSPL)<length(dBSPL)
rmeddis@0 551 error('makeTone:dBSPL specification must have the same length as frequencies')
rmeddis@0 552 end
rmeddis@0 553
rmeddis@0 554 time=dt:dt:toneDuration;
rmeddis@0 555 amplitudes=28e-6* 10.^(dBSPL/20);
rmeddis@0 556
rmeddis@0 557 tone=zeros(size(time));
rmeddis@0 558 for i=1:length(frequencies)
rmeddis@0 559 frequency=frequencies(i);
rmeddis@0 560 phase=phases(i);
rmeddis@0 561 tone=tone+amplitudes(i)*sin(2*pi*frequency*time+phase);
rmeddis@0 562 end
rmeddis@0 563
rmeddis@0 564 % figure(1), plot(time, signal)
rmeddis@0 565
rmeddis@0 566
rmeddis@0 567 %---------------------------------------------------- makeOHIOtones
rmeddis@0 568 function stimulus=makeOHIOtones(globalStimParams, stimComponents)
rmeddis@0 569
rmeddis@0 570 % Generates a stimulus consisting of one or more 10-ms tones
rmeddis@0 571 % Tones are presented at 10-ms intervals
rmeddis@0 572 % Each tone has its own amplitude and its own ramp.
rmeddis@0 573
rmeddis@0 574 frequencies=stimComponents.frequencies;
rmeddis@0 575 amplitudesdB=stimComponents.amplitudesdB;
rmeddis@0 576 nFrequencies=length(frequencies);
rmeddis@0 577
rmeddis@0 578 dt=globalStimParams.dt;
rmeddis@0 579 toneDuration=.010;
rmeddis@0 580 time=dt:dt:toneDuration;
rmeddis@0 581
rmeddis@0 582 rampDuration=stimComponents.rampOnDur;
rmeddis@0 583 rampTime=dt:dt:rampDuration;
rmeddis@0 584 ramp=[0.5*(1+cos(2*pi*rampTime/(2*rampDuration)+pi)) ones(1,length(time)-length(rampTime))];
rmeddis@0 585 ramp=ramp.*fliplr(ramp);
rmeddis@0 586
rmeddis@0 587 stimulus= zeros(1,round((toneDuration+globalStimParams.beginSilences(end))/dt)+1);
rmeddis@0 588
rmeddis@0 589 for i=1:nFrequencies
rmeddis@0 590 toneBeginPTR=round(globalStimParams.beginSilences(i)/dt)+1;
rmeddis@0 591
rmeddis@0 592 frequency=frequencies(i);
rmeddis@0 593 dBSPL=amplitudesdB(i);
rmeddis@0 594 amplitude=28e-6* 10.^(dBSPL/20);
rmeddis@0 595 tone=amplitude*sin(2*pi*frequency*time);
rmeddis@0 596 tone=tone.*ramp;
rmeddis@0 597 stimulus(toneBeginPTR:toneBeginPTR+length(tone)-1)=stimulus(toneBeginPTR:toneBeginPTR+length(tone)-1)+tone;
rmeddis@0 598 end
rmeddis@0 599 % figure(2), plot( stimulus')
rmeddis@0 600
rmeddis@0 601
rmeddis@0 602 %---------------------------------------------------- makeFMtone
rmeddis@0 603 function tone=makeFMtone(globalStimParams, stimComponents)
rmeddis@0 604 % maketone generates a stimComponents tone
rmeddis@0 605 % tone=maketone(dt, frequencies, toneDuration, dBSPL, phases)
rmeddis@0 606 % tone is returned in Pascals
rmeddis@0 607 % frequencies is a list of frequencies
rmeddis@0 608 % phase is list of phases or 'sin', 'cos', 'alt'
rmeddis@0 609 %
rmeddis@0 610 % defaults:
rmeddis@0 611 % phase = sin
rmeddis@0 612 % dBSPL=56 dB SPL
rmeddis@0 613
rmeddis@0 614 dt=globalStimParams.dt;
rmeddis@0 615 frequencies=stimComponents.frequencies;
rmeddis@0 616 toneDuration=stimComponents.toneDuration;
rmeddis@0 617 dBSPL=stimComponents.amplitudesdB;
rmeddis@0 618 phases=stimComponents.phases;
rmeddis@0 619 fmDepth=stimComponents.fmDepth;
rmeddis@0 620 fmFrequency=stimComponents.fmFrequency;
rmeddis@0 621
rmeddis@0 622 if ischar(phases)
rmeddis@0 623 switch phases
rmeddis@0 624 case 'sin'
rmeddis@0 625 phases= zeros(1,length(frequencies));
rmeddis@0 626 case 'cos'
rmeddis@0 627 phases= pi/2*ones(1,length(frequencies));
rmeddis@0 628 case 'alt'
rmeddis@0 629 phases= repmat([0 pi/2], 1, floor(length(frequencies)/2));
rmeddis@0 630 if length(phases)<length(frequencies)
rmeddis@0 631 phases=[phases 0];
rmeddis@0 632 end
rmeddis@0 633 end
rmeddis@0 634 end
rmeddis@0 635
rmeddis@0 636 if length(phases)==1, phases=repmat(phases(1), 1, length(frequencies)); end
rmeddis@0 637 if length(phases)<length(frequencies)
rmeddis@0 638 error('makeTone:phase specification must have the same length as frequencies')
rmeddis@0 639 end
rmeddis@0 640
rmeddis@0 641 if length(dBSPL)==1, dBSPL=repmat(dBSPL(1), 1, length(frequencies)); end
rmeddis@0 642 if length(dBSPL)<length(dBSPL)
rmeddis@0 643 error('makeTone:dBSPL specification must have the same length as frequencies')
rmeddis@0 644 end
rmeddis@0 645
rmeddis@0 646 time=dt:dt:toneDuration;
rmeddis@0 647 amplitudes=28e-6* 10.^(dBSPL/20);
rmeddis@0 648
rmeddis@0 649 tone=zeros(size(time));
rmeddis@0 650 for i=1:length(frequencies)
rmeddis@0 651 frequency=frequencies(i);
rmeddis@0 652 phase=phases(i);
rmeddis@0 653 tone=tone+amplitudes(i)*sin(2*pi*frequency*time+phase + fmDepth*sin(2*pi*fmFrequency*time));
rmeddis@0 654 end
rmeddis@0 655
rmeddis@0 656 % figure(1), plot(time, signal)
rmeddis@0 657
rmeddis@0 658 %----------------------------------------------------makeTransposedStimulus
rmeddis@0 659 function [transposedStimulus]=makeTransposedStimulus(globalStimParams, stim)
rmeddis@0 660 % globalStimParams.FS=100000;
rmeddis@0 661 % globalStimParams.overallDuration=.1; % s
rmeddis@0 662 % globalStimParams.doPlot=1;
rmeddis@0 663 %
rmeddis@0 664 % stim.type='transposedStimulus';
rmeddis@0 665 % stim.phases='sin';
rmeddis@0 666 % stim.toneDuration=.05;;
rmeddis@0 667 % stim.frequencies=500;
rmeddis@0 668 % stim.amplitudesdB=50;
rmeddis@0 669 % stim.beginSilence=.01;
rmeddis@0 670 % stim.endSilence=-1;
rmeddis@0 671 % stim.rampOnDur=.002;
rmeddis@0 672 % stim.rampOffDur=-1;
rmeddis@0 673 %
rmeddis@0 674 % stim.transCarrierFreq=4000;
rmeddis@0 675 % stim.transModFreq=100;
rmeddis@0 676
rmeddis@0 677 transposedStimulus=[];
rmeddis@0 678 % make envelope of transposed tone
rmeddis@0 679 for i=1:length(stim.transModFreq)
rmeddis@0 680 stim.type='tone';
rmeddis@0 681 stim.frequencies=stim.transModFreq(i);
rmeddis@0 682 stim.endsilence=-1; stim.beginSilence=0;
rmeddis@0 683 [envelope, msg]=stimulusCreate(globalStimParams, stim); % NB recursive
rmeddis@0 684 envelope=envelope(:,1); % mono
rmeddis@0 685 % HW rectify
rmeddis@0 686 envelope(find(envelope<0))=0;
rmeddis@0 687 % LP filter
rmeddis@0 688 maxEnvelope=max(envelope);
rmeddis@0 689 envelope=UTIL_Butterworth (envelope, globalStimParams.dt, 10, .2*stim.transModFreq(i), 2);
rmeddis@0 690 envelope=envelope*maxEnvelope/max(envelope);
rmeddis@0 691
rmeddis@0 692 % make the carrier
rmeddis@0 693 stim.frequencies=stim.transCarrierFreq(i);
rmeddis@0 694 stim.endsilence=-1; stim.beginSilence=0;
rmeddis@0 695 [audio, msg]=stimulusCreate(globalStimParams, stim);
rmeddis@0 696 carrier=audio(:,1);
rmeddis@0 697 x= (carrier.*envelope)';
rmeddis@0 698 % base amplitude on peak of unmodulated carrier
rmeddis@0 699 x=x/max(carrier);
rmeddis@0 700 transposedStimulus=[transposedStimulus; x];
rmeddis@0 701 end
rmeddis@0 702 transposedStimulus=sum(transposedStimulus,1);
rmeddis@0 703 % clf,plot(transposedStimulus)
rmeddis@0 704
rmeddis@0 705 %--------------------------------------------------------------------makeClicks
rmeddis@0 706 function clickTrain=makeClicks(globalStimParams, stimComponents)
rmeddis@0 707 % makeClicks(F0, clickTimes, duration, FS);
rmeddis@0 708 % F0 specifies the repetition rate of the click sequence
rmeddis@0 709 % If F0=-1, a single click is generated at the start of the duration of the signal
rmeddis@0 710 %
rmeddis@0 711 % clickTimes a are fractions of the period
rmeddis@0 712 % and specify when the click appears in the period
rmeddis@0 713 % A click time of 1 is reset to zero.
rmeddis@0 714 % if the clicktime plus the click width is greater than the period, no click is generated
rmeddis@0 715 % clicks are treated as 20 microPascal high before amplification
rmeddis@0 716 % unless otherwise specified in stimComponents.clickHeight
rmeddis@0 717 % click width is dt unless specified in stimComponents.clickWidth
rmeddis@0 718 %
rmeddis@0 719 % for regular pulse train set clicktimes=1 or zero;
rmeddis@0 720 % FS is the sampling interval;
rmeddis@0 721 % CarlyonClickTrain(100, [.4 1], 40, 441000);
rmeddis@0 722
rmeddis@0 723 FS=globalStimParams.FS; % sample rate
rmeddis@0 724 dt=1/FS;
rmeddis@0 725
rmeddis@0 726 try,clickWidth=stimComponents.clickWidth;catch, clickWidth=dt; end
rmeddis@0 727 try,clickHeight=stimComponents.clickHeight; catch, clickHeight=28e-6 * 10^(stimComponents.amplitudesdB/20); end
rmeddis@0 728 try, clickTimes=stimComponents.clickTimes; catch, clickTimes=1; end
rmeddis@0 729
rmeddis@0 730 % clickTimes are the times in a cycle that the click
rmeddis@0 731 % occurs
rmeddis@0 732 checkClickTimes=clickTimes-1;
rmeddis@0 733 if max(checkClickTimes)>1
rmeddis@0 734 msg= 'click times must be <= than 1 (period)';
rmeddis@0 735 return
rmeddis@0 736 end
rmeddis@0 737
rmeddis@0 738 if clickWidth>=1/stimComponents.clickRepeatFrequency
rmeddis@0 739 msg= 'click width is too great for frequency';
rmeddis@0 740 return
rmeddis@0 741 end
rmeddis@0 742
rmeddis@0 743 duration=stimComponents.toneDuration;
rmeddis@0 744 totalLength=round(stimComponents.toneDuration/dt);
rmeddis@0 745 F0=stimComponents.clickRepeatFrequency;
rmeddis@0 746 F0=round(F0/dt)*dt;
rmeddis@0 747 if F0==-1 % single click required
rmeddis@0 748 F0=1/duration;
rmeddis@0 749 repetitions=1;
rmeddis@0 750 clickStartTimes=1; %clicktimes are fractions of a period
rmeddis@0 751 else
rmeddis@0 752 repetitions=round(F0*duration)-1;
rmeddis@0 753 duration=repetitions/F0;
rmeddis@0 754 clickStartTimes=clickTimes;
rmeddis@0 755 end
rmeddis@0 756 % if a clickTime=1 (end of duty period) set it to the beginning
rmeddis@0 757 clickStartTimes(clickStartTimes==1)=0;
rmeddis@0 758
rmeddis@0 759 period=1/F0;
rmeddis@0 760 time=dt:dt:period;
rmeddis@0 761 nPoints=length(time);
rmeddis@0 762 signal=zeros(1,nPoints);
rmeddis@0 763 dBSPL=stimComponents.amplitudesdB;
rmeddis@0 764
rmeddis@0 765 % compute click train for a single cycle
rmeddis@0 766 clickWidthNpoints=round(clickWidth*FS);
rmeddis@0 767 for i=1:length(clickStartTimes)
rmeddis@0 768 % if clickStartTimes(i)<clickWidth
rmeddis@0 769 % clickStartTimes(i)=dt;
rmeddis@0 770 % end
rmeddis@0 771 clickTime=round(period*clickStartTimes(i)/dt -dt);
rmeddis@0 772 % clicks are treated as 20 microPascal high
rmeddis@0 773 if clickTime+clickWidthNpoints<length(signal)
rmeddis@0 774 signal(clickTime+1:clickTime+clickWidthNpoints)=clickHeight;
rmeddis@0 775 end
rmeddis@0 776 end
rmeddis@0 777
rmeddis@0 778 clickTrain=repmat(signal, 1, repetitions);
rmeddis@0 779
rmeddis@0 780 if length(clickTrain)>totalLength
rmeddis@0 781 clickTrain=clickTrain(1:totalLength);
rmeddis@0 782 elseif length(clickTrain)<totalLength
rmeddis@0 783 timeToAdd=zeros(1,round((totalLength-length(clickTrain))));
rmeddis@0 784 clickTrain=[clickTrain timeToAdd];
rmeddis@0 785 % figure (1), plot(clickTrain)
rmeddis@0 786 end
rmeddis@0 787
rmeddis@0 788 %----------------------------------------------------------------makePressnitzerClicks
rmeddis@0 789 function signal=makePressnitzerClicks(globalStimParams, stimComponents)
rmeddis@0 790 % PressnitzerClicks(k,duration,dt)
rmeddis@0 791 % Generates a sequence of clicks with intervals kxx
rmeddis@0 792 % where x= rand*k/2
rmeddis@0 793 % This is not the same as Kaernbach and Demany clicks
rmeddis@0 794
rmeddis@0 795 FS=globalStimParams.FS; % sample rate
rmeddis@0 796 dt=1/FS;
rmeddis@0 797
rmeddis@0 798 % obligatory parameter
rmeddis@0 799 try
rmeddis@0 800 k=stimComponents.k;
rmeddis@0 801 catch
rmeddis@0 802 error('PressnitzerClicks: field ''k'' is missing from stimcomponent')
rmeddis@0 803 end
rmeddis@0 804
rmeddis@0 805 % optional parameters
rmeddis@0 806 if isfield(stimComponents,'clickWidth')
rmeddis@0 807 clickWidth=stimComponents.clickWidth;
rmeddis@0 808 else
rmeddis@0 809 clickWidth=dt;
rmeddis@0 810 end
rmeddis@0 811 clickWidthNpoints=round(clickWidth*FS);
rmeddis@0 812
rmeddis@0 813 if isfield(stimComponents,'clickHeight')
rmeddis@0 814 clickHeight=stimComponents.clickHeight;
rmeddis@0 815 else
rmeddis@0 816 clickHeight=28e-6 * 10^(stimComponents.amplitudesdB/20);
rmeddis@0 817 end
rmeddis@0 818
rmeddis@0 819 duration=stimComponents.toneDuration;
rmeddis@0 820
rmeddis@0 821 signalLength=round(duration/dt);
rmeddis@0 822 signal=zeros(1,signalLength);
rmeddis@0 823 kInterval=round(k/dt);
rmeddis@0 824 halfk=k/2;
rmeddis@0 825 signal(1)=clickHeight;
rmeddis@0 826 timeIdx=0;
rmeddis@0 827 while timeIdx<signalLength
rmeddis@0 828 % first interval = k
rmeddis@0 829 clickTime=timeIdx+kInterval;
rmeddis@0 830 signal(clickTime:clickTime+clickWidthNpoints)=clickHeight;
rmeddis@0 831 timeIdx=timeIdx+kInterval;
rmeddis@0 832
rmeddis@0 833 % second interval = 0 : k/2
rmeddis@0 834 intervalx1=round(rand*halfk/dt);
rmeddis@0 835 clickTime=timeIdx+intervalx1;
rmeddis@0 836 signal(clickTime:clickTime+clickWidthNpoints)=clickHeight;
rmeddis@0 837 timeIdx=timeIdx+intervalx1;
rmeddis@0 838
rmeddis@0 839 % third interval = 0 : k/2
rmeddis@0 840 intervalx1=round(rand*halfk/dt);
rmeddis@0 841 clickTime=timeIdx+intervalx1;
rmeddis@0 842 signal(clickTime:clickTime+clickWidthNpoints)=clickHeight;
rmeddis@0 843 timeIdx=timeIdx+intervalx1;
rmeddis@0 844 end
rmeddis@0 845
rmeddis@0 846 signal=signal(1:signalLength);
rmeddis@0 847 % figure(1), plot(dt:dt:duration,signal)
rmeddis@0 848
rmeddis@0 849 %----------------------------------------------------------------makePressnitzerABXClicks
rmeddis@0 850 function signal=makePressnitzerABxClicks(globalStimParams, stimComponents)
rmeddis@0 851 % Generates a sequence of clicks with intervals ABx
rmeddis@0 852 % AB interval is 2*k
rmeddis@0 853 % where A= rand* k
rmeddis@0 854 % B= k-A
rmeddis@0 855 % x= k/2
rmeddis@0 856 % These are second order clicks
rmeddis@0 857
rmeddis@0 858 FS=globalStimParams.FS; % sample rate
rmeddis@0 859 dt=1/FS;
rmeddis@0 860
rmeddis@0 861 % obligatory parameter
rmeddis@0 862 try
rmeddis@0 863 k=stimComponents.k;
rmeddis@0 864 catch
rmeddis@0 865 error('PressnitzerClicks: field ''k'' is missing from stimcomponent')
rmeddis@0 866 end
rmeddis@0 867
rmeddis@0 868 % optional parameters
rmeddis@0 869 if isfield(stimComponents,'clickWidth')
rmeddis@0 870 clickWidth=stimComponents.clickWidth;
rmeddis@0 871 else
rmeddis@0 872 clickWidth=dt;
rmeddis@0 873 end
rmeddis@0 874 clickWidthNpoints=round(clickWidth*FS);
rmeddis@0 875
rmeddis@0 876 if isfield(stimComponents,'clickHeight')
rmeddis@0 877 clickHeight=stimComponents.clickHeight;
rmeddis@0 878 else
rmeddis@0 879 clickHeight=28e-6 * 10^(stimComponents.amplitudesdB/20);
rmeddis@0 880 end
rmeddis@0 881
rmeddis@0 882 duration=stimComponents.toneDuration;
rmeddis@0 883
rmeddis@0 884 signalLength=round(duration/dt);
rmeddis@0 885 signal=zeros(1,2*signalLength); % allow for overrun
rmeddis@0 886 ABinterval=k/dt; % i.e. the number of dt steps
rmeddis@0 887 randomInterval=ABinterval/2;
rmeddis@0 888 signal(1)=clickHeight;
rmeddis@0 889 time=0;
rmeddis@0 890 while time<signalLength
rmeddis@0 891 % first interval = A
rmeddis@0 892 intervalA=rand*ABinterval;
rmeddis@0 893 clickTime=round(time+intervalA)+1; % +1 avoids zero index
rmeddis@0 894 signal(clickTime:clickTime+clickWidthNpoints)=clickHeight;
rmeddis@0 895 time=time+intervalA;
rmeddis@0 896
rmeddis@0 897 % second interval = B
rmeddis@0 898 intervalB=ABinterval-intervalA;
rmeddis@0 899 clickTime=round(time+intervalB)+1;
rmeddis@0 900 signal(clickTime:clickTime+clickWidthNpoints-1)=clickHeight;
rmeddis@0 901 time=time+intervalB;
rmeddis@0 902
rmeddis@0 903 % third interval = 0 : k/2
rmeddis@0 904 intervalx1=rand*randomInterval; % mean random interval=k
rmeddis@0 905 clickTime=round(time+intervalx1)+1;
rmeddis@0 906 signal(clickTime:clickTime+clickWidthNpoints-1)=clickHeight;
rmeddis@0 907 time=time+intervalx1;
rmeddis@0 908 end
rmeddis@0 909
rmeddis@0 910 signal=signal(1:signalLength);
rmeddis@0 911 % figure(1), plot(dt:dt:duration,signal)
rmeddis@0 912
rmeddis@0 913 %-----------------------------------------------------makeABxClicks
rmeddis@0 914 function signal=makeABxClicks(globalStimParams, stimComponents)
rmeddis@0 915 % Generates a sequence of clicks with intervals ABx
rmeddis@0 916 % AB interval is 2*k
rmeddis@0 917 % where A= rand* k
rmeddis@0 918 % B= k-A
rmeddis@0 919 % x= rand*2*k
rmeddis@0 920 % These are second order clicks
rmeddis@0 921
rmeddis@0 922 FS=globalStimParams.FS; % sample rate
rmeddis@0 923 dt=1/FS;
rmeddis@0 924
rmeddis@0 925 % obligatory parameter
rmeddis@0 926 try
rmeddis@0 927 k=stimComponents.k;
rmeddis@0 928 catch
rmeddis@0 929 error('PressnitzerClicks: field ''k'' is missing from stimcomponent')
rmeddis@0 930 end
rmeddis@0 931
rmeddis@0 932 % optional parameters
rmeddis@0 933 if isfield(stimComponents,'clickWidth')
rmeddis@0 934 clickWidth=stimComponents.clickWidth;
rmeddis@0 935 else
rmeddis@0 936 clickWidth=dt;
rmeddis@0 937 end
rmeddis@0 938 clickWidthNpoints=round(clickWidth*FS);
rmeddis@0 939
rmeddis@0 940 if isfield(stimComponents,'clickHeight')
rmeddis@0 941 clickHeight=stimComponents.clickHeight;
rmeddis@0 942 else
rmeddis@0 943 clickHeight=28e-6 * 10^(stimComponents.amplitudesdB/20);
rmeddis@0 944 end
rmeddis@0 945
rmeddis@0 946 duration=stimComponents.toneDuration;
rmeddis@0 947
rmeddis@0 948 signalLength=round(duration/dt);
rmeddis@0 949 signal=zeros(1,2*signalLength); % allow for overrun
rmeddis@0 950 ABinterval=2*k/dt;
rmeddis@0 951 randomInterval=ABinterval;
rmeddis@0 952 signal(1)=clickHeight;
rmeddis@0 953 timeIdx=0;
rmeddis@0 954 while timeIdx<signalLength
rmeddis@0 955 % first interval = A
rmeddis@0 956 intervalA=round(rand*ABinterval);
rmeddis@0 957 clickTime=timeIdx+intervalA+1;
rmeddis@0 958 signal(clickTime:clickTime+clickWidthNpoints-1)=clickHeight;
rmeddis@0 959 timeIdx=timeIdx+intervalA;
rmeddis@0 960
rmeddis@0 961 % second interval = B
rmeddis@0 962 intervalB=round(ABinterval-intervalA);
rmeddis@0 963 clickTime=timeIdx+intervalB;
rmeddis@0 964 signal(clickTime:clickTime+clickWidthNpoints-1)=clickHeight;
rmeddis@0 965 timeIdx=timeIdx+intervalB;
rmeddis@0 966
rmeddis@0 967 % third interval = 0 : k
rmeddis@0 968 intervalx1=round(rand*randomInterval); % mean random interval=k
rmeddis@0 969 clickTime=timeIdx+intervalx1;
rmeddis@0 970 signal(clickTime:clickTime+clickWidthNpoints-1)=clickHeight;
rmeddis@0 971 timeIdx=timeIdx+intervalx1;
rmeddis@0 972 end
rmeddis@0 973
rmeddis@0 974 signal=signal(1:signalLength);
rmeddis@0 975 % figure(1), plot(dt:dt:duration,signal)
rmeddis@0 976
rmeddis@0 977 %----------------------------------------------------------------makeYostClicks
rmeddis@0 978 function signal=makeYostClicks(globalStimParams, stimComponents)
rmeddis@0 979 % Generates a shuffled sequence of clicks with intervals kxxxx
rmeddis@0 980 % where max(x)= 2*k
rmeddis@0 981 % and there are n occurrences of x
rmeddis@0 982 % this section requires:
rmeddis@0 983 % stimComponents.k
rmeddis@0 984 % stimComponents.nXs
rmeddis@0 985 % stimComponents.toneDuration
rmeddis@0 986 % optional:
rmeddis@0 987 % stimComponents.clickWidth %useful because width depends on dt
rmeddis@0 988 % stimComponents.clickHeight %best left to amplitude rescaling later
rmeddis@0 989
rmeddis@0 990 FS=globalStimParams.FS; % sample rate
rmeddis@0 991 dt=1/FS;
rmeddis@0 992
rmeddis@0 993 % obligatory parameters
rmeddis@0 994 try
rmeddis@0 995 k=stimComponents.k;
rmeddis@0 996 catch
rmeddis@0 997 error('makeYostClicks: field ''k'' is missing from stimComponents')
rmeddis@0 998 end
rmeddis@0 999
rmeddis@0 1000 try
rmeddis@0 1001 nXs=stimComponents.nXs;
rmeddis@0 1002 catch
rmeddis@0 1003 error('makeYostClicks: field ''nXs'' is missing from stimComponents')
rmeddis@0 1004 end
rmeddis@0 1005
rmeddis@0 1006 try
rmeddis@0 1007 shuffled=stimComponents.shuffled;
rmeddis@0 1008 catch
rmeddis@0 1009 error('makeYostClicks: field ''shuffled'' is missing from stimComponents')
rmeddis@0 1010 end
rmeddis@0 1011
rmeddis@0 1012 try
rmeddis@0 1013 duration=stimComponents.toneDuration;
rmeddis@0 1014 catch
rmeddis@0 1015 error('makeYostClicks: field ''toneDuration'' is missing from stimComponents')
rmeddis@0 1016 end
rmeddis@0 1017
rmeddis@0 1018 % optional parameters
rmeddis@0 1019 if isfield(stimComponents,'clickWidth')
rmeddis@0 1020 clickWidth=stimComponents.clickWidth;
rmeddis@0 1021 else
rmeddis@0 1022 clickWidth=dt;
rmeddis@0 1023 end
rmeddis@0 1024 clickWidthNpoints=round(clickWidth*FS);
rmeddis@0 1025
rmeddis@0 1026 if isfield(stimComponents,'clickHeight')
rmeddis@0 1027 clickHeight=stimComponents.clickHeight;
rmeddis@0 1028 else
rmeddis@0 1029 clickHeight=28e-6 * 10^(stimComponents.amplitudesdB/20);
rmeddis@0 1030 end
rmeddis@0 1031
rmeddis@0 1032 kInterval=round(k/dt);
rmeddis@0 1033 twoK=k*2; % max width of x interval
rmeddis@0 1034
rmeddis@0 1035 signalLength=round(duration/dt);
rmeddis@0 1036 signal=zeros(1,signalLength);
rmeddis@0 1037
rmeddis@0 1038 timeIdx=0;
rmeddis@0 1039 intervalCount=0;
rmeddis@0 1040 while timeIdx<signalLength
rmeddis@0 1041 timeIdx=timeIdx+kInterval;
rmeddis@0 1042 if timeIdx>signalLength, break,end
rmeddis@0 1043 intervalCount=intervalCount+1;
rmeddis@0 1044 intervals(intervalCount)=kInterval;
rmeddis@0 1045
rmeddis@0 1046 % repeat x intervals as required
rmeddis@0 1047 if nXs>0
rmeddis@0 1048 for nX=1:nXs
rmeddis@0 1049 xInterval=round(rand*twoK/dt);
rmeddis@0 1050 timeIdx=timeIdx+xInterval;
rmeddis@0 1051 if timeIdx>signalLength, break,end
rmeddis@0 1052 intervalCount=intervalCount+1;
rmeddis@0 1053 intervals(intervalCount)=xInterval;
rmeddis@0 1054 end
rmeddis@0 1055 end
rmeddis@0 1056 if timeIdx>signalLength, break,end
rmeddis@0 1057 end
rmeddis@0 1058
rmeddis@0 1059 % shuffle intervals
rmeddis@0 1060 if shuffled
rmeddis@0 1061 randomNumbers=rand(1,length(intervals));
rmeddis@0 1062 [randomNumbers idx]=sort(randomNumbers);
rmeddis@0 1063 intervals=intervals(idx);
rmeddis@0 1064 idx=intervals>0;
rmeddis@0 1065 intervals=intervals(idx);
rmeddis@0 1066 end
rmeddis@0 1067
rmeddis@0 1068 intervalCount=length(intervals);
rmeddis@0 1069 signal(1)=clickHeight;
rmeddis@0 1070 clickTime=0;
rmeddis@0 1071 for i=1:intervalCount
rmeddis@0 1072 clickTime=clickTime+intervals(i);
rmeddis@0 1073 signal(clickTime:clickTime+clickWidthNpoints)=clickHeight;
rmeddis@0 1074 end
rmeddis@0 1075 signal=signal(1:signalLength);
rmeddis@0 1076 % figure(1), plot(dt:dt:duration,signal)
rmeddis@0 1077
rmeddis@0 1078 %--------------------------------------------------------------------makeKxxClicks
rmeddis@0 1079 function signal=makeKxxClicks(globalStimParams, stimComponents)
rmeddis@0 1080 % Click train consists of kkxxx.. sequences
rmeddis@0 1081 % k is the duration of a fixed interval (seconds)
rmeddis@0 1082 % random intervals are distributed 0 : 2* k (NB not like Pressnitzer clicks)
rmeddis@0 1083 % nKs is the number of successive 'k' intervals
rmeddis@0 1084 % nXs is the number of random intervals between k sequences
rmeddis@0 1085 % sequences of 3 x intervals > k are replaced with new sequences
rmeddis@0 1086 % shuffled causes all intervals to be reordered randomly
rmeddis@0 1087 % NB 1/k is the mean click rate
rmeddis@0 1088
rmeddis@0 1089 FS=globalStimParams.FS; % sample rate
rmeddis@0 1090 dt=1/FS;
rmeddis@0 1091
rmeddis@0 1092 try
rmeddis@0 1093 k=stimComponents.k; % duration (s) of fixed intervals
rmeddis@0 1094 catch
rmeddis@0 1095 error('makeYostClicks: field ''k'' is missing from stimComponents')
rmeddis@0 1096 end
rmeddis@0 1097
rmeddis@0 1098 try
rmeddis@0 1099 duration=stimComponents.toneDuration;
rmeddis@0 1100 catch
rmeddis@0 1101 error('makeYostClicks: field ''duration'' is missing from stimComponents')
rmeddis@0 1102 end
rmeddis@0 1103
rmeddis@0 1104 if isfield(stimComponents,'clickWidth')
rmeddis@0 1105 clickWidth=stimComponents.clickWidth;
rmeddis@0 1106 else
rmeddis@0 1107 clickWidth=dt;
rmeddis@0 1108 end
rmeddis@0 1109
rmeddis@0 1110 if isfield(stimComponents,'clickHeight')
rmeddis@0 1111 clickHeight=stimComponents.clickHeight;
rmeddis@0 1112 else
rmeddis@0 1113 clickHeight=28e-6 * 10^(stimComponents.amplitudesdB/20);
rmeddis@0 1114 end
rmeddis@0 1115
rmeddis@0 1116
rmeddis@0 1117 if isfield(stimComponents,'order')
rmeddis@0 1118 order=stimComponents.order;
rmeddis@0 1119 else
rmeddis@0 1120 order=1;
rmeddis@0 1121 end
rmeddis@0 1122
rmeddis@0 1123 if isfield(stimComponents,'nKs')
rmeddis@0 1124 nKs=stimComponents.nKs;
rmeddis@0 1125 else
rmeddis@0 1126 nKs=1;
rmeddis@0 1127 end
rmeddis@0 1128
rmeddis@0 1129 if isfield(stimComponents,'nXs')
rmeddis@0 1130 nXs=stimComponents.nXs;
rmeddis@0 1131 else
rmeddis@0 1132 nXs=1;
rmeddis@0 1133 end
rmeddis@0 1134
rmeddis@0 1135 if isfield(stimComponents,'shuffled')
rmeddis@0 1136 shuffled=stimComponents.shuffled;
rmeddis@0 1137 else
rmeddis@0 1138 shuffled=1;
rmeddis@0 1139 end
rmeddis@0 1140
rmeddis@0 1141 kLength=round(k/dt); % fixed interval
rmeddis@0 1142 xLength=2*kLength; % maximum random interval
rmeddis@0 1143 requiredSignalLength=round(duration/dt);
rmeddis@0 1144 intervalsPerCycle=(nKs+nXs);
rmeddis@0 1145 cycleLength=nKs*kLength+nXs*xLength;
rmeddis@0 1146 % more cycles to allow for uncertainty
rmeddis@0 1147 nCycles=5*round(requiredSignalLength/cycleLength);
rmeddis@0 1148 nIntervals=nCycles*intervalsPerCycle;
rmeddis@0 1149
rmeddis@0 1150 % random intervals
rmeddis@0 1151 if nXs>0
rmeddis@0 1152 xIntervals=floor(rand(1,nIntervals)*2*kLength);
rmeddis@0 1153 % weed out triple intervals > 2*k
rmeddis@0 1154 rogues=1;
rmeddis@0 1155 while sum(rogues)
rmeddis@0 1156 y=(xIntervals>kLength);
rmeddis@0 1157 rogues=(sum([y(1:end-2)' y(2:end-1)' y(3:end)'],2)>2);
rmeddis@0 1158 xIntervals(rogues)=floor(rand*2*kLength);
rmeddis@0 1159 end
rmeddis@0 1160 xIntervals=reshape(xIntervals,nCycles,intervalsPerCycle);
rmeddis@0 1161 else
rmeddis@0 1162 xIntervals=[];
rmeddis@0 1163 end
rmeddis@0 1164
rmeddis@0 1165 % insert constrained (k) intervals
rmeddis@0 1166 if nKs>0
rmeddis@0 1167 switch order
rmeddis@0 1168 case 1
rmeddis@0 1169 kIntervals=floor(ones(nCycles,nKs)*kLength);
rmeddis@0 1170 case 2
rmeddis@0 1171 nKs=1; % force this
rmeddis@0 1172 kIntervals=floor(rand(nCycles,1)*kLength);
rmeddis@0 1173 kIntervals=[kIntervals kLength-kIntervals];
rmeddis@0 1174 end
rmeddis@0 1175 else
rmeddis@0 1176 kIntervals=[];
rmeddis@0 1177 end
rmeddis@0 1178
rmeddis@0 1179 % combine fixed and random
rmeddis@0 1180 intervals=[kIntervals xIntervals(:,nKs+1:end)];
rmeddis@0 1181 % make a single array;
rmeddis@0 1182 [r c]=size(intervals);
rmeddis@0 1183 intervals=reshape(intervals',1,r*c);
rmeddis@0 1184
rmeddis@0 1185 % shuffle intervals
rmeddis@0 1186 if shuffled
rmeddis@0 1187 randomNumbers=rand(1,length(intervals));
rmeddis@0 1188 [randomNumbers idx]=sort(randomNumbers);
rmeddis@0 1189 intervals=intervals(idx);
rmeddis@0 1190 idx=intervals>0;
rmeddis@0 1191 intervals=intervals(idx);
rmeddis@0 1192 end
rmeddis@0 1193
rmeddis@0 1194 % convert intervals to clicks
rmeddis@0 1195 clickTimes=cumsum(intervals);
rmeddis@0 1196 signal(clickTimes)=clickHeight;
rmeddis@0 1197 signal=signal(1:requiredSignalLength);
rmeddis@0 1198 % figure(1), clf, plot(signal)
rmeddis@0 1199
rmeddis@0 1200
rmeddis@0 1201
rmeddis@0 1202 %--------------------------------------------------------------------makeNoise
rmeddis@0 1203 function noise=makeNoise(globalStimParams, stimComponents)
rmeddis@0 1204 % FS in Hz, noiseDuration in s, delay in s;
rmeddis@0 1205 % noise is returned with overall level dB(rms) = amplitudesdB
rmeddis@0 1206 %
rmeddis@0 1207 % % You need
rmeddis@0 1208 %
rmeddis@0 1209 % stim.type='noise'; % or 'IRN', or 'pinkNoise'
rmeddis@0 1210 % stim.toneDuration=.05;
rmeddis@0 1211 % stim.amplitudesdB=50;
rmeddis@0 1212 % stim.beginSilence=.01;
rmeddis@0 1213 % stim.endSilence=-1;
rmeddis@0 1214 % stim.rampOnDur=.002;
rmeddis@0 1215 % stim.rampOffDur=-1;
rmeddis@0 1216 %
rmeddis@0 1217 % % Mandatory structure fields
rmeddis@0 1218 % globalStimParams.FS=100000;
rmeddis@0 1219 % globalStimParams.overallDuration=.1; % s
rmeddis@0 1220 % globalStimParams.doPlot=1;
rmeddis@0 1221 % globalStimParams.doPlay=1;
rmeddis@0 1222 %
rmeddis@0 1223 % [audio, msg]=stimulusCreate(globalStimParams, stim, );
rmeddis@0 1224 %
rmeddis@0 1225 % % local
rmeddis@0 1226 % stim.type='noise'; % or 'IRN'
rmeddis@0 1227 %
rmeddis@0 1228 FS=globalStimParams.FS;
rmeddis@0 1229 noiseDuration= stimComponents.toneDuration;
rmeddis@0 1230 npts=round(noiseDuration*FS);
rmeddis@0 1231 noise=randn(1,npts); % NB randn (normally distributed)
rmeddis@0 1232
rmeddis@0 1233 switch stimComponents.type
rmeddis@0 1234 case 'pinkNoise'
rmeddis@0 1235 % noise=UTIL_lowpassFilterFreq(noise, 100, 1/FS);
rmeddis@0 1236 noise=UTIL_bandPassFilter(noise, 1, 100, 200, 1/FS,[]);
rmeddis@0 1237 end
rmeddis@0 1238
rmeddis@0 1239 rms=(mean(noise.^2)^.5); %should be 20 microPascals for 0 dB SPL
rmeddis@0 1240 adjust=20e-6/rms;
rmeddis@0 1241 noise=noise*adjust;
rmeddis@0 1242 rms=(mean(noise.^2)^.5);
rmeddis@0 1243 amplitude=10.^(stimComponents.amplitudesdB/20);
rmeddis@0 1244 noise=amplitude*noise;
rmeddis@0 1245 % rms=(mean(noise.^2)^.5);
rmeddis@0 1246 % dBnoise=20*log10(rms/20e-6)
rmeddis@0 1247
rmeddis@0 1248
rmeddis@0 1249 %--------------------------------------------------------------------makeWhiteNoise
rmeddis@0 1250 function noise=makeWhiteNoise(globalStimParams, stimComponents)
rmeddis@0 1251 % FS in Hz, noiseDuration in s, delay in s;
rmeddis@0 1252 % noise is bandpass filtered between 100 and 10000 Hz
rmeddis@0 1253 % spectrum level (dB/Hz) is 40 dB below nominal level.
rmeddis@0 1254 % noise is returned with dB(rms) = amplitudesdB
rmeddis@0 1255 %
rmeddis@0 1256 % % You need
rmeddis@0 1257 %
rmeddis@0 1258 % stim.type='noise'; % or 'IRN', or 'pinkNoise'
rmeddis@0 1259 % stim.toneDuration=.05;
rmeddis@0 1260 % stim.amplitudesdB=50;
rmeddis@0 1261 % stim.beginSilence=.01;
rmeddis@0 1262 % stim.endSilence=-1;
rmeddis@0 1263 % stim.rampOnDur=.002;
rmeddis@0 1264 % stim.rampOffDur=-1;
rmeddis@0 1265 %
rmeddis@0 1266 % % Mandatory structure fields
rmeddis@0 1267 % globalStimParams.FS=100000;
rmeddis@0 1268 % globalStimParams.overallDuration=.1; % s
rmeddis@0 1269 % globalStimParams.doPlot=1;
rmeddis@0 1270 % globalStimParams.doPlay=1;
rmeddis@0 1271 %
rmeddis@0 1272 % [audio, msg]=stimulusCreate(globalStimParams, stim, );
rmeddis@0 1273 %
rmeddis@0 1274 % % local
rmeddis@0 1275 % stim.type='noise'; % or 'IRN'
rmeddis@0 1276 %
rmeddis@0 1277 FS=globalStimParams.FS;
rmeddis@0 1278 noiseDuration= stimComponents.toneDuration;
rmeddis@0 1279 npts=round(noiseDuration*FS);
rmeddis@0 1280 noise=randn(1,npts);
rmeddis@0 1281
rmeddis@0 1282 noise=UTIL_bandPassFilter (noise, 6, 100, 10000, 1/FS, []);
rmeddis@0 1283
rmeddis@0 1284 rms=(mean(noise.^2)^.5); %should be 20 microPascals for 0 dB SPL
rmeddis@0 1285 adjust=20e-6/rms;
rmeddis@0 1286 noise=noise*adjust;
rmeddis@0 1287 rms=(mean(noise.^2)^.5);
rmeddis@0 1288 amplitude=10.^(stimComponents.amplitudesdB/20);
rmeddis@0 1289 noise=amplitude*noise;
rmeddis@0 1290 % rms=(mean(noise.^2)^.5);
rmeddis@0 1291 % dBnoise=20*log10(rms/20e-6)
rmeddis@0 1292
rmeddis@0 1293
rmeddis@0 1294 %-----------------------------------------------------------------makeIRN
rmeddis@0 1295 function noise=makeIRN(globalStimParams, stimComponents)
rmeddis@0 1296 % FS in Hz, noiseDuration in s, delay in s;
rmeddis@0 1297 % noise is returned with dB(rms) = amplitudesdB
rmeddis@0 1298 %
rmeddis@0 1299 % % You need
rmeddis@0 1300 %
rmeddis@0 1301 % stim.type='noise'; % or 'IRN', or 'pinkNoise'
rmeddis@0 1302 % stim.toneDuration=.05;
rmeddis@0 1303 % stim.amplitudesdB=50;
rmeddis@0 1304 % stim.beginSilence=.01;
rmeddis@0 1305 % stim.endSilence=-1;
rmeddis@0 1306 % stim.rampOnDur=.002;
rmeddis@0 1307 % stim.rampOffDur=-1;
rmeddis@0 1308 %
rmeddis@0 1309 % % Mandatory structure fields
rmeddis@0 1310 % globalStimParams.FS=100000;
rmeddis@0 1311 % globalStimParams.overallDuration=.1; % s
rmeddis@0 1312 % globalStimParams.doPlot=1;
rmeddis@0 1313 % globalStimParams.doPlay=1;
rmeddis@0 1314 %
rmeddis@0 1315 % [audio, msg]=stimulusCreate(globalStimParams, stim, );
rmeddis@0 1316 %
rmeddis@0 1317 % % local
rmeddis@0 1318 % stim.type='noise'; % or 'IRN'
rmeddis@0 1319 % % for IRN only
rmeddis@0 1320 % stim.niterations = 8; %0 for white noise
rmeddis@0 1321 % stim.delay = 1/150;
rmeddis@0 1322 % stim.irnGain = 1;
rmeddis@0 1323 %
rmeddis@0 1324 FS=globalStimParams.FS;
rmeddis@0 1325 noiseDuration= stimComponents.toneDuration;
rmeddis@0 1326
rmeddis@0 1327 nIterations=stimComponents.niterations;
rmeddis@0 1328 if nIterations==0
rmeddis@0 1329 % white noise is specified as nIterations=1
rmeddis@0 1330 nIterations=1;
rmeddis@0 1331 IRNgain=0;
rmeddis@0 1332 delay=0.01; % dummy
rmeddis@0 1333 else
rmeddis@0 1334 % IRN
rmeddis@0 1335 delay=stimComponents.delay;
rmeddis@0 1336 IRNgain=stimComponents.irnGain;
rmeddis@0 1337 end
rmeddis@0 1338
rmeddis@0 1339 npts=round(noiseDuration*FS);
rmeddis@0 1340 dels=round(delay*FS);
rmeddis@0 1341 noise=randn(1,npts);
rmeddis@0 1342
rmeddis@0 1343 %fringe=nIterations*dels;
rmeddis@0 1344 %npts=npts+fringe;
rmeddis@0 1345
rmeddis@0 1346 for i=1:nIterations,
rmeddis@0 1347 dnoise=[noise(dels+1:npts) noise(1:dels)];
rmeddis@0 1348 dnoise=dnoise.*IRNgain;
rmeddis@0 1349 noise=noise+dnoise;
rmeddis@0 1350 end;
rmeddis@0 1351
rmeddis@0 1352 switch stimComponents.type
rmeddis@0 1353 case 'pinkNoise'
rmeddis@0 1354 noise=UTIL_lowpassFilterFreq(noise, 10000, 1/FS);
rmeddis@0 1355 end
rmeddis@0 1356
rmeddis@0 1357 rms=(mean(noise.^2)^.5); %should be 20 microPascals for 0 dB SPL
rmeddis@0 1358 adjust=20e-6/rms;
rmeddis@0 1359 noise=noise*adjust;
rmeddis@0 1360 rms=(mean(noise.^2)^.5);
rmeddis@0 1361 amplitude=10.^(stimComponents.amplitudesdB/20);
rmeddis@0 1362 noise=amplitude*noise;
rmeddis@0 1363 % rms=(mean(noise.^2)^.5);
rmeddis@0 1364 % dBnoise=20*log10(rms/20e-6)
rmeddis@0 1365
rmeddis@0 1366 %------------------------------------------------------------------ makeRPN
rmeddis@0 1367 function RPN=makeRPN(globalStimParams, stim)
rmeddis@0 1368 % 'period' is a collection of samples - AAABCD
rmeddis@0 1369 % you need
rmeddis@0 1370 %
rmeddis@0 1371 % stim.type='RPN';
rmeddis@0 1372 % stim.toneDuration=.2;
rmeddis@0 1373 % stim.amplitudesdB=50;
rmeddis@0 1374 % stim.beginSilence=.01;
rmeddis@0 1375 % stim.rampOnDur=.002;
rmeddis@0 1376 % stim.rampOffDur=-1;
rmeddis@0 1377 %
rmeddis@0 1378 % stim.sampleDuration=.005; %200 Hz pitch
rmeddis@0 1379 % stim.nSimilarSamples=5; % pitch strength
rmeddis@0 1380 % stim.nIndependentSamples=1% dilutes strength
rmeddis@0 1381 %
rmeddis@0 1382 % % Mandatory structure fields
rmeddis@0 1383 % globalStimParams.FS=44100;
rmeddis@0 1384 % globalStimParams.overallDuration=.21; % s
rmeddis@0 1385 %
rmeddis@0 1386 % globalStimParams.doPlot=1;
rmeddis@0 1387 % globalStimParams.doPlay=1;
rmeddis@0 1388 % [audio, msg]=stimulusCreate(globalStimParams, stim);
rmeddis@0 1389
rmeddis@0 1390 FS=globalStimParams.FS;
rmeddis@0 1391 ptsPerSample=floor(stim.sampleDuration*FS);
rmeddis@0 1392
rmeddis@0 1393 samplesPerPeriod=stim.nSimilarSamples+stim.nIndependentSamples;
rmeddis@0 1394 periodDuration=samplesPerPeriod*stim.sampleDuration;
rmeddis@0 1395
rmeddis@0 1396 totalNumPeriods=2*floor(stim.toneDuration/periodDuration); % longer than necessary
rmeddis@0 1397 if totalNumPeriods<1
rmeddis@0 1398 error('stimulusCreate: RPN, stimulus duration needs to be longer')
rmeddis@0 1399 end
rmeddis@0 1400
rmeddis@0 1401 RPN=[];
rmeddis@0 1402 for j=1:totalNumPeriods
rmeddis@0 1403 noise=randn(1,ptsPerSample);
rmeddis@0 1404 for i=1:stim.nSimilarSamples
rmeddis@0 1405 RPN=[RPN noise];
rmeddis@0 1406 end
rmeddis@0 1407
rmeddis@0 1408 for i=1:stim.nIndependentSamples
rmeddis@0 1409 noise=randn(1,ptsPerSample);
rmeddis@0 1410 RPN=[RPN noise];
rmeddis@0 1411 end
rmeddis@0 1412 end
rmeddis@0 1413
rmeddis@0 1414 targetStimulusLength=round(stim.toneDuration/FS);
rmeddis@0 1415 RPN=RPN(1:floor(stim.toneDuration*FS)); % take enough for stimulus
rmeddis@0 1416
rmeddis@0 1417 rms=(mean(RPN.^2)^.5); %should be 20 microPascals for 0 dB SPL
rmeddis@0 1418 adjust=20e-6/rms;
rmeddis@0 1419 RPN=RPN*adjust;
rmeddis@0 1420 rms=(mean(RPN.^2)^.5);
rmeddis@0 1421 amplitude=10.^(stim.amplitudesdB/20);
rmeddis@0 1422 RPN=amplitude*RPN;
rmeddis@0 1423 % rms=(mean(noise.^2)^.5);
rmeddis@0 1424 % dBnoise=20*log10(rms/20e-6)
rmeddis@0 1425
rmeddis@0 1426 %--------------------------------------------------------------------applyRampOn
rmeddis@0 1427 function signal=applyRampOn(signal, rampDur, rampOnTime, sampleRate)
rmeddis@0 1428 %applyRampOn applies raised cosine ramp
rmeddis@0 1429 %rampOntime is the time at which the ramp begins
rmeddis@0 1430 %At all other times the mask has a value of 1
rmeddis@0 1431 %signal=applyRampOn(signal, rampDur, rampOnTime, sampleRate)
rmeddis@0 1432
rmeddis@0 1433 rampDurPoints=round(rampDur*sampleRate);
rmeddis@0 1434 rampOn= (1+cos(pi:pi/(rampDurPoints-1): 2*pi))/2';
rmeddis@0 1435
rmeddis@0 1436 sigDurPoints=length(signal);
rmeddis@0 1437 mask(1:sigDurPoints)=1;
rmeddis@0 1438 rampOnStartIndex=round(rampOnTime*sampleRate+1);
rmeddis@0 1439 mask(rampOnStartIndex: rampOnStartIndex+ rampDurPoints-1)=rampOn;
rmeddis@0 1440 signal=signal.*mask;
rmeddis@0 1441 %plot(mask)
rmeddis@0 1442
rmeddis@0 1443 %--------------------------------------------------------------------applyRampOff
rmeddis@0 1444 function signal=applyRampOff(signal, rampDur, rampOffTime, sampleRate)
rmeddis@0 1445 %applyRampOn applies raised cosine squared ramp
rmeddis@0 1446 %rampOffTime is the time at which the ramp begins
rmeddis@0 1447 %At all other times the mask has a value of 1
rmeddis@0 1448 % signal=applyRampOff(signal, rampDur, rampOffTime, sampleRate)
rmeddis@0 1449
rmeddis@0 1450 rampDurPoints=round(rampDur*sampleRate);
rmeddis@0 1451 rampOff= (1+cos(0:pi/(rampDurPoints-1): pi))/2';
rmeddis@0 1452
rmeddis@0 1453 sigDurPoints=length(signal);
rmeddis@0 1454 mask=ones(1,sigDurPoints);
rmeddis@0 1455 rampOffStartIndex=round(rampOffTime*sampleRate+1);
rmeddis@0 1456 mask(rampOffStartIndex: round(rampOffStartIndex+ rampDurPoints-1))=rampOff;
rmeddis@0 1457 if length(mask)>sigDurPoints, mask=mask(1:sigDurPoints); end
rmeddis@0 1458 signal=signal.*mask;
rmeddis@0 1459 %plot(mask)
rmeddis@0 1460
rmeddis@0 1461 function signal=applyGaussianRamps(signal, sigma, sampleRate)
rmeddis@0 1462 dt=1/sampleRate;
rmeddis@0 1463 time=dt:dt:dt*length(signal);
rmeddis@0 1464 ramp=1-exp(-time.^2/(2*sigma^2));
rmeddis@0 1465 % apply onset ramp
rmeddis@0 1466 signal=signal.*ramp;
rmeddis@0 1467 % apply offset ramp
rmeddis@0 1468 ramp=fliplr(ramp);
rmeddis@0 1469 signal=signal.*ramp;
rmeddis@0 1470
rmeddis@0 1471
rmeddis@0 1472
rmeddis@0 1473 %--------------------------------------------------------------------checkDescriptors
rmeddis@0 1474 function [globalStimParams, stimComponents]=checkDescriptors(globalStimParams, stimComponents);
rmeddis@0 1475
rmeddis@0 1476 try
rmeddis@0 1477 % if FS exists, it takes priority
rmeddis@0 1478 globalStimParams.dt=1/globalStimParams.FS;
rmeddis@0 1479 catch
rmeddis@0 1480 % otherwise set FS using dt
rmeddis@0 1481 globalStimParams.FS=1/globalStimParams.dt;
rmeddis@0 1482 end
rmeddis@0 1483
rmeddis@0 1484 globalStimParams.nSignalPoints=round(globalStimParams.overallDuration/globalStimParams.dt);
rmeddis@0 1485
rmeddis@0 1486 % optional field (ears)
rmeddis@0 1487 try
rmeddis@0 1488 globalStimParams.ears;
rmeddis@0 1489 catch
rmeddis@0 1490 % default: dichotic.
rmeddis@0 1491 globalStimParams.ears='dichotic';
rmeddis@0 1492 end
rmeddis@0 1493
rmeddis@0 1494 % audioOutCorrection is optional
rmeddis@0 1495 % audioOutCorrection is a scalar for reducing the sound
rmeddis@0 1496 try
rmeddis@0 1497 globalStimParams.audioOutCorrection;
rmeddis@0 1498 catch
rmeddis@0 1499 % set to 1 if omitted
rmeddis@0 1500 globalStimParams.audioOutCorrection=1;
rmeddis@0 1501 end
rmeddis@0 1502
rmeddis@0 1503 try
rmeddis@0 1504 globalStimParams.doPlay;
rmeddis@0 1505 catch
rmeddis@0 1506 % default plays sound only if explicitly requested
rmeddis@0 1507 globalStimParams.doPlay=0;
rmeddis@0 1508 end
rmeddis@0 1509
rmeddis@0 1510 try
rmeddis@0 1511 globalStimParams.doPlot;
rmeddis@0 1512 catch
rmeddis@0 1513 % no plotting unless explicitly requested
rmeddis@0 1514 globalStimParams.doPlot=0;
rmeddis@0 1515 end
rmeddis@0 1516
rmeddis@0 1517
rmeddis@0 1518
rmeddis@0 1519 [ears nComponentSounds]=size(stimComponents);
rmeddis@0 1520
rmeddis@0 1521 for ear=1:2 % 1=left/ 2=right
rmeddis@0 1522
rmeddis@0 1523 % create a list of components whose type is specified
rmeddis@0 1524 % if no type is specified assume that it is an empty specification
rmeddis@0 1525 % this is allowed
rmeddis@0 1526 validStimComponents=[];
rmeddis@0 1527 for i=1:nComponentSounds
rmeddis@0 1528 try
rmeddis@0 1529 if ~isempty(stimComponents(ear,i).type)
rmeddis@0 1530 validStimComponents=[validStimComponents i];
rmeddis@0 1531 end
rmeddis@0 1532 catch
rmeddis@0 1533 end
rmeddis@0 1534 end
rmeddis@0 1535
rmeddis@0 1536 for componentNo=validStimComponents
rmeddis@0 1537 % If no AM filed is present, create it for completeness
rmeddis@0 1538 if ~isfield(stimComponents(ear,componentNo),'AMfrequency') |...
rmeddis@0 1539 ~isfield(stimComponents(ear,componentNo),'AMdepth')
rmeddis@0 1540 stimComponents(ear,componentNo).AMfrequency=0;
rmeddis@0 1541 stimComponents(ear,componentNo).AMdepth=0;
rmeddis@0 1542 end
rmeddis@0 1543
rmeddis@0 1544 % all signals must have durations, amplitudes and ramps
rmeddis@0 1545 if ...
rmeddis@0 1546 isempty(stimComponents(ear,componentNo).type) |...
rmeddis@0 1547 isempty(stimComponents(ear,componentNo).toneDuration) |...
rmeddis@0 1548 isempty(stimComponents(ear,componentNo).amplitudesdB) |...
rmeddis@0 1549 isempty(stimComponents(ear,componentNo).rampOnDur)
rmeddis@0 1550 descriptorError( 'missing stimComponent descriptor', stimComponents, ear, componentNo)
rmeddis@0 1551 end
rmeddis@0 1552
rmeddis@0 1553 try, stimComponents(ear,componentNo).endSilence; catch, stimComponents(ear,componentNo).endSilence=-1; end
rmeddis@0 1554
rmeddis@0 1555 % ramp checks do not apply to file input
rmeddis@0 1556 if ~strcmp(stimComponents(ear,componentNo).type, 'file')
rmeddis@0 1557 % match offset ramp to onset if not explicitly specified
rmeddis@0 1558 if stimComponents(ear,componentNo).rampOffDur==-1,
rmeddis@0 1559 stimComponents(ear,componentNo).rampOffDur=stimComponents(ear,componentNo).rampOnDur;
rmeddis@0 1560 end
rmeddis@0 1561 % ramps must be shorter than the stimulus
rmeddis@0 1562 if stimComponents(ear,componentNo).rampOffDur> stimComponents(ear,componentNo).toneDuration | ...
rmeddis@0 1563 stimComponents(ear,componentNo).rampOnDur> stimComponents(ear,componentNo).toneDuration
rmeddis@0 1564 descriptorError( 'ramp longer than sound component', stimComponents, ear, componentNo)
rmeddis@0 1565 end
rmeddis@0 1566 end
rmeddis@0 1567
rmeddis@0 1568 % end silence is measured to fit into the global duration
rmeddis@0 1569 if stimComponents(ear,componentNo).endSilence==-1,
rmeddis@0 1570 endSilenceNpoints=...
rmeddis@0 1571 globalStimParams.nSignalPoints ...
rmeddis@0 1572 -round(stimComponents(ear,componentNo).beginSilence*globalStimParams.FS)...
rmeddis@0 1573 -round(stimComponents(ear,componentNo).toneDuration*globalStimParams.FS);
rmeddis@0 1574 stimComponents(ear,componentNo).endSilence=endSilenceNpoints/globalStimParams.FS;
rmeddis@0 1575 % if endSilence < 0, we have a problem
rmeddis@0 1576 if stimComponents(ear,componentNo).endSilence<0
rmeddis@0 1577 globalStimParams
rmeddis@0 1578 descriptorError( 'component durations greater than overallDuration', stimComponents, ear, componentNo)
rmeddis@0 1579 end
rmeddis@0 1580 end
rmeddis@0 1581
rmeddis@0 1582 % check overall duration of this component against global duration
rmeddis@0 1583 totalDuration= ...
rmeddis@0 1584 stimComponents(ear,componentNo).beginSilence+...
rmeddis@0 1585 stimComponents(ear,componentNo).toneDuration+...
rmeddis@0 1586 stimComponents(ear,componentNo).endSilence;
rmeddis@0 1587
rmeddis@0 1588 % avoid annoying error message for single stimulus component
rmeddis@0 1589 if ears==1 && nComponentSounds==1
rmeddis@0 1590 globalStimParams.overallDuration= totalDuration;
rmeddis@0 1591 end
rmeddis@0 1592
rmeddis@0 1593
rmeddis@0 1594 if round(totalDuration*globalStimParams.FS)>round(globalStimParams.overallDuration*globalStimParams.FS)
rmeddis@0 1595 globalStimParams
rmeddis@0 1596 descriptorError( 'Component durations greater than overallDuration', stimComponents, ear, componentNo)
rmeddis@0 1597 end
rmeddis@0 1598
rmeddis@0 1599 % check total duration
rmeddis@0 1600 totalSignalPoints= round((stimComponents(ear,componentNo).beginSilence+ stimComponents(ear,componentNo).toneDuration+...
rmeddis@0 1601 stimComponents(ear,componentNo).endSilence)/globalStimParams.dt);
rmeddis@0 1602 if totalSignalPoints >globalStimParams.nSignalPoints
rmeddis@0 1603 descriptorError( 'Signal component duration does not match overall duration ', stimComponents, ear, componentNo)
rmeddis@0 1604 end
rmeddis@0 1605
rmeddis@0 1606 % no ramps for clicks please!
rmeddis@0 1607 % if strcmp(stimComponents(ear,componentNo).type, 'clicks') & stimComponents(ear,componentNo).clickRepeatFrequency==-1
rmeddis@0 1608 % if strcmp(stimComponents(ear,componentNo).type, 'clicks')
rmeddis@0 1609 % stimComponents(ear,componentNo).rampOnDur=0;
rmeddis@0 1610 % stimComponents(ear,componentNo).rampOffDur=0;
rmeddis@0 1611 % end
rmeddis@0 1612
rmeddis@0 1613 if isfield(stimComponents(ear,componentNo), 'filter')
rmeddis@0 1614 if ~isequal(length(stimComponents(ear,componentNo).filter), 3)
rmeddis@0 1615 descriptorError( 'Filter parameter must have three elements ', stimComponents, ear, componentNo)
rmeddis@0 1616 end
rmeddis@0 1617 end
rmeddis@0 1618 end % component
rmeddis@0 1619 % ??
rmeddis@0 1620 if strcmp(globalStimParams.ears,'monoticL') | strcmp(globalStimParams.ears, 'monoticR'), break, end
rmeddis@0 1621 end % ear
rmeddis@0 1622
rmeddis@0 1623
rmeddis@0 1624 %-------------------------------------------------------------------- descriptorError
rmeddis@0 1625 function descriptorError( msg, stimComponents, ear, componentNo)
rmeddis@0 1626 stimComponents(ear, componentNo)
rmeddis@0 1627
rmeddis@0 1628 disp(' *********** **************** ************')
rmeddis@0 1629 disp([ '...Error in stimComponents description: '])
rmeddis@0 1630 disp([msg ])
rmeddis@0 1631 disp(['Ear = ' num2str(ear) ' component No ' num2str(componentNo)])
rmeddis@0 1632 disp(' *********** **************** ************')
rmeddis@0 1633 error('myError ')
rmeddis@0 1634
rmeddis@0 1635
rmeddis@0 1636 %-------------------------------------------------------------------- normalize
rmeddis@0 1637 function [normalizedSignal, gain]= normalize(signal)
rmeddis@0 1638 % normalize (signal)
rmeddis@0 1639 maxSignal=max(max(signal));
rmeddis@0 1640 minSignal=min(min(signal));
rmeddis@0 1641 if -minSignal>maxSignal, normalizingFactor=-minSignal; else normalizingFactor=maxSignal; end
rmeddis@0 1642 normalizingFactor=1.01*normalizingFactor;
rmeddis@0 1643 gain= 20*log10(normalizingFactor);
rmeddis@0 1644 normalizedSignal=signal/normalizingFactor;
rmeddis@0 1645
rmeddis@0 1646
rmeddis@0 1647 %--------------------------------------------------------------------Butterworth
rmeddis@0 1648 function y=Butterworth (x, dt, fl, fu, order)
rmeddis@0 1649 % Butterworth (x, dt, fu, fl, order)
rmeddis@0 1650 % Taken from Yuel and beauchamp page 261
rmeddis@0 1651 % NB error in their table for K (see their text)
rmeddis@0 1652 % x is original signal
rmeddis@0 1653 % fu, fl upper and lower cutoff
rmeddis@0 1654 % order is the number of times the filter is applied
rmeddis@0 1655
rmeddis@0 1656 q=(pi*dt*(fu-fl));
rmeddis@0 1657 J=1/(1+ cot(q));
rmeddis@0 1658 K= (2*cos(pi*dt*(fu+fl)))/(1+tan(q)*cos(q));
rmeddis@0 1659 L= (tan(q)-1)/(tan(q)+1);
rmeddis@0 1660 b=[J -J];
rmeddis@0 1661 a=[1 -K -L];
rmeddis@0 1662 for i=1:order
rmeddis@0 1663 y=filter(b, a, x);
rmeddis@0 1664 x=y;
rmeddis@0 1665 end
rmeddis@0 1666
rmeddis@0 1667
rmeddis@0 1668 % -------------------------------------------------------- UTIL_amp2dB
rmeddis@0 1669 function [y] = UTIL_amp2dB (x, ref)
rmeddis@0 1670 % Calculates a dB (ref. ref) value 'y' from a peak amplitude number 'x'.
rmeddis@0 1671 % if ref omitted treat as dB
rmeddis@0 1672 % Check the number of arguments that are passed in.
rmeddis@0 1673 if (nargin < 2)
rmeddis@0 1674 ref=1;
rmeddis@0 1675 end
rmeddis@0 1676 if (nargin > 2)
rmeddis@0 1677 error ('Too many arguments');
rmeddis@0 1678 end
rmeddis@0 1679
rmeddis@0 1680 % Check arguments.
rmeddis@0 1681 if x < 0.0
rmeddis@0 1682 error ('Can not calculate the log10 of a negative number');
rmeddis@0 1683 elseif x == 0.0
rmeddis@0 1684 warning ('log10 of zero. The result is set to -1000.0');
rmeddis@0 1685 y = -1000.0;
rmeddis@0 1686 else
rmeddis@0 1687 % Do calculations.
rmeddis@0 1688 y = 20.0 * log10(x/(sqrt(2)*ref));
rmeddis@0 1689
rmeddis@0 1690 end
rmeddis@0 1691
rmeddis@0 1692 %-------------------------------------------------------------------- FFT
rmeddis@0 1693 function showFFT (getFFTsignal, dt)
rmeddis@0 1694 color='r';
rmeddis@0 1695 figure(2), clf,
rmeddis@0 1696 hold off
rmeddis@0 1697
rmeddis@0 1698 % trim initial silence
rmeddis@0 1699 idx=find(getFFTsignal>0);
rmeddis@0 1700 if ~isempty(idx)
rmeddis@0 1701 getFFTsignal=getFFTsignal(idx(1):end);
rmeddis@0 1702 end
rmeddis@0 1703 %trim final silence
rmeddis@0 1704 getFFTsignal=getFFTsignal(end:-1:1);
rmeddis@0 1705 idx=find(getFFTsignal>0);
rmeddis@0 1706 if ~isempty(idx)
rmeddis@0 1707 getFFTsignal=getFFTsignal(idx(1):end);
rmeddis@0 1708 getFFTsignal=getFFTsignal(end:-1:1);
rmeddis@0 1709 end
rmeddis@0 1710
rmeddis@0 1711 % Analyse make stimComponents length a power of 2
rmeddis@0 1712 x=length(getFFTsignal);
rmeddis@0 1713 squareLength=2;
rmeddis@0 1714 while squareLength<=x
rmeddis@0 1715 squareLength=squareLength*2;
rmeddis@0 1716 end
rmeddis@0 1717 squareLength=round(squareLength/2);
rmeddis@0 1718 getFFTsignal=getFFTsignal(1:squareLength);
rmeddis@0 1719 n=length(getFFTsignal);
rmeddis@0 1720
rmeddis@0 1721 minf=100; maxf=20000;
rmeddis@0 1722
rmeddis@0 1723 fft_result = fft(getFFTsignal, n); % Compute FFT of the input signal.
rmeddis@0 1724 fft_power = fft_result .* conj(fft_result);% / n; % Compute power spectrum. Dividing by 'n' we get the power spectral density.
rmeddis@0 1725 fft_phase = angle(fft_result); % Compute the phase spectrum.
rmeddis@0 1726
rmeddis@0 1727 frequencies = (1/dt)*(1:n/2)/n;
rmeddis@0 1728 fft_power=fft_power(1:length(fft_power)/2); % remove mirror frequencies
rmeddis@0 1729 fft_phase=fft_phase(1:length(fft_phase)/2); % remove mirror frequencies
rmeddis@0 1730 fft_powerdB = UTIL_amp2dB (fft_power, max(fft_power)); % convert to dB
rmeddis@0 1731 % jags=find(diff(fft_phase)>0); % unwrap phase
rmeddis@0 1732 % for i=jags, fft_phase(i+1:end)=fft_phase(i+1:end)-2*pi; end
rmeddis@0 1733
rmeddis@0 1734 xlim([minf maxf])
rmeddis@0 1735 semilogx(frequencies, fft_powerdB-max(fft_powerdB), color)
rmeddis@0 1736 ylim([ -20 5])
rmeddis@0 1737
rmeddis@0 1738
rmeddis@0 1739
rmeddis@0 1740 function y=UTIL_lowpassFilterFreq(x, cutOffFrequency, dt)
rmeddis@0 1741 % UTIL_lowpassFilterFreq multi-channel filter
rmeddis@0 1742 %
rmeddis@0 1743 % Usage:
rmeddis@0 1744 % output=UTIL_lowpassFilterFreq(input, cutOffFrequency, dt)
rmeddis@0 1745 %
rmeddis@0 1746 % cutoff should be around 100 Hz for audio work
rmeddis@0 1747 % dt should be <1/50000 s for audio work
rmeddis@0 1748 %
rmeddis@0 1749 % Attenuation is - 6 dB per octave above cutoff.
rmeddis@0 1750
rmeddis@0 1751
rmeddis@0 1752 sampleRate=1/dt;
rmeddis@0 1753
rmeddis@0 1754 if 4*cutOffFrequency>sampleRate
rmeddis@0 1755 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' ])
rmeddis@0 1756 cutOffFrequency=sampleRate/4;
rmeddis@0 1757 end
rmeddis@0 1758
rmeddis@0 1759 tau=1/(2*pi*cutOffFrequency);
rmeddis@0 1760
rmeddis@0 1761 y=zeros(size(x));
rmeddis@0 1762 [numChannels numPoints]=size(x);
rmeddis@0 1763 for i=1:numChannels
rmeddis@0 1764 y(i,:)=filter([dt/tau], [1 -(1-dt/tau)], x(i,:));
rmeddis@0 1765 end
rmeddis@0 1766
rmeddis@0 1767