|
#!/usr/bin/env python |
|
# -*- coding: utf-8 -*- |
|
""" |
|
This experiment was created using PsychoPy3 Experiment Builder (v3.0.0b11), |
|
on 12月 12, 2018, at 20:56 |
|
If you publish work using this script please cite the PsychoPy publications: |
|
Peirce, JW (2007) PsychoPy - Psychophysics software in Python. |
|
Journal of Neuroscience Methods, 162(1-2), 8-13. |
|
Peirce, JW (2009) Generating stimuli for neuroscience using PsychoPy. |
|
Frontiers in Neuroinformatics, 2:10. doi: 10.3389/neuro.11.010.2008 |
|
""" |
|
|
|
from __future__ import absolute_import, division |
|
from psychopy import locale_setup, sound, gui, visual, core, data, event, logging, clock, parallel |
|
from psychopy.constants import (NOT_STARTED, STARTED, PLAYING, PAUSED, |
|
STOPPED, FINISHED, PRESSED, RELEASED, FOREVER) |
|
import numpy as np # whole numpy lib is available, prepend 'np.' |
|
from numpy import (sin, cos, tan, log, log10, pi, average, |
|
sqrt, std, deg2rad, rad2deg, linspace, asarray) |
|
from numpy.random import random, randint, normal, shuffle |
|
import os # handy system and path functions |
|
import sys # to get file system encoding |
|
|
|
# Ensure that relative paths start from the same directory as this script |
|
_thisDir = os.path.dirname(os.path.abspath(__file__)) |
|
os.chdir(_thisDir) |
|
|
|
# Store info about the experiment session |
|
expName = 'gratings_hemi_right' # from the Builder filename that created this script |
|
expInfo = {'participant': '', 'session': '001'} |
|
expInfo['date'] = data.getDateStr() # add a simple timestamp |
|
expInfo['expName'] = expName |
|
|
|
# Data file name stem = absolute path + name; later add .psyexp, .csv, .log, etc |
|
filename = _thisDir + os.sep + 'data/%s_%s_%s' %(expInfo['participant'], expName, expInfo['date']) |
|
|
|
# An ExperimentHandler isn't essential but helps with data saving |
|
thisExp = data.ExperimentHandler(name=expName, version='', |
|
extraInfo=expInfo, runtimeInfo=None, |
|
originPath='F:\\gratings_hemi_right_50min.py', |
|
savePickle=True, saveWideText=False, |
|
dataFileName=filename) |
|
logging.console.setLevel(logging.WARNING) # this outputs to the screen, not a file |
|
|
|
endExpNow = False # flag for 'escape' or other condition => quit the exp |
|
|
|
# Start Code - component code to be run before the window creation |
|
|
|
# Setup the Window |
|
win = visual.Window( |
|
size=[1920, 1080], fullscr=True, screen=0, |
|
allowGUI=False, allowStencil=False, |
|
monitor='testMonitor', color=[-1.0,-1.0,-1.0], colorSpace='rgb', |
|
blendMode='avg', useFBO=True, |
|
units='deg') |
|
# store frame rate of monitor if we can measure it |
|
expInfo['frameRate'] = win.getActualFrameRate() |
|
if expInfo['frameRate'] != None: |
|
frameDur = 1.0 / round(expInfo['frameRate']) |
|
else: |
|
frameDur = 1.0 / 60.0 # could not measure, so guess |
|
|
|
# Initialize components for Routine "instruction_pre" |
|
instruction_preClock = core.Clock() |
|
instruction_txt = visual.TextStim(win=win, name='instruction_txt', |
|
text='Press "Esc" to quit.', |
|
font='Arial', |
|
pos=(0, -5.0), height=0.5, wrapWidth=None, ori=0, |
|
color='white', colorSpace='rgb', opacity=1, |
|
languageStyle='LTR', |
|
depth=0.0); |
|
fixation_cross = visual.TextStim(win=win, name='fixation_cross', |
|
text='+', |
|
font='Arial', |
|
units='deg', pos=(-1.0, 0.1), height=1.0, wrapWidth=None, ori=0, |
|
color='red', colorSpace='rgb', opacity=1, |
|
languageStyle='LTR', |
|
depth=-1.0); |
|
|
|
# Initialize components for Routine "trial" |
|
trialClock = core.Clock() |
|
grating_right_inverse = visual.GratingStim( |
|
win=win, name='grating_right_inverse',units='deg', |
|
tex='sqrXsqr', mask='circle', |
|
ori=0, pos=[0.0, 0.0], size=[27.0, 27.0], sf=[0.833,0.833], phase=[0.75,0.25], |
|
color=[1,1,1], colorSpace='rgb', opacity=1,blendmode='avg', |
|
texRes=256, interpolate=True, depth=0.0) |
|
grating_right = visual.GratingStim( |
|
win=win, name='grating_right',units='deg', |
|
tex='sqrXsqr', mask='circle', |
|
ori=0, pos=[0.0, 0], size=[27.0, 27.0], sf=[0.833,0.833], phase=[0.25,0.25], |
|
color=[1,1,1], colorSpace='rgb', opacity=1,blendmode='avg', |
|
texRes=256, interpolate=True, depth=-1.0) |
|
grating_mask_left = visual.GratingStim( |
|
win=win, name='grating_mask_left',units='deg', |
|
tex='sin', mask=None, |
|
ori=0, pos=[-10.0, 0], size=[20.0, 27.0], sf=0, phase=0.0, |
|
color=[-1.0,-1.0,-1.0], colorSpace='rgb', opacity=1,blendmode='avg', |
|
texRes=128, interpolate=True, depth=-2.0) |
|
fixation_cross_main = visual.TextStim(win=win, name='fixation_cross_main', |
|
text='+', |
|
font='Arial', |
|
units='deg', pos=[-1.0, 0.1], height=1.0, wrapWidth=None, ori=0, |
|
color='red', colorSpace='rgb', opacity=1, |
|
languageStyle='LTR', |
|
depth=-3.0); |
|
p_port = parallel.ParallelPort(address='0xD010') |
|
|
|
# custom function |
|
def trigger(): |
|
p_port.setData(int(255)) |
|
core.wait(0.0002) # 0.2 ms |
|
p_port.setData(int(0)) |
|
|
|
# Create some handy timers |
|
globalClock = core.Clock() # to track the time since experiment started |
|
routineTimer = core.CountdownTimer() # to track time remaining of each (non-slip) routine |
|
|
|
# ------Prepare to start Routine "instruction_pre"------- |
|
t = 0 |
|
instruction_preClock.reset() # clock |
|
frameN = -1 |
|
continueRoutine = True |
|
routineTimer.add(2.000000) |
|
# update component parameters for each repeat |
|
# keep track of which components have finished |
|
instruction_preComponents = [instruction_txt, fixation_cross] |
|
for thisComponent in instruction_preComponents: |
|
if hasattr(thisComponent, 'status'): |
|
thisComponent.status = NOT_STARTED |
|
|
|
# -------Start Routine "instruction_pre"------- |
|
while continueRoutine and routineTimer.getTime() > 0: |
|
# get current time |
|
t = instruction_preClock.getTime() |
|
frameN = frameN + 1 # number of completed frames (so 0 is the first frame) |
|
# update/draw components on each frame |
|
|
|
# *instruction_txt* updates |
|
if t >= 0.0 and instruction_txt.status == NOT_STARTED: |
|
# keep track of start time/frame for later |
|
instruction_txt.tStart = t |
|
instruction_txt.frameNStart = frameN # exact frame index |
|
instruction_txt.setAutoDraw(True) |
|
frameRemains = 0.0 + 1.0- win.monitorFramePeriod * 0.75 # most of one frame period left |
|
if instruction_txt.status == STARTED and t >= frameRemains: |
|
instruction_txt.setAutoDraw(False) |
|
|
|
# *fixation_cross* updates |
|
if t >= 0.0 and fixation_cross.status == NOT_STARTED: |
|
# keep track of start time/frame for later |
|
fixation_cross.tStart = t |
|
fixation_cross.frameNStart = frameN # exact frame index |
|
fixation_cross.setAutoDraw(True) |
|
frameRemains = 0.0 + 2.0- win.monitorFramePeriod * 0.75 # most of one frame period left |
|
if fixation_cross.status == STARTED and t >= frameRemains: |
|
fixation_cross.setAutoDraw(False) |
|
|
|
# check if all components have finished |
|
if not continueRoutine: # a component has requested a forced-end of Routine |
|
break |
|
continueRoutine = False # will revert to True if at least one component still running |
|
for thisComponent in instruction_preComponents: |
|
if hasattr(thisComponent, "status") and thisComponent.status != FINISHED: |
|
continueRoutine = True |
|
break # at least one component has not yet finished |
|
|
|
# check for quit (the Esc key) |
|
if endExpNow or event.getKeys(keyList=["escape"]): |
|
core.quit() |
|
|
|
# refresh the screen |
|
if continueRoutine: # don't flip if this routine is over or we'll get a blank screen |
|
win.flip() |
|
|
|
# -------Ending Routine "instruction_pre"------- |
|
for thisComponent in instruction_preComponents: |
|
if hasattr(thisComponent, "setAutoDraw"): |
|
thisComponent.setAutoDraw(False) |
|
|
|
# set up handler to look after randomisation of conditions etc |
|
trials = data.TrialHandler(nReps=1000, method='sequential', |
|
extraInfo=expInfo, originPath=-1, |
|
trialList=[None], |
|
seed=None, name='trials') |
|
thisExp.addLoop(trials) # add the loop to the experiment |
|
thisTrial = trials.trialList[0] # so we can initialise stimuli with some values |
|
# abbreviate parameter names if possible (e.g. rgb = thisTrial.rgb) |
|
if thisTrial != None: |
|
for paramName in thisTrial: |
|
exec('{} = thisTrial[paramName]'.format(paramName)) |
|
|
|
for thisTrial in trials: |
|
currentLoop = trials |
|
# abbreviate parameter names if possible (e.g. rgb = thisTrial.rgb) |
|
if thisTrial != None: |
|
for paramName in thisTrial: |
|
exec('{} = thisTrial[paramName]'.format(paramName)) |
|
|
|
# ------Prepare to start Routine "trial"------- |
|
t = 0 |
|
trialClock.reset() # clock |
|
frameN = -1 |
|
continueRoutine = True |
|
routineTimer.add(1.000000) |
|
# update component parameters for each repeat |
|
# keep track of which components have finished |
|
trialComponents = [grating_right_inverse, grating_right, grating_mask_left, fixation_cross_main, p_port] |
|
for thisComponent in trialComponents: |
|
if hasattr(thisComponent, 'status'): |
|
thisComponent.status = NOT_STARTED |
|
|
|
# -------Start Routine "trial"------- |
|
while continueRoutine and routineTimer.getTime() > 0: |
|
# get current time |
|
t = trialClock.getTime() |
|
frameN = frameN + 1 # number of completed frames (so 0 is the first frame) |
|
# update/draw components on each frame |
|
|
|
# *grating_right_inverse* updates |
|
if t >= 0.0 and grating_right_inverse.status == NOT_STARTED: |
|
# keep track of start time/frame for later |
|
grating_right_inverse.tStart = t |
|
grating_right_inverse.frameNStart = frameN # exact frame index |
|
grating_right_inverse.setAutoDraw(True) |
|
frameRemains = 0.0 + 1.0- win.monitorFramePeriod * 0.75 # most of one frame period left |
|
if grating_right_inverse.status == STARTED and t >= frameRemains: |
|
grating_right_inverse.setAutoDraw(False) |
|
|
|
# *grating_right* updates |
|
if t >= 0.5 and grating_right.status == NOT_STARTED: |
|
# keep track of start time/frame for later |
|
grating_right.tStart = t |
|
grating_right.frameNStart = frameN # exact frame index |
|
grating_right.setAutoDraw(True) |
|
frameRemains = 0.5 + 0.5- win.monitorFramePeriod * 0.75 # most of one frame period left |
|
if grating_right.status == STARTED and t >= frameRemains: |
|
grating_right.setAutoDraw(False) |
|
|
|
# *grating_mask_left* updates |
|
if t >= 0.0 and grating_mask_left.status == NOT_STARTED: |
|
# keep track of start time/frame for later |
|
grating_mask_left.tStart = t |
|
grating_mask_left.frameNStart = frameN # exact frame index |
|
grating_mask_left.setAutoDraw(True) |
|
frameRemains = 0.0 + 1.0- win.monitorFramePeriod * 0.75 # most of one frame period left |
|
if grating_mask_left.status == STARTED and t >= frameRemains: |
|
grating_mask_left.setAutoDraw(False) |
|
|
|
# *fixation_cross_main* updates |
|
if t >= 0.0 and fixation_cross_main.status == NOT_STARTED: |
|
# keep track of start time/frame for later |
|
fixation_cross_main.tStart = t |
|
fixation_cross_main.frameNStart = frameN # exact frame index |
|
fixation_cross_main.setAutoDraw(True) |
|
frameRemains = 0.0 + 1.0- win.monitorFramePeriod * 0.75 # most of one frame period left |
|
if fixation_cross_main.status == STARTED and t >= frameRemains: |
|
fixation_cross_main.setAutoDraw(False) |
|
# *p_port* updates |
|
if t >= 0.5 and p_port.status == NOT_STARTED: |
|
# keep track of start time/frame for later |
|
p_port.tStart = t |
|
p_port.frameNStart = frameN # exact frame index |
|
p_port.status = STARTED |
|
# win.callOnFlip(p_port.setData, int(255)) |
|
win.callOnFlip(trigger) # custom |
|
frameRemains = 0.5 + 0.05- win.monitorFramePeriod * 0.75 # most of one frame period left |
|
if p_port.status == STARTED and t >= frameRemains: |
|
p_port.status = STOPPED |
|
# win.callOnFlip(p_port.setData, int(0)) |
|
|
|
# check if all components have finished |
|
if not continueRoutine: # a component has requested a forced-end of Routine |
|
break |
|
continueRoutine = False # will revert to True if at least one component still running |
|
for thisComponent in trialComponents: |
|
if hasattr(thisComponent, "status") and thisComponent.status != FINISHED: |
|
continueRoutine = True |
|
break # at least one component has not yet finished |
|
|
|
# check for quit (the Esc key) |
|
if endExpNow or event.getKeys(keyList=["escape"]): |
|
core.quit() |
|
|
|
# refresh the screen |
|
if continueRoutine: # don't flip if this routine is over or we'll get a blank screen |
|
win.flip() |
|
|
|
# -------Ending Routine "trial"------- |
|
for thisComponent in trialComponents: |
|
if hasattr(thisComponent, "setAutoDraw"): |
|
thisComponent.setAutoDraw(False) |
|
if p_port.status == STARTED: |
|
win.callOnFlip(p_port.setData, int(0)) |
|
thisExp.nextEntry() |
|
|
|
# completed 1000 repeats of 'trials' |
|
|
|
# these shouldn't be strictly necessary (should auto-save) |
|
thisExp.saveAsPickle(filename) |
|
# make sure everything is closed down |
|
thisExp.abort() # or data files will save again on exit |
|
win.close() |
|
core.quit() |
5. チェッカーボードのコントラストの変え方
4. Checkerboardのサイズの変更 (2) プロパティ画面で変更できます
[1.0, 1.0, 1.0] は[R, G, B]の指定で、この場合白になります。
それぞれ値は-1.0 ~ 1.0まで取ります。例えば[-1.0, -1.0, -1.0]は黒、[1.0, -1.0, -1.0]だと赤、といった具合です。
指定できるのはチェッカーボードの白黒片方の色(白)で、もう一方の色(黒)は自動で指定されます。1.0, 1.0, 1.0だともう一方は指定されませんが、自動的に[-1.0, -1.0, -1.0]の黒として処理されます。0.5, 0.5, 0.5を指定すると黒の方は自動で-0.5, -0.5, -0.5になります。この白と黒の関係は任意に(片方が白でもう片方がグレー、など)変更できません(正確に言うとひどく難易度が上がります)。
コントラストを下げたい場合は[0.0, 0.0, 0.0] ~ [1.0, 1.0, 1.0]の間で変更することになります。[0.0, 0.0, 0.0]だとグレーでコントラスト0になります。いろいろ変更してみると理解できるかと思います。
同様に"gratin・・・nverse"をクリックして"色"の値を変更します。
以上になります。
5.1. 背景の色を変えたい時
(1) メイン画面より矢印の歯車アイコン(実験のプロパティ?)をクリック
(2) プロパティ画面から矢印の"スクリーン"タブを開く
(3) "スクリーン"タブの"色"の値[-1.0, -1.0, -1.0] (ここでは黒)を任意のRGB値に変更する
注意点
1.0)、yが輝度変化(最低輝度最高輝度を0~1に正規化したもの)。