1 README.timekeeping: Keeping time in KStars
2 copyright 2002 by Jason Harris and the KStars team.
3 This document is licensed under the terms of the GNU Free Documentation License
4 -------------------------------------------------------------------------------
9 Timekeeping is handled by the SimClock class. SimClock stores the
10 simulation time as the Julian Day, in a long double variable
11 ("julian"). A long double is required to provide sub-second resolution
12 in the Julian Day value. The date can be converted to a calendar date
13 (QDateTime object) with the UTC() function. julian is updated every
14 0.1 sec by an internal QTimer, using the SimClock::tick() SLOT,
15 connected to the internal QTimer's timeout() SIGNAL.
17 We make a distinction between "system time" and "simulation time".
18 System time is real time, according to the computer's CPU clock.
19 Simulation time is the time according to KStars; since the time and
20 date are adjustable, system time and simulation time can have an
21 arbitrary offset. Furthermore, SimClock has an adjustable Scale
22 parameter that determines how many seconds of simulation time pass for
23 each second of system time. Scale can even be negative, indicating
24 that the simulation clock is running backwards.
26 The simplest way to advance the simulation time would be to add
27 (0.1*Scale) seconds to julian every time tick() is called. However,
28 this is not accurate, because there is always some error associated
29 with the time it takes to execute tick(), and these errors would
30 accumulate during each cycle. Instead, tick() measures the elapsed
31 time since some fixed system-time marker ("sysmark"), and adds
32 (elapsed_time*Scale) seconds to "julianmark", a fixed simulation-time
33 marker that was the exact simulation time at the moment the system-time
34 marker was set. This is much more accurate, because any errors in
35 tick() do not accumulate. Any time the clock is started, or its
36 scale changed, the sysmark and julianmark markers are reset (they are
37 also reset if they have not changed in more than 24 hours of real time).
39 tick() emits the timeAdvanced() signal, which is connected to
40 KStarsData::updateTime(), which takes care of updating object
41 coordinates and drawing the skymap (see below for details).
43 Note also that the SimClock class only handles the Julian Day and the
44 Universal Time, not the local time. Time zone corrections and daylight
45 savings time are handled by KStarsData::updateTime().
50 The above procedure works well, as long as tick() takes less than 0.1 sec,
51 on average (including the time taken by KStarsData::updateTime()). In
52 practice, large values of Scale cause more calls to updateTime() than the
53 CPU is able to handle. This results in some time steps being skipped
54 altogether, which makes the simulation seem jerky.
56 To compensate for this, we implemented a "Manual Mode" for SimClock. In
57 Manual mode, the internal QTimer is stopped, so that tick() is not
58 triggered every 0.1 seconds. Instead, a similar function (manualTick())
59 is called whenever KStarsData::updateTime() has finished. manualTick()
60 adds Scale seconds to the simulation time. So, the Scale parameter has
61 a slightly different meaning in Manual mode. The simulation time
62 no longer runs at strictly Scale seconds per real-time second; rather,
63 every update of the simulation occurs exactly Scale simulation-seconds
64 after the previous update, no matter how long the update takes.
66 There are two bool variables in SimClock, ManualMode and ManualActive.
67 The first controls whether the clock is using Manual Mode (accessed by
68 isManualMode()); the second controls whether the clock is running in
69 Manual Mode (recall that the internal timer is halted when in Manual
70 Mode). The function isActive() returns whether the clock is running,
71 for both the standard mode and Manual Mode.
74 3. KStarsData::updateTime()
76 updateTime() is a SLOT connected to the SimClock's timeAdvanced()
77 SIGNAL, which is emitted every tick() or manualTick().
79 KStarsData keeps its own representation of the universal time as a
80 QDateTime object (UTime); the first thing that updateTime() does is to
81 reset this with clock->UTC(). It then sets the local time QDateTime
82 object (LTime) by adding 3600*geo->TZ() seconds to UTime. It then
83 checks if it has reached the next daylight savings time change point,
84 and adjusts the Time Zone offset, if necessary.
86 There is a group of time-dependent numbers such as the obliquity and
87 the sun's mean anomaly; these are kept in the KSNumbers class. The next
88 thing updateTime() does is create a KSNumbers object appropriate for the
89 current julian day value [we may be able to save some time by keeping a
90 persistent KSNumbers object, and not updating it on every call to
91 updateTime(), as the values stored there don't change very quickly].
93 There are several things that don't need to be updated on every call to
94 updateTime(). To save time, we only update them if a certain amount of
95 time has passed since the last update. For example, the LastNumUpdate
96 variable stores the julian day of the last time object coordinates were
97 updated for precession/nutation/aberration. This needs to happen once
98 per simulation day, so whenever (CurrentDate-LastNumUpdate) exceeds 1.0,
99 it signals the update (by setting needNewCoords=true) and resets
100 LastNumUpdate to CurrentDate. Similarly, we use LastPlanetUpdate to
101 update planet coordinates 100 times per day. LastSkyUpdate monitors
102 the last time the horizontal coordinates were updated (the update
103 interval is dependent on the current zoom setting).
105 Next, we update the focus position. If no object is being tracked, and
106 useAltAz=true, then the focus RA needs to advance at the sidereal rate
107 (one second on the sky per sidereal second of time). If the simulation
108 is tracking an object, then the focus is set to the object's coordinates.
109 (See README.skymap for details on the focus position and animated
112 Finally, the last thing updateTime() does is to re-draw the sky by calling
113 SkyMap::update(); see README.skymap for details.