1

i want my program to do a task every x frames. However it does not seem to work, due to the fact that the timer in python seems to be inaccurate. How do i get this piece of code to obey my set framerate?

import time
fps = 5
skipticks = 1/(fps*1.0)
i= 0
nextsnap=time.clock()
print skipticks, fps
while (True):
    tim= time.clock()
    i=i+1
    # this prints the fps
    #'print 'Fps at start',i, 1/(time.time()-tim)
    # this is the sleep that limits the fps
    nextsnap+=skipticks
    sleeptime = nextsnap-time.clock()
    if (sleeptime>0):
        time.sleep (sleeptime)
    else:
        print 'took too long'
    print 'Fps at end:#', i, 1/(time.clock()-tim)

this produces on my computer:

 Fps at end:# 45 4.36627853079
Fps at end:# 46 6.44119324776
Fps at end:# 47 4.53966049676
Fps at end:# 48 4.66471670624
Fps at end:# 49 7.18312473536
Fps at end:# 50 4.34786490268
Fps at end:# 51 6.5263951487
Fps at end:# 52 4.71715853908
Fps at end:# 53 4.59636712435
Fps at end:# 54 6.87201830723
Fps at end:# 55 4.31062740848

Why are there frames that are rendered too fast? And why is the fps count inaccurate?

David Segonds
  • 83,345
  • 10
  • 45
  • 66
tarrasch
  • 2,630
  • 8
  • 37
  • 61
  • 3
    You are assuming that your logic runs instantly, which it doesn't. – Blender Dec 05 '11 at 17:05
  • 1
    what is the clock if you display it on every frame? you might have to measure your frame rate over time then adjust the frame skip, rather than access the clock on every frame. – Joseph Le Brech Dec 05 '11 at 17:20
  • this will be a screengrabber that i am trying to implement. There will be a ImageGrab.grab() within the loop. Since i take screenshots, it is important that the framerate runs steady, else the video will not run smooth – tarrasch Dec 06 '11 at 07:46

2 Answers2

4

If it's about mesuring the accuracy you can have with time.clock() and time.sleep(), use something as simple as possible like:

import time

fps = 5
time_delta = 1./fps

while True:
    t0 = time.clock()
    time.sleep(time_delta)
    t1 = time.clock()
    print 1. / (t1 - t0)

What is your OS and what is the result of this simple mesure ?

If it's about cleaning your code, I would separate more clearly the FPS evaluation, the processing and the sleep call. Here is an example (the loop #0 frequency displayed should be ignored).

import time
import random
from itertools import count

fps = 5
loop_delta = 1./fps

current_time = target_time = time.clock()
for i in count():
    #### loop frequency evaluation
    previous_time, current_time = current_time, time.clock()
    time_delta = current_time - previous_time
    print 'loop #%d frequency: %s' % (i, 1. / time_delta)

    #### processing
    # processing example that sleeps a random time between 0 and loop_delta/2.
    time.sleep(random.uniform(0, loop_delta / 2.))

    #### sleep management
    target_time += loop_delta
    sleep_time = target_time - time.clock()
    if sleep_time > 0:
        time.sleep(sleep_time)
    else:
        print 'took too long'

Also, you probably want time.time() rather than time.clock(). See time.clock() vs. time.time() - accuracy answer.

Community
  • 1
  • 1
kasyc
  • 293
  • 1
  • 9
0

The python documentation explains why time.sleep is not very accurate.

What os are you using?

If you are using linux, you can use powernap, which uses Linux's real-time clock (RTC) for more accurate timing.

Gary van der Merwe
  • 9,134
  • 3
  • 49
  • 80