Obtaining Reliable 1-Wire Wind Speed Data

Taming those insanely high Wind Gusts

I have been fighting a well-known problem with the anemometer since I first bought it. It randomly records insanely high wind gusts (100+ MPH). It was a problem when I was using the AAG software, it was a problem with the WService software, and it was a problem with my 1-Wire Weather Service for Java. This article describes how I solved the problem.

Contact Bounce
I have heard a lot of discussion about "contact bounce", in which the reed switches bounce mechanically, causing the counters to register multiple events for each passage of a magnet. This seems unlikely, since the DS2423 has built-in debouncing logic, and it is pretty fail-safe (note 13 from the DS2423 data sheet):
Each low-going edge on a counter input resets the channel’s debounce timer. The debounce time starts as the input voltage rises beyond the trip point. In order for the next pulse to be counted the debounce time must have expired.
This means that the DS2423 keeps extending the debounce window until the switch has remained quiet for the debounce time (170 to 460 microseconds, representing 5.9KHz to 2.2KHz respectively). That is in line with the faint "ping" tone you hear when the switches turn on.

Flight Recorder
What I thought might be contact bounce in the magnetic reed switches, or problems with the MicroLan, or problems with the power supply, or radio interference, might just be a timebase problem. I wrote my software to detect and filter out the insanely high gusts, but I was never satisfied with that solution, particularly since my filter could lop off some legitimate gusts in the process. So I built a "flight recorder" that records a running history of ten samples, along with collection times. When the filter detects an out of range sample, it records five more samples, for a total of five samples before and five samples after the out-of-range sample.

I captured a few of these events. Instead of an unusual jump in the spin counter data, I found a gap in the timebase: The anemometer task thread got suspended at a critical time (i.e., between reading the anemometer spin counter and reading the current time). While the thread is suspended, the anemometer continues to spin, and the counter continues to count. We calculate the RPM, which reads low because we have a long time interval and a low count. But look out for that next sample! If it starts at the scheduled time, it will be shorter than usual, and the count will include all the rotations that occurred while the thread was suspended during the previous sample. Here is an example:
Spin Counter History Buffer
 8: 1137475009667 5662 5664
 9: 1137475014283 5667 5668
 0: 1137475018309 5707 5710
 1: 1137475018960 5747 5749
 2: 1137475019150 5752 5752
 3: 1137475019381 5754 5754
 4: 1137475019461 5755 5755
 5: 1137475019551 5756 5755
 6: 1137475019641 5757 5756
 7: 1137475019741 5758 5757
The first column is the buffer index. The second column is the system time in milliseconds since January 01, 1970 UTC. The third and fourth columns are the spin counter values. (Each counter is connected to a separate magnetic reed switch. The counts may differ slightly depending on where the magnet is when the count is sampled. The choice of which one to use for wind speed calculations is arbitrary.)

Note the interval between index 9 and 0. The elapsed time is nearly 4000 milliseconds (4 seconds), while the count increased by only 40. The thread got suspended for nearly 4 seconds. The interval between 0 and 1 was a mere 651 milliseconds, but the count increased by 40 again. Since the rotor RPM is expressed as
rotorRPM = 
    (((count – prevCount) * 60000 / n) / (msec – prevMsec))
where n is the number of magnets in the instrument (2), the RPM for the first interval was calculated as 300, whereas the RPM for the second interval was calculated as 1843. Those correspond to wind speeds of 12 MPH and 75 MPH, respectively. The average wind speed at that time was about 11 MPH.

The wind speed obtained by plugging in the times and counts from the first and last entry calculates to about 12 MPH, so the overall counts and overall times are correct. If the anomaly had been due to contact bounce, the overall calculation would have been much higher.

Time Sync
Another source of trouble comes from the use of System.currentTimeMillis, which is a time-of-day clock. As such, it is subject to non-monotonic disruptions from NTP synchronization, such as the insertion of leap seconds, or users manually setting the system clock.

A much better solution is System.nanoTime, which is documented to be monotonic. Note that timing in Java can be tricky though, because Java is a cross-platform language. Java has to rely on the timing quality of whatever hardware platform it happens to be running on.