a wx.Timer like timer without wx package?

We need to insert a bit of a reality check here. Windows provides NO interfaces to a hardware real-time clock. ALL of Windows timing is based off of the periodic firing of the on-board countdown timer -- the tick counter. This timer is notoriously inaccurate, and on many perfectly normal systems is off by as much as 5 seconds per day. For you to expect sub-second accuracy over the period of a day, much less over several months, is simply unrealistic.

If you need a counter to fire roughly every 10 seconds, then the solutions presented are more than adequate. If you have a life-or-death situation that requires exactly 10 seconds, day and night, week after week, then you MUST use an external time base hardware, or an interface to an NTP server. Such things are available, but they will use a custom interface.

I'm curious to know exactly what your application is. I can't imagine a use case requiring multiple months of continuous uptime in which these accumulated errors would be important.

···

On Wed, 10 Nov 2004 12:54:33 +0800, Qiangning Hong <hongqn@gmail.com> wrote:

2. There is still some extra time for calculating (t - time()), although it is very short, but if the timer runs for months, it could become unacceptable.

A good timer, I think, just as wx.Timer, should only calculate the clock ticks of system and independ on the actual system time. And it should hook itself with the hardware clock interface which OS provide. I am just curious about why all this kind of timer are bind to a GUI framework like Windows, GTK, wx, etc.?

--
- Tim Roberts, timr@probo.com
  Providenza & Boekelheide, Inc.

No, my application doesn't require the counter to fire ROUGHLY EVERY 10 seconds, and not care about the real-time clock. It just want a counter to fire according to the system ticks, and will not drift away over months, that is, when the OS runs for 60 days, the counter should has fired for 60*24*360 times.

Well, let me make things more clear. I am implementing a long-run sample-and-record system. It collects data from a PCI card every 10 seconds, saves the data (timestamped with the current system time) in the hard disk, and shows them on the screen. There is also a GPS receiver module exists on the system, which correct the system time (and the hardware time) when it drifts away too much.

The system requires the average sample rate is 6 times per minute to analysis. If the OS clock runs too fast or too slow, we can get the infomation by the GPS module's log file, and then correct the analysised result with that infomation.

So, wo need the counter to meet these requirements:

1. fires 6 times per minute, or to say, fires 60*24*360 times per 60 days.
2. will not be affected by the change of system time, foreward or backward.
3. no need for external hardware device, of cource.

In John Hoffman's solution, the sleep(t-time()) statement will be parsed as following. We can see the extra time cost for calculating (t-time()) will cause the fire interval slightly more than 10 seconds every time.

t = time() -> 1:00.000, t=1:00.000
while True:
  do_something() -> 1:00.010
  t += 10 -> 1:02.010, t=1:10.000
  now = time() -> 1:02.020, now=1:02.020
  interval = t - now -> 1:02.030, interval=7.980
  sleep(interval) -> 1:02.040, sleep for 7.980 seconds
# the second loop:
  do_something() -> 1:10.020

Tim Roberts wrote:

···

On Wed, 10 Nov 2004 12:54:33 +0800, Qiangning Hong <hongqn@gmail.com> > wrote:

2. There is still some extra time for calculating (t - time()), although it is very short, but if the timer runs for months, it could become unacceptable.

A good timer, I think, just as wx.Timer, should only calculate the clock ticks of system and independ on the actual system time. And it should hook itself with the hardware clock interface which OS provide. I am just curious about why all this kind of timer are bind to a GUI framework like Windows, GTK, wx, etc.?

We need to insert a bit of a reality check here. Windows provides NO interfaces to a hardware real-time clock. ALL of Windows timing is based off of the periodic firing of the on-board countdown timer -- the tick counter. This timer is notoriously inaccurate, and on many perfectly normal systems is off by as much as 5 seconds per day. For you to expect sub-second accuracy over the period of a day, much less over several months, is simply unrealistic.

If you need a counter to fire roughly every 10 seconds, then the solutions presented are more than adequate. If you have a life-or-death situation that requires exactly 10 seconds, day and night, week after week, then you MUST use an external time base hardware, or an interface to an NTP server. Such things are available, but they will use a custom interface.

I'm curious to know exactly what your application is. I can't imagine a use case requiring multiple months of continuous uptime in which these accumulated errors would be important.

In John Hoffman's solution, the sleep(t-time()) statement will be parsed as following. We can see the extra time cost for calculating (t-time()) will cause the fire interval slightly more than 10 seconds every time.

t = time() -> 1:00.000, t=1:00.000
while True:
    do_something() -> 1:00.010
    t += 10 -> 1:02.010, t=1:10.000
    now = time() -> 1:02.020, now=1:02.020
    interval = t - now -> 1:02.030, interval=7.980
    sleep(interval) -> 1:02.040, sleep for 7.980 seconds
# the second loop:
    do_something() -> 1:10.020

I suggest you run that loop through a few times. The first interval may be slightly longer than 10 seconds, but succeeding intervals will be fairly precisely on 10 seconds, and it shouldn't drift so long as the system clock doesn't drift.

John Hoffman wrote:

I suggest you run that loop through a few times. The first interval may be slightly longer than 10 seconds, but succeeding intervals will be fairly precisely on 10 seconds, and it shouldn't drift so long as the system clock doesn't drift.

Sorry for my fault. Your code will indeed call do_something() every 10 seconds if system time isn't changed. So it meet my first requirement. Sorry.

But for the second requirement, I haven't got any solution to make the counter not affected by the system change. Could anyone give me a hint?

Qiangning Hong wrote:

John Hoffman wrote:

I suggest you run that loop through a few times. The first interval may be slightly longer than 10 seconds, but succeeding intervals will be fairly precisely on 10 seconds, and it shouldn't drift so long as the system clock doesn't drift.

Sorry for my fault. Your code will indeed call do_something() every 10 seconds if system time isn't changed. So it meet my first requirement. Sorry.

But for the second requirement, I haven't got any solution to make the counter not affected by the system change. Could anyone give me a hint?

What about this?

t = time()
while True:
     do_something()
     t += 10
     now = time()
     interval = t - now
     # If the time skews enough that we are outside of are 10 second
     # interval, switch back to a 10 second pulse
     if interval < 0 or interval > 10:
        interval = 10
         t = now + interval
     sleep(interval)

It doesn't guarantee exactly 60*24*360 per 60 days, but it does keep things to a small blip before resetting itself. The only real problem is if do_something() takes longer than 10s, then it starts acting weird.

The only other way that I can think of would mean that you have to have a way of telling this loop that you are changing the time, and by how much. One possibility is something like:

def mythread(t): #t needs to be a list
   t[0] = time()
   while True:
     do_something()
     t[0] += 10
     now = time()
     interval = t[0] - now

     sleep(interval)

By making t a list, and only modifying items inside it, you can pass information between your threads. So then from the other thread you could add/subtract from the t[0] to adjust for the clock changing.

John
=:->

Hi Qiangning

I do a very similar system using win32 waitable timers in wx in C++.
But if you're wanting to do it using standard python modules, I suggest use ask on comp.lang.python, I'm sure you'll get a good response there...

David

Qiangning Hong wrote:

···

No, my application doesn't require the counter to fire ROUGHLY EVERY 10 seconds, and not care about the real-time clock. It just want a counter to fire according to the system ticks, and will not drift away over months, that is, when the OS runs for 60 days, the counter should has fired for 60*24*360 times.

Well, let me make things more clear. I am implementing a long-run sample-and-record system. It collects data from a PCI card every 10 seconds, saves the data (timestamped with the current system time) in the hard disk, and shows them on the screen. There is also a GPS receiver module exists on the system, which correct the system time (and the hardware time) when it drifts away too much.

The system requires the average sample rate is 6 times per minute to analysis. If the OS clock runs too fast or too slow, we can get the infomation by the GPS module's log file, and then correct the analysised result with that infomation.

So, wo need the counter to meet these requirements:

1. fires 6 times per minute, or to say, fires 60*24*360 times per 60 days.
2. will not be affected by the change of system time, foreward or backward.
3. no need for external hardware device, of cource.

In John Hoffman's solution, the sleep(t-time()) statement will be parsed as following. We can see the extra time cost for calculating (t-time()) will cause the fire interval slightly more than 10 seconds every time.

t = time() -> 1:00.000, t=1:00.000
while True:
    do_something() -> 1:00.010
    t += 10 -> 1:02.010, t=1:10.000
    now = time() -> 1:02.020, now=1:02.020
    interval = t - now -> 1:02.030, interval=7.980
    sleep(interval) -> 1:02.040, sleep for 7.980 seconds
# the second loop:
    do_something() -> 1:10.020

Tim Roberts wrote:

On Wed, 10 Nov 2004 12:54:33 +0800, Qiangning Hong <hongqn@gmail.com> >> wrote:

2. There is still some extra time for calculating (t - time()), although it is very short, but if the timer runs for months, it could become unacceptable.

A good timer, I think, just as wx.Timer, should only calculate the clock ticks of system and independ on the actual system time. And it should hook itself with the hardware clock interface which OS provide. I am just curious about why all this kind of timer are bind to a GUI framework like Windows, GTK, wx, etc.?

We need to insert a bit of a reality check here. Windows provides NO interfaces to a hardware real-time clock. ALL of Windows timing is based off of the periodic firing of the on-board countdown timer -- the tick counter. This timer is notoriously inaccurate, and on many perfectly normal systems is off by as much as 5 seconds per day. For you to expect sub-second accuracy over the period of a day, much less over several months, is simply unrealistic.

If you need a counter to fire roughly every 10 seconds, then the solutions presented are more than adequate. If you have a life-or-death situation that requires exactly 10 seconds, day and night, week after week, then you MUST use an external time base hardware, or an interface to an NTP server. Such things are available, but they will use a custom interface.

I'm curious to know exactly what your application is. I can't imagine a use case requiring multiple months of continuous uptime in which these accumulated errors would be important.

---------------------------------------------------------------------
To unsubscribe, e-mail: wxPython-users-unsubscribe@lists.wxwidgets.org
For additional commands, e-mail: wxPython-users-help@lists.wxwidgets.org

Qiangning Hong wrote:

So, wo need the counter to meet these requirements:

1. fires 6 times per minute, or to say, fires 60*24*360 times per 60 days.

So I take it the total count, after a while is more important than an exactly 10 sec interval. This is good, it will make it easier.

2. will not be affected by the change of system time, foreward or backward.

This is the really hard one! All kinds of things on a system can get screwed up by changing the system time. That's why systems that automatically keep the system time in sync with a time server only change the system time it a little at a time. If you can make sure that whoever runs the system doesn't go making big jumps in system time, you could be fine.

3. no need for external hardware device, of cource.

Fair enough. How about a network connection? Could you talk to a time server? I think you could count on a time server not to drift or have a big jump in the time. You may be able to talk to one with Python with:

http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/117211

In that case, or even with a system clock that doesn't get changed more than say 5 seconds at a time, you could take an approach of always checking the current time against a reference time, such as when the program starts. That way the interval you use isn't very important.

Like maybe this, which I'm sure could be made more robust:
#!/usr/bin/env python2.3

import wxversion
wxversion.select("2.5.3")

import wx
import wx.stc as stc
import time

class DemoFrame(wx.Frame):
     """ This window displays a button """
     def __init__(self, title = "Timer Demo"):
         wx.Frame.__init__(self, None , -1, title, size = (500,400))

         self.TextCtrl = stc.StyledTextCtrl(self, wx.NewId())

         self.StartTime = time.time()
         self.Counter = 0
         self.Interval = 5 # interval in seconds
         # now set up the timer:
         self.Timer = wx.Timer(self)
         self.Bind(wx.EVT_TIMER, self.OnTimer)
         self.Timer.Start(500)

     def OnTimer(self,Event):
         CurTime = time.time() # (you might want to use time.clock on Windows)
         NumIntervals = int( (CurTime - self.StartTime) / self.Interval )
         if NumIntervals >= self.Counter:
             TimeString = time.strftime("%c", time.localtime(CurTime))
             self.TextCtrl.AddText("Time: %s: Interval number: %i\n"%(TimeString,NumIntervals))
             self.Counter+= 1

     def OnQuit(self,Event):
         self.Destroy()

app = wx.PySimpleApp(0)
frame = DemoFrame()
frame.Show()
app.MainLoop()

···

--
Christopher Barker, Ph.D.
Oceanographer
                                         
NOAA/OR&R/HAZMAT (206) 526-6959 voice
7600 Sand Point Way NE (206) 526-6329 fax
Seattle, WA 98115 (206) 526-6317 main reception

Chris.Barker@noaa.gov