Need very precise timings to show a stimulus

Got a LiveCode personal license? Are you a beginner, hobbyist or educator that's new to LiveCode? This forum is the place to go for help getting started. Welcome!

Moderators: FourthWorld, heatherlaine, Klaus, kevinmiller

PoLyGLoT
Posts: 105
Joined: Sat Jan 14, 2012 12:37 am

Need very precise timings to show a stimulus

Post by PoLyGLoT » Tue May 03, 2016 8:03 pm

Hi all,

I am doing a priming experiment and need very precise timing manipulations to show a stimulus. The basic idea is that the experiment will start with a row of XXXXXX, then a prime (either LEFT, RIGHT, or blank), then return to a row of XXXXXX. I need the prime (LEFT, RIGHT, or blank) to appear for either 16.7 milliseconds or 200 milliseconds before returning back to the XXXXXX.

I can get it to "work" with something like this:

Code: Select all

put "XXXXXXX" into cd fld "CueField" of cd "study" 
wait for 50 milliseconds
put "LEFT" into cd fld "CueField" of cd "study" 
wait for 16.7 milliseconds 
put "XXXXXXX" into cd fld "CueField" of cd "study" 
wait for 800 milliseconds
The problem is that sometimes, the "wait" command acts really weird (as in, it seems to jump around and not do things SEQUENTIALLY). Basically, it will sometimes just be a row of XXXXXX and nothing will change, and then it will go to the next card without even putting in the prime. I need this order to be precise and the timings to be precise. It has to be sequential!

I am currently doing this all on one card, but maybe I should put each display on a separate card? Maybe that will make the timings more precise? I've also thought about using the "send" command but I'm not sure that would be any better (and might actually be worse if I understand it correctly).

Basically I need a way to put livecode into complete hibernation mode until the time has elapsed, and then run the next bit of script, then back into hibernation mode, etc. until the trials are complete.

I appreciate any help!

dunbarx
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 10330
Joined: Wed May 06, 2009 2:28 pm

Re: Need very precise timings to show a stimulus

Post by dunbarx » Tue May 03, 2016 9:22 pm

Hi.

How are you determining the accuracy of your actions?

"...cd fld"? Are you an old HC guy? Lose "cd".

Navigating, or not, is not the issue.

Have you tried sending a message in time? With messages? Or setting up a loop that interrogates the milliseconds, and sends a message at designated values?

You are in all cases fighting a battle between "ideal" time and system time, which has to share with all sorts of other processes. Try each variant, but I ask again, how are you vetting the time?

Craig Newman

PoLyGLoT
Posts: 105
Joined: Sat Jan 14, 2012 12:37 am

Re: Need very precise timings to show a stimulus

Post by PoLyGLoT » Tue May 03, 2016 9:41 pm

dunbarx wrote:Hi.

How are you determining the accuracy of your actions?

"...cd fld"? Are you an old HC guy? Lose "cd".

Navigating, or not, is not the issue.

Have you tried sending a message in time? With messages? Or setting up a loop that interrogates the milliseconds, and sends a message at designated values?

You are in all cases fighting a battle between "ideal" time and system time, which has to share with all sorts of other processes. Try each variant, but I ask again, how are you vetting the time?

Craig Newman
Hi Craig,

Thanks for your reply. The problem can be boiled down to this: The "subliminal" trials should all be "the same" -- a quick blink on the screen without any real idea what you just saw (i.e., it should move so quickly that you know something was there but you can't tell what it was).

The problem: There is a lot of variability for that specific trial. Sometimes it's a blur and you can't tell what you just saw, and other times there is no "blur". It just stays a row of X's and then moves on to the next trial. Sometimes, although rarer, it changes but not fast enough such that you CAN tell what you just saw (even though it's pretty quick). The timings just seem inconsistent, which lead me to read up on the "wait" command. I read that it is not really a "wait" command, that other processes can be occurring while in "wait" mode. This is not ideal -- I want to completely stop the program during the "wait" cycle.

I tried a few more things since I posted this:
1. Using "case/break" with the same basic setup instead of "if/else". Did not work.
2. Using a repeat loop (i.e., send wait50 to me in 1 millisecond, if over 50 exit). Did not work but could have been set up wrong (this actually made it much worse).
3. Putting the initial X's, prime trial, and final X's on 3 separate cards. This is actually the best I've gotten so far, although it still seems that sometimes the subliminal trials have variability (sometimes it's a blur, other times it seems slightly slower).

I realize that I could be scientific and measure the exact times that things are being presented for, but here's the thing: Psychologically, if there is inconsistency from one trial to the next, it doesn't matter if both trials are presented for 16.7 milliseconds. For instance, if the program hangs for an extra 50 milliseconds BEFORE it presents the 16.7 millisecond priming trial, then it will FEEL much longer and that kind of thing is very bad for my needs (even though measuring trial A and B would both be presented for 16.7 ms, one would have an extra 50 ms of processing time and therefore be perceived completely differently).

So what I really need is a way to minimize variability as much as possible, so that once the "prime trial" starts, it will always be executed the same (i.e., it will ALWAYS be the same speed of a quick blur without anything else happening). I appreciate any help on this and I hope it's clear.

I am completely flexible in what I need to do to achieve this, whether it be precaching things, using send with messages, etc. I've already tried a lot of different things and keep coming up closer but not quite there.

dunbarx
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 10330
Joined: Wed May 06, 2009 2:28 pm

Re: Need very precise timings to show a stimulus

Post by dunbarx » Tue May 03, 2016 11:45 pm

Hi.

No, "wait" is blocking, unless you include "with messages". LC shuts its eyes.

So the actual timing is not critical, only consistent timing. I tried holding the "LEFT" in the field for 50 ms, and could read it. Not quite subliminal. I went down gradually, until below about 25 ms I could not read it at all. But the actual dwell time for "LEFT" seemed, felt, exactly the same regardless of the value of that dwell time. So I cannot say where your perception of the unstable timing derives from.

I am on a fast Mac. What are you on?

Craig

PoLyGLoT
Posts: 105
Joined: Sat Jan 14, 2012 12:37 am

Re: Need very precise timings to show a stimulus

Post by PoLyGLoT » Wed May 04, 2016 12:15 am

dunbarx wrote:Hi.

No, "wait" is blocking, unless you include "with messages". LC shuts its eyes.

So the actual timing is not critical, only consistent timing. I tried holding the "LEFT" in the field for 50 ms, and could read it. Not quite subliminal. I went down gradually, until below about 25 ms I could not read it at all. But the actual dwell time for "LEFT" seemed, felt, exactly the same regardless of the value of that dwell time. So I cannot say where your perception of the unstable timing derives from.

I am on a fast Mac. What are you on?

Craig
Thanks for your response, Craig. I am going to try it again using my original code. I am on a relatively fast laptop (mid-range core i7), so I don't think speed is necessarily the issue here.

I might try to do it this way: have three fields (one for X's, one for LEFT, and one for RIGHT), and then just show / hide them (maybe the manual "putting" and reputing into the same field is causing an issue).

I will keep you posted. Thanks again for your assistance!

PoLyGLoT
Posts: 105
Joined: Sat Jan 14, 2012 12:37 am

Re: Need very precise timings to show a stimulus

Post by PoLyGLoT » Wed May 04, 2016 2:34 am

I tried the following, but none helped:

1. Using show/hide fields instead of the put into command (did not help)
2. Referencing less global variables (perhaps it was a memory issue) (did not help)

I calculated total amount of time for the entire set of trials (X's, prime, and X's again) to occur, and I always get around the same time. So the program is keeping the timing consistent.

But the problem is that sometimes the X's change / get updated, and other times they just remain a row of X's. It's really bizarre. Almost like my conditional statements work sometimes but not others? But why would that occur?

Is there a way to clear the cache or something before I start executing the code? I am at a loss here as to what to try!

PoLyGLoT
Posts: 105
Joined: Sat Jan 14, 2012 12:37 am

Re: Need very precise timings to show a stimulus

Post by PoLyGLoT » Wed May 04, 2016 3:19 am

Quick update:

If I "set the acceleratedRendering of this stack to false", the problem gets WAY WORSE (it almost never works).

If I "set the acceleratedRendering of this stack to true", the problem gets WAY BETTER (almost always works).

It's not 100%, but this helped A LOT.

So why could this be? I've also noticed that if I wait awhile before reloading the card, that helps too.

So it seems like it's related to the rendering of the fields and giving the processor time to catch up.

Perhaps I could put in some short "wait with messages" lines throughout my program? Or is there another bit of code I could try based on this new info?

Thanks!!!

bn
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 4172
Joined: Sun Jan 07, 2007 9:12 pm

Re: Need very precise timings to show a stimulus

Post by bn » Wed May 04, 2016 7:21 am

Hi PolyGLot,

it is tricky to time the display as exact as you want it. You have to take into account the times for screen update and computation.

Computation is usually not taking long but screen update can take some milliseconds.

you can test this by making a new stack with 1 card and 2 fields
In a button you put this script

Code: Select all

on mouseUp
   lock screen
   put the milliseconds into tTime
   put "yyyXXXYYyyyxx" into field 1
   unlock screen
   put the milliseconds - tTime into field 2
end mouseUp
when you unlock the screen the screen update will take place and then you have an idea how long it takes.

For your purpose I think the "send in time" approach is more suited than the "wait" approach. It frees Livecode because when sending in time LC can do its housekeeping which it can not with a blocking wait.

Without knowing how long your experiment will run I did a little sample script to show what I mean.
Here you can compensate for the screen update by calculating the remaining milliseconds. This is just an example, you would have to familiarize yourself with this sort of scripts. I.e. the use of script local variables that are declared outside of a handler, usually at the top of a script, in this case "local sCueList, sIntervals" and the timing. Also if your list of cues will be very long you would have to think about access time for lines and items. Usually with less than 50 lines/items this should not be a problem.

But if you want to get down to a precise 16.7 milliseconds display time it will be hard to do. If you can live with +- 1 millisecond it probably can be done.

Key is benchmarking the important factors like I showed for screen update.

If you get a negative result for send "xyz" in tExact milliseconds it will be executed immediately but not in the past :)

Code: Select all

local sCueList, sIntervals

on mouseUp
   put "" into field 2 -- for debugging
   put "XXXXXXXX" & cr & "LEFT" & cr & "YYYYYY" & cr into sCueList
   put "50,16,800,0" into sIntervals
   send "runSequence 1" to me in 0 milliseconds
end mouseUp

on runSequence pRound
   if pRound > 4 then exit runSequence
   put the milliseconds into tTime
   put line pRound of sCueList into tCue
   put tCue into field 1
   put item pRound of sIntervals into tWhen
   put the milliseconds - tTime into tElapsed
   put  tWhen - tElapsed into tExact
   put tExact & cr after field 2 -- for debugging
   add 1 to pRound
   send "runSequence pRound" to me in tExact milliseconds
end runSequence
Kind regards
Bernd

PoLyGLoT
Posts: 105
Joined: Sat Jan 14, 2012 12:37 am

Re: Need very precise timings to show a stimulus

Post by PoLyGLoT » Wed May 04, 2016 12:23 pm

bn wrote:Hi PolyGLot,

it is tricky to time the display as exact as you want it. You have to take into account the times for screen update and computation.

Computation is usually not taking long but screen update can take some milliseconds.

you can test this by making a new stack with 1 card and 2 fields
In a button you put this script

Code: Select all

on mouseUp
   lock screen
   put the milliseconds into tTime
   put "yyyXXXYYyyyxx" into field 1
   unlock screen
   put the milliseconds - tTime into field 2
end mouseUp
when you unlock the screen the screen update will take place and then you have an idea how long it takes.

For your purpose I think the "send in time" approach is more suited than the "wait" approach. It frees Livecode because when sending in time LC can do its housekeeping which it can not with a blocking wait.

Without knowing how long your experiment will run I did a little sample script to show what I mean.
Here you can compensate for the screen update by calculating the remaining milliseconds. This is just an example, you would have to familiarize yourself with this sort of scripts. I.e. the use of script local variables that are declared outside of a handler, usually at the top of a script, in this case "local sCueList, sIntervals" and the timing. Also if your list of cues will be very long you would have to think about access time for lines and items. Usually with less than 50 lines/items this should not be a problem.

But if you want to get down to a precise 16.7 milliseconds display time it will be hard to do. If you can live with +- 1 millisecond it probably can be done.

Key is benchmarking the important factors like I showed for screen update.

If you get a negative result for send "xyz" in tExact milliseconds it will be executed immediately but not in the past :)

Code: Select all

local sCueList, sIntervals

on mouseUp
   put "" into field 2 -- for debugging
   put "XXXXXXXX" & cr & "LEFT" & cr & "YYYYYY" & cr into sCueList
   put "50,16,800,0" into sIntervals
   send "runSequence 1" to me in 0 milliseconds
end mouseUp

on runSequence pRound
   if pRound > 4 then exit runSequence
   put the milliseconds into tTime
   put line pRound of sCueList into tCue
   put tCue into field 1
   put item pRound of sIntervals into tWhen
   put the milliseconds - tTime into tElapsed
   put  tWhen - tElapsed into tExact
   put tExact & cr after field 2 -- for debugging
   add 1 to pRound
   send "runSequence pRound" to me in tExact milliseconds
end runSequence
Kind regards
Bernd
Hi Bernd,

Thanks for your input. I will not be able to test your code until later tonight, but I will definitely test it out!

Also, just so you know, +/- 1 millisecond is completely fine and within my range of acceptable behavior. As long as it remains subliminal, it's OK (e.g., 17 or 18 milliseconds should be fine).

I have 300 trials total for priming, then they do 2 other tasks following that prime trial. I have a text field with 300 lines and 3 columns in a separate card, and this info is imported into a global variable at the start of the program. Then my card that has my prime trials just reads from that global variable, determines which trial it is, and goes for it. Maybe it would be better to use different cards for the longer vs shorter prime trials? For instance, subliminal trials will get their own card, and supraliminal will get their own card. My thought is that those cards will then have less code to run through, which means less CPU time and processing, which might help.

Just thinking out loud here. Also, any idea why accceleratedRendering would help so much? And any other code like that?

Anyways, I will try your code later tonight, thank you very much!

bn
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 4172
Joined: Sun Jan 07, 2007 9:12 pm

Re: Need very precise timings to show a stimulus

Post by bn » Wed May 04, 2016 1:09 pm

Hi Polyglot,
I have a text field with 300 lines and 3 columns in a separate card, and this info is imported into a global variable at the start of the program
this might be a bit too much, depending how often you need to access that data for each round. It takes as a worst case about 4 milliseconds to access item 3 of line 300 of the global variable.

I made a little stack that compares access times for a list of 300 lines and 3 columns and an array of 300 keys with 3 columns each. The array is also kept as a global variable. I am using the long seconds to measure access time.

The point I am trying to make: test each step of your setup and know how much time it needs.

Look at "syncrate" in the dictionary to get more "display slots", but beware the dictionary got it wrong. Decreasing the syncrate increases the responsiveness and increases the processor load.

But first I would try to get this running without changing any secondary parameters like acceleratedRendering or syncrate.

Kind regards
Bernd
Attachments
testAccessTime.livecode.zip
(1.39 KiB) Downloaded 249 times

PoLyGLoT
Posts: 105
Joined: Sat Jan 14, 2012 12:37 am

Re: Need very precise timings to show a stimulus

Post by PoLyGLoT » Thu May 05, 2016 1:45 am

bn wrote:Hi Polyglot,
I have a text field with 300 lines and 3 columns in a separate card, and this info is imported into a global variable at the start of the program
this might be a bit too much, depending how often you need to access that data for each round. It takes as a worst case about 4 milliseconds to access item 3 of line 300 of the global variable.

I made a little stack that compares access times for a list of 300 lines and 3 columns and an array of 300 keys with 3 columns each. The array is also kept as a global variable. I am using the long seconds to measure access time.

The point I am trying to make: test each step of your setup and know how much time it needs.

Look at "syncrate" in the dictionary to get more "display slots", but beware the dictionary got it wrong. Decreasing the syncrate increases the responsiveness and increases the processor load.

But first I would try to get this running without changing any secondary parameters like acceleratedRendering or syncrate.

Kind regards
Bernd
Hi Bernd,

So I have been experimenting with things, and still stuck. I tested your access theory by eliminating the need for any access whatsoever -- I created 4 cards (2 subliminal, 2 supraliminal). Each card has 1 job --> either show a subliminal or supraliminal prime WITHOUT any conditionals. Just open the card and do it immediately. And guess what? Even eliminating any need for access issues still results in the problem: Sometimes, there is no "flicker" -- it just shows the final field (all X's without a LEFT or RIGHT flickering in there). So it definitely isn't an access problem - it's something more fundamental.

I have seen other cases of this happening by searching around (see here http://use-livecode.runrev.narkive.com/ ... on-the-mac). I have tinkered with syncrate and acceleratedRendering -- neither have totally resolved the issue (I still get it about 50% of the time).

Here is my current code:

Code: Select all

on opencard
   global sTime, matlist, data
   --set the syncrate to 1
   --set the acceleratedRendering of this stack to true
   put the ticks into sTime
   # initial X
   show fld "X" of cd "subLEFT"
   wait for 50 milliseconds
   hide fld "X" of cd "subLEFT"
   # prime part
   show fld "LEFT" of cd "subLEFT"
   wait for 16.7 milliseconds
   hide fld "LEFT" of cd "subLEFT"
   # final X
   show fld "X" of cd "subLEFT"
   wait for 800 milliseconds
   hide fld "X" of cd "subLEFT"
   set the itemDelimiter to tab
   # end 
   --put "no response needed" into item XYZ of line XYZ of data #which item
   --put (the ticks - sTime)/60  into item XYZ of line XYZ of data #which item
   --go to cd "button" #feedback instead?
end opencard
Fld "x" and fld "LEFT" are just basic fields with X's or the word LEFT in all caps. You can test it yourself and you will see that, if you test it 10 times, it will work only around half of the time (half the time you'll see a flicker and prime, the other half you will just see X's with no change).

Other ideas:
--change the properties of the fields?
-- wait with messages?
-- send "whatever" to me in 1 milliseconds
--unlock screen?
--refresh rate on my monitor is a limitation??

I'm at a loss. I have yet to find a language that can reliably accomplish what I want. Your help is appreciated!

PoLyGLoT
Posts: 105
Joined: Sat Jan 14, 2012 12:37 am

Re: Need very precise timings to show a stimulus

Post by PoLyGLoT » Thu May 05, 2016 4:38 am

I have perhaps found a solution. It is not elegant, but so far this is working 100% of the time!

Code: Select all

on opencard
   global sTime, matlist, data
 put the ticks into sTime
   # initial X
   show fld "X" of cd "subLEFT"
   wait for 50 milliseconds
   hide fld "X" of cd "subLEFT"
   # prime part
   wait until fld "X" of cd "subLEFT" is not visible
   if fld "X" of cd "subLEFT" is not visible then
      set the syncrate to 1
      set the acceleratedRendering of this stack to false
      set the acceleratedRendering of this stack to true
      show fld "LEFT" of cd "subLEFT"
      wait for 16.7 milliseconds with messages
      hide fld "LEFT" of cd "subLEFT"
   end if
   # final X
   wait until fld "LEFT" of cd "subLEFT" is not visible
   if fld "LEFT" of cd "subLEFT" is not visible then
      show fld "X" of cd "subLEFT"
      wait for 800 milliseconds
      hide fld "X" of cd "subLEFT"
   end if
My logic for why it works: By toggling the acceleratedRendering function to false/true, it updates how it is going to render the next "thing" it gets presented with. And since I do that right before my "prime" text, it gives the program just enough time to "slow down" and show the prime quickly.

I've tried it this way about 10 times or so and it "flickers" and gives the desired effect 100% of the time so far. Again, it's not elegant, but this might work for me.

Notice that I also added a few other little tidbits to cause the program to stop and think for just a few brief milliseconds before it goes to the next part of the code. Not sure that helps or not, but if it's working why mess with it I suppose!

bn
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 4172
Joined: Sun Jan 07, 2007 9:12 pm

Re: Need very precise timings to show a stimulus

Post by bn » Thu May 05, 2016 8:44 am

Hi PolyGlot,

I tried your solution and I see some screen changes/flickering. What operating system do you use and what version of LC?

The longer I think about your requirement of not seeing ANY flickering the less I think LC or many other programs can do it. There is a lot that comes into play with milliseconds-exact visual presentation. Much of it is due to how computers are redrawing the screen. Apparently they don't redraw at predetermined intervals.
What you are trying to achieve to present a visual effect for exactly 16.7 milliseconds duration means you would have to have a framerate of 60/sec. The only way to reliably achieve this is probably playing a real movie. I.e. one running from a wheel at 60 frames per second. Then you can be sure that your frame is actually shown and not dropped nor shown too long. If you are doing research you have to be pretty sure that you actually show the text.
Subliminal presentation in research has been done for a long time, how did they do this technically?

I attach a stack that is trying very basically to do what I posted as script above. Additionally I tried to sync to the system clock. This is an idea I got from a stack by Kevin Miller "Chrystal Ball". He syncs to animation to the system clock at a framerate of 25. Look at the card script -> handler "scheduleSwirl"

In my stack there is a button "testScreenUpdate" It is supposed to measure the time in milliseconds it takes for unlocking a screen = refreshing display. Try to block the wait for part.
In addition there are two buttons "runSequence" and "runSequenceAdapted". Please try those and tell me if you find the flickering acceptable or not. If this is too much flickering I am out of ideas how to present this.
Note that I put the text into one field, the field is set to dynamic layer mode, it is transparent to reduce contrast and the length of "XXXX" is about the same as "Left" to reduce flickering.

Kind regards
Bernd
Attachments
RunRev Crystal Ball.rev.zip
(23.78 KiB) Downloaded 249 times
subliminal Cueing Polyglot.livecode.zip
(1.71 KiB) Downloaded 250 times

bn
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 4172
Joined: Sun Jan 07, 2007 9:12 pm

Re: Need very precise timings to show a stimulus

Post by bn » Thu May 05, 2016 9:39 am

Hi PolyGlot,

I am using LC 8 almost exclusively now. But for this I tested stack "subliminal Cueing" using LC 6.7.10 and the flickering is much less noticeable compared to LC8 when using button "runSequence". This is on a MacBookPro mid 2010 using MacOSX 10.9.5.

Kind regards
Bernd

PoLyGLoT
Posts: 105
Joined: Sat Jan 14, 2012 12:37 am

Re: Need very precise timings to show a stimulus

Post by PoLyGLoT » Thu May 05, 2016 2:13 pm

Hi Bernd,

Thanks for your code. I took a quick look at it, and it seems promising. I will need a little more time to understand it fully, but just the idea of waiting on the screen to refresh is a good one.

Your code did inspire me to quickly calculate my timings (i.e., how long my prime was actually being presented). Turns out my trick of toggling the rendering to false/true eats up around 10 millisecs, which was being added to my prime duration. So I shifted my code around and calculated my timings and got everything to take as long as it should and still use the toggling trick.

Code: Select all

 put the millisecs into sTime
   # initial X
   show fld "X" of cd "subLEFT"
   wait for 38 millisecs
   set the syncrate to 1
   set the acceleratedRendering of this stack to false
   set the acceleratedRendering of this stack to true
   hide fld "X" of cd "subLEFT"
   put the millisecs- sTime into fld "Field1"
   # prime part
   put the millisecs into tTime
   show fld "LEFT"
   wait for 15 millisecs
   hide fld "LEFT"
   put the millisecs - tTime into fld "Field"
This code consistently gave me around 16 millisecs for the prime duration and right around 50 for the X's. The problem is that perhaps that will be dependent on processor speed, which means I would need to calibrate new numbers for use on a different CPU.

Btw, I'm using livecode 7.1.1 community edition. Maybe a newer version would be better? Also, I know that "e-prime" software is apparently good for priming experiments, but it cost $995! I'd prefer to find a free solution if possible (and also, I'm a fan of livecode anyways).

At any rate, your code might hold the solution, and I will explore it more fully tonight. Thank you for all your help thus far.

Post Reply