I think this is a case where the script is doing exactly what you tell it to, but you’re perhaps just not sure what that is. With example values you’ve provided (Poly_Velocity = -196.3515
and Img_StartPosX = 640
), we can tabulate the x position of your stimulus, counting from the zeroth (i.e. first) frame onwards:
frame t x round(x) diff
0 0.0000 640.0000 640
1 0.0167 636.7275 637 -3
2 0.0333 633.4550 633 -4
3 0.0500 630.1824 630 -3
4 0.0667 626.9099 627 -3
…
86 1.4333 358.5629 359 -3
87 1.4500 355.2903 355 -4
88 1.4667 352.0178 352 -3
89 1.4833 348.7453 349 -3
90 1.5000 345.4728 345 -4
91 1.5167 342.2002 342 -3
This is assuming a monitor with a refresh rate of 60 Hz, and hence 0.0167 seconds between successive stimulus updates.
Notice what happens when x
gets into the range you are interested in (pixel values of 349, 351, 353).
- The stimulus is actually jumping by 3.275 pixels between each screen refresh, so concerning yourself with pixel target values that are separated by only 2 pixels is not practical, as that is less than the smallest jump the stimulus makes on its successive appearances.
- Pixels in the real world are discrete physical objects and can be counted (i.e. they should be addressed by integer values). Now I don’t know what PsychoPy does when you provide a non-integer value to a stimulus location. A reasonable guess is that it effectively gets rounded so that the stimulus appears at the closest discrete pixel to the continuous value you provided. e.g. the x value of
348.7453
above (on frame 89) would appear at pixel349
, but the stimulus will never appear at either pixel 351 or 353, because none of your generated values round to one of those integer values.
Now I really don’t know what your task is about and what the goal is, but perhaps you need to take a step back and think about the level of precision involved and exactly what you are trying to achieve. You are currently doing the right thing in your comparisons by using <=
or >=
instead of ==
, because you can’t reliably compare floating point values for equality (that only works for integers, which computers can store exactly).
Effectively your task (at 60 Hz at least) is stepping the target by either 3 or 4 pixels per cycle (to produce an average step value of 3.2725 pixels per frame). Any calculations you do have to reflect that level of granularity in the animation. If you want more precision, run a faster monitor (e.g. gaming LCDs these days routinely run at 144 Hz) and/or one with much higher pixel resolution (say 4K). The combination of high refresh rate and high pixel density implies the need for a pretty good graphics card to handle the load. Otherwise if that level of precision is not actually required, just continue as you are but incorporate the actual level of granularity in your code’s logic.
You can certainly do that - but you just need to be aware of the level of precision in your animation and the actual pixel values involved. At the simplest level, you can just round()
the output of your pixel calculation to have no decimal places, forcing it to be an integer:
round((t * Poly_Velocity) + Img_StartPosX))
and as above, perhaps tabulate the output of your function in a spreadsheet beforehand so you know which actual pixel locations it will land on, so that you don’t test against a pixel location that it actually skips over.