Monday, 12 April 2021

Inaccurate timings when timer is set in separate function

I am having an issue getting my timers to work reliably. I essentially have a loop that is set to call functions as close to the scheduled time as possible. The timings are accurate enough except for the very first tick. For some reason, when setting last_time (I've also tried time.time(), time.process_time()) outside the fixed update, (in this example the start_counting method), it is not accurate.

When running the code below you will get something like this:

---start---
Time since last 1.5854037 Time accrued by step: 1.6
Time since last 1.5996268 Time accrued by step: 1.6
---start---
Time since last 1.5247734999999998 Time accrued by step: 1.6
Time since last 1.5997646000000003 Time accrued by step: 1.6
Time since last 1.5997717000000007 Time accrued by step: 1.6
Time since last 1.5998178999999997 Time accrued by step: 1.6
Time since last 1.5997903000000004 Time accrued by step: 1.6

As you can see the very first iteration from when I start the counter, to the first tick, the timing is way off. However, every tick after that is as accurate as I expected 1.599~, while the initial can be anywhere from 1.52 to 1.58 What exactly am I missing here? The timing should be the same since the steps are the same from start to step reset. I feel like I'm missing something, but for the life of me I can't figure it out.

Here is my code, runnable as Python 3.7. Tested with 3.6 as well..

import time
from collections import deque

class FixedStepLoop:
    def __init__(self, update_func, step, max_step):
        self.update_func = update_func
        self.step = step
        self.max_step = max_step
        self.accumulator = 0.0
        self.next_ts = time.perf_counter()
        self.last_ts = None
        self.cumulative_time = 0
        self.times = deque()
        
    def update_time(self):
        ts = time.perf_counter()
        if self.last_ts is None:
            delta_t = 0
        else:
            delta_t = ts - self.last_ts
            self.times.appendleft(delta_t)
            if len(self.times) > 10:
                self.cumulative_time -= self.times.pop()
        self.cumulative_time += delta_t
        self.last_ts = ts
        return delta_t
        
    def tick(self):
        dt = self.update_time()
        
        if dt > self.max_step:
            dt = self.max_step

        self.accumulator += dt

        while self.accumulator >= self.step:
            self.update_func(self.step)
            self.accumulator -= self.step

tick_count = 16

class FixedCounter:
    def __init__(self):
        self.steps = None
        self.last_time = time.perf_counter()
        self.counting = False
        self.loop = FixedStepLoop(self.fixed_update, 1/10, 0.2)
        
    def start_counting(self):
        print("---start---")
        self.steps = 0
        self.last_time = time.perf_counter()
        
    def fixed_update(self, dt):
        if self.steps is not None:
            self.steps += 1
            
            if self.steps == tick_count:
                print("Time since last", time.perf_counter() - self.last_time, "Time accrued by step:", self.steps * 0.1)
                self.last_time = time.perf_counter()
                self.steps = 0
    
fixed_counter = FixedCounter()

i = 0
while True:
    fixed_counter.loop.tick()

    i += 1
    
    if i == 8000:
        fixed_counter.start_counting()
        
    if i == 2000000:
        fixed_counter.start_counting()

Any help is greatly appreciated.



from Inaccurate timings when timer is set in separate function

No comments:

Post a Comment