annotate utilities/stimulusCreate.m @ 37:771a643d5c29

mainly nmanuals
author Ray Meddis <rmeddis@essex.ac.uk>
date Thu, 06 Oct 2011 15:43:20 +0100
parents 25d53244d5c8
children c2204b18f4a2
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@35 503 if ispc
rmeddis@35 504 wavplay(audio,globalStimParams.FS)
rmeddis@35 505 else
rmeddis@35 506 sound(audio,globalStimParams.FS)
rmeddis@35 507 end
rmeddis@35 508
rmeddis@0 509 wavplay(audio,globalStimParams.FS)
rmeddis@0 510 end
rmeddis@0 511 % all Done
rmeddis@0 512 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
rmeddis@0 513
rmeddis@0 514
rmeddis@0 515
rmeddis@0 516 %---------------------------------------------------- maketone
rmeddis@0 517 function tone=maketone(globalStimParams, stimComponents)
rmeddis@0 518 % maketone generates a stimComponents tone
rmeddis@0 519 % tone=maketone(dt, frequencies, toneDuration, dBSPL, phases)
rmeddis@0 520 % tone is returned in Pascals
rmeddis@0 521 % frequencies is a list of frequencies
rmeddis@0 522 % phase is list of phases or 'sin', 'cos', 'alt'
rmeddis@0 523 %
rmeddis@0 524 % defaults:
rmeddis@0 525 % phase = sin
rmeddis@0 526 % dBSPL=56 dB SPL
rmeddis@0 527
rmeddis@0 528 dt=globalStimParams.dt;
rmeddis@0 529 frequencies=stimComponents.frequencies;
rmeddis@0 530 toneDuration=stimComponents.toneDuration;
rmeddis@0 531 dBSPL=stimComponents.amplitudesdB;
rmeddis@0 532 phases=stimComponents.phases;
rmeddis@0 533
rmeddis@0 534 if ischar(phases)
rmeddis@0 535 switch phases
rmeddis@0 536 case 'sin'
rmeddis@0 537 phases= zeros(1,length(frequencies));
rmeddis@0 538 case 'cos'
rmeddis@0 539 phases= pi/2*ones(1,length(frequencies));
rmeddis@0 540 case 'alt'
rmeddis@0 541 phases= repmat([0 pi/2], 1, floor(length(frequencies)/2));
rmeddis@0 542 if length(phases)<length(frequencies)
rmeddis@0 543 phases=[phases 0];
rmeddis@0 544 end
rmeddis@0 545 case {'ran', 'rand'}
rmeddis@0 546 phases= 2*pi*rand(1,length(frequencies));
rmeddis@0 547 end
rmeddis@0 548 end
rmeddis@0 549
rmeddis@0 550 if length(phases)==1, phases=repmat(phases(1), 1, length(frequencies)); end
rmeddis@0 551 if length(phases)<length(frequencies)
rmeddis@0 552 error('makeTone:phase specification must have the same length as frequencies')
rmeddis@0 553 end
rmeddis@0 554
rmeddis@0 555 if length(dBSPL)==1, dBSPL=repmat(dBSPL(1), 1, length(frequencies)); end
rmeddis@0 556 if length(dBSPL)<length(dBSPL)
rmeddis@0 557 error('makeTone:dBSPL specification must have the same length as frequencies')
rmeddis@0 558 end
rmeddis@0 559
rmeddis@0 560 time=dt:dt:toneDuration;
rmeddis@0 561 amplitudes=28e-6* 10.^(dBSPL/20);
rmeddis@0 562
rmeddis@0 563 tone=zeros(size(time));
rmeddis@0 564 for i=1:length(frequencies)
rmeddis@0 565 frequency=frequencies(i);
rmeddis@0 566 phase=phases(i);
rmeddis@0 567 tone=tone+amplitudes(i)*sin(2*pi*frequency*time+phase);
rmeddis@0 568 end
rmeddis@0 569
rmeddis@0 570 % figure(1), plot(time, signal)
rmeddis@0 571
rmeddis@0 572
rmeddis@0 573 %---------------------------------------------------- makeOHIOtones
rmeddis@0 574 function stimulus=makeOHIOtones(globalStimParams, stimComponents)
rmeddis@0 575
rmeddis@0 576 % Generates a stimulus consisting of one or more 10-ms tones
rmeddis@0 577 % Tones are presented at 10-ms intervals
rmeddis@0 578 % Each tone has its own amplitude and its own ramp.
rmeddis@0 579
rmeddis@0 580 frequencies=stimComponents.frequencies;
rmeddis@0 581 amplitudesdB=stimComponents.amplitudesdB;
rmeddis@0 582 nFrequencies=length(frequencies);
rmeddis@0 583
rmeddis@0 584 dt=globalStimParams.dt;
rmeddis@0 585 toneDuration=.010;
rmeddis@0 586 time=dt:dt:toneDuration;
rmeddis@0 587
rmeddis@0 588 rampDuration=stimComponents.rampOnDur;
rmeddis@0 589 rampTime=dt:dt:rampDuration;
rmeddis@0 590 ramp=[0.5*(1+cos(2*pi*rampTime/(2*rampDuration)+pi)) ones(1,length(time)-length(rampTime))];
rmeddis@0 591 ramp=ramp.*fliplr(ramp);
rmeddis@0 592
rmeddis@0 593 stimulus= zeros(1,round((toneDuration+globalStimParams.beginSilences(end))/dt)+1);
rmeddis@0 594
rmeddis@0 595 for i=1:nFrequencies
rmeddis@0 596 toneBeginPTR=round(globalStimParams.beginSilences(i)/dt)+1;
rmeddis@0 597
rmeddis@0 598 frequency=frequencies(i);
rmeddis@0 599 dBSPL=amplitudesdB(i);
rmeddis@0 600 amplitude=28e-6* 10.^(dBSPL/20);
rmeddis@0 601 tone=amplitude*sin(2*pi*frequency*time);
rmeddis@0 602 tone=tone.*ramp;
rmeddis@0 603 stimulus(toneBeginPTR:toneBeginPTR+length(tone)-1)=stimulus(toneBeginPTR:toneBeginPTR+length(tone)-1)+tone;
rmeddis@0 604 end
rmeddis@0 605 % figure(2), plot( stimulus')
rmeddis@0 606
rmeddis@0 607
rmeddis@0 608 %---------------------------------------------------- makeFMtone
rmeddis@0 609 function tone=makeFMtone(globalStimParams, stimComponents)
rmeddis@0 610 % maketone generates a stimComponents tone
rmeddis@0 611 % tone=maketone(dt, frequencies, toneDuration, dBSPL, phases)
rmeddis@0 612 % tone is returned in Pascals
rmeddis@0 613 % frequencies is a list of frequencies
rmeddis@0 614 % phase is list of phases or 'sin', 'cos', 'alt'
rmeddis@0 615 %
rmeddis@0 616 % defaults:
rmeddis@0 617 % phase = sin
rmeddis@0 618 % dBSPL=56 dB SPL
rmeddis@0 619
rmeddis@0 620 dt=globalStimParams.dt;
rmeddis@0 621 frequencies=stimComponents.frequencies;
rmeddis@0 622 toneDuration=stimComponents.toneDuration;
rmeddis@0 623 dBSPL=stimComponents.amplitudesdB;
rmeddis@0 624 phases=stimComponents.phases;
rmeddis@0 625 fmDepth=stimComponents.fmDepth;
rmeddis@0 626 fmFrequency=stimComponents.fmFrequency;
rmeddis@0 627
rmeddis@0 628 if ischar(phases)
rmeddis@0 629 switch phases
rmeddis@0 630 case 'sin'
rmeddis@0 631 phases= zeros(1,length(frequencies));
rmeddis@0 632 case 'cos'
rmeddis@0 633 phases= pi/2*ones(1,length(frequencies));
rmeddis@0 634 case 'alt'
rmeddis@0 635 phases= repmat([0 pi/2], 1, floor(length(frequencies)/2));
rmeddis@0 636 if length(phases)<length(frequencies)
rmeddis@0 637 phases=[phases 0];
rmeddis@0 638 end
rmeddis@0 639 end
rmeddis@0 640 end
rmeddis@0 641
rmeddis@0 642 if length(phases)==1, phases=repmat(phases(1), 1, length(frequencies)); end
rmeddis@0 643 if length(phases)<length(frequencies)
rmeddis@0 644 error('makeTone:phase specification must have the same length as frequencies')
rmeddis@0 645 end
rmeddis@0 646
rmeddis@0 647 if length(dBSPL)==1, dBSPL=repmat(dBSPL(1), 1, length(frequencies)); end
rmeddis@0 648 if length(dBSPL)<length(dBSPL)
rmeddis@0 649 error('makeTone:dBSPL specification must have the same length as frequencies')
rmeddis@0 650 end
rmeddis@0 651
rmeddis@0 652 time=dt:dt:toneDuration;
rmeddis@0 653 amplitudes=28e-6* 10.^(dBSPL/20);
rmeddis@0 654
rmeddis@0 655 tone=zeros(size(time));
rmeddis@0 656 for i=1:length(frequencies)
rmeddis@0 657 frequency=frequencies(i);
rmeddis@0 658 phase=phases(i);
rmeddis@0 659 tone=tone+amplitudes(i)*sin(2*pi*frequency*time+phase + fmDepth*sin(2*pi*fmFrequency*time));
rmeddis@0 660 end
rmeddis@0 661
rmeddis@0 662 % figure(1), plot(time, signal)
rmeddis@0 663
rmeddis@0 664 %----------------------------------------------------makeTransposedStimulus
rmeddis@0 665 function [transposedStimulus]=makeTransposedStimulus(globalStimParams, stim)
rmeddis@0 666 % globalStimParams.FS=100000;
rmeddis@0 667 % globalStimParams.overallDuration=.1; % s
rmeddis@0 668 % globalStimParams.doPlot=1;
rmeddis@0 669 %
rmeddis@0 670 % stim.type='transposedStimulus';
rmeddis@0 671 % stim.phases='sin';
rmeddis@0 672 % stim.toneDuration=.05;;
rmeddis@0 673 % stim.frequencies=500;
rmeddis@0 674 % stim.amplitudesdB=50;
rmeddis@0 675 % stim.beginSilence=.01;
rmeddis@0 676 % stim.endSilence=-1;
rmeddis@0 677 % stim.rampOnDur=.002;
rmeddis@0 678 % stim.rampOffDur=-1;
rmeddis@0 679 %
rmeddis@0 680 % stim.transCarrierFreq=4000;
rmeddis@0 681 % stim.transModFreq=100;
rmeddis@0 682
rmeddis@0 683 transposedStimulus=[];
rmeddis@0 684 % make envelope of transposed tone
rmeddis@0 685 for i=1:length(stim.transModFreq)
rmeddis@0 686 stim.type='tone';
rmeddis@0 687 stim.frequencies=stim.transModFreq(i);
rmeddis@0 688 stim.endsilence=-1; stim.beginSilence=0;
rmeddis@0 689 [envelope, msg]=stimulusCreate(globalStimParams, stim); % NB recursive
rmeddis@0 690 envelope=envelope(:,1); % mono
rmeddis@0 691 % HW rectify
rmeddis@0 692 envelope(find(envelope<0))=0;
rmeddis@0 693 % LP filter
rmeddis@0 694 maxEnvelope=max(envelope);
rmeddis@0 695 envelope=UTIL_Butterworth (envelope, globalStimParams.dt, 10, .2*stim.transModFreq(i), 2);
rmeddis@0 696 envelope=envelope*maxEnvelope/max(envelope);
rmeddis@0 697
rmeddis@0 698 % make the carrier
rmeddis@0 699 stim.frequencies=stim.transCarrierFreq(i);
rmeddis@0 700 stim.endsilence=-1; stim.beginSilence=0;
rmeddis@0 701 [audio, msg]=stimulusCreate(globalStimParams, stim);
rmeddis@0 702 carrier=audio(:,1);
rmeddis@0 703 x= (carrier.*envelope)';
rmeddis@0 704 % base amplitude on peak of unmodulated carrier
rmeddis@0 705 x=x/max(carrier);
rmeddis@0 706 transposedStimulus=[transposedStimulus; x];
rmeddis@0 707 end
rmeddis@0 708 transposedStimulus=sum(transposedStimulus,1);
rmeddis@0 709 % clf,plot(transposedStimulus)
rmeddis@0 710
rmeddis@0 711 %--------------------------------------------------------------------makeClicks
rmeddis@0 712 function clickTrain=makeClicks(globalStimParams, stimComponents)
rmeddis@0 713 % makeClicks(F0, clickTimes, duration, FS);
rmeddis@0 714 % F0 specifies the repetition rate of the click sequence
rmeddis@0 715 % If F0=-1, a single click is generated at the start of the duration of the signal
rmeddis@0 716 %
rmeddis@0 717 % clickTimes a are fractions of the period
rmeddis@0 718 % and specify when the click appears in the period
rmeddis@0 719 % A click time of 1 is reset to zero.
rmeddis@0 720 % if the clicktime plus the click width is greater than the period, no click is generated
rmeddis@0 721 % clicks are treated as 20 microPascal high before amplification
rmeddis@0 722 % unless otherwise specified in stimComponents.clickHeight
rmeddis@0 723 % click width is dt unless specified in stimComponents.clickWidth
rmeddis@0 724 %
rmeddis@0 725 % for regular pulse train set clicktimes=1 or zero;
rmeddis@0 726 % FS is the sampling interval;
rmeddis@0 727 % CarlyonClickTrain(100, [.4 1], 40, 441000);
rmeddis@0 728
rmeddis@0 729 FS=globalStimParams.FS; % sample rate
rmeddis@0 730 dt=1/FS;
rmeddis@0 731
rmeddis@0 732 try,clickWidth=stimComponents.clickWidth;catch, clickWidth=dt; end
rmeddis@0 733 try,clickHeight=stimComponents.clickHeight; catch, clickHeight=28e-6 * 10^(stimComponents.amplitudesdB/20); end
rmeddis@0 734 try, clickTimes=stimComponents.clickTimes; catch, clickTimes=1; end
rmeddis@0 735
rmeddis@0 736 % clickTimes are the times in a cycle that the click
rmeddis@0 737 % occurs
rmeddis@0 738 checkClickTimes=clickTimes-1;
rmeddis@0 739 if max(checkClickTimes)>1
rmeddis@0 740 msg= 'click times must be <= than 1 (period)';
rmeddis@0 741 return
rmeddis@0 742 end
rmeddis@0 743
rmeddis@0 744 if clickWidth>=1/stimComponents.clickRepeatFrequency
rmeddis@0 745 msg= 'click width is too great for frequency';
rmeddis@0 746 return
rmeddis@0 747 end
rmeddis@0 748
rmeddis@0 749 duration=stimComponents.toneDuration;
rmeddis@0 750 totalLength=round(stimComponents.toneDuration/dt);
rmeddis@0 751 F0=stimComponents.clickRepeatFrequency;
rmeddis@0 752 F0=round(F0/dt)*dt;
rmeddis@0 753 if F0==-1 % single click required
rmeddis@0 754 F0=1/duration;
rmeddis@0 755 repetitions=1;
rmeddis@0 756 clickStartTimes=1; %clicktimes are fractions of a period
rmeddis@0 757 else
rmeddis@0 758 repetitions=round(F0*duration)-1;
rmeddis@0 759 duration=repetitions/F0;
rmeddis@0 760 clickStartTimes=clickTimes;
rmeddis@0 761 end
rmeddis@0 762 % if a clickTime=1 (end of duty period) set it to the beginning
rmeddis@0 763 clickStartTimes(clickStartTimes==1)=0;
rmeddis@0 764
rmeddis@0 765 period=1/F0;
rmeddis@0 766 time=dt:dt:period;
rmeddis@0 767 nPoints=length(time);
rmeddis@0 768 signal=zeros(1,nPoints);
rmeddis@0 769 dBSPL=stimComponents.amplitudesdB;
rmeddis@0 770
rmeddis@0 771 % compute click train for a single cycle
rmeddis@0 772 clickWidthNpoints=round(clickWidth*FS);
rmeddis@0 773 for i=1:length(clickStartTimes)
rmeddis@0 774 % if clickStartTimes(i)<clickWidth
rmeddis@0 775 % clickStartTimes(i)=dt;
rmeddis@0 776 % end
rmeddis@0 777 clickTime=round(period*clickStartTimes(i)/dt -dt);
rmeddis@0 778 % clicks are treated as 20 microPascal high
rmeddis@0 779 if clickTime+clickWidthNpoints<length(signal)
rmeddis@0 780 signal(clickTime+1:clickTime+clickWidthNpoints)=clickHeight;
rmeddis@0 781 end
rmeddis@0 782 end
rmeddis@0 783
rmeddis@0 784 clickTrain=repmat(signal, 1, repetitions);
rmeddis@0 785
rmeddis@0 786 if length(clickTrain)>totalLength
rmeddis@0 787 clickTrain=clickTrain(1:totalLength);
rmeddis@0 788 elseif length(clickTrain)<totalLength
rmeddis@0 789 timeToAdd=zeros(1,round((totalLength-length(clickTrain))));
rmeddis@0 790 clickTrain=[clickTrain timeToAdd];
rmeddis@0 791 % figure (1), plot(clickTrain)
rmeddis@0 792 end
rmeddis@0 793
rmeddis@0 794 %----------------------------------------------------------------makePressnitzerClicks
rmeddis@0 795 function signal=makePressnitzerClicks(globalStimParams, stimComponents)
rmeddis@0 796 % PressnitzerClicks(k,duration,dt)
rmeddis@0 797 % Generates a sequence of clicks with intervals kxx
rmeddis@0 798 % where x= rand*k/2
rmeddis@0 799 % This is not the same as Kaernbach and Demany clicks
rmeddis@0 800
rmeddis@0 801 FS=globalStimParams.FS; % sample rate
rmeddis@0 802 dt=1/FS;
rmeddis@0 803
rmeddis@0 804 % obligatory parameter
rmeddis@0 805 try
rmeddis@0 806 k=stimComponents.k;
rmeddis@0 807 catch
rmeddis@0 808 error('PressnitzerClicks: field ''k'' is missing from stimcomponent')
rmeddis@0 809 end
rmeddis@0 810
rmeddis@0 811 % optional parameters
rmeddis@0 812 if isfield(stimComponents,'clickWidth')
rmeddis@0 813 clickWidth=stimComponents.clickWidth;
rmeddis@0 814 else
rmeddis@0 815 clickWidth=dt;
rmeddis@0 816 end
rmeddis@0 817 clickWidthNpoints=round(clickWidth*FS);
rmeddis@0 818
rmeddis@0 819 if isfield(stimComponents,'clickHeight')
rmeddis@0 820 clickHeight=stimComponents.clickHeight;
rmeddis@0 821 else
rmeddis@0 822 clickHeight=28e-6 * 10^(stimComponents.amplitudesdB/20);
rmeddis@0 823 end
rmeddis@0 824
rmeddis@0 825 duration=stimComponents.toneDuration;
rmeddis@0 826
rmeddis@0 827 signalLength=round(duration/dt);
rmeddis@0 828 signal=zeros(1,signalLength);
rmeddis@0 829 kInterval=round(k/dt);
rmeddis@0 830 halfk=k/2;
rmeddis@0 831 signal(1)=clickHeight;
rmeddis@0 832 timeIdx=0;
rmeddis@0 833 while timeIdx<signalLength
rmeddis@0 834 % first interval = k
rmeddis@0 835 clickTime=timeIdx+kInterval;
rmeddis@0 836 signal(clickTime:clickTime+clickWidthNpoints)=clickHeight;
rmeddis@0 837 timeIdx=timeIdx+kInterval;
rmeddis@0 838
rmeddis@0 839 % second 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
rmeddis@0 845 % third interval = 0 : k/2
rmeddis@0 846 intervalx1=round(rand*halfk/dt);
rmeddis@0 847 clickTime=timeIdx+intervalx1;
rmeddis@0 848 signal(clickTime:clickTime+clickWidthNpoints)=clickHeight;
rmeddis@0 849 timeIdx=timeIdx+intervalx1;
rmeddis@0 850 end
rmeddis@0 851
rmeddis@0 852 signal=signal(1:signalLength);
rmeddis@0 853 % figure(1), plot(dt:dt:duration,signal)
rmeddis@0 854
rmeddis@0 855 %----------------------------------------------------------------makePressnitzerABXClicks
rmeddis@0 856 function signal=makePressnitzerABxClicks(globalStimParams, stimComponents)
rmeddis@0 857 % Generates a sequence of clicks with intervals ABx
rmeddis@0 858 % AB interval is 2*k
rmeddis@0 859 % where A= rand* k
rmeddis@0 860 % B= k-A
rmeddis@0 861 % x= k/2
rmeddis@0 862 % These are second order clicks
rmeddis@0 863
rmeddis@0 864 FS=globalStimParams.FS; % sample rate
rmeddis@0 865 dt=1/FS;
rmeddis@0 866
rmeddis@0 867 % obligatory parameter
rmeddis@0 868 try
rmeddis@0 869 k=stimComponents.k;
rmeddis@0 870 catch
rmeddis@0 871 error('PressnitzerClicks: field ''k'' is missing from stimcomponent')
rmeddis@0 872 end
rmeddis@0 873
rmeddis@0 874 % optional parameters
rmeddis@0 875 if isfield(stimComponents,'clickWidth')
rmeddis@0 876 clickWidth=stimComponents.clickWidth;
rmeddis@0 877 else
rmeddis@0 878 clickWidth=dt;
rmeddis@0 879 end
rmeddis@0 880 clickWidthNpoints=round(clickWidth*FS);
rmeddis@0 881
rmeddis@0 882 if isfield(stimComponents,'clickHeight')
rmeddis@0 883 clickHeight=stimComponents.clickHeight;
rmeddis@0 884 else
rmeddis@0 885 clickHeight=28e-6 * 10^(stimComponents.amplitudesdB/20);
rmeddis@0 886 end
rmeddis@0 887
rmeddis@0 888 duration=stimComponents.toneDuration;
rmeddis@0 889
rmeddis@0 890 signalLength=round(duration/dt);
rmeddis@0 891 signal=zeros(1,2*signalLength); % allow for overrun
rmeddis@0 892 ABinterval=k/dt; % i.e. the number of dt steps
rmeddis@0 893 randomInterval=ABinterval/2;
rmeddis@0 894 signal(1)=clickHeight;
rmeddis@0 895 time=0;
rmeddis@0 896 while time<signalLength
rmeddis@0 897 % first interval = A
rmeddis@0 898 intervalA=rand*ABinterval;
rmeddis@0 899 clickTime=round(time+intervalA)+1; % +1 avoids zero index
rmeddis@0 900 signal(clickTime:clickTime+clickWidthNpoints)=clickHeight;
rmeddis@0 901 time=time+intervalA;
rmeddis@0 902
rmeddis@0 903 % second interval = B
rmeddis@0 904 intervalB=ABinterval-intervalA;
rmeddis@0 905 clickTime=round(time+intervalB)+1;
rmeddis@0 906 signal(clickTime:clickTime+clickWidthNpoints-1)=clickHeight;
rmeddis@0 907 time=time+intervalB;
rmeddis@0 908
rmeddis@0 909 % third interval = 0 : k/2
rmeddis@0 910 intervalx1=rand*randomInterval; % mean random interval=k
rmeddis@0 911 clickTime=round(time+intervalx1)+1;
rmeddis@0 912 signal(clickTime:clickTime+clickWidthNpoints-1)=clickHeight;
rmeddis@0 913 time=time+intervalx1;
rmeddis@0 914 end
rmeddis@0 915
rmeddis@0 916 signal=signal(1:signalLength);
rmeddis@0 917 % figure(1), plot(dt:dt:duration,signal)
rmeddis@0 918
rmeddis@0 919 %-----------------------------------------------------makeABxClicks
rmeddis@0 920 function signal=makeABxClicks(globalStimParams, stimComponents)
rmeddis@0 921 % Generates a sequence of clicks with intervals ABx
rmeddis@0 922 % AB interval is 2*k
rmeddis@0 923 % where A= rand* k
rmeddis@0 924 % B= k-A
rmeddis@0 925 % x= rand*2*k
rmeddis@0 926 % These are second order clicks
rmeddis@0 927
rmeddis@0 928 FS=globalStimParams.FS; % sample rate
rmeddis@0 929 dt=1/FS;
rmeddis@0 930
rmeddis@0 931 % obligatory parameter
rmeddis@0 932 try
rmeddis@0 933 k=stimComponents.k;
rmeddis@0 934 catch
rmeddis@0 935 error('PressnitzerClicks: field ''k'' is missing from stimcomponent')
rmeddis@0 936 end
rmeddis@0 937
rmeddis@0 938 % optional parameters
rmeddis@0 939 if isfield(stimComponents,'clickWidth')
rmeddis@0 940 clickWidth=stimComponents.clickWidth;
rmeddis@0 941 else
rmeddis@0 942 clickWidth=dt;
rmeddis@0 943 end
rmeddis@0 944 clickWidthNpoints=round(clickWidth*FS);
rmeddis@0 945
rmeddis@0 946 if isfield(stimComponents,'clickHeight')
rmeddis@0 947 clickHeight=stimComponents.clickHeight;
rmeddis@0 948 else
rmeddis@0 949 clickHeight=28e-6 * 10^(stimComponents.amplitudesdB/20);
rmeddis@0 950 end
rmeddis@0 951
rmeddis@0 952 duration=stimComponents.toneDuration;
rmeddis@0 953
rmeddis@0 954 signalLength=round(duration/dt);
rmeddis@0 955 signal=zeros(1,2*signalLength); % allow for overrun
rmeddis@0 956 ABinterval=2*k/dt;
rmeddis@0 957 randomInterval=ABinterval;
rmeddis@0 958 signal(1)=clickHeight;
rmeddis@0 959 timeIdx=0;
rmeddis@0 960 while timeIdx<signalLength
rmeddis@0 961 % first interval = A
rmeddis@0 962 intervalA=round(rand*ABinterval);
rmeddis@0 963 clickTime=timeIdx+intervalA+1;
rmeddis@0 964 signal(clickTime:clickTime+clickWidthNpoints-1)=clickHeight;
rmeddis@0 965 timeIdx=timeIdx+intervalA;
rmeddis@0 966
rmeddis@0 967 % second interval = B
rmeddis@0 968 intervalB=round(ABinterval-intervalA);
rmeddis@0 969 clickTime=timeIdx+intervalB;
rmeddis@0 970 signal(clickTime:clickTime+clickWidthNpoints-1)=clickHeight;
rmeddis@0 971 timeIdx=timeIdx+intervalB;
rmeddis@0 972
rmeddis@0 973 % third interval = 0 : k
rmeddis@0 974 intervalx1=round(rand*randomInterval); % mean random interval=k
rmeddis@0 975 clickTime=timeIdx+intervalx1;
rmeddis@0 976 signal(clickTime:clickTime+clickWidthNpoints-1)=clickHeight;
rmeddis@0 977 timeIdx=timeIdx+intervalx1;
rmeddis@0 978 end
rmeddis@0 979
rmeddis@0 980 signal=signal(1:signalLength);
rmeddis@0 981 % figure(1), plot(dt:dt:duration,signal)
rmeddis@0 982
rmeddis@0 983 %----------------------------------------------------------------makeYostClicks
rmeddis@0 984 function signal=makeYostClicks(globalStimParams, stimComponents)
rmeddis@0 985 % Generates a shuffled sequence of clicks with intervals kxxxx
rmeddis@0 986 % where max(x)= 2*k
rmeddis@0 987 % and there are n occurrences of x
rmeddis@0 988 % this section requires:
rmeddis@0 989 % stimComponents.k
rmeddis@0 990 % stimComponents.nXs
rmeddis@0 991 % stimComponents.toneDuration
rmeddis@0 992 % optional:
rmeddis@0 993 % stimComponents.clickWidth %useful because width depends on dt
rmeddis@0 994 % stimComponents.clickHeight %best left to amplitude rescaling later
rmeddis@0 995
rmeddis@0 996 FS=globalStimParams.FS; % sample rate
rmeddis@0 997 dt=1/FS;
rmeddis@0 998
rmeddis@0 999 % obligatory parameters
rmeddis@0 1000 try
rmeddis@0 1001 k=stimComponents.k;
rmeddis@0 1002 catch
rmeddis@0 1003 error('makeYostClicks: field ''k'' is missing from stimComponents')
rmeddis@0 1004 end
rmeddis@0 1005
rmeddis@0 1006 try
rmeddis@0 1007 nXs=stimComponents.nXs;
rmeddis@0 1008 catch
rmeddis@0 1009 error('makeYostClicks: field ''nXs'' is missing from stimComponents')
rmeddis@0 1010 end
rmeddis@0 1011
rmeddis@0 1012 try
rmeddis@0 1013 shuffled=stimComponents.shuffled;
rmeddis@0 1014 catch
rmeddis@0 1015 error('makeYostClicks: field ''shuffled'' is missing from stimComponents')
rmeddis@0 1016 end
rmeddis@0 1017
rmeddis@0 1018 try
rmeddis@0 1019 duration=stimComponents.toneDuration;
rmeddis@0 1020 catch
rmeddis@0 1021 error('makeYostClicks: field ''toneDuration'' is missing from stimComponents')
rmeddis@0 1022 end
rmeddis@0 1023
rmeddis@0 1024 % optional parameters
rmeddis@0 1025 if isfield(stimComponents,'clickWidth')
rmeddis@0 1026 clickWidth=stimComponents.clickWidth;
rmeddis@0 1027 else
rmeddis@0 1028 clickWidth=dt;
rmeddis@0 1029 end
rmeddis@0 1030 clickWidthNpoints=round(clickWidth*FS);
rmeddis@0 1031
rmeddis@0 1032 if isfield(stimComponents,'clickHeight')
rmeddis@0 1033 clickHeight=stimComponents.clickHeight;
rmeddis@0 1034 else
rmeddis@0 1035 clickHeight=28e-6 * 10^(stimComponents.amplitudesdB/20);
rmeddis@0 1036 end
rmeddis@0 1037
rmeddis@0 1038 kInterval=round(k/dt);
rmeddis@0 1039 twoK=k*2; % max width of x interval
rmeddis@0 1040
rmeddis@0 1041 signalLength=round(duration/dt);
rmeddis@0 1042 signal=zeros(1,signalLength);
rmeddis@0 1043
rmeddis@0 1044 timeIdx=0;
rmeddis@0 1045 intervalCount=0;
rmeddis@0 1046 while timeIdx<signalLength
rmeddis@0 1047 timeIdx=timeIdx+kInterval;
rmeddis@0 1048 if timeIdx>signalLength, break,end
rmeddis@0 1049 intervalCount=intervalCount+1;
rmeddis@0 1050 intervals(intervalCount)=kInterval;
rmeddis@0 1051
rmeddis@0 1052 % repeat x intervals as required
rmeddis@0 1053 if nXs>0
rmeddis@0 1054 for nX=1:nXs
rmeddis@0 1055 xInterval=round(rand*twoK/dt);
rmeddis@0 1056 timeIdx=timeIdx+xInterval;
rmeddis@0 1057 if timeIdx>signalLength, break,end
rmeddis@0 1058 intervalCount=intervalCount+1;
rmeddis@0 1059 intervals(intervalCount)=xInterval;
rmeddis@0 1060 end
rmeddis@0 1061 end
rmeddis@0 1062 if timeIdx>signalLength, break,end
rmeddis@0 1063 end
rmeddis@0 1064
rmeddis@0 1065 % shuffle intervals
rmeddis@0 1066 if shuffled
rmeddis@0 1067 randomNumbers=rand(1,length(intervals));
rmeddis@0 1068 [randomNumbers idx]=sort(randomNumbers);
rmeddis@0 1069 intervals=intervals(idx);
rmeddis@0 1070 idx=intervals>0;
rmeddis@0 1071 intervals=intervals(idx);
rmeddis@0 1072 end
rmeddis@0 1073
rmeddis@0 1074 intervalCount=length(intervals);
rmeddis@0 1075 signal(1)=clickHeight;
rmeddis@0 1076 clickTime=0;
rmeddis@0 1077 for i=1:intervalCount
rmeddis@0 1078 clickTime=clickTime+intervals(i);
rmeddis@0 1079 signal(clickTime:clickTime+clickWidthNpoints)=clickHeight;
rmeddis@0 1080 end
rmeddis@0 1081 signal=signal(1:signalLength);
rmeddis@0 1082 % figure(1), plot(dt:dt:duration,signal)
rmeddis@0 1083
rmeddis@0 1084 %--------------------------------------------------------------------makeKxxClicks
rmeddis@0 1085 function signal=makeKxxClicks(globalStimParams, stimComponents)
rmeddis@0 1086 % Click train consists of kkxxx.. sequences
rmeddis@0 1087 % k is the duration of a fixed interval (seconds)
rmeddis@0 1088 % random intervals are distributed 0 : 2* k (NB not like Pressnitzer clicks)
rmeddis@0 1089 % nKs is the number of successive 'k' intervals
rmeddis@0 1090 % nXs is the number of random intervals between k sequences
rmeddis@0 1091 % sequences of 3 x intervals > k are replaced with new sequences
rmeddis@0 1092 % shuffled causes all intervals to be reordered randomly
rmeddis@0 1093 % NB 1/k is the mean click rate
rmeddis@0 1094
rmeddis@0 1095 FS=globalStimParams.FS; % sample rate
rmeddis@0 1096 dt=1/FS;
rmeddis@0 1097
rmeddis@0 1098 try
rmeddis@0 1099 k=stimComponents.k; % duration (s) of fixed intervals
rmeddis@0 1100 catch
rmeddis@0 1101 error('makeYostClicks: field ''k'' is missing from stimComponents')
rmeddis@0 1102 end
rmeddis@0 1103
rmeddis@0 1104 try
rmeddis@0 1105 duration=stimComponents.toneDuration;
rmeddis@0 1106 catch
rmeddis@0 1107 error('makeYostClicks: field ''duration'' is missing from stimComponents')
rmeddis@0 1108 end
rmeddis@0 1109
rmeddis@0 1110 if isfield(stimComponents,'clickWidth')
rmeddis@0 1111 clickWidth=stimComponents.clickWidth;
rmeddis@0 1112 else
rmeddis@0 1113 clickWidth=dt;
rmeddis@0 1114 end
rmeddis@0 1115
rmeddis@0 1116 if isfield(stimComponents,'clickHeight')
rmeddis@0 1117 clickHeight=stimComponents.clickHeight;
rmeddis@0 1118 else
rmeddis@0 1119 clickHeight=28e-6 * 10^(stimComponents.amplitudesdB/20);
rmeddis@0 1120 end
rmeddis@0 1121
rmeddis@0 1122
rmeddis@0 1123 if isfield(stimComponents,'order')
rmeddis@0 1124 order=stimComponents.order;
rmeddis@0 1125 else
rmeddis@0 1126 order=1;
rmeddis@0 1127 end
rmeddis@0 1128
rmeddis@0 1129 if isfield(stimComponents,'nKs')
rmeddis@0 1130 nKs=stimComponents.nKs;
rmeddis@0 1131 else
rmeddis@0 1132 nKs=1;
rmeddis@0 1133 end
rmeddis@0 1134
rmeddis@0 1135 if isfield(stimComponents,'nXs')
rmeddis@0 1136 nXs=stimComponents.nXs;
rmeddis@0 1137 else
rmeddis@0 1138 nXs=1;
rmeddis@0 1139 end
rmeddis@0 1140
rmeddis@0 1141 if isfield(stimComponents,'shuffled')
rmeddis@0 1142 shuffled=stimComponents.shuffled;
rmeddis@0 1143 else
rmeddis@0 1144 shuffled=1;
rmeddis@0 1145 end
rmeddis@0 1146
rmeddis@0 1147 kLength=round(k/dt); % fixed interval
rmeddis@0 1148 xLength=2*kLength; % maximum random interval
rmeddis@0 1149 requiredSignalLength=round(duration/dt);
rmeddis@0 1150 intervalsPerCycle=(nKs+nXs);
rmeddis@0 1151 cycleLength=nKs*kLength+nXs*xLength;
rmeddis@0 1152 % more cycles to allow for uncertainty
rmeddis@0 1153 nCycles=5*round(requiredSignalLength/cycleLength);
rmeddis@0 1154 nIntervals=nCycles*intervalsPerCycle;
rmeddis@0 1155
rmeddis@0 1156 % random intervals
rmeddis@0 1157 if nXs>0
rmeddis@0 1158 xIntervals=floor(rand(1,nIntervals)*2*kLength);
rmeddis@0 1159 % weed out triple intervals > 2*k
rmeddis@0 1160 rogues=1;
rmeddis@0 1161 while sum(rogues)
rmeddis@0 1162 y=(xIntervals>kLength);
rmeddis@0 1163 rogues=(sum([y(1:end-2)' y(2:end-1)' y(3:end)'],2)>2);
rmeddis@0 1164 xIntervals(rogues)=floor(rand*2*kLength);
rmeddis@0 1165 end
rmeddis@0 1166 xIntervals=reshape(xIntervals,nCycles,intervalsPerCycle);
rmeddis@0 1167 else
rmeddis@0 1168 xIntervals=[];
rmeddis@0 1169 end
rmeddis@0 1170
rmeddis@0 1171 % insert constrained (k) intervals
rmeddis@0 1172 if nKs>0
rmeddis@0 1173 switch order
rmeddis@0 1174 case 1
rmeddis@0 1175 kIntervals=floor(ones(nCycles,nKs)*kLength);
rmeddis@0 1176 case 2
rmeddis@0 1177 nKs=1; % force this
rmeddis@0 1178 kIntervals=floor(rand(nCycles,1)*kLength);
rmeddis@0 1179 kIntervals=[kIntervals kLength-kIntervals];
rmeddis@0 1180 end
rmeddis@0 1181 else
rmeddis@0 1182 kIntervals=[];
rmeddis@0 1183 end
rmeddis@0 1184
rmeddis@0 1185 % combine fixed and random
rmeddis@0 1186 intervals=[kIntervals xIntervals(:,nKs+1:end)];
rmeddis@0 1187 % make a single array;
rmeddis@0 1188 [r c]=size(intervals);
rmeddis@0 1189 intervals=reshape(intervals',1,r*c);
rmeddis@0 1190
rmeddis@0 1191 % shuffle intervals
rmeddis@0 1192 if shuffled
rmeddis@0 1193 randomNumbers=rand(1,length(intervals));
rmeddis@0 1194 [randomNumbers idx]=sort(randomNumbers);
rmeddis@0 1195 intervals=intervals(idx);
rmeddis@0 1196 idx=intervals>0;
rmeddis@0 1197 intervals=intervals(idx);
rmeddis@0 1198 end
rmeddis@0 1199
rmeddis@0 1200 % convert intervals to clicks
rmeddis@0 1201 clickTimes=cumsum(intervals);
rmeddis@0 1202 signal(clickTimes)=clickHeight;
rmeddis@0 1203 signal=signal(1:requiredSignalLength);
rmeddis@0 1204 % figure(1), clf, plot(signal)
rmeddis@0 1205
rmeddis@0 1206
rmeddis@0 1207
rmeddis@0 1208 %--------------------------------------------------------------------makeNoise
rmeddis@0 1209 function noise=makeNoise(globalStimParams, stimComponents)
rmeddis@0 1210 % FS in Hz, noiseDuration in s, delay in s;
rmeddis@0 1211 % noise is returned with overall level dB(rms) = amplitudesdB
rmeddis@0 1212 %
rmeddis@0 1213 % % You need
rmeddis@0 1214 %
rmeddis@0 1215 % stim.type='noise'; % or 'IRN', or 'pinkNoise'
rmeddis@0 1216 % stim.toneDuration=.05;
rmeddis@0 1217 % stim.amplitudesdB=50;
rmeddis@0 1218 % stim.beginSilence=.01;
rmeddis@0 1219 % stim.endSilence=-1;
rmeddis@0 1220 % stim.rampOnDur=.002;
rmeddis@0 1221 % stim.rampOffDur=-1;
rmeddis@0 1222 %
rmeddis@0 1223 % % Mandatory structure fields
rmeddis@0 1224 % globalStimParams.FS=100000;
rmeddis@0 1225 % globalStimParams.overallDuration=.1; % s
rmeddis@0 1226 % globalStimParams.doPlot=1;
rmeddis@0 1227 % globalStimParams.doPlay=1;
rmeddis@0 1228 %
rmeddis@0 1229 % [audio, msg]=stimulusCreate(globalStimParams, stim, );
rmeddis@0 1230 %
rmeddis@0 1231 % % local
rmeddis@0 1232 % stim.type='noise'; % or 'IRN'
rmeddis@0 1233 %
rmeddis@0 1234 FS=globalStimParams.FS;
rmeddis@0 1235 noiseDuration= stimComponents.toneDuration;
rmeddis@0 1236 npts=round(noiseDuration*FS);
rmeddis@0 1237 noise=randn(1,npts); % NB randn (normally distributed)
rmeddis@0 1238
rmeddis@0 1239 switch stimComponents.type
rmeddis@0 1240 case 'pinkNoise'
rmeddis@0 1241 % noise=UTIL_lowpassFilterFreq(noise, 100, 1/FS);
rmeddis@0 1242 noise=UTIL_bandPassFilter(noise, 1, 100, 200, 1/FS,[]);
rmeddis@0 1243 end
rmeddis@0 1244
rmeddis@0 1245 rms=(mean(noise.^2)^.5); %should be 20 microPascals for 0 dB SPL
rmeddis@0 1246 adjust=20e-6/rms;
rmeddis@0 1247 noise=noise*adjust;
rmeddis@0 1248 rms=(mean(noise.^2)^.5);
rmeddis@0 1249 amplitude=10.^(stimComponents.amplitudesdB/20);
rmeddis@0 1250 noise=amplitude*noise;
rmeddis@0 1251 % rms=(mean(noise.^2)^.5);
rmeddis@0 1252 % dBnoise=20*log10(rms/20e-6)
rmeddis@0 1253
rmeddis@0 1254
rmeddis@0 1255 %--------------------------------------------------------------------makeWhiteNoise
rmeddis@0 1256 function noise=makeWhiteNoise(globalStimParams, stimComponents)
rmeddis@0 1257 % FS in Hz, noiseDuration in s, delay in s;
rmeddis@0 1258 % noise is bandpass filtered between 100 and 10000 Hz
rmeddis@0 1259 % spectrum level (dB/Hz) is 40 dB below nominal level.
rmeddis@0 1260 % noise is returned with dB(rms) = amplitudesdB
rmeddis@0 1261 %
rmeddis@0 1262 % % You need
rmeddis@0 1263 %
rmeddis@0 1264 % stim.type='noise'; % or 'IRN', or 'pinkNoise'
rmeddis@0 1265 % stim.toneDuration=.05;
rmeddis@0 1266 % stim.amplitudesdB=50;
rmeddis@0 1267 % stim.beginSilence=.01;
rmeddis@0 1268 % stim.endSilence=-1;
rmeddis@0 1269 % stim.rampOnDur=.002;
rmeddis@0 1270 % stim.rampOffDur=-1;
rmeddis@0 1271 %
rmeddis@0 1272 % % Mandatory structure fields
rmeddis@0 1273 % globalStimParams.FS=100000;
rmeddis@0 1274 % globalStimParams.overallDuration=.1; % s
rmeddis@0 1275 % globalStimParams.doPlot=1;
rmeddis@0 1276 % globalStimParams.doPlay=1;
rmeddis@0 1277 %
rmeddis@0 1278 % [audio, msg]=stimulusCreate(globalStimParams, stim, );
rmeddis@0 1279 %
rmeddis@0 1280 % % local
rmeddis@0 1281 % stim.type='noise'; % or 'IRN'
rmeddis@0 1282 %
rmeddis@0 1283 FS=globalStimParams.FS;
rmeddis@0 1284 noiseDuration= stimComponents.toneDuration;
rmeddis@0 1285 npts=round(noiseDuration*FS);
rmeddis@0 1286 noise=randn(1,npts);
rmeddis@0 1287
rmeddis@0 1288 noise=UTIL_bandPassFilter (noise, 6, 100, 10000, 1/FS, []);
rmeddis@0 1289
rmeddis@0 1290 rms=(mean(noise.^2)^.5); %should be 20 microPascals for 0 dB SPL
rmeddis@0 1291 adjust=20e-6/rms;
rmeddis@0 1292 noise=noise*adjust;
rmeddis@0 1293 rms=(mean(noise.^2)^.5);
rmeddis@0 1294 amplitude=10.^(stimComponents.amplitudesdB/20);
rmeddis@0 1295 noise=amplitude*noise;
rmeddis@0 1296 % rms=(mean(noise.^2)^.5);
rmeddis@0 1297 % dBnoise=20*log10(rms/20e-6)
rmeddis@0 1298
rmeddis@0 1299
rmeddis@0 1300 %-----------------------------------------------------------------makeIRN
rmeddis@0 1301 function noise=makeIRN(globalStimParams, stimComponents)
rmeddis@0 1302 % FS in Hz, noiseDuration in s, delay in s;
rmeddis@0 1303 % noise is returned with dB(rms) = amplitudesdB
rmeddis@0 1304 %
rmeddis@0 1305 % % You need
rmeddis@0 1306 %
rmeddis@0 1307 % stim.type='noise'; % or 'IRN', or 'pinkNoise'
rmeddis@0 1308 % stim.toneDuration=.05;
rmeddis@0 1309 % stim.amplitudesdB=50;
rmeddis@0 1310 % stim.beginSilence=.01;
rmeddis@0 1311 % stim.endSilence=-1;
rmeddis@0 1312 % stim.rampOnDur=.002;
rmeddis@0 1313 % stim.rampOffDur=-1;
rmeddis@0 1314 %
rmeddis@0 1315 % % Mandatory structure fields
rmeddis@0 1316 % globalStimParams.FS=100000;
rmeddis@0 1317 % globalStimParams.overallDuration=.1; % s
rmeddis@0 1318 % globalStimParams.doPlot=1;
rmeddis@0 1319 % globalStimParams.doPlay=1;
rmeddis@0 1320 %
rmeddis@0 1321 % [audio, msg]=stimulusCreate(globalStimParams, stim, );
rmeddis@0 1322 %
rmeddis@0 1323 % % local
rmeddis@0 1324 % stim.type='noise'; % or 'IRN'
rmeddis@0 1325 % % for IRN only
rmeddis@0 1326 % stim.niterations = 8; %0 for white noise
rmeddis@0 1327 % stim.delay = 1/150;
rmeddis@0 1328 % stim.irnGain = 1;
rmeddis@0 1329 %
rmeddis@0 1330 FS=globalStimParams.FS;
rmeddis@0 1331 noiseDuration= stimComponents.toneDuration;
rmeddis@0 1332
rmeddis@0 1333 nIterations=stimComponents.niterations;
rmeddis@0 1334 if nIterations==0
rmeddis@0 1335 % white noise is specified as nIterations=1
rmeddis@0 1336 nIterations=1;
rmeddis@0 1337 IRNgain=0;
rmeddis@0 1338 delay=0.01; % dummy
rmeddis@0 1339 else
rmeddis@0 1340 % IRN
rmeddis@0 1341 delay=stimComponents.delay;
rmeddis@0 1342 IRNgain=stimComponents.irnGain;
rmeddis@0 1343 end
rmeddis@0 1344
rmeddis@0 1345 npts=round(noiseDuration*FS);
rmeddis@0 1346 dels=round(delay*FS);
rmeddis@0 1347 noise=randn(1,npts);
rmeddis@0 1348
rmeddis@0 1349 %fringe=nIterations*dels;
rmeddis@0 1350 %npts=npts+fringe;
rmeddis@0 1351
rmeddis@0 1352 for i=1:nIterations,
rmeddis@0 1353 dnoise=[noise(dels+1:npts) noise(1:dels)];
rmeddis@0 1354 dnoise=dnoise.*IRNgain;
rmeddis@0 1355 noise=noise+dnoise;
rmeddis@0 1356 end;
rmeddis@0 1357
rmeddis@0 1358 switch stimComponents.type
rmeddis@0 1359 case 'pinkNoise'
rmeddis@0 1360 noise=UTIL_lowpassFilterFreq(noise, 10000, 1/FS);
rmeddis@0 1361 end
rmeddis@0 1362
rmeddis@0 1363 rms=(mean(noise.^2)^.5); %should be 20 microPascals for 0 dB SPL
rmeddis@0 1364 adjust=20e-6/rms;
rmeddis@0 1365 noise=noise*adjust;
rmeddis@0 1366 rms=(mean(noise.^2)^.5);
rmeddis@0 1367 amplitude=10.^(stimComponents.amplitudesdB/20);
rmeddis@0 1368 noise=amplitude*noise;
rmeddis@0 1369 % rms=(mean(noise.^2)^.5);
rmeddis@0 1370 % dBnoise=20*log10(rms/20e-6)
rmeddis@0 1371
rmeddis@0 1372 %------------------------------------------------------------------ makeRPN
rmeddis@0 1373 function RPN=makeRPN(globalStimParams, stim)
rmeddis@0 1374 % 'period' is a collection of samples - AAABCD
rmeddis@0 1375 % you need
rmeddis@0 1376 %
rmeddis@0 1377 % stim.type='RPN';
rmeddis@0 1378 % stim.toneDuration=.2;
rmeddis@0 1379 % stim.amplitudesdB=50;
rmeddis@0 1380 % stim.beginSilence=.01;
rmeddis@0 1381 % stim.rampOnDur=.002;
rmeddis@0 1382 % stim.rampOffDur=-1;
rmeddis@0 1383 %
rmeddis@0 1384 % stim.sampleDuration=.005; %200 Hz pitch
rmeddis@0 1385 % stim.nSimilarSamples=5; % pitch strength
rmeddis@0 1386 % stim.nIndependentSamples=1% dilutes strength
rmeddis@0 1387 %
rmeddis@0 1388 % % Mandatory structure fields
rmeddis@0 1389 % globalStimParams.FS=44100;
rmeddis@0 1390 % globalStimParams.overallDuration=.21; % s
rmeddis@0 1391 %
rmeddis@0 1392 % globalStimParams.doPlot=1;
rmeddis@0 1393 % globalStimParams.doPlay=1;
rmeddis@0 1394 % [audio, msg]=stimulusCreate(globalStimParams, stim);
rmeddis@0 1395
rmeddis@0 1396 FS=globalStimParams.FS;
rmeddis@0 1397 ptsPerSample=floor(stim.sampleDuration*FS);
rmeddis@0 1398
rmeddis@0 1399 samplesPerPeriod=stim.nSimilarSamples+stim.nIndependentSamples;
rmeddis@0 1400 periodDuration=samplesPerPeriod*stim.sampleDuration;
rmeddis@0 1401
rmeddis@0 1402 totalNumPeriods=2*floor(stim.toneDuration/periodDuration); % longer than necessary
rmeddis@0 1403 if totalNumPeriods<1
rmeddis@0 1404 error('stimulusCreate: RPN, stimulus duration needs to be longer')
rmeddis@0 1405 end
rmeddis@0 1406
rmeddis@0 1407 RPN=[];
rmeddis@0 1408 for j=1:totalNumPeriods
rmeddis@0 1409 noise=randn(1,ptsPerSample);
rmeddis@0 1410 for i=1:stim.nSimilarSamples
rmeddis@0 1411 RPN=[RPN noise];
rmeddis@0 1412 end
rmeddis@0 1413
rmeddis@0 1414 for i=1:stim.nIndependentSamples
rmeddis@0 1415 noise=randn(1,ptsPerSample);
rmeddis@0 1416 RPN=[RPN noise];
rmeddis@0 1417 end
rmeddis@0 1418 end
rmeddis@0 1419
rmeddis@0 1420 targetStimulusLength=round(stim.toneDuration/FS);
rmeddis@0 1421 RPN=RPN(1:floor(stim.toneDuration*FS)); % take enough for stimulus
rmeddis@0 1422
rmeddis@0 1423 rms=(mean(RPN.^2)^.5); %should be 20 microPascals for 0 dB SPL
rmeddis@0 1424 adjust=20e-6/rms;
rmeddis@0 1425 RPN=RPN*adjust;
rmeddis@0 1426 rms=(mean(RPN.^2)^.5);
rmeddis@0 1427 amplitude=10.^(stim.amplitudesdB/20);
rmeddis@0 1428 RPN=amplitude*RPN;
rmeddis@0 1429 % rms=(mean(noise.^2)^.5);
rmeddis@0 1430 % dBnoise=20*log10(rms/20e-6)
rmeddis@0 1431
rmeddis@0 1432 %--------------------------------------------------------------------applyRampOn
rmeddis@0 1433 function signal=applyRampOn(signal, rampDur, rampOnTime, sampleRate)
rmeddis@0 1434 %applyRampOn applies raised cosine ramp
rmeddis@0 1435 %rampOntime is the time at which the ramp begins
rmeddis@0 1436 %At all other times the mask has a value of 1
rmeddis@0 1437 %signal=applyRampOn(signal, rampDur, rampOnTime, sampleRate)
rmeddis@0 1438
rmeddis@0 1439 rampDurPoints=round(rampDur*sampleRate);
rmeddis@0 1440 rampOn= (1+cos(pi:pi/(rampDurPoints-1): 2*pi))/2';
rmeddis@0 1441
rmeddis@0 1442 sigDurPoints=length(signal);
rmeddis@0 1443 mask(1:sigDurPoints)=1;
rmeddis@0 1444 rampOnStartIndex=round(rampOnTime*sampleRate+1);
rmeddis@0 1445 mask(rampOnStartIndex: rampOnStartIndex+ rampDurPoints-1)=rampOn;
rmeddis@0 1446 signal=signal.*mask;
rmeddis@0 1447 %plot(mask)
rmeddis@0 1448
rmeddis@0 1449 %--------------------------------------------------------------------applyRampOff
rmeddis@0 1450 function signal=applyRampOff(signal, rampDur, rampOffTime, sampleRate)
rmeddis@0 1451 %applyRampOn applies raised cosine squared ramp
rmeddis@0 1452 %rampOffTime is the time at which the ramp begins
rmeddis@0 1453 %At all other times the mask has a value of 1
rmeddis@0 1454 % signal=applyRampOff(signal, rampDur, rampOffTime, sampleRate)
rmeddis@0 1455
rmeddis@0 1456 rampDurPoints=round(rampDur*sampleRate);
rmeddis@0 1457 rampOff= (1+cos(0:pi/(rampDurPoints-1): pi))/2';
rmeddis@0 1458
rmeddis@0 1459 sigDurPoints=length(signal);
rmeddis@0 1460 mask=ones(1,sigDurPoints);
rmeddis@0 1461 rampOffStartIndex=round(rampOffTime*sampleRate+1);
rmeddis@0 1462 mask(rampOffStartIndex: round(rampOffStartIndex+ rampDurPoints-1))=rampOff;
rmeddis@0 1463 if length(mask)>sigDurPoints, mask=mask(1:sigDurPoints); end
rmeddis@0 1464 signal=signal.*mask;
rmeddis@0 1465 %plot(mask)
rmeddis@0 1466
rmeddis@0 1467 function signal=applyGaussianRamps(signal, sigma, sampleRate)
rmeddis@0 1468 dt=1/sampleRate;
rmeddis@0 1469 time=dt:dt:dt*length(signal);
rmeddis@0 1470 ramp=1-exp(-time.^2/(2*sigma^2));
rmeddis@0 1471 % apply onset ramp
rmeddis@0 1472 signal=signal.*ramp;
rmeddis@0 1473 % apply offset ramp
rmeddis@0 1474 ramp=fliplr(ramp);
rmeddis@0 1475 signal=signal.*ramp;
rmeddis@0 1476
rmeddis@0 1477
rmeddis@0 1478
rmeddis@0 1479 %--------------------------------------------------------------------checkDescriptors
rmeddis@30 1480 function [globalStimParams, stimComponents]=...
rmeddis@30 1481 checkDescriptors(globalStimParams, stimComponents)
rmeddis@0 1482
rmeddis@0 1483 try
rmeddis@0 1484 % if FS exists, it takes priority
rmeddis@0 1485 globalStimParams.dt=1/globalStimParams.FS;
rmeddis@0 1486 catch
rmeddis@0 1487 % otherwise set FS using dt
rmeddis@0 1488 globalStimParams.FS=1/globalStimParams.dt;
rmeddis@0 1489 end
rmeddis@0 1490
rmeddis@30 1491 sampleRate=globalStimParams.FS;
rmeddis@30 1492
rmeddis@30 1493 globalStimParams.nSignalPoints=...
rmeddis@30 1494 round(globalStimParams.overallDuration* sampleRate);
rmeddis@0 1495
rmeddis@0 1496 % optional field (ears)
rmeddis@0 1497 try
rmeddis@0 1498 globalStimParams.ears;
rmeddis@0 1499 catch
rmeddis@0 1500 % default: dichotic.
rmeddis@0 1501 globalStimParams.ears='dichotic';
rmeddis@0 1502 end
rmeddis@0 1503
rmeddis@0 1504 % audioOutCorrection is optional
rmeddis@0 1505 % audioOutCorrection is a scalar for reducing the sound
rmeddis@0 1506 try
rmeddis@0 1507 globalStimParams.audioOutCorrection;
rmeddis@0 1508 catch
rmeddis@0 1509 % set to 1 if omitted
rmeddis@0 1510 globalStimParams.audioOutCorrection=1;
rmeddis@0 1511 end
rmeddis@0 1512
rmeddis@0 1513 try
rmeddis@0 1514 globalStimParams.doPlay;
rmeddis@0 1515 catch
rmeddis@0 1516 % default plays sound only if explicitly requested
rmeddis@0 1517 globalStimParams.doPlay=0;
rmeddis@0 1518 end
rmeddis@0 1519
rmeddis@0 1520 try
rmeddis@0 1521 globalStimParams.doPlot;
rmeddis@0 1522 catch
rmeddis@0 1523 % no plotting unless explicitly requested
rmeddis@0 1524 globalStimParams.doPlot=0;
rmeddis@0 1525 end
rmeddis@0 1526
rmeddis@0 1527 [ears nComponentSounds]=size(stimComponents);
rmeddis@0 1528
rmeddis@0 1529 for ear=1:2 % 1=left/ 2=right
rmeddis@0 1530
rmeddis@0 1531 % create a list of components whose type is specified
rmeddis@0 1532 % if no type is specified assume that it is an empty specification
rmeddis@0 1533 % this is allowed
rmeddis@0 1534 validStimComponents=[];
rmeddis@0 1535 for i=1:nComponentSounds
rmeddis@0 1536 try
rmeddis@0 1537 if ~isempty(stimComponents(ear,i).type)
rmeddis@0 1538 validStimComponents=[validStimComponents i];
rmeddis@0 1539 end
rmeddis@0 1540 catch
rmeddis@0 1541 end
rmeddis@0 1542 end
rmeddis@0 1543
rmeddis@0 1544 for componentNo=validStimComponents
rmeddis@0 1545 % If no AM filed is present, create it for completeness
rmeddis@0 1546 if ~isfield(stimComponents(ear,componentNo),'AMfrequency') |...
rmeddis@0 1547 ~isfield(stimComponents(ear,componentNo),'AMdepth')
rmeddis@0 1548 stimComponents(ear,componentNo).AMfrequency=0;
rmeddis@0 1549 stimComponents(ear,componentNo).AMdepth=0;
rmeddis@0 1550 end
rmeddis@0 1551
rmeddis@0 1552 % all signals must have durations, amplitudes and ramps
rmeddis@0 1553 if ...
rmeddis@0 1554 isempty(stimComponents(ear,componentNo).type) |...
rmeddis@0 1555 isempty(stimComponents(ear,componentNo).toneDuration) |...
rmeddis@0 1556 isempty(stimComponents(ear,componentNo).amplitudesdB) |...
rmeddis@0 1557 isempty(stimComponents(ear,componentNo).rampOnDur)
rmeddis@0 1558 descriptorError( 'missing stimComponent descriptor', stimComponents, ear, componentNo)
rmeddis@0 1559 end
rmeddis@0 1560
rmeddis@0 1561 try, stimComponents(ear,componentNo).endSilence; catch, stimComponents(ear,componentNo).endSilence=-1; end
rmeddis@0 1562
rmeddis@0 1563 % ramp checks do not apply to file input
rmeddis@0 1564 if ~strcmp(stimComponents(ear,componentNo).type, 'file')
rmeddis@0 1565 % match offset ramp to onset if not explicitly specified
rmeddis@0 1566 if stimComponents(ear,componentNo).rampOffDur==-1,
rmeddis@0 1567 stimComponents(ear,componentNo).rampOffDur=stimComponents(ear,componentNo).rampOnDur;
rmeddis@0 1568 end
rmeddis@0 1569 % ramps must be shorter than the stimulus
rmeddis@0 1570 if stimComponents(ear,componentNo).rampOffDur> stimComponents(ear,componentNo).toneDuration | ...
rmeddis@0 1571 stimComponents(ear,componentNo).rampOnDur> stimComponents(ear,componentNo).toneDuration
rmeddis@0 1572 descriptorError( 'ramp longer than sound component', stimComponents, ear, componentNo)
rmeddis@0 1573 end
rmeddis@0 1574 end
rmeddis@0 1575
rmeddis@0 1576 % end silence is measured to fit into the global duration
rmeddis@0 1577 if stimComponents(ear,componentNo).endSilence==-1,
rmeddis@30 1578 stimComponents(ear,componentNo).endSilence=...
rmeddis@30 1579 globalStimParams.overallDuration-...
rmeddis@30 1580 stimComponents(ear,componentNo).beginSilence -...
rmeddis@30 1581 stimComponents(ear,componentNo).toneDuration;
rmeddis@30 1582
rmeddis@30 1583 endSilenceNpoints=stimComponents(ear,componentNo).endSilence...
rmeddis@30 1584 *sampleRate;
rmeddis@30 1585 end
rmeddis@30 1586 if stimComponents(ear,componentNo).endSilence<0
rmeddis@30 1587 globalStimParams
rmeddis@30 1588 descriptorError( 'component durations greater than overallDuration', stimComponents, ear, componentNo)
rmeddis@0 1589 end
rmeddis@0 1590
rmeddis@0 1591 % check overall duration of this component against global duration
rmeddis@0 1592 totalDuration= ...
rmeddis@0 1593 stimComponents(ear,componentNo).beginSilence+...
rmeddis@0 1594 stimComponents(ear,componentNo).toneDuration+...
rmeddis@0 1595 stimComponents(ear,componentNo).endSilence;
rmeddis@0 1596
rmeddis@0 1597 % avoid annoying error message for single stimulus component
rmeddis@0 1598 if ears==1 && nComponentSounds==1
rmeddis@0 1599 globalStimParams.overallDuration= totalDuration;
rmeddis@0 1600 end
rmeddis@0 1601
rmeddis@0 1602 % check total duration
rmeddis@30 1603 totalSignalPoints= round(totalDuration* sampleRate);
rmeddis@0 1604 if totalSignalPoints >globalStimParams.nSignalPoints
rmeddis@0 1605 descriptorError( 'Signal component duration does not match overall duration ', stimComponents, ear, componentNo)
rmeddis@0 1606 end
rmeddis@0 1607
rmeddis@0 1608 if isfield(stimComponents(ear,componentNo), 'filter')
rmeddis@0 1609 if ~isequal(length(stimComponents(ear,componentNo).filter), 3)
rmeddis@0 1610 descriptorError( 'Filter parameter must have three elements ', stimComponents, ear, componentNo)
rmeddis@0 1611 end
rmeddis@0 1612 end
rmeddis@0 1613 end % component
rmeddis@0 1614 % ??
rmeddis@0 1615 if strcmp(globalStimParams.ears,'monoticL') | strcmp(globalStimParams.ears, 'monoticR'), break, end
rmeddis@0 1616 end % ear
rmeddis@0 1617
rmeddis@0 1618
rmeddis@0 1619 %-------------------------------------------------------------------- descriptorError
rmeddis@0 1620 function descriptorError( msg, stimComponents, ear, componentNo)
rmeddis@0 1621 stimComponents(ear, componentNo)
rmeddis@0 1622
rmeddis@0 1623 disp(' *********** **************** ************')
rmeddis@0 1624 disp([ '...Error in stimComponents description: '])
rmeddis@0 1625 disp([msg ])
rmeddis@0 1626 disp(['Ear = ' num2str(ear) ' component No ' num2str(componentNo)])
rmeddis@0 1627 disp(' *********** **************** ************')
rmeddis@0 1628 error('myError ')
rmeddis@0 1629
rmeddis@0 1630
rmeddis@0 1631 %-------------------------------------------------------------------- normalize
rmeddis@0 1632 function [normalizedSignal, gain]= normalize(signal)
rmeddis@0 1633 % normalize (signal)
rmeddis@0 1634 maxSignal=max(max(signal));
rmeddis@0 1635 minSignal=min(min(signal));
rmeddis@0 1636 if -minSignal>maxSignal, normalizingFactor=-minSignal; else normalizingFactor=maxSignal; end
rmeddis@0 1637 normalizingFactor=1.01*normalizingFactor;
rmeddis@0 1638 gain= 20*log10(normalizingFactor);
rmeddis@0 1639 normalizedSignal=signal/normalizingFactor;
rmeddis@0 1640
rmeddis@0 1641
rmeddis@0 1642 %--------------------------------------------------------------------Butterworth
rmeddis@0 1643 function y=Butterworth (x, dt, fl, fu, order)
rmeddis@0 1644 % Butterworth (x, dt, fu, fl, order)
rmeddis@0 1645 % Taken from Yuel and beauchamp page 261
rmeddis@0 1646 % NB error in their table for K (see their text)
rmeddis@0 1647 % x is original signal
rmeddis@0 1648 % fu, fl upper and lower cutoff
rmeddis@0 1649 % order is the number of times the filter is applied
rmeddis@0 1650
rmeddis@0 1651 q=(pi*dt*(fu-fl));
rmeddis@0 1652 J=1/(1+ cot(q));
rmeddis@0 1653 K= (2*cos(pi*dt*(fu+fl)))/(1+tan(q)*cos(q));
rmeddis@0 1654 L= (tan(q)-1)/(tan(q)+1);
rmeddis@0 1655 b=[J -J];
rmeddis@0 1656 a=[1 -K -L];
rmeddis@0 1657 for i=1:order
rmeddis@0 1658 y=filter(b, a, x);
rmeddis@0 1659 x=y;
rmeddis@0 1660 end
rmeddis@0 1661
rmeddis@0 1662
rmeddis@0 1663 % -------------------------------------------------------- UTIL_amp2dB
rmeddis@0 1664 function [y] = UTIL_amp2dB (x, ref)
rmeddis@0 1665 % Calculates a dB (ref. ref) value 'y' from a peak amplitude number 'x'.
rmeddis@0 1666 % if ref omitted treat as dB
rmeddis@0 1667 % Check the number of arguments that are passed in.
rmeddis@0 1668 if (nargin < 2)
rmeddis@0 1669 ref=1;
rmeddis@0 1670 end
rmeddis@0 1671 if (nargin > 2)
rmeddis@0 1672 error ('Too many arguments');
rmeddis@0 1673 end
rmeddis@0 1674
rmeddis@0 1675 % Check arguments.
rmeddis@0 1676 if x < 0.0
rmeddis@0 1677 error ('Can not calculate the log10 of a negative number');
rmeddis@0 1678 elseif x == 0.0
rmeddis@0 1679 warning ('log10 of zero. The result is set to -1000.0');
rmeddis@0 1680 y = -1000.0;
rmeddis@0 1681 else
rmeddis@0 1682 % Do calculations.
rmeddis@0 1683 y = 20.0 * log10(x/(sqrt(2)*ref));
rmeddis@0 1684
rmeddis@0 1685 end
rmeddis@0 1686
rmeddis@0 1687 %-------------------------------------------------------------------- FFT
rmeddis@0 1688 function showFFT (getFFTsignal, dt)
rmeddis@0 1689 color='r';
rmeddis@0 1690 figure(2), clf,
rmeddis@0 1691 hold off
rmeddis@0 1692
rmeddis@0 1693 % trim initial silence
rmeddis@0 1694 idx=find(getFFTsignal>0);
rmeddis@0 1695 if ~isempty(idx)
rmeddis@0 1696 getFFTsignal=getFFTsignal(idx(1):end);
rmeddis@0 1697 end
rmeddis@0 1698 %trim final silence
rmeddis@0 1699 getFFTsignal=getFFTsignal(end:-1:1);
rmeddis@0 1700 idx=find(getFFTsignal>0);
rmeddis@0 1701 if ~isempty(idx)
rmeddis@0 1702 getFFTsignal=getFFTsignal(idx(1):end);
rmeddis@0 1703 getFFTsignal=getFFTsignal(end:-1:1);
rmeddis@0 1704 end
rmeddis@0 1705
rmeddis@0 1706 % Analyse make stimComponents length a power of 2
rmeddis@0 1707 x=length(getFFTsignal);
rmeddis@0 1708 squareLength=2;
rmeddis@0 1709 while squareLength<=x
rmeddis@0 1710 squareLength=squareLength*2;
rmeddis@0 1711 end
rmeddis@0 1712 squareLength=round(squareLength/2);
rmeddis@0 1713 getFFTsignal=getFFTsignal(1:squareLength);
rmeddis@0 1714 n=length(getFFTsignal);
rmeddis@0 1715
rmeddis@0 1716 minf=100; maxf=20000;
rmeddis@0 1717
rmeddis@0 1718 fft_result = fft(getFFTsignal, n); % Compute FFT of the input signal.
rmeddis@0 1719 fft_power = fft_result .* conj(fft_result);% / n; % Compute power spectrum. Dividing by 'n' we get the power spectral density.
rmeddis@0 1720 fft_phase = angle(fft_result); % Compute the phase spectrum.
rmeddis@0 1721
rmeddis@0 1722 frequencies = (1/dt)*(1:n/2)/n;
rmeddis@0 1723 fft_power=fft_power(1:length(fft_power)/2); % remove mirror frequencies
rmeddis@0 1724 fft_phase=fft_phase(1:length(fft_phase)/2); % remove mirror frequencies
rmeddis@0 1725 fft_powerdB = UTIL_amp2dB (fft_power, max(fft_power)); % convert to dB
rmeddis@0 1726 % jags=find(diff(fft_phase)>0); % unwrap phase
rmeddis@0 1727 % for i=jags, fft_phase(i+1:end)=fft_phase(i+1:end)-2*pi; end
rmeddis@0 1728
rmeddis@0 1729 xlim([minf maxf])
rmeddis@0 1730 semilogx(frequencies, fft_powerdB-max(fft_powerdB), color)
rmeddis@0 1731 ylim([ -20 5])
rmeddis@0 1732
rmeddis@0 1733
rmeddis@0 1734
rmeddis@0 1735 function y=UTIL_lowpassFilterFreq(x, cutOffFrequency, dt)
rmeddis@0 1736 % UTIL_lowpassFilterFreq multi-channel filter
rmeddis@0 1737 %
rmeddis@0 1738 % Usage:
rmeddis@0 1739 % output=UTIL_lowpassFilterFreq(input, cutOffFrequency, dt)
rmeddis@0 1740 %
rmeddis@0 1741 % cutoff should be around 100 Hz for audio work
rmeddis@0 1742 % dt should be <1/50000 s for audio work
rmeddis@0 1743 %
rmeddis@0 1744 % Attenuation is - 6 dB per octave above cutoff.
rmeddis@0 1745
rmeddis@0 1746
rmeddis@0 1747 sampleRate=1/dt;
rmeddis@0 1748
rmeddis@0 1749 if 4*cutOffFrequency>sampleRate
rmeddis@0 1750 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 1751 cutOffFrequency=sampleRate/4;
rmeddis@0 1752 end
rmeddis@0 1753
rmeddis@0 1754 tau=1/(2*pi*cutOffFrequency);
rmeddis@0 1755
rmeddis@0 1756 y=zeros(size(x));
rmeddis@0 1757 [numChannels numPoints]=size(x);
rmeddis@0 1758 for i=1:numChannels
rmeddis@0 1759 y(i,:)=filter([dt/tau], [1 -(1-dt/tau)], x(i,:));
rmeddis@0 1760 end
rmeddis@0 1761
rmeddis@0 1762