WorldViz User Forum

WorldViz User Forum (https://forum.worldviz.com/index.php)
-   Vizard (https://forum.worldviz.com/forumdisplay.php?f=17)
-   -   motion tracker changes Vizard timing (https://forum.worldviz.com/showthread.php?t=5740)

jelly 06-07-2016 01:29 PM

motion tracker changes Vizard timing
 
Hello!

I am having very weird timing problems when running my script with the Polhemus motion tracker as opposed to without.

It only happens when I uncomment the section of the code that writes an output file with the position data of the tracker markers. It does not matter if Polhemus is running in parallel, as long as the Vizard script is not using the data.

Has anyone ever had anything similar and knows how to solve this problem? :confused:

Thanks in advance!

J

Jeff 06-09-2016 02:10 AM

Can you explain further what you mean by timing problems? It would probably help if you post example code that shows the issue.

jelly 06-09-2016 04:53 AM

Dear Jeff,

I will try to post some code later this evening, the script is so large by now, it really is difficult to tell what is causing it. So I will need to try and create a simpler version.

In principle, I think it could be related to frequency or sampling. I've had a colleague who has told me that she had sounds in her script (like me) and they did not play at exactly the same time from one execution to the next. Another one had a countdown timer clock that was sometimes skipping the display of seconds. And another who had a beep sound that played three times at the end of a trial. There was supposed to be a 1s gap between each beep but sometimes the gaps were audibly uneven and the timer on screen was a bit slow. While for them this was not crucial, the timing of the sounds in my experiment is! All of us were/are using the Polhemus motion tracker.

I will follow this up later with a less complex code version that hopefully still illustrates the problem!

jelly 06-09-2016 12:17 PM

Dear Jeff,

I have some code below, which is also writing an output file. It only requires a sound .wav file as a cue, otherwise it should run on the spot and illustrate the issue.

When running it, you can see on the screen display that the sampling will freeze and skip seconds. Mostly it seems as if it balances itself out, meaning that if one second froze for too long, then another second at another time will be skipped.

Another thing I am thinking is (because my other colleagues also had similar problem when using sound) that maybe the sampling is faster than the sound and this interaction somehow causes some problems. But running the code with all the sound related things commented still has the problem...:confused:


Code:

import time
import viztask
import numpy as np
import random
import vizact
import itertools

viz.go()

###########################
## GENERAL SETUP
###########################


viz.MainView.setPosition(0,1.8,0)
viz.MainView.setEuler(0,0,0)
viz.mouse.setVisible(viz.OFF)                                                                                #Stops the mouse appearing on the screen.
viz.mouse.setOverride(viz.ON)                                                                                #Stops Vizard navigation using the mouse.

#Set background colour
viz.clearcolor(viz.BLACK)                                                                                        #Set background colour to black

ID = input('Participant ID: ')                                                                                #This is the unique ID number to identify the participant.
suffix = input('Suffix: ')                                                                                        #This is the suffix to the participant's ID number, used for not overwriting data files.
#Create a data ID and data header for the participant:
dataID = str(ID) + '_' + str(suffix)                                                                #Adds a suffix to the session number so that files can't be overwritten.
#Create a first line to write to data files:
firstLine = 'Study Data \n'       


####~~~~~~~Make Windows for Textures~~~~~~~####

#make box for clock
timeBox = viz.addText('', viz.SCREEN)                                                               
timeBox.setPosition(0.5,0.5)
timeBox.setScale([0.4, 0.4, 0.4])
timeBox.alignment(viz.ALIGN_CENTER_CENTER)
timeBox.color([1,1,1])

###########################
## OUTPUT FILE
###########################

####~~~~~~~OUTPUT~~~~~~~####
Data = open(str(dataID)  + '_Data3.txt','w')                                               
DataHeaders = 'ID\tPic\tTimeNow\tPicstate\tBeepstate\n'
Data.write(firstLine)
Data.close()

####~~~~~~~Create fuction for saving data~~~~~~~####

def saveData():

        global picstateString, beepstateString, timeNow
       
        Data = open(str(dataID)  + '_Data3.txt','a', 1) # 'a' means append the file rather than overwrite

        vars = "%s\t%s\t%s\t%s\t%s\n" %(
        ID, hno, timeNow, picstateString, beepstateString)

        Data.write(vars)
               

###########################
## STIMULI
###########################

### Cue sound
cue = viz.addAudio('cues\dong.wav')
cueDuration = cue.getDuration()

picList = np.arange(1, 59, 1) # this is in the real experiment an actual list of jpegs


### Timings ###

beeptimes = []
otimes2 = []
ctimes2 = []
otimes_short2 = []
otimes_long2 = []
ctimes_short2 = []
ctimes_long2 = []


def uniform_min_range(a, b, n, min_dist):
        while True:
                atimes = np.random.uniform(a, b, size=n)
                np.sort(atimes)
                if np.all(np.diff(atimes) >= min_dist):
                        return atimes

def timings():
        global condition, beeptimes, otimes, ctimes, otimes2, ctimes2, otimes_short2, otimes_long2, ctimes_short2, ctimes_long2, ctimes2String, otimes2String, beeptimesString

        beeptimes = uniform_min_range(0, 20, 5, 1.0) 
        print 'beep times: ', beeptimes
        beeptimesString = 'BeepTimes: '+','.join(map(str,beeptimes)) + '\n'
        num_to_select = 4

        otimes = random.sample(beeptimes, num_to_select)
        ctimes = list(set(beeptimes) - set(otimes))

        otimes1 = [oo + 0.8 for oo in otimes]
        otimes2 = np.sort(otimes1)
        print 'otimes short', otimes2
        ctimes2 = [ctimes[0] + 0.8]
        print 'ctimes short', ctimes2
               
        otimes2String = 'S1 Times: ' + ',' .join(map(str,otimes2)) +'\n'
        ctimes2String = 'S2 Times: ' + ','.join(map(str,ctimes2)) +'\n'
       
### Picture state

hno = 30

def setup_pics(): # at 0 nothing happens; at 1 (or -1) something happens (a beep, a pic) --> this sets it up
        global tt, picstate, beepstate, picstateString, beepstateString, beeptimesString, otimes2String, ctimes2String

        global beeptimes, otimes, ctimes, otimes_short2, otimes_long2, ctimes_short2, ctimes_long2
        timings()
       
        Data = open(str(dataID) + '_Data3.txt','a',1)
        Data.write(beeptimesString)
        Data.write(otimes2String)
        Data.write(ctimes2String)
        Data.write(DataHeaders)


        tt =[]
        dt = 0.04 #seconds for increment
        tt.append(0) #first elem in tt is 0

        picstate = []
        picstate.append(0) #first elem in picstate is 0

        beepstate = []
        beepstate.append(0)

        n=0
        done = 0
        while not done: #keep adding elements to the picstate list
                n=n+1 #elem by elem
                picstate.append(0)
                beepstate.append(0)
                tt.append(tt[n-1]+dt) #keep adding time elements to time list, by adding dt = 0.04 s to the one b4

               
                for oo in otimes2: # for each elem in the otimes
                        if (oo - tt[n]<0.5 and oo-tt[n]>0): #if the element in the otimes minus the current element in tt is lower than 0.5 and bigger than 0 (basically between 0 and 0,5) than choose action 1
                                picstate[n] = 1
                for pp in ctimes2: #if the element in the closing times minus the current element in tt is lower than 0.5 and bigger than 0 (basically between 0 and 0,5) than choose action 2
                        if (pp - tt[n]<0.5 and pp-tt[n]>0):
                                picstate[n] = -1
                for bs in beeptimes:
                        if (bs - tt[n]<0.5 and bs-tt[n]>0):
                                beepstate[n] = 1
                if tt[n] > 25: # if the current element in tt is bigger than 20 then stop the loop to add to the list, it's over
                        done = 1

        print 'tt', tt
        print 'picstate', picstate
        print 'beepstate', beepstate

def choose_pic():
        global picstate, beepstate, picstateString, beepstateString, timeNow
        global hno
        global tt, start, ntt

       
        ntt = viz.tick()-start # get time NOW since start of trial (can be made to be since start of experiment)
        nn = np.searchsorted(tt,ntt,side='left')

        thispic = picstate[nn]
        thisbeep = beepstate[nn]

        if thisbeep == 1 and thisbeep-1 == 0:
                def cueplay():
                        cue.play()
                        #yield viztask.waitTime(cueDuration)
                        #cue.stop()
                cueplay()
               
               
        picstateString = str(picstate[nn])
        beepstateString = str(beepstate[nn])
        timeNow = str(round(ntt,2)) # string of time Now ntt (rounded) to print in output file

        ### DEFAULT - random walk
        if thispic==0:
                prob = [0.05, 0.95]  # Probability to move up or down
                rr = np.random.random(1)
                if hno<27:
                        hno = hno+2
                elif hno>35:
                        hno = hno-2
                else:
                        if rr < prob[0] and hno>27:
                                hno = hno-1
                        elif rr > prob[1] and hno<35:
                                hno = hno+1

        ### STATE1
        elif thispic==1:  ## state for triggering action 1
                if hno<54:
                        hno = hno+5

        ### STATE2
        elif thispic==-1: ## state for triggering action 1
                if hno>4:
                        hno = hno-5
       
        ##save stuff
        saveData()
       
        ## DISPLAY
        time_left = round(20-ntt,0)
       
        timeBox.message('Time: '+str(int(round(ntt)))+'  -  '+'PictureNo: '+ str(picstate[nn])+ '  -  '+ 'Beep: '+str(beepstate[nn])+'  -  ' + str(nn))


###########################
## TRIAL
###########################

def mainTrial():                                                               
        global start, nn
        nn = 1
        setup_pics()
        start = viz.tick()
        vizact.ontimer2(0.035,500,choose_pic)
        yield viztask.waitTime(25)


viztask.schedule(mainTrial())

The problem with the tracker may be more complex but it is possible that not the tracker is the problem after all. The code I have embedded below, ignores the motion tracker altogether and still I have some timing issues. I guess it is better to understand/solve these first, before moving on.

Any help or ideas are very welcome and I would be very grateful for them!

jelly 06-13-2016 11:34 AM

For now, I think I have found the problem! It explains why I had the issue with the motion tracker on or off. The cause was not the tracker itself but the way the function which was writing the output was implemented. It was messing up the sampling, slowing it down, since the output file had to be opened, data saved and written each time.

Now that I am only saving data at each timepoint and writing it only once at the very end, the issue seems to be gone.


All times are GMT -7. The time now is 09:03 PM.

Powered by vBulletin® Version 3.8.7
Copyright ©2000 - 2021, vBulletin Solutions, Inc.
Copyright 2002-2018 WorldViz LLC