Unstable NSTimer causes fluctuations in counting - objective-c

I use NSTimer to count from a certain moment.
int totalSeconds;
int totalMinutes;
int totalHours;
If the totalSeconds are 60, totalMinuts become +1. Its very simple and should work.
For example i started the NSTimer together with the clock of my mac. (running on simulator).
When i look at the clock of my mac and the timer and compare the time the first 10-20 seconds its counting perfectly synchronous. After that it fluctuates or goes ahead 5 seconds or more.
So i output my timer and found this:
2012-10-24 14:45:44.002 xxApp driveTime: 0:0:44
2012-10-24 14:45:45.002 xxApp driveTime: 0:0:45
2012-10-24 14:45:45.813 xxApp driveTime: 0:0:46
2012-10-24 14:45:46.002 xxApp driveTime: 0:0:47
The milliseconds are timed at 002 as you see. But at the third row its 813. This happens very randomly and causes the fluctuations.
Is there a more stable way to count?

From the NSTimer documentation
A timer is not a real-time mechanism; it fires only when one of the run loop modes to which the timer has been added is running and able to check if the timer’s firing time has passed. Because of the various input sources a typical run loop manages, the effective resolution of the time interval for a timer is limited to on the order of 50-100 milliseconds.
If your goal is to compute the total time that has passed since your program has started running, this is quite easy. As soon as you want to begin keeping track of time, store -[NSDate date] into a variable. Whenever you want to compute how much time has passed, call -[NSDate date again and do the following, assuming originalDate is a property where you stored the result of the first call to -[NSDate date]:
NSDate *presentDate = [NSDate date];
NSTimeInterval runningTime = [presentDate timeIntervalSinceDate:originalDate];
runningTime will be the total number of seconds that have elapsed since you started keeping track of time. In order to get the number of hours, minutes, seconds, and so on, an NSDateComponents object should be used.
This mechanism will allow you to use a timer to update your total running time "just about once a second" without losing accuracy.

Related

Create a variable to count from 1 to n in AnyLogic

I am looking to add a variable to count from 1 to 217 every hour in AnyLogic, in order to use as a choice condition to set a parameters row reference.
I am assuming I either need to use an event or a state chart however I am really struggling with the exact and cannot find anything online.
If you have any tips please let me know, any help would be appreciated
Thank you,
Tash
A state machine isn't necessary in this case as this can be achieve using a calculation or a timed event. AnyLogic has time() function which returns time since model start as a double in model time units of measurements.
For example: if model time units is seconds and it has been running for 2hr 2min 10sec then time(SECOND) will return 7330.0 (it is always a double value). 1/217th of an hour corresponds to about 3600/217 = 16.58 seconds. Also, java has a handy function Math.floor() which rounds down a double value, so Math.floor(8.37) = 8.0.
Assembling it all together:
// how many full hours have elapsed from the start of the model
double fullHrsFromStart = Math.floor(time(HOUR));
// how many seconds have elapsed in the current model hour
double secondsInCurrentHour = time(SECOND) - fullHrsFromStart * 3600.0;
// how many full 16.58 (1/217th of an hour) intervals have elapsed
int fullIntervals = (int)(secondsInCurrentHour / 16.58);
This can be packaged into a function and called any time and it is pretty fast.
Alternatively: an Event can be created which increments some count by 1 every 16.58 seconds and ten resets it back to 0 when the count reaches 217.

How to pause objective-c for an time less then an second

I am writing an app in Xcode 5.1.1 and objective-c.
I want to pause the program for 0.1 second.
To pause an program I normally use something like this:
sleep(1);
But "sleep" only takes an integer.
Question: is there an equivalent of sleep which can take floats?
Use following code. Convert your time to micro seconds.
usleep(100000); //Sleep Time 0.1 seconds
usleep(1000000);//Sleep Time 1 second.
or
[NSThread sleepForTimeInterval:0.1f];

Will performSelector:withObject:afterDelay: work with times under 1 sec?

Although you can pass sub-second times to performSelector:withObject:afterDelay:, it appears that the timer will fire as quickly as it can for any delay under 1 sec. For example, if I set the delay to 100 msec (0.100) or 10 msec (0.010), the timer will still fire in 2 or 3 msec. Is this a known limitation?
For performSelection:withObject:afterDelay:, the documentation for the delay reads:
delay — The minimum time before which the message is sent. Specifying a delay of 0 does not necessarily cause the selector to be performed immediately. The selector is still queued on the thread’s run loop and performed as soon as possible.
Compare this to NSTimer, where the documentation reads:
seconds — The number of seconds between firings of the timer. If seconds is less than or equal to 0.0, this method chooses the nonnegative value of 0.1 milliseconds instead.
It appears that performSelector:withObject:afterDelay: uses its delay setting just like NSTimer's seconds setting when a negative value is provided.
Can anyone confirm that that is correct?
As a follow-up, I discovered that performSelector:withObject:afterDelay: was working just fine, and that it wasn't triggering at sub-second intervals because I was passing it an int delay as follows:
int delay = 0.025; // 25 msec
[self performSelector:#selector(blahBlah:) withObject:nil afterDelay:delay];
OK, my bad! However, this leads to another observation — I thought the compiler would have reported a "loss of precision" when converting a double to an int without an explicit cast. However, it does not. Beware!
if you set the delay to 100 msec (0.100) using performSelector:withObject:afterDelay:, it will NOT be fired in 2 or 3 msec. It will be scheduled on the runloop after 100 msec, and wait until the runloop has the chance to perform. So it may be fired 102 or 103 msec after.

Incrementing a double is never whole

In Objective-C I have a timer fire every 0.1 seconds and increment a double value (seconds) by 0.1.
So it should basically keep time counting up by 1/10 of a second. When it fires it checks some if-else statements to see if time (seconds) is equal to 3, 9, 33, etc., but these are never triggered. I suppose it is because of the way doubles are represented in bits, that is the decimal is an approximation and never actually a whole number.
How can I fix this so my statements are triggered?
-(void)timeSeconds:(NSTimer*)theTimer {
seconds = seconds + 0.1;
NSLog(#"%f", seconds);
if (seconds == 3.0) {
[player pause];
[secondsTimer invalidate];
}
else if (seconds == 9){
[player pause];
[secondsTimer invalidate];
}
The floating point types cannot represent some numbers exactly, so when these are added, the error is compounded and the floating point type becomes less and less precise.
Use an integral type but represent the time difference using greater resolution, for example, use an NSUInteger to represent milliseconds instead of seconds, and increment by 100 instead of 0.1. Instead of comparing seconds == 3.0, you would use milliseconds == 3000, etc.
Keep in mind that timers are not fired very precisely:
A timer is not a real-time mechanism; it fires only when one of the run loop modes to which the timer has been added is running and able to check if the timer’s firing time has passed.
You may find that when milliseconds==9000, more than 9 seconds has actually passed (but probably not much more). There are other tools available if more precise timing is required.
0.1 cannot be represented exactly in binary floating point, so you get a small error that accumulates over time. If you want an exact value, use an int or long variable that get incremented by 1 each time called tenthsOfSeconds.
Floating point math is imprecise, using floating to count is not a great idea, but if you must, check that the difference between the count and the variable is very small.

How can I (reasonably) precisely perform an action every N milliseconds?

I have a machine which uses an NTP client to sync up to internet time so it's system clock should be fairly accurate.
I've got an application which I'm developing which logs data in real time, processes it and then passes it on. What I'd like to do now is output that data every N milliseconds aligned with the system clock. So for example if I wanted to do 20ms intervals, my oututs ought to be something like this:
13:15:05:000
13:15:05:020
13:15:05:040
13:15:05:060
I've seen suggestions for using the stopwatch class, but that only measures time spans as opposed to looking for specific time stamps. The code to do this is running in it's own thread, so should be a problem if I need to do some relatively blocking calls.
Any suggestions on how to achieve this to a reasonable (close to or better than 1ms precision would be nice) would be very gratefully received.
Don't know how well it plays with C++/CLR but you probably want to look at multimedia timers,
Windows isn't really real-time but this is as close as it gets
You can get a pretty accurate time stamp out of timeGetTime() when you reduce the time period. You'll just need some work to get its return value converted to a clock time. This sample C# code shows the approach:
using System;
using System.Runtime.InteropServices;
class Program {
static void Main(string[] args) {
timeBeginPeriod(1);
uint tick0 = timeGetTime();
var startDate = DateTime.Now;
uint tick1 = tick0;
for (int ix = 0; ix < 20; ++ix) {
uint tick2 = 0;
do { // Burn 20 msec
tick2 = timeGetTime();
} while (tick2 - tick1 < 20);
var currDate = startDate.Add(new TimeSpan((tick2 - tick0) * 10000));
Console.WriteLine(currDate.ToString("HH:mm:ss:ffff"));
tick1 = tick2;
}
timeEndPeriod(1);
Console.ReadLine();
}
[DllImport("winmm.dll")]
private static extern int timeBeginPeriod(int period);
[DllImport("winmm.dll")]
private static extern int timeEndPeriod(int period);
[DllImport("winmm.dll")]
private static extern uint timeGetTime();
}
On second thought, this is just measurement. To get an action performed periodically, you'll have to use timeSetEvent(). As long as you use timeBeginPeriod(), you can get the callback period pretty close to 1 msec. One nicety is that it will automatically compensate when the previous callback was late for any reason.
Your best bet is using inline assembly and writing this chunk of code as a device driver.
That way:
You have control over instruction count
Your application will have execution priority
Ultimately you can't guarantee what you want because the operating system has to honour requests from other processes to run, meaning that something else can always be busy at exactly the moment that you want your process to be running. But you can improve matters using timeBeginPeriod to make it more likely that your process can be switched to in a timely manner, and perhaps being cunning with how you wait between iterations - eg. sleeping for most but not all of the time and then using a busy-loop for the remainder.
Try doing this in two threads. In one thread, use something like this to query a high-precision timer in a loop. When you detect a timestamp that aligns to (or is reasonably close to) a 20ms boundary, send a signal to your log output thread along with the timestamp to use. Your log output thread would simply wait for a signal, then grab the passed-in timestamp and output whatever is needed. Keeping the two in separate threads will make sure that your log output thread doesn't interfere with the timer (this is essentially emulating a hardware timer interrupt, which would be the way I would do it on an embedded platform).
CreateWaitableTimer/SetWaitableTimer and a high-priority thread should be accurate to about 1ms. I don't know why the millisecond field in your example output has four digits, the max value is 999 (since 1000 ms = 1 second).
Since as you said, this doesn't have to be perfect, there are some thing that can be done.
As far as I know, there doesn't exist a timer that syncs with a specific time. So you will have to compute your next time and schedule the timer for that specific time. If your timer only has delta support, then that is easily computed but adds more error since the you could easily be kicked off the CPU between the time you compute your delta and the time the timer is entered into the kernel.
As already pointed out, Windows is not a real time OS. So you must assume that even if you schedule a timer to got off at ":0010", your code might not even execute until well after that time (for example, ":0540"). As long as you properly handle those issues, things will be "ok".
20ms is approximately the length of a time slice on Windows. There is no way to hit 1ms kind of timings in windows reliably without some sort of RT add on like Intime. In windows proper I think your options are WaitForSingleObject, SleepEx, and a busy loop.