Encoder block: how to start timer at intervals, compensating for early /

I have a silly but serious case of an encoder block. Please help me work through this so that my brain stops hurting and refuses to answer my questions.

I want to start a timer with an interval until the last time. For example, if t = 0, my target is 100 and my interval is 20, I want to shoot at 0, 20, 40, 60, 80 and 100.

The timer is not accurate and may go off sooner or later. If he first shot at 22, I want to shoot again at 18. If he first shot at 19, I want to shoot at 21. All I know when the timer goes off is the current time, target time, and shooting interval. What should I do?

Edit: Sorry, I was not too specific about what I am actually asking. I'm trying to figure out what math (possibly related to using a module for something) needs to be done to calculate the delay until the next firing. Ideally, I also want the timer to match the end time - so if I start the timer initially at 47, it schedules the fire itself at 60, not 67, so the last firing will still be at 100.

+2


source to share


4 answers


If your language / platform, the underlying timers don't do what you want, then it is usually best to use timers in terms of "target times", which means the absolute time at which you want the timer to start next. If your platform asks for "absolute time", you give it a target time. If it asks for "relative time" (or, like sleep

, duration), then it is, of course target_time - current_time

.

A quick way to count each target time in turn:

  • When you set up the timer first, you compute the "interval" (which should probably be a floating point value, assuming it won't crash) as well as the "target time" of the first timer (again, you may need fractions) ... Write both down and set your basic timer mechanism, whatever it is.
  • When the timer fires, work out the next target time by adding the interval to the previous target time.

The problem with this approach is that you can get very small cumulative errors as you add the interval to the target time (or not so tiny if you didn't float).

So the longer and more accurate way is to store the very first start time, target end time, and number of arrows (n). You then recalculate the target time for each new shot in turn, ensuring you don't get cumulative rounding errors. The formula for this:



target(k) = start + ((target_end - start) * k) / n

      

If you prefer:

target(k) = (k/n) * end + (1-k/n) * start

      

If the timer firing is k = 1, 2, 3, ... n. I was going to do it based on 0 and then realized it was silly ;-)

The last thing you have to struggle with when implementing timers is the difference between the wall clock time and the real elapsed time measured by your hardware clock. The wall time can suddenly move forward or backward (either by an hour if your wall clock is affected by daylight saving time, or by any amount if the system clock is adjusted or corrected). Realtime is always increasing (until it wraps around). What you want your timer to respect depends on the intended purpose. If you want to know when the last bus leaves, you want the timer to fire daily according to the wall clock time, but more often than not, you care about the elapsed time in real time. A good timer API has options for this kind of thing.

+1


source


If the primitive functionality you have is "schedule X to fire once at time T", then your X procedure processing should know the time T0 at which it should have fired (the time T1 at which it actually started , not required), as well as the desired interval DT and the schedule for the time T0 + DT. If the primitive is "fire D from now on", then it should schedule D = T0 + DT-T1 (if this is negative, then it needs to schedule itself immediately, but write down that the scheduled time and "should have fired", the time is different, so he can continue to compensate for the next shooting).



Someone already mentioned that .NET Timer does this for you; also Python sched

stdlib module; so i'm doing a lot of other languages ​​/ frameworks / libraries. But in the end, you can build it, if necessary, on top of one of the one-off primitives above (one for absolute time, or one for relative delta from now on) while you keep track of both the desired and actual firing times! _)

+4


source


I would use the system clock to check your interval. For example, if you know your interval is every 20 minutes, fire the first interval, check what time it was, and adjust the start time of the next interval.

+3


source


Create a table showing the desired acceleration times, for example, 10:00, 10:20, 10:40, 11:00 and 11:20.

If the timer function takes absolute time, the rest is trivial. Set the fire at every required time. If for some reason you can only set one timer at a time, well, set it the first time. When this event occurs, set it again the next time in the table, no matter what time it is now. Every time through, pick up next time until you finish.

If the timer function only takes an interval, it doesn't really matter. Find the difference between the desired time and the current time and set the fire for this in this interval. For example, if the first time is 10:00, and now it is 9:23, set it at 10:00 minus 9:23 equal to 37 minutes. Then, when this happens, set the interval to the next desired time minus the current time. If he actually fired at 10:02, then the interval 10:20 minus 10:02 equals 18 minutes. Etc.

You should probably check the possibility that the next fire time has already passed. If the process may take longer than it can go through, and even if not, the system may be shut down. If there is no downtime, you may need to do catch-up runs or just skip it and move on to the next desired time depending on the details of your application.

If you can't save the entire table - as it goes on forever - then just save the next fire time. Each time in the process, add a fixed amount at the next fire time, regardless of when the current process started. Then calculate the interval based on the current time. For example, if you have a desired interval of 20 minutes lasting forever from 10:00 AM and now 9:23 AM, you would set the first interval to 37 minutes. Let's say it happens at 9:59 am. You set the next fire time to 10:00, plus 20 minutes, equal to 10:20, i.e. Base it on the target time, not the actual time. Then calculate the interval to the next fire time based on the current time, that is 10:20 minus 9:59 is 21 minutes. Etc.

0


source







All Articles