def test_weibull(): #fit to the fake data fit = data.FitWeibull(contrasts, responses, display=0, expectedMin=0.5) #check threshold is close (maybe not identical because not same function) assert thresh-fit.inverse(0.75)<0.01 #check that inverse works too modResps = fit.eval(contrasts) invs = fit.inverse(modResps) assert numpy.allclose(contrasts,invs), contrasts-invs#inverse should match the forwards function #do a plot to check fits look right if PLOTTING: plotFit(modResps, thresh, 'Weibull (thresh=%.2f, params=%s)' %(fit.inverse(0.75), fit.params))
def test_weibull(): #fit to the fake data fit = data.FitWeibull(contrasts, responses, display=0, expectedMin=0.5) #check threshold is close (maybe not identical because not same function) assert thresh - fit.inverse(0.75) < 0.001 #check that inverse works too modelResponses = fit.eval(contrasts) invs = fit.inverse(modelResponses) assert numpy.allclose( contrasts, invs), contrasts - invs #inverse should match the forwards function #do a plot to check fits look right if PLOTTING: pylab.figure(1) pylab.plot(contrasts, responses, 'o') pylab.plot(contrasts, fit.eval(contrasts)) pylab.plot([0, thresh], [0.75, 0.75], '--b') #horiz pylab.plot([thresh, thresh], [0., 0.75], '--b') #vert pylab.title('Fitting Weibull (thresh=%.2f)' % (fit.inverse(0.75)))
for fileN, thisStair in enumerate(allIntensities): # lines.extend(pylab.plot(thisStair)) # uncomment for a legend for files # names = files[fileN] pylab.plot(thisStair, label=files[fileN]) # pylab.legend() # get combined data i, r, n = data.functionFromStaircase(allIntensities, allResponses, bins='unique') combinedInten, combinedResp, combinedN = i, r, n combinedN = pylab.array(combinedN) # convert to array so we can do maths # fit curve fit = data.FitWeibull(combinedInten, combinedResp, expectedMin=expectedMin, sems=1.0 / combinedN) smoothInt = pylab.arange(min(combinedInten), max(combinedInten), 0.001) smoothResp = fit.eval(smoothInt) thresh = fit.inverse(threshVal) print(thresh) # plot curve pylab.subplot(122) pylab.plot(smoothInt, smoothResp, 'k-') pylab.plot([thresh, thresh], [0, threshVal], 'k--') # vertical dashed line pylab.plot([0, thresh], [threshVal, threshVal], 'k--') # horizontal dashed line pylab.title('threshold (%.2f) = %0.3f' % (threshVal, thresh)) # plot points
#plot each staircase pylab.subplot(121) lines, names = [],[] for fileN, thisStair in enumerate(allIntensities): #lines.extend(pylab.plot(thisStair)) #names = files[fileN] pylab.plot(thisStair, label=files[fileN]) #pylab.legend() #get combined data combinedInten, combinedResp, combinedN = \ data.functionFromStaircase(allIntensities, allResponses, 'unique') #fit curve guess= [num.average(combinedInten), num.average(combinedInten)/5] fit = data.FitWeibull(combinedInten, combinedResp, guess=guess, expectedMin=0.0) smoothInt = num.arange(min(combinedInten), max(combinedInten), 0.001) smoothResp = fit.eval(smoothInt) thresh = fit.inverse(0.5) print thresh #plot curve pylab.subplot(122) pylab.plot(smoothInt, smoothResp, '-') pylab.plot([thresh, thresh],[0,0.5],'--'); pylab.plot([0, thresh],[0.5,0.5],'--') pylab.title('threshold = %0.3f' %(thresh)) #plot points pylab.plot(combinedInten, combinedResp, 'o') pylab.ylim([0,1]) pylab.show()
staircase.importData( toStaircase(noiseEachTrial,descendingPsycho), np.array(corrEachTrial) ) printStaircase(staircase, briefTrialUpdate=False, printInternalVal=True, alsoLog=False) #Fit and plot data descendingPsycho = False fit = None intensityForCurveFitting = outOfStaircase(staircase.intensities,staircase,descendingPsycho) #print('intensityForCurveFitting=',intensityForCurveFitting) if descendingPsycho: intensityForCurveFitting = 100-staircase.intensities #because fitWeibull assumes curve is ascending #convert from list of trials to probabilities combinedInten, combinedResp, combinedN = \ data.functionFromStaircase(intensityForCurveFitting, staircase.data, bins='unique') print('combinedInten=',combinedInten,'combinedResp=',combinedResp) try: fit = data.FitWeibull(combinedInten, combinedResp, expectedMin=0, sems = 1.0/len(staircase.intensities)) print('fit=',fit) except: print("Fit failed.") plotDataAndPsychometricCurve(staircase,fit,descendingPsycho,threshVal=0.75) pylab.show() #must call this to actually show plot testNoise = True if testNoise: #Test noise myWin = visual.Window() proportnNoise = 0.9 noiseFieldWidthPix = 200 bgColor = [-.7,-.7,-.7] (noise,allFieldCoords,numNoiseDots) = createNoise(proportnNoise,myWin,noiseFieldWidthPix, bgColor) print("allFieldCoords[0:3]=",allFieldCoords[0:3])
from psychopy import data import numpy as np #my data x = np.array([5.0, 10.0, 20.0, 50.0, 70.0, 80.0, 95.0]) y = np.array([0.4, 0.4, 0.4, 0.57, 1.0, 1.0, 1.0]) #good expectedMin = 0 try: data.FitWeibull(x, y, expectedMin=expectedMin) print('Fit succeeded on my 1st dataset') except: print('Fit failed on my 1st dataset') #my data x = np.array([5.0, 10.0, 20.0, 50.0, 70.0, 80.0, 95.0]) y = np.array([0.0, 0.0, 0.0, 0.57, 1.0, 1.0, 1.0]) #bad FIT FAILS. Doesnt seem to like zeros expectedMin = 0 try: data.FitWeibull(x, y, expectedMin=expectedMin) print('Fit succeeded on my 2nd dataset') except: print('Fit failed on my 2nd dataset') #JWP JND_staircase_exp data x = np.array([0.0, 1.0, 2.0, 3.0, 4.0, 12.0, 20.0]) y = np.array([0.4, 0.63, 0.8, 0.92, 1.0, 1.0, 1.0]) expectedMin = 0 try: data.FitWeibull(x, y, expectedMin=expectedMin)
printStaircase(staircase, descendingPsycho, briefTrialUpdate=True, printInternalVal=True, alsoLog=False) #print('staircase.quantile=',round(staircase.quantile(),2),' sd=',round(staircase.sd(),2)) threshNoise = round(staircase.quantile(),3) if descendingPsycho: threshNoise = 100- threshNoise threshNoise = max( 0, threshNoise ) #e.g. ff get all trials wrong, posterior peaks at a very negative number msg= 'Staircase estimate of threshold = ' + str(threshNoise) + ' with sd=' + str(round(staircase.sd(),2)) logging.info(msg); print(msg) myWin.close() #Fit and plot data fit = None try: intensityForCurveFitting = staircase.intensities if descendingPsycho: intensityForCurveFitting = 100-staircase.intensities #because fitWeibull assumes curve is ascending fit = data.FitWeibull(intensityForCurveFitting, staircase.data, expectedMin=1/26., sems = 1.0/len(staircase.intensities)) except: print("Fit failed.") plotDataAndPsychometricCurve(staircase,fit,descendingPsycho,threshCriterion) #save figure to file pylab.savefig(fileName+'.pdf') print('The plot has been saved, as '+fileName+'.pdf') pylab.show() #must call this to actually show plot else: #not staircase noisePercent = defaultNoiseLevel phasesMsg = 'Experiment will have '+str(trials.nTotal)+' trials. Letters will be drawn with superposed noise of' + "{:.2%}".format(defaultNoiseLevel) print(phasesMsg); logging.info(phasesMsg) #myWin= openMyStimWindow(); myWin.flip(); myWin.flip();myWin.flip();myWin.flip() nDoneMain =0 while nDoneMain < trials.nTotal and expStop==False:
def run_quest_procedure(self, n_trials=10, start=20, start_sd=10, maxvalue=40, beta=3.5, delta=0.01, gamma=0.01, grain=0.01): print("RUNNING QUEST\n" \ "-------------\n") startVal=start startValSd=start_sd pThreshold=0.75 nTrials=n_trials minVal=0 maxVal=maxvalue beta=beta delta=delta gamma=gamma grain=grain method='quantile' conditions = { 'startVal': startVal, 'startValSd': startValSd, 'minVal': 0, 'maxVal': maxVal, 'pThreshold': 0.75, 'gamma': gamma, 'delta': delta, 'grain': grain, 'method': method, 'nTrials': n_trials, } self.conditions = [ dict({'label': 'staircase_1'}.items() + conditions.items()), dict({'label': 'staircase_2'}.items() + conditions.items()), ] self.quest = data.MultiStairHandler(stairType='quest', method='random', conditions=self.conditions) t1 = self.quest.staircases[0].mean() t2 = self.quest.staircases[1].mean() sd1 = self.quest.staircases[0].sd() sd2 = self.quest.staircases[1].sd() beta1 = contrib.quest.QuestObject.beta(self.quest.staircases[0]) beta1 = contrib.quest.QuestObject.beta(self.quest.staircases[1]) t_mean = (t1 + t2) / 2 beta_mean = (beta1 + beta2) / 2 fit = data.FitWeibull(t_mean, beta_mean, sems=1/n_trials) for n, stim_level in enumerate(self.quest): print("Calibration trial {0} / {1}\n" \ "Stimulation level = {2}\n" \ "-----------------------------".format(n + 1, n_trials, stim_level)) response = None # Repeat if subject doesn't respond while response == None: trial = ConditioningTrial(self, n, True, max_voltage=stim_level) response = trial.run() # Add the response if response: print("Stimulation detected") else: print("Stimulation not detected") if n >= self.config['quest_settings']['n_ignored']: self.quest.addResponse(int(response)) p0 = fit.inverse(0) p25 = fit.inverse(.25) p50 = fit.inverse(.50) p75 = fit.inverse(.75) print("1% detection probability level = {0}\n" "25% detection probability level = {1}\n" "50% detection probability level = {2}\n" "75% detection probability level = {3}\n".format(self.quest.quantile(0.01), self.quest.quantile(.25), self.quest.quantile(.5), self.quest.quantile(.75))) return p0, p25, p50, p75
quantilePctNoise = 100-staircase.quantile() #print('staircase quantile (median)=','{:.4f}'.format(staircase.quantile()), end='') #gets the median. Prints as floating point with 4 digits of precision print('Median of posterior distribution according to QUEST, percent noise=','{:.4f}'.format(quantilePctNoise)) if plotFakeDataInstead: #plot standard fake data instead. intensities = np.array([5.00, 20.00, 20.00, 20.00, 50.00, 50.00, 50.00, 5.00, 80.00, 80.00, 80.00, 5.00, 95.00, 95.00, 95.00, 74.56, 75.89, 76.94, 77.72, 78.43, 79.05, 79.68, 80.28, 80.87, 81.53, 82.22, 83.05, 84.01, 85.04, 86.09, 87.02, 87.80, 88.47, 89.03, 89.49, 89.88, 90.20, 90.49, 90.74, 90.96, 91.16, 89.97, 90.12, 90.24, 90.37, 90.48, 90.59, 90.69, 90.79, 90.10, 90.18, 90.26, 90.33, 90.40, 90.47, 90.54, 90.60, 90.66, 90.72, 90.28, 90.33, 90.37, 90.42, 90.06, 89.73 ]) #debug, example data corrEachTrial= np.array([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1 ]) #debug, example data staircase.importData( toStaircase(intensities,descendingPsycho), corrEachTrial) intensities = outOfStaircase( staircase.intensities, staircase, descendingPsycho ) #inverse log, 100- responses = staircase.data expectedMin = 1.0/26 #fit curve fit = None try: intensityForCurveFitting = intensities if descendingPsycho: intensityForCurveFitting = 100-intensities #because fitWeibull assumes curve is ascending fit = data.FitWeibull(intensityForCurveFitting, responses, expectedMin=expectedMin, sems = 1.0/len(intensityForCurveFitting)) except: print("Fit failed.") plotDataAndPsychometricCurve(staircase,fit,descendingPsycho,threshCriterion) #save figure to file outputFile = 'test_staircase_plot' # os.path.join(dataDir, 'test_staircase_plot') pylab.savefig(outputFile + '.pdf') pylab.savefig(outputFile + '.jpg') pylab.show() #must call this to actually show plot
#plot each staircase pylab.subplot(121) colors = 'brgkcmbrgkcm' lines, names = [], [] for fileN, thisStair in enumerate(allIntensities): #lines.extend(pylab.plot(thisStair)) #names = files[fileN] pylab.plot(thisStair, label=files[fileN]) #pylab.legend() #get combined data combinedInten, combinedResp, combinedN = \ data.functionFromStaircase(allIntensities, allResponses, 5) #fit curve fit = data.FitWeibull(combinedInten, combinedResp, guess=[0.2, 0.5]) smoothInt = pylab.arange(min(combinedInten), max(combinedInten), 0.001) smoothResp = fit.eval(smoothInt) thresh = fit.inverse(0.8) print thresh #plot curve pylab.subplot(122) pylab.plot(smoothInt, smoothResp, 'k-') pylab.plot([thresh, thresh], [0, 0.8], 'k--') pylab.plot([0, thresh], [0.8, 0.8], 'k--') pylab.title('threshold = %0.3f' % (thresh)) #plot points pylab.plot(combinedInten, combinedResp, 'ko') pylab.ylim([0, 1])