Added the scripts of the previous developer

master
Miguel Descalzo 3 years ago
parent 5c521a14d4
commit dedbcccee8
  1. 341
      Code/Matlab/AuditoryThresholdsExperiment.m
  2. 631
      Code/Matlab/AuditoryThresholds_v3.m
  3. 158
      Code/Matlab/CalibrateAudioStimuli.m
  4. 158
      Code/Matlab/CalibrateVisualStim.m
  5. 66
      Code/Matlab/GenerateNoisyImage.m
  6. 38
      Code/Matlab/MakeBeep_v2.m
  7. 31464
      Code/Matlab/Psychtoolbox_Abriefguide.pdf
  8. BIN
      Code/Matlab/Results/VisualThreshold/test/test_VisualThreshold_2s1Repetitions_13-02-2020_20.47.16.mat
  9. BIN
      Code/Matlab/Results/VisualThreshold/test/test_VisualThreshold_2s1Repetitions_13-02-2020_20.47.16.png
  10. BIN
      Code/Matlab/Results/VisualThreshold/test/test_VisualThreshold_2s1Repetitions_13-02-2020_20.50.45.mat
  11. BIN
      Code/Matlab/Results/VisualThreshold/test/test_VisualThreshold_2s1Repetitions_13-02-2020_20.50.45.png
  12. BIN
      Code/Matlab/Results/VisualThreshold/test/test_VisualThreshold_2s1Repetitions_23-02-2020_11.05.23.mat
  13. BIN
      Code/Matlab/Results/VisualThreshold/test/test_VisualThreshold_2s1Repetitions_23-02-2020_11.05.23.png
  14. 475
      Code/Matlab/VisualThresholds_v0.m
  15. 72
      Code/Matlab/a00_Test.m
  16. 34
      Code/Matlab/a01_Test.m
  17. 237
      Code/Matlab/psychMethodSIAM.m
  18. 15
      Code/Matlab/untitled.m
  19. 4
      README.md

@ -0,0 +1,341 @@
function AuditoryThresholdsExperiment(participantId, sessionId, testMode)
% Script to run the experiments on auditory thresholds
if (exist('participantId','var')==0) && (exist('sessionId','var')==0)
% Collect Participant's Information
titleBar = 'Información del Participante';
userPrompt = {'Número de Participante','Sesión','Modo test'};
defaultInput = {'test','-1','1'};
caUserInput = inputdlg(userPrompt, titleBar, 1,defaultInput);
if isempty(caUserInput),return,end % Bail out if they clicked Cancel.
participantId = caUserInput{1};
sessionId = caUserInput{2};
% Activate or deactivate the test mode
testMode = str2num(caUserInput{3});
end
% -1 values indicate when the threshold has to be measured
frequencies = [500, 1000, 2000, 4000, -1];
volumes = [60 75 90 105 -1];
repetitions = 1;
durations = 1;
responseTime = 0.8;
intraStimuliInterval = 1;
interStimuliInterval = 3;
% All possible values to calculate thresholds
allFrequencies = [500:100:6000];
% allFrequencies = 1000;
allVolumes = [40:2:120];
% allRepetitions = [1:3];
allRepetitions = 1;
% Folder to store results
currDate = datestr(now, 'yyyy-mm-dd');
path = ['Results/AuditoryThreshold/', participantId, '/'];
mkdir(path);
fileName = [participantId, '_', sessionId, '_', currDate];
% xlswrite([path, fileName, '.xlsx'],{'Freq (Hz)','Volume (amplitude)', '# Repetitions', 'Duration (s)', 'Threshold', 'Var4Threshold'},'A1:F1');
% Define conditions
[gridFreq, gridVol, gridRep] = meshgrid(frequencies, volumes, repetitions);
conditions = cat(2, gridFreq(:), gridVol(:), gridRep(:));
% Remove conditions where more than one threshold has to be measured
aux2Remove = (conditions < 0);
aux2Remove = sum(aux2Remove,2);
rows2Remove = ((aux2Remove > 1) | (aux2Remove < 1));
conditions(logical(rows2Remove),:) = [];
% Shuffle conditions randomly
conditions = conditions(randperm(size(conditions,1)),:);
thresholds = zeros(1,size(conditions,1));
% Show instructions
wPtr = DrawInstructionsPage(testMode);
% Establish key mapping: ESCape aborts, Space to continue after showing the
% instructions
KbName('UnifyKeynames');
SPACE = KbName('space');
keyList = zeros(1,256);
keyCode = keyList;
keyList(SPACE) = 1;
% Participant's response
KbQueueCreate([],keyList);
KbQueueStart;
KbQueueFlush;
% Show instructions while space bar is not pressed
while ~keyCode(SPACE)
% Check keyboard:
[isDown, keyCode]=KbQueueCheck;
end
KbQueueFlush;
KbQueueStop;
KbQueueRelease;
KbReleaseWait;
for c = 1:size(conditions,1)
freq = conditions(c,1);
vol = conditions(c,2);
rep = conditions(c,3);
if freq < 0 % Threshold measured on the frequency
freq = allFrequencies;
strVar4Threshold = 'Freq';
var4Threshold = allFrequencies;
auxFileName = [fileName,'_',num2str(vol),'dBA_',num2str(rep),'Rep'];
end
if vol < 0 % Threshold measured on the volume
vol = allVolumes;
strVar4Threshold = 'Volume';
var4Threshold = allVolumes;
auxFileName = [fileName,'_',num2str(freq),'Hz_',num2str(rep),'Rep'];
end
if rep < 0 % Threshold measured on the repetitions
rep = allRepetitions;
strVar4Threshold = 'Repetitions';
var4Threshold = allRepetitions;
auxFileName = [fileName,'_',num2str(vol),'dBA_',num2str(freq),'Hz'];
end
% Close the displayed screen
Screen('Close',wPtr);
disp(['Measuring threshold ', num2str(c), ' out of ', num2str(size(conditions,1))]);
[thresholds(c), history, responses, responseTimes] = AuditoryThresholds_v3(participantId,vol,freq,durations,interStimuliInterval,rep,intraStimuliInterval,responseTime,testMode);
% Save results of this condition
save([path, auxFileName, '.mat'], 'participantId','c','conditions','durations','intraStimuliInterval','interStimuliInterval','thresholds','strVar4Threshold','history','responses','responseTimes');
% Save all results
save([path, fileName, '.mat'], 'participantId','conditions','durations','intraStimuliInterval','interStimuliInterval','thresholds');
% Write threshold in xls file
% xlswrite([path, fileName, '.xlsx'], cat(2,conditions(c,:),durations,thresholds(c)), ['A',num2str(c+1),':E',num2str(c+1)]);
% xlswrite([path, fileName, '.xlsx'], {strVar4Threshold}, ['F',num2str(c+1),':F',num2str(c+1)]);
wPtr = DrawBreakPage(testMode);
WaitSecs(5);
% % Plot psychometric function
% % Get values presented and the number of times they have been presented
% uniqueVar4Threshold = unique(data4Psychometric);
% nCorrect = zeros(1, length(uniqueVar4Threshold));
% nTrialsDone = zeros(1, length(uniqueVar4Threshold));
% pCorrectHistory = zeros(1,size(data4Psychometric,2));
%
% for i = 1:length(uniqueVar4Threshold)
% id = data4Psychometric==uniqueVar4Threshold(i);
% nTrialsDone(i) = sum(id);
% nCorrect(i) = sum(responses4Psychometric(id));
% pCorrectHistory(id) = nCorrect(i)/nTrialsDone(i);
% end
%
% pCorrect = nCorrect./nTrialsDone;
%
% figure,
% plot(uniqueVar4Threshold, 100*pCorrect, '-k', 'LineWidth', 2);
% hold on;
% % Loop through each unique value so each data point can have its own
% % size
% for i = 1:length(uniqueVar4Threshold)
% sz = nTrialsDone(i)*10+5;
% scatter(uniqueVar4Threshold(i), 100*pCorrect(i), sz, [0 0 0], 'filled', 'HandleVisibility','off');
% end
% % hold off;
% ylim([0 100]);
% xlabel(strVar4Threshold);
% ylabel('Percentage of Correct');
%
% % Fit psychometric function using a Weibull function
% [alpha,beta,thresh50] = FitWeibYN(uniqueVar4Threshold, nCorrect, nTrialsDone-nCorrect,median(uniqueVar4Threshold),[]);
% xWeibull = [min(uniqueVar4Threshold(:)):((max(uniqueVar4Threshold(:))-min(uniqueVar4Threshold(:)))./10000):max(uniqueVar4Threshold(:))];
% yWeibull = ComputeWeibYN(xWeibull,alpha,beta);
% plot(xWeibull,yWeibull*100, 'LineWidth', 2);
%
% % Calculate R-Squared
% yWeibullPred = ComputeWeibYN(data4Psychometric,alpha,beta);
% % rSquaredWeibull = GoF(pCorrectHistory,yWeibullPred);
% rSquaredWeibull = corrcoef(pCorrectHistory,yWeibullPred);
% rSquaredWeibull = rSquaredWeibull(2,1)^2;
%
% disp(['R-Squared of the Weibull model: ', num2str(rSquaredWeibull)]);
%
% % % Fit psychometric function using a General Linear Model
% % [logitCoef,dev] = glmfit(uniqueVar4Threshold,[nCorrect' nTrialsDone'],'binomial','link', 'probit');
% % logitFit = glmval(logitCoef,uniqueVar4Threshold,'probit','size',nTrialsDone');
% %
% % figure,
% % plot(uniqueVar4Threshold,pCorrect*100,'bs', uniqueVar4Threshold,logitFit*100,'r-');
% % xlabel(strVar4Threshold);
% % ylabel('Percent of Discomfort');
%
% % Fit psychometric function using a Cumulative Normal Distribution
% [muEst, sigmaEst] = FitCumNormYN(uniqueVar4Threshold, nCorrect, nTrialsDone-nCorrect);
% xCum = [min(uniqueVar4Threshold(:)):((max(uniqueVar4Threshold(:))-min(uniqueVar4Threshold(:)))./10000):max(uniqueVar4Threshold(:))];
% yCum = ComputeCumNormYN(xCum,muEst,sigmaEst);
% plot(xCum,yCum*100, 'Color', [0.65 0.84 0.75], 'LineWidth', 2);
% % Calculate the confidence intervals
% alphaErrors = [0.01, 0.05, 0.1];
% quantileFunction = -sqrt(2).*erfinv(alphaErrors-1); % Mix of https://en.wikipedia.org/wiki/Confidence_interval and https://en.wikipedia.org/wiki/Normal_distribution#Cumulative_distribution_function
% ciCumLow = muEst - sigmaEst.*quantileFunction;
% ciCumHigh = muEst + sigmaEst.*quantileFunction;
% str = '';
% for i = 1:size(alphaErrors,2)
% str = [str,'alpha = ',num2str(alphaErrors(i)),', CI = [',num2str(ciCumLow(i)),',',num2str(ciCumHigh(i)),']; '];
% end
% disp(str);
%
% % Calculate R-Squared
% yCumPred = 0.5.*(1+erf((data4Psychometric-muEst)/(sigmaEst*sqrt(2))));
% % rSquaredCum = GoF(pCorrectHistory,yCumPred);
% rSquaredCum = corrcoef(pCorrectHistory,yCumPred);
% rSquaredCum = rSquaredCum(2,1)^2;
%
% disp(['R-Squared of the Cumulative model: ', num2str(rSquaredCum)]);
end
save([path, fileName, '.mat'], 'conditions', 'thresholds');
% Clear the screen
Screen('Close',wPtr);
% Draw instructions page
function wPtr = DrawInstructionsPage(testMode)
% Open window with a fixation point
screenColor = [128 128 128];
screenFreq = 60; %120;%120;%In Hz (desired freq) %60 for testing purposes
screenFreqTolerance = 5;
screenNumber = max(Screen('Screens')); %0: single display setting
screenNumber = 1;
screenSize = zeros(1,2);
[screenSize(1), screenSize(2)] = Screen('WindowSize', screenNumber);
if testMode
PsychDebugWindowConfiguration(0, 0.25)
% wPtr = Screen('OpenWindow', screenNumber, screenColor, [1 1 screenSize(1) screenSize(2)*0.25]);
wPtr = Screen('OpenWindow',screenNumber,screenColor);
else
clear Screen;
Screen('Preference', 'ConserveVRAM', 4096);
Screen('Preference', 'SkipSyncTests', 1 );
wPtr = Screen('OpenWindow',screenNumber,screenColor);
end
% Get timing information from screen
screenRefreshRate = Screen('GetFlipInterval', wPtr);
disp(['Screen rate: ' num2str(screenRefreshRate)]);
ScreenFreqDiscrepancy = screenFreq - 1/screenRefreshRate;
Screen('FillRect', wPtr, screenColor);
% Check the monitor's configuration
if ~testMode
if (ScreenFreqDiscrepancy < screenFreqTolerance)
disp('Refresh rate is the desired one');
else
disp(['Refresh frequency should be ' screenFreq]);
error('Screen was not propperly configured');
end
end
% Set font style in window
tfont='Arial';
tsize=15;
tstyle=1; %1=normal 2=bold 3=italic 4=underline
vSpacing = 3;
Screen('TextFont', wPtr, tfont);
Screen('TextSize', wPtr, tsize);
Screen('TextStyle', wPtr, tstyle);
% Get coordinates in the window
windowSize = zeros(1,2);
[windowSize(1), windowSize(2)] = Screen('WindowSize', wPtr);
windowCenter = zeros(1,2);
windowCenter(1) = floor(windowSize(1)/2);
windowCenter(2) = floor(windowSize(2)/2);
screenNumber = Screen('WindowScreenNumber', wPtr);
% Define black and white
white = WhiteIndex(screenNumber);
black = BlackIndex(screenNumber);
strInstructions = 'En este experimento se le presentará un estímulo auditivo y debe indicar si le causa molestia o no. En caso que le cause molestia, debe pulsar la tecla que se indica como "Molesto", en caso contrario, debe pulsar la tecla "NO Molesto". Debe indicar su respuesta lo más rápido posible cuando la cruz de la pantalla sea de color negro (indicará que el estímulo ha terminado de ser presentado). La tecla de la derecha corresponde a la tecla "F" y la de la izquierda a la tecla "A".';
strInstructions2 = 'Pulse la barra espaciadora para continuar';
DrawFormattedText(wPtr,strInstructions,'center',windowSize(2)*0.25,black, 80, 0, 0, vSpacing);
DrawFormattedText(wPtr,strInstructions2,'center',windowSize(2)*0.66,black, 80, 0, 0, vSpacing);
% Flip to the screen
Screen('Flip', wPtr);
% Draw page to do a mini-break
function wPtr = DrawBreakPage(testMode)
% Open window with a fixation point
screenColor = [128 128 128];
screenFreq = 60; %120;%120;%In Hz (desired freq) %60 for testing purposes
screenFreqTolerance = 5;
screenNumber = max(Screen('Screens')); %0: single display setting
screenSize = zeros(1,2);
[screenSize(1), screenSize(2)] = Screen('WindowSize', screenNumber);
if testMode
PsychDebugWindowConfiguration(0, 0.25)
% wPtr = Screen('OpenWindow', screenNumber, screenColor, [1 1 screenSize(1) screenSize(2)*0.25]);
wPtr = Screen('OpenWindow',screenNumber,screenColor);
else
wPtr = Screen('OpenWindow',screenNumber,screenColor);
end
% Get timing information from screen
screenRefreshRate = Screen('GetFlipInterval', wPtr);
disp(['Screen rate: ' num2str(screenRefreshRate)]);
ScreenFreqDiscrepancy = screenFreq - 1/screenRefreshRate;
Screen('FillRect', wPtr, screenColor);
% Check the monitor's configuration
if ~testMode
if (ScreenFreqDiscrepancy < screenFreqTolerance)
disp('Refresh rate is the desired one');
else
disp(['Refresh frequency should be ' screenFreq]);
error('Screen was not propperly configured');
end
end
% Set font style in window
tfont='Arial';
tsize=14;
tstyle=1; %1=normal 2=bold 3=italic 4=underline
Screen('TextFont', wPtr, tfont);
Screen('TextSize', wPtr, tsize);
Screen('TextStyle', wPtr, tstyle);
% Get coordinates in the window
windowSize = zeros(1,2);
[windowSize(1), windowSize(2)] = Screen('WindowSize', wPtr);
windowCenter = zeros(1,2);
windowCenter(1) = floor(windowSize(1)/2);
windowCenter(2) = floor(windowSize(2)/2);
screenNumber = Screen('WindowScreenNumber', wPtr);
% Define black and white
white = WhiteIndex(screenNumber);
black = BlackIndex(screenNumber);
DrawFormattedText(wPtr,'5 segundos de pausa...','center','center',black);
% Flip to the screen
Screen('Flip', wPtr);

@ -0,0 +1,631 @@
function [threshold, history, responsesStaircase, reactionTimes] = AuditoryThresholds_v3(participantId, volumes, frequencies, durations, interStimuliInterval, repetitions, intraStimuliInterval, responseDuration, testMode)
% Calculate discomfort thresholds from auditory stimuli. A pure tone of a
% specified frequency, duration and number of repetitions would be
% presented and the participant would response whether it causes dicomfort
% or not.
% The threshold will be measured on the variable with a length greater than
% 1.
if nargin < 8
volumes = [40:5:140]; % in dBA
frequencies = 1000; % in Hz
durations = 1; % in seconds
interStimuliInterval = 3; % in seconds
repetitions = 1;
intraStimuliInterval = 1; % in seconds
responseDuration = 0.8; % in seconds
end
if exist('testMode','var') == 0
testMode = 1;
simulateResponses = 1;
else
simulateResponses = 0;
end
simulateResponses = 0;
% if nargin < 1
% error('Participant Id not specified');
% end
% Parameters to set before experiment
viewingDistanceCm = 70; % in cm
screenSizeCm = [50 30]; % width and height in cm
fixationSizeDeg = 0.5; % in visual degrees
buttonsSeparationDeg = 1; % in degrees
fixationColor_sRGB = [1 1 1];
responseColor_sRGB = [0 0 0];
backgroundColor_sRGB = [0.5 0.5 0.5];
enableCorrections = 1;
% Check variable to measure the threshold
bVolumeThreshold = 0;
bFreqThreshold = 0;
bDurationsThreshold = 0;
bRepetitionsThreshold = 0;
if length(volumes) > 1
disp('Threshold measured on volume');
bVolumeThreshold = 1;
variable4Threshold = volumes;
end
if length(frequencies) > 1
disp('Threshold measured on frequencies');
bFreqThreshold = 1;
variable4Threshold = frequencies;
end
if length(durations) > 1
disp('Threshold measured on durations');
bDurationsThreshold = 1;
variable4Threshold = durations;
end
if length(repetitions) > 1
disp('Threshold measured on repetitions');
bRepetitionsThreshold = 1;
variable4Threshold = repetitions;
end
if (bVolumeThreshold+bFreqThreshold+bDurationsThreshold+bRepetitionsThreshold) ~= 1
error('Variable to measure the threshold is not defined properly');
end
% Establish key mapping: ESCape aborts, Space toggles between auto-
% movement of sound source or user mouse controlled movement:
KbName('UnifyKeynames');
SPACE = KbName('space');
ESC = KbName('ESCAPE');
AKEY = KbName('A');
FKEY = KbName('F');
keyList = zeros(1,256);
keyList(SPACE) = 1;
keyList(ESC) = 1;
keyList(AKEY) = 1;
keyList(FKEY) = 1;
fixationColor_sRGB = uint8(fixationColor_sRGB.*255);
responseColor_sRGB = uint8(responseColor_sRGB.*255);
backgroundColor_sRGB = uint8(backgroundColor_sRGB.*255);
% Perform basic initialization of the sound driver:
InitializePsychSound(1);
% Get audio devices
% 1=Windows/DirectSound, 2=Windows/MME, 11=Windows/WDMKS, 13=Windows/WASAPI, 8=Linux/ALSA, 7=Linux/OSS, 12=Linux/JACK, 5=MacOSX/CoreAudio.
deviceType = 13;
devices = PsychPortAudio('GetDevices', deviceType);
deviceId = devices.DeviceIndex;
% deviceFreq: Requested playback/capture rate in samples per second (Hz).
deviceSamplingRate = devices.DefaultSampleRate;
% deviceChannels: Number of audio channels to use, defaults to 2 for stereo.
deviceChannels = devices.NrOutputChannels;
% Mode: Defaults to 1 == sound playback only. Can be set to 2 == audio
% capture, or 3 for simultaneous capture and playback of sound. Note however that
% mode 3 (full duplex) does not work reliably on all sound hardware.
soundMode = 1;
% ReqLatency: Level 0 means: Don’t care about latency or timing
% precision. This mode works always and with all settings, plays nicely with other
% sound applications. Level 1 (the default) means: Try to get the lowest latency
% that is possible under the constraint of reliable playback, freedom of choice
% for all parameters and interoperability with other applications. Level 2 means:
% Take full control over the audio device, even if this causes other sound
% applications to fail or shutdown. Level 3 means: As level 2, but request the
% most aggressive settings for the given device. Level 4: Same as 3, but fail if
% device can’t meet the strictest requirements.
reqLatency = 2; % should be 2
try
pahandle = PsychPortAudio('Open', deviceId, soundMode, reqLatency, deviceSamplingRate, deviceChannels);
catch
% Close Audio Port
try
PsychPortAudio('Close', pahandle);
catch
PsychPortAudio('Close');
end
pahandle = PsychPortAudio('Open', deviceId, soundMode, reqLatency, deviceSamplingRate, deviceChannels);
end
% Open window and transform units from degrees to pixels
[wPtr, tFlip] = InitWindow(backgroundColor_sRGB, testMode);
screenSizePix = zeros(1,2);
[screenSizePix(1) screenSizePix(2)] = Screen('WindowSize', wPtr);
pixelsPerDegree = (screenSizePix./2) ./ (atan((screenSizeCm./2)./viewingDistanceCm).*360/(2*pi));
if ~ismembertol(pixelsPerDegree(1),pixelsPerDegree(2))
warning('Monitor size is not coherent');
end
fixationSizePix = round(fixationSizeDeg*pixelsPerDegree(1)); % in pixels
buttonsSeparationPix = round(buttonsSeparationDeg*pixelsPerDegree(1)); % in pixels
% wPtr = DrawFixationPoint([], testMode);
[wPtr, tFixation] = DrawFixationPoint(wPtr, fixationSizePix, fixationColor_sRGB, 0, [], buttonsSeparationPix, backgroundColor_sRGB, 0, tFlip, testMode);
status = PsychPortAudio('GetStatus', pahandle);
oldRunMode = PsychPortAudio('RunMode', pahandle, 1);
% A-weights
% Weights extracted from Harrison, M. (2004). The measurement and behaviour of sound. Vehicle Refinement, 17–73
aWeights = [-63.4 -56.7 -50.5 -44.7 -39.4 -34.6 -30.2 -26.2 -22.5 -19.1 -16.1 -13.4 -10.9 -8.6 -6.6 -4.8 -3.2 -1.9 -0.8 0 0.6 1 1.2 1.3 1.2 1 0.5 -0.1 -1.1 -2.5 -4.3 -6.6 -9.3];
aFreqs = [12.5 16 20 25 31.5 40 50 63 80 100 125 160 200 250 315 400 500 630 800 1000 1250 1600 2000 2500 3150 4000 5000 6300 8000 10000 12500 16000 20000];
aXs = linspace(min(aFreqs(:)), max(aFreqs(:)), 10000);
aYs = interp1(aFreqs, aWeights, aXs);
% figure,
% semilogx(aXs, aYs);
% title('A-Weighting');
% Set general parameters of SIAM method
possibleValues = variable4Threshold;
initValue = variable4Threshold(round(length(variable4Threshold)/4));
stepSize = [16 8 4 2 1];
trialStepSize = [0:1:size(stepSize,2)-1];
nReversals = 20;
nReversalTrials = 4;
nMaxTrials = 300;
[nextValue, isFinished, finalValue, methodState] = psychMethodSIAM(possibleValues,initValue,stepSize,trialStepSize,nReversals,nReversalTrials,nMaxTrials);
% Set frequency of the stimulus
if ~bFreqThreshold
freq = frequencies;
else
freq = nextValue;
end
% Set volume of the stimulus
if ~bVolumeThreshold
vol = volumes;
else
vol = nextValue;
end
% Set number of repetitions of the stimulus
if ~bRepetitionsThreshold
rep = repetitions;
else
rep = nextValue;
end
% Set duration of the stimulus
if ~bDurationsThreshold
dur = durations;
else
dur = nextValue;
end
% To test the script
if testMode
warning('Test mode is activated');
simulatedResponses = zeros(1,nMaxTrials);
% responses(1:2:end) = 1;
simulatedResponses((randi(2,1,nMaxTrials)-1)==1) = 1;
end
aafafaafafafaafaaffaafafaaffaffaaaffffafaa responses = ones(2, nMaxTrials).*(-1);
reactionTimes = ones(2, nMaxTrials).*(-1);
trial = 1;
while ~isFinished
% Initialize sound variable
stimulusSampling = round(dur*deviceSamplingRate);
% intraStimuliIntervalSampling = round(intraStimuliInterval*deviceSamplingRate);
% auditoryStimulusLength = stimulusSampling+intraStimuliIntervalSampling;
auditoryStimulusLength = stimulusSampling;
% From volume (dBA) to amplitude
weight = interp1(aFreqs, aWeights, freq);
amp = 20e-6*10^((vol-weight)/20);
% Create pure tone
auditoryStimulus = zeros(1,auditoryStimulusLength);
auditoryStimulus(1,1:stimulusSampling) = MakeBeep_v2(freq, dur, deviceSamplingRate, 1);
auditoryStimulus = repmat(auditoryStimulus, [deviceChannels 1]); % repeat it to do it stereo
% From amplitude to volume (dBA)
% Set volume of the stimulus
PsychPortAudio('Volume', pahandle, amp);
% Volume in dB, considering the air reference (20 microPascals).
% Amplitude ratio to dB conversion: GdB = 20 log10(A2 / A1), where
% A2 is the amplitude level, A1 is the referenced amplitude level and
% GdB is the amplitude ratio or gain in dB. Extracted from https://www.rapidtables.com/electric/decibel.html
volumeDB = 20*log10(amp/(20e-6));
volumeDBA = volumeDB + interp1(aFreqs, aWeights, freq);
disp(['Stimulus'' ', 'volume values: ', num2str(volumeDB), ' dB (', num2str(freq), ' Hz), i.e. ', num2str(volumeDBA), ' dBA'])
% Fill the audio playback buffer with the audio data:
PsychPortAudio('FillBuffer', pahandle, auditoryStimulus);
% Set randmonly the key that corresponds to discomfort and
% non-discomfort, respective
auxRand = rand;
if auxRand < 0.5
aKey = 0; % 'A' key non-discomfort
fKey = 1; % 'F' key discomfort
buttonsOrder = [0, 1];
else
aKey = 1; % 'A' key discomfort
fKey = 0; % 'F' key non-discomfort
buttonsOrder = [1, 0];
end
% Start playback for these sources:
for r = 1:rep
startTime = PsychPortAudio('Start', pahandle);
% Stop playback of all sources:
[startTime endPositionSecs xruns estStopTime] = PsychPortAudio('Stop', pahandle, 1); % wait until the stimulus is finished
if r~=rep
WaitSecs(intraStimuliInterval);
end
end
% Draw response page
[wPtr, tStartResponse] = DrawFixationPoint(wPtr, fixationSizePix, responseColor_sRGB, 1, buttonsOrder, buttonsSeparationPix, backgroundColor_sRGB, 0, tFlip, testMode);
% Participant's response
KbQueueCreate([],keyList);
KbQueueStart;
KbQueueFlush;
timeOut = 0;
isDown = 0;
while ((~isDown) && (~timeOut))
% Check keyboard:
[isDown, keyCode]=KbQueueCheck;
% For test purposes
if testMode
if simulateResponses
isDown = 1;
if simulatedResponses(trial)
keyCode(FKEY) = 1;
else
keyCode(AKEY) = 1;
end
end
end
% Get participant's response
if isDown
tReaction = GetSecs;
KbQueueFlush;
% Check correction
if enableCorrections
isDownCorrection = 0;
while ((~isDownCorrection) && (~timeOut))
% Check keyboard:
[isDownCorrection, keyCodeCorrection]=KbQueueCheck;
if isDownCorrection
tReactionCorrection = GetSecs;
% Save reaction time of the correction
reactionTimes(2,trial) = tReactionCorrection-tStartResponse;
if keyCodeCorrection(AKEY) > 0
if aKey % A key means discomfort
responses(2,trial) = 1;
else
responses(2,trial) = 0;
end
end
if keyCodeCorrection(FKEY) > 0
if fKey % F key means discomfort
responses(2,trial) = 1;
else
responses(2,trial) = 0;
end
end
end
if ((~isDownCorrection) && ((GetSecs-tStartResponse) > responseDuration))
responses(2,trial) = 2;
reactionTimes(2,trial) = -1;
timeOut = 1;
end
end
end % end enableCorrections
if keyCode(ESC) > 0
warning('Operation terminated by user');
break;
end
if keyCode(AKEY) > 0
reactionTimes(1,trial) = tReaction-tStartResponse;
if aKey % A key means discomfort
responses(1,trial) = 1;
else
responses(1,trial) = 0;
end
end
if keyCode(FKEY) > 0
reactionTimes(1,trial) = tReaction-tStartResponse;
if fKey % F key means discomfort
responses(1,trial) = 1;
else
responses(1,trial) = 0;
end
end
if responses(2,trial)==2 % There is no correction done
[nextValue, isFinished, finalValue, methodState] = psychMethodSIAM(responses(1,trial), methodState);
if responses(1,trial) == 1
disp(['Stimulus is discomfort: Next value is ', num2str(nextValue)]);
else
disp(['Stimulus is NOT discomfort: Next value is ', num2str(nextValue)]);
end
else
disp(['Correction done: Next value is ', num2str(nextValue)]);
end
KbQueueFlush;
KbQueueStop;
KbQueueRelease;
KbReleaseWait;
end
% If the participant has not responded during the response window,
% it is considered as a missed response and the stimulus is
% presented again
if ((~isDown) && ((GetSecs-tStartResponse) > responseDuration))
responses(1,trial) = 2;
reactionTimes(1,trial) = -1;
disp(['Missed response: Next value is ', num2str(nextValue)]);
timeOut = 1;
KbQueueFlush;
KbQueueStop;
KbQueueRelease;
KbReleaseWait;
end
end
[wPtr, tStartResponse] = DrawFixationPoint(wPtr, fixationSizePix, fixationColor_sRGB, 0, [], buttonsSeparationPix, backgroundColor_sRGB, 0, tFlip, testMode);
if keyCode(ESC)
break;
end
% Update the value according to the response
if bFreqThreshold
freq = nextValue;
else
if bVolumeThreshold
vol = nextValue;
else
if bRepetitionsThreshold
rep = nextValue;
else
if bDurationsThreshold
dur = nextValue;
else
error('Variable to measure the threshold is undefined');
end
end
end
end
% Delete buffer:
result = PsychPortAudio('DeleteBuffer');
trial = trial + 1;
WaitSecs(interStimuliInterval);
end
responses(:,trial:end) = [];
reactionTimes(:,trial:end) = [];
Screen('Close',wPtr);
fig = figure;
stairs([1:size(methodState.history,2)], methodState.history, 'LineWidth', 2);
title('Auditory Threshold');
xlabel('# Trial');
if bFreqThreshold
ylabel('Frequency (Hz)');
strDisp = ' Hz';
fileName = [participantId,'_FrequencyThreshold_',num2str(volumes),'_dBA_',num2str(durations),'s',num2str(rep),'Repetitions'];
else
if bVolumeThreshold
ylabel('Volume (dBA)');
strDisp = ' amplitude';
fileName = [participantId,'_VolumeThreshold_',num2str(freq),'Hz_',num2str(durations),'s_',num2str(rep),'Repetitions'];
else
if bRepetitionsThreshold
ylabel('# Repetitions');
strDisp = ' repetitions';
fileName = [participantId,'_RepetitionsThreshold_',num2str(volumes),'_dBA_',num2str(freq),'Hz_',num2str(durations),'s'];
else
if bDurationsThreshold
ylabel('Duration (s)');
strDisp = ' s';
fileName = [participantId,'_DurationThreshold_',num2str(volumes),'_dBA_',num2str(freq),'Hz_',num2str(rep),'Repetitions'];
else
error('Variable to measure the threshold is not defined properly');
end
end
end
end
% Output variables
threshold = finalValue;
history = methodState.history;
responsesStaircase = methodState.responses;
disp(['The threshold is defined at ', num2str(threshold), strDisp]);
% Save results
pathName = ['Results/AuditoryThreshold/',participantId,'/'];
saveas(fig,[pathName,fileName,'.png']);
save([pathName,fileName,'.mat'],'participantId','volumes','frequencies','durations','interStimuliInterval','repetitions','intraStimuliInterval','responseDuration','deviceType','deviceId','deviceSamplingRate','deviceChannels','methodState','threshold','history','responsesStaircase','responses','reactionTimes');
% Wait a bit:
WaitSecs(0.1);
% Close Audio Port
PsychPortAudio('Close', pahandle);
sca;
% Done
return;
function [wPtr, tFlip] = InitWindow(screenColor_RGB, testMode)
% Open window
screenFreq = 60; %120;%120;%In Hz (desired freq) %60 for testing purposes
screenFreqTolerance = 5;
screenNumber = max(Screen('Screens')); %0: single display setting
screenSize = zeros(1,2);
[screenSize(1), screenSize(2)] = Screen('WindowSize', screenNumber);
if testMode
PsychDebugWindowConfiguration(0, 0.25)
% wPtr = Screen('OpenWindow', screenNumber, screenColor, [1 1 screenSize(1) screenSize(2)*0.25]);
wPtr = Screen('OpenWindow',screenNumber,screenColor_RGB);
else
Screen('Preference', 'ConserveVRAM', 4096);
% Screen('Preference', 'SkipSyncTests', 0);
Screen('Preference', 'SkipSyncTests', 1);
wPtr = Screen('OpenWindow',screenNumber,screenColor_RGB);
end
% Get timing information from screen
screenRefreshRate = Screen('GetFlipInterval', wPtr);
disp(['Screen rate: ' num2str(screenRefreshRate)]);
ScreenFreqDiscrepancy = screenFreq - 1/screenRefreshRate;
Screen('FillRect', wPtr, screenColor_RGB);
% Check the monitor's configuration
if ~testMode
if (ScreenFreqDiscrepancy < screenFreqTolerance)
disp('Refresh rate is the desired one');
else
disp(['Refresh frequency should be ' screenFreq]);
% error('Screen was not propperly configured');
end
end
% Set font style in window
tfont='Arial';
tsize=14;
tstyle=1; %1=normal 2=bold 3=italic 4=underline
Screen('TextFont', wPtr, tfont);
Screen('TextSize', wPtr, tsize);
Screen('TextStyle', wPtr, tstyle);
% Flip to the screen
[tFlipStart,~,tFlipEnd] = Screen('Flip', wPtr);
tFlip = tFlipEnd-tFlipStart;
function [wPtr, tFixation] = DrawFixationPoint(wPtr, fixationSizePix, fixation_sRGB, showButtons, buttonsOrder, buttonsSeparationPix, background_sRGB, whenFixation, tFlip, testMode)
if exist('wPtr','var')==0 || isempty(wPtr)
% Open window with a fixation point
screenColor = [128 128 128];
screenFreq = 60; %120;%120;%In Hz (desired freq) %60 for testing purposes
screenFreqTolerance = 5;
screenNumber = max(Screen('Screens')); %0: single display setting
screenSize = zeros(1,2);
[screenSize(1), screenSize(2)] = Screen('WindowSize', screenNumber);
if testMode
PsychDebugWindowConfiguration(0, 0.25)
wPtr = Screen('OpenWindow', screenNumber, screenColor, [1 1 screenSize(1) screenSize(2)*0.25]);
else
wPtr = Screen('OpenWindow',screenNumber,screenColor);
end
% Get timing information from screen
screenRefreshRate = Screen('GetFlipInterval', wPtr);
disp(['Screen rate: ' num2str(screenRefreshRate)]);
ScreenFreqDiscrepancy = screenFreq - 1/screenRefreshRate;
Screen('FillRect', wPtr, screenColor);
% Check the monitor's configuration
if ~testMode
assert(isequal(screenSize, windowSize));
if (ScreenFreqDiscrepancy < screenFreqTolerance)
disp('Refresh rate is the desired one');
else
disp(['Refresh frequency should be ' screenFreq]);
error('Screen was not propperly configured');
end
end
% Set font style in window
tfont='Arial';
tsize=14;
tstyle=1; %1=normal 2=bold 3=italic 4=underline
Screen('TextFont', wPtr, tfont);
Screen('TextSize', wPtr, tsize);
Screen('TextStyle', wPtr, tstyle);
else
screenNumber = Screen('WindowScreenNumber',wPtr);
end
if tFlip > whenFixation
tFlip = 0;
end
Screen('FillRect', wPtr, background_sRGB);
% Get coordinates in the window
windowSize = zeros(1,2);
[windowSize(1), windowSize(2)] = Screen('WindowSize', wPtr);
windowCenter = zeros(1,2);
windowCenter(1) = floor(windowSize(1)/2);
windowCenter(2) = floor(windowSize(2)/2);
% Here we set the size of the arms of our fixation cross
fixCrossDimPix = round(fixationSizePix/2);
% Now we set the coordinates (these are all relative to zero we will let
% the drawing routine center the cross in the center of our monitor for us)
xCoords = [-fixCrossDimPix fixCrossDimPix 0 0];
yCoords = [0 0 -fixCrossDimPix fixCrossDimPix];
allCoords = [xCoords; yCoords];
% Set the line width for our fixation cross
lineWidthPix = 4;
% Draw the fixation cross in white, set it to the center of our screen and
% set good quality antialiasing
Screen('DrawLines', wPtr, allCoords, lineWidthPix, fixation_sRGB, windowCenter);
% Draw the buttons to guide the participant
if showButtons
% Set font style in window
tsize=20;
Screen('TextSize', wPtr, tsize);
if buttonsOrder(1)
strLeft = 'Molesto';
strRight = 'NO Molesto';
else
strLeft = 'NO Molesto';
strRight = 'Molesto';
end
xTextSizePix = tsize*max(strlength(strLeft),strlength(strRight));
yTextSizePix = round(tsize/2);
DrawFormattedText(wPtr,strLeft,'right',windowCenter(2)+fixCrossDimPix,fixation_sRGB,[],[],[],[],0,[windowCenter(1)-xTextSizePix-buttonsSeparationPix, windowCenter(2)-yTextSizePix, windowCenter(1)-buttonsSeparationPix, windowCenter(2)+yTextSizePix]);
DrawFormattedText(wPtr,strRight,windowCenter(1)+buttonsSeparationPix,windowCenter(2)+fixCrossDimPix,fixation_sRGB,[],[],[],[],0,[windowCenter(1)+buttonsSeparationPix, windowCenter(2)-yTextSizePix, windowCenter(1)+xTextSizePix+buttonsSeparationPix, windowCenter(2)+yTextSizePix]);
end
% Flip to the screen
tFixation = Screen('Flip', wPtr, whenFixation-tFlip);

@ -0,0 +1,158 @@
function CalibrateAudioStimuli()
% Script to measure the difference (in terms of intensity) between the
% sent and the presented stimuli using the sonometer.
% Stimuli parameters
volumes = [30:2:60]; % in dBA
frequencies = 1000; % in Hz
durations = 3; % in seconds
interStimuliInterval = 3; % in seconds
stimulusRepetitions = 5;
intraStimuliInterval = 6; % in seconds
calibrationRepetitions = 3;
% Perform basic initialization of the sound driver:
InitializePsychSound(1);
% Get audio devices
% 1=Windows/DirectSound, 2=Windows/MME, 11=Windows/WDMKS, 13=Windows/WASAPI, 8=Linux/ALSA, 7=Linux/OSS, 12=Linux/JACK, 5=MacOSX/CoreAudio.
deviceType = 3;
devices = PsychPortAudio('GetDevices', deviceType);
deviceId = devices.DeviceIndex;
% deviceFreq: Requested playback/capture rate in samples per second (Hz).
deviceSamplingRate = devices.DefaultSampleRate;
% deviceChannels: Number of audio channels to use, defaults to 2 for stereo.
deviceChannels = devices.NrOutputChannels;
% Mode: Defaults to 1 == sound playback only. Can be set to 2 == audio
% capture, or 3 for simultaneous capture and playback of sound. Note however that
% mode 3 (full duplex) does not work reliably on all sound hardware.
soundMode = 1;
% ReqLatency: Level 0 means: Don’t care about latency or timing
% precision. This mode works always and with all settings, plays nicely with other
% sound applications. Level 1 (the default) means: Try to get the lowest latency
% that is possible under the constraint of reliable playback, freedom of choice
% for all parameters and interoperability with other applications. Level 2 means:
% Take full control over the audio device, even if this causes other sound
% applications to fail or shutdown. Level 3 means: As level 2, but request the
% most aggressive settings for the given device. Level 4: Same as 3, but fail if
% device can’t meet the strictest requirements.
reqLatency = 2; % should be 2
try
pahandle = PsychPortAudio('Open', deviceId, soundMode, reqLatency, deviceSamplingRate, deviceChannels);
catch
% Close Audio Port
try
PsychPortAudio('Close', pahandle);
catch
PsychPortAudio('Close');
end
pahandle = PsychPortAudio('Open', deviceId, soundMode, reqLatency, deviceSamplingRate, deviceChannels);
end
status = PsychPortAudio('GetStatus', pahandle);
oldRunMode = PsychPortAudio('RunMode', pahandle, 1);
% A-weights
% Weights extracted from Harrison, M. (2004). The measurement and behaviour of sound. Vehicle Refinement, 17–73
aWeights = [-63.4 -56.7 -50.5 -44.7 -39.4 -34.6 -30.2 -26.2 -22.5 -19.1 -16.1 -13.4 -10.9 -8.6 -6.6 -4.8 -3.2 -1.9 -0.8 0 0.6 1 1.2 1.3 1.2 1 0.5 -0.1 -1.1 -2.5 -4.3 -6.6 -9.3];
aFreqs = [12.5 16 20 25 31.5 40 50 63 80 100 125 160 200 250 315 400 500 630 800 1000 1250 1600 2000 2500 3150 4000 5000 6300 8000 10000 12500 16000 20000];
aXs = linspace(min(aFreqs(:)), max(aFreqs(:)), 10000);
aYs = interp1(aFreqs, aWeights, aXs);
% figure,
% semilogx(aXs, aYs);
% title('A-Weighting');
calibrationCurve = zeros(calibrationRepetitions,size(volumes,2));
for c = 1:calibrationRepetitions
for trial = 1:size(volumes,2)
% Initialize sound variable
stimulusSampling = round(durations*deviceSamplingRate);
% intraStimuliIntervalSampling = round(intraStimuliInterval*deviceSamplingRate);
% auditoryStimulusLength = stimulusSampling+intraStimuliIntervalSampling;
auditoryStimulusLength = stimulusSampling;
% From volume (dBA) to amplitude
weight = interp1(aFreqs, aWeights, frequencies);
vol = volumes(trial);
amp = 20e-6*10^((vol-weight)/20);
% Create pure tone
auditoryStimulus = zeros(1,auditoryStimulusLength);
auditoryStimulus(1,1:stimulusSampling) = MakeBeep_v2(frequencies, durations, deviceSamplingRate, 1);
auditoryStimulus = repmat(auditoryStimulus, [deviceChannels 1]); % repeat it ti di it stereo
% From amplitude to volume (dBA)
% Set volume of the stimulus
PsychPortAudio('Volume', pahandle, amp);
% Volume in dB, considering the air reference (20 microPascals).
% Amplitude ratio to dB conversion: GdB = 20 log10(A2 / A1), where
% A2 is the amplitude level, A1 is the referenced amplitude level and
% GdB is the amplitude ratio or gain in dB. Extracted from https://www.rapidtables.com/electric/decibel.html
volumeDB = 20*log10(amp/(20e-6));
volumeDBA = volumeDB + interp1(aFreqs, aWeights, frequencies);
disp(['Stimulus'' ', 'volume values: ', num2str(volumeDB), ' dB (', num2str(frequencies), ' Hz), i.e. ', num2str(volumeDBA), ' dBA'])
% Fill the audio playback buffer with the audio data:
PsychPortAudio('FillBuffer', pahandle, auditoryStimulus);
% Start playback for these sources:
for r = 1:stimulusRepetitions
startTime = PsychPortAudio('Start', pahandle);
% Stop playback of all sources:
[startTime endPositionSecs xruns estStopTime] = PsychPortAudio('Stop', pahandle, 1); % wait until the stimulus is finished
if r~=stimulusRepetitions
WaitSecs(intraStimuliInterval);
end
end
% Collect measured intensity (in dBA)
titleBar = 'Calibración de los estímulos';
userPrompt = {'Intensidad observada (en dBA)'};
caUserInput = inputdlg(userPrompt, titleBar, 1);
if isempty(caUserInput),return,end % Bail out if they clicked Cancel.
calibrationCurve(c,trial) = str2double(caUserInput{1});
% Delete buffer:
result = PsychPortAudio('DeleteBuffer');
WaitSecs(interStimuliInterval);
end
end
% Save results
currDate = datestr(now, 'yyyy-mm-dd');
save(['Results/AudioCalibration/',currDate,'_',num2str(frequencies),'Hz.mat'],'volumes','calibrationCurve','frequencies','durations');
figure,
hold on;
errorbar(volumes, mean(calibrationCurve,1), std(calibrationCurve,0,1), 'Color', [0.25 0.25 0.25], 'LineWidth', 2);
% plot(volumes, mean(calibrationCurve,1), 'Color', [0.25 0.25 0.25], 'LineWidth', 2);
scatter(volumes, mean(calibrationCurve,1), 40, [0 0 0]);
hold off;
xlim([min(min(volumes(:)),min(calibrationCurve(:))) max(max(volumes(:)),max(calibrationCurve(:)))]);
ylim([min(min(volumes(:)),min(calibrationCurve(:))) max(max(volumes(:)),max(calibrationCurve(:)))]);
xlabel('Sent intensity (in dBA)');
ylabel('Measured intensity (in dBA)');
title('Intensity calibration of audio stimuli');
disp('Calibration done');
% Wait a bit:
WaitSecs(0.1);
% Close Audio Port
PsychPortAudio('Close', pahandle);
% Done
return;

@ -0,0 +1,158 @@
function CalibrateAudioStimuli()
% Script to measure the difference (in terms of intensity) between the
% sent and the presented stimuli using the sonometer.
% Stimuli parameters
volumes = [30:2:60]; % in dBA
frequencies = 1000; % in Hz
durations = 3; % in seconds
interStimuliInterval = 3; % in seconds
stimulusRepetitions = 5;
intraStimuliInterval = 6; % in seconds
calibrationRepetitions = 3;
% Perform basic initialization of the sound driver:
InitializePsychSound(1);
% Get audio devices
% 1=Windows/DirectSound, 2=Windows/MME, 11=Windows/WDMKS, 13=Windows/WASAPI, 8=Linux/ALSA, 7=Linux/OSS, 12=Linux/JACK, 5=MacOSX/CoreAudio.
deviceType = 3;
devices = PsychPortAudio('GetDevices', deviceType);
deviceId = devices.DeviceIndex;
% deviceFreq: Requested playback/capture rate in samples per second (Hz).
deviceSamplingRate = devices.DefaultSampleRate;
% deviceChannels: Number of audio channels to use, defaults to 2 for stereo.
deviceChannels = devices.NrOutputChannels;
% Mode: Defaults to 1 == sound playback only. Can be set to 2 == audio
% capture, or 3 for simultaneous capture and playback of sound. Note however that
% mode 3 (full duplex) does not work reliably on all sound hardware.
soundMode = 1;
% ReqLatency: Level 0 means: Don’t care about latency or timing
% precision. This mode works always and with all settings, plays nicely with other
% sound applications. Level 1 (the default) means: Try to get the lowest latency
% that is possible under the constraint of reliable playback, freedom of choice
% for all parameters and interoperability with other applications. Level 2 means:
% Take full control over the audio device, even if this causes other sound
% applications to fail or shutdown. Level 3 means: As level 2, but request the
% most aggressive settings for the given device. Level 4: Same as 3, but fail if
% device can’t meet the strictest requirements.
reqLatency = 2; % should be 2
try
pahandle = PsychPortAudio('Open', deviceId, soundMode, reqLatency, deviceSamplingRate, deviceChannels);
catch
% Close Audio Port
try
PsychPortAudio('Close', pahandle);
catch
PsychPortAudio('Close');
end
pahandle = PsychPortAudio('Open', deviceId, soundMode, reqLatency, deviceSamplingRate, deviceChannels);
end
status = PsychPortAudio('GetStatus', pahandle);
oldRunMode = PsychPortAudio('RunMode', pahandle, 1);
% A-weights
% Weights extracted from Harrison, M. (2004). The measurement and behaviour of sound. Vehicle Refinement, 17–73
aWeights = [-63.4 -56.7 -50.5 -44.7 -39.4 -34.6 -30.2 -26.2 -22.5 -19.1 -16.1 -13.4 -10.9 -8.6 -6.6 -4.8 -3.2 -1.9 -0.8 0 0.6 1 1.2 1.3 1.2 1 0.5 -0.1 -1.1 -2.5 -4.3 -6.6 -9.3];
aFreqs = [12.5 16 20 25 31.5 40 50 63 80 100 125 160 200 250 315 400 500 630 800 1000 1250 1600 2000 2500 3150 4000 5000 6300 8000 10000 12500 16000 20000];
aXs = linspace(min(aFreqs(:)), max(aFreqs(:)), 10000);
aYs = interp1(aFreqs, aWeights, aXs);
% figure,
% semilogx(aXs, aYs);
% title('A-Weighting');
calibrationCurve = zeros(calibrationRepetitions,size(volumes,2));
for c = 1:calibrationRepetitions
for trial = 1:size(volumes,2)
% Initialize sound variable
stimulusSampling = round(durations*deviceSamplingRate);
% intraStimuliIntervalSampling = round(intraStimuliInterval*deviceSamplingRate);
% auditoryStimulusLength = stimulusSampling+intraStimuliIntervalSampling;
auditoryStimulusLength = stimulusSampling;
% From volume (dBA) to amplitude
weight = interp1(aFreqs, aWeights, frequencies);
vol = volumes(trial);
amp = 20e-6*10^((vol-weight)/20);
% Create pure tone
auditoryStimulus = zeros(1,auditoryStimulusLength);
auditoryStimulus(1,1:stimulusSampling) = MakeBeep_v2(frequencies, durations, deviceSamplingRate, 1);
auditoryStimulus = repmat(auditoryStimulus, [deviceChannels 1]); % repeat it ti di it stereo
% From amplitude to volume (dBA)
% Set volume of the stimulus
PsychPortAudio('Volume', pahandle, amp);
% Volume in dB, considering the air reference (20 microPascals).
% Amplitude ratio to dB conversion: GdB = 20 log10(A2 / A1), where
% A2 is the amplitude level, A1 is the referenced amplitude level and
% GdB is the amplitude ratio or gain in dB. Extracted from https://www.rapidtables.com/electric/decibel.html
volumeDB = 20*log10(amp/(20e-6));
volumeDBA = volumeDB + interp1(aFreqs, aWeights, frequencies);
disp(['Stimulus'' ', 'volume values: ', num2str(volumeDB), ' dB (', num2str(frequencies), ' Hz), i.e. ', num2str(volumeDBA), ' dBA'])
% Fill the audio playback buffer with the audio data:
PsychPortAudio('FillBuffer', pahandle, auditoryStimulus);
% Start playback for these sources:
for r = 1:stimulusRepetitions
startTime = PsychPortAudio('Start', pahandle);
% Stop playback of all sources:
[startTime endPositionSecs xruns estStopTime] = PsychPortAudio('Stop', pahandle, 1); % wait until the stimulus is finished
if r~=stimulusRepetitions
WaitSecs(intraStimuliInterval);
end
end
% Collect measured intensity (in dBA)
titleBar = 'Calibración de los estímulos';
userPrompt = {'Intensidad observada (en dBA)'};
caUserInput = inputdlg(userPrompt, titleBar, 1);
if isempty(caUserInput),return,end % Bail out if they clicked Cancel.
calibrationCurve(c,trial) = str2double(caUserInput{1});
% Delete buffer:
result = PsychPortAudio('DeleteBuffer');
WaitSecs(interStimuliInterval);
end
end
% Save results
currDate = datestr(now, 'yyyy-mm-dd');
save(['Results/AudioCalibration/',currDate,'_',num2str(frequencies),'Hz.mat'],'volumes','calibrationCurve','frequencies','durations');
figure,
hold on;
errorbar(volumes, mean(calibrationCurve,1), std(calibrationCurve,0,1), 'Color', [0.25 0.25 0.25], 'LineWidth', 2);
% plot(volumes, mean(calibrationCurve,1), 'Color', [0.25 0.25 0.25], 'LineWidth', 2);
scatter(volumes, mean(calibrationCurve,1), 40, [0 0 0]);
hold off;
xlim([min(min(volumes(:)),min(calibrationCurve(:))) max(max(volumes(:)),max(calibrationCurve(:)))]);
ylim([min(min(volumes(:)),min(calibrationCurve(:))) max(max(volumes(:)),max(calibrationCurve(:)))]);
xlabel('Sent intensity (in dBA)');
ylabel('Measured intensity (in dBA)');
title('Intensity calibration of audio stimuli');
disp('Calibration done');
% Wait a bit:
WaitSecs(0.1);
% Close Audio Port
PsychPortAudio('Close', pahandle);
% Done
return;

@ -0,0 +1,66 @@
function rgbImage = GenerateNoisyImage( imSize, meanIntensity, standardDeviation, rgbColor, circularImage )
% This functions generates an image composed by Gaussian noise of
% mean=meanIntensity and size=imSize. Optionally, the user can specify the
% rgbColor (black and white by default) of the noise and whether the image
% has circular shape (rectangular shape by default).
% Check that all parameters are well defined
% if nargin < 2
% error('Number of arguments is insufficient');
% end
if length(imSize) < 2
error('Image size should be defined by a vector of length equal to two (nrows, ncols)');
end
if (meanIntensity > 1) || (meanIntensity < 0)
error('The mean intensity must be between 0 and 1');
end
if exist('standardDeviation','var')==0 || isempty(standardDeviation)
% standardDeviation = min(meanIntensity,1-meanIntensity);
standardDeviation = 0.1;
end
if exist('rgbColor','var')==0 || isempty(rgbColor)
rgbColor = [0 0 0];
end
if exist('circularImage','var')==0 || isempty(circularImage)
circularImage = 0;
end
% Transform RGB color to HSV to be able to just change the intensity
hsvColor = rgb2hsv(rgbColor);
% Assign the chromatic values of the image
hsvImage = zeros(imSize(1), imSize(2), 3);
hsvImage(:,:,1) = hsvColor(1);
hsvImage(:,:,2) = hsvColor(2);
% To do the circular image
imageCenter = imSize / 2;
distanceMatrix = zeros(imSize(1),imSize(2));
randomVector = zeros(1,imSize(1)*imSize(2));
threshold = min(imageCenter);
if circularImage
for i = 1:imSize(1)
for j = 1:imSize(2)
distanceMatrix(i,j) = sqrt((i-imageCenter(1))^2 + (j-imageCenter(2))^2);
end
end
randomVector = zeros(1,length(distanceMatrix(distanceMatrix<threshold)));
end
% Randomize the intensity plane of the image
randomVector = random('norm',meanIntensity,standardDeviation,1,length(randomVector));
auxVector = zeros(imSize(1), imSize(2));
auxVector(distanceMatrix(:)<threshold) = randomVector;
hsvImage(:,:,3) = reshape(auxVector,imSize(1),imSize(2));
% Transform the image back to RGB color space
rgbImage = hsv2rgb(hsvImage);
% Present the image
% figure, imshow(rgbImage);
end

@ -0,0 +1,38 @@
function [beep,samplingRate] = MakeBeep_v2(freq,duration,samplingRate,amplitude)
% [beep,samplingRate] = MakeBeep(freq,duration,[samplingRate])
%
% Compute array that can be used by Snd to produce a pure tone of specified
% "freq" (Hz) and "duration" (s). The "samplingRate" defaults to
% Snd('DefaultRate').
%
% beep = MakeBeep(freq,duration);
% Snd('Open');
% .... do some stuff ....
% Snd('Play',beep);
%
% See Snd.
% 6/21/95 dhb, ccc PlayBeep: Wrote it.
% 3/29/97 dgp Updated
% 4/2/97 dgp Expanded comments above.
% 11/25/97 dhb Fixed comment to correctly indicate milliseconds.
% 12/10/97 dhb Add samplingRate and DONTPLAY args, snd return.
% 2/9/98 dgp Updated to use Snd instead of SndPlay.
% 2/13/98 dhb Return sampling rate.
% 2/16/98 dgp MakeBeep: Based on PlayBeep, but "duration" is now
% in s, not ms, and default sampling rate is now same as Snd.
% 11/1/99 dgp Cosmetic.
% 4/13/02 dgp Make the default samplingRate platform dependent, to match Snd.
% 4/13/02 dgp Get the default samplingRate from Snd.
% 2/07/19 dcn Off by one fixed.
if nargin<2 || isempty(duration)
error('Usage: beep=MakeBeep(freq,duration,[samplingRate]);')
end
if nargin<3 || isempty(samplingRate)
samplingRate = Snd('DefaultRate');
end
if nargin<4 || isempty(amplitude)
amplitude = 1;
end
beep = amplitude.*sin(2*pi*freq*(0:duration*samplingRate-1)/samplingRate);

File diff suppressed because it is too large Load Diff