-
Notifications
You must be signed in to change notification settings - Fork 2.6k
RDC Phase optimization
The contiki radio duty cycle (RDC) layer interfaces between the network stack and the radio driver. The radio is kept off as much as possible, briefly turning on to check for packets to be received. Typically, that "channel check" is done at 4 or 8 Hz, so as not to compromise response time. However, the power savings for the receiver will be shifted to increased power requirements for the transmitter unless there is a mechanism for the tx to keep track of the rx wake periods. The rx RDC can be turned off by the application, one example being a USB-powered border router which is always listening; but, it still should use the same RDC as all the nodes, for network efficiency (else, it would retransmit many times until the receiver awakens and ACKs the packet).
Conceptually, this is not hard to accomplish; simply give both sides the same channel check interval, and have the tx keep track of the phase of the rx based on the last successful transmission. The next tx then can be delayed until the rx is known to be awake. In practice, different clock rates between the two adds a complication. Unless both are crystal-controlled, the parameters for phase optimization need to be adjusted based on the observed phase drift.
Fortunately, most PCs ping at a precise 1 Hz rate; so, sending a short ping (1 RF packet) will result in an ACK with precise time intervals.
Here is an example of the phase drift between a Raven and Econotag over 100 pings. The Econotag runs at 18778 rtimer ticks per second; thus, an 8 Hz RDC results in a 2347.25 tick phase window. At 8 Hz, the Raven wakes for 500 microseconds based on its 7812 rtimer ticks per second, which is derived from the internal RC clock of the 1284p MCU. The Econotag strobes the ping packet until the Raven responds with an ACK; and, the timing of the ACK relative to the Econotag rtimer shows the relative clock rates.
Here is the plot of phase, modulo 1 second, that shows the Raven clock loses 1/4 second in just about 20 seconds. The Econotag sends up to 32 packets over 2348 ticks; the number of those is shown in red. Blue shows the rtimer count when the ACK is received form the Raven.
1% accuracy is considered pretty good for the internal RC oscillator; but, as can be seen if the Econotag started strobing at the last Raven phase, it would send 3 packets before the Raven awakens. If +/- 1% accuracy is considered, it would have to start 1/80th of a second early, with a 6 packet cost. Since the average number of strobes is only ~17 when no phase optimization is used, that gives only a 50% further reduction in Econotag tx power usage.
The data was obtained using print in contikimac:
#if WITH_PHASE_OPTIMIZATION if(is_known_receiver && got_strobe_ack) { PRINTF("no miss %d wake-ups %d\n", packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[0], strobes); } if(!is_broadcast) { printf("%d %d\n", strobes, encounter_time%RTIMER_ARCH_SECOND); <------------------- if(collisions == 0 && is_receiver_awake == 0) { phase_update(&phase_list, packetbuf_addr(PACKETBUF_ADDR_RECEIVER), encounter_time, ret); } } #endif /* WITH_PHASE_OPTIMIZATION */
but, the actual Econotag phase delay was disabled in order to see the drift. Keeping it disabled, but adding a print to the phase delay routine to show what the default would be:
if(!RTIMER_CLOCK_LT(expected, now)) { /* Wait until the receiver is expected to be awake */ printf("%d ", expected%cycle_time); // while(RTIMER_CLOCK_LT(RTIMER_NOW(), expected)); } return PHASE_SEND_NOW;
gives
The tx would have started at the previous phase less the "guard" time. In contikimac, the default guard time is set to 10 * CHECK_TIME + CHECK_TIME_TX; for the econotag in this example, CHECK_TIME is 8 rtimer ticks, and CHECK_TIME_TX is 24 ticks giving a guard time of 104 ticks. That is the vertical distance between the light blue opposing arrow symbol and the dark blue box for the previous data point.
Starting the strobes at this point should give about 8 strobes per ping. Let's enable the actual tx delay; and see:
Voila! The bad news is that the minimum number of strobes is also 8 because of the forced early turn-on, even when the phase would have been correct. Obviously, we want to tighten the guard time.
What does a web page load look like? As you might expect, after longer delays, the number of strobes goes up because of the increased clock drift:
So, let's try a first order drift correction to the estimated phase time. We save the time difference between the last two encounters in e->drift; then, calculate the phase change per cycle:
#if DRIFT_CORRECTION { int32_t s; s = e->drift%cycle_time/(e->drift/cycle_time); //drift per cycle s = s*(now-sync)/cycle_time; //estimated drift to now sync += s; //add it in } #endif s = sync%cycle_time - now%cycle_time; //now, compute estimated phase if (s > 0) wait = (rtimer_clock_t) s; else wait = (rtimer_clock_t) (cycle_time + s);
That indeed allows reducing the guard time; but not too much, or failures will occur. The Raven does two channel checks spaced 500 microseconds apart; so, the encounter times can suddenly shift by that much (e.g., 1014 seconds).
These spaced web page loads also show the failure, caused by two close packets that had the 500 microsecond shift followed by a longer delay over which that apparent drift was applied.
Of course, the average packet delivery delay will still be half the channel check interval, plus the guard time (occasionally, the transmitter will have to wait almost an entire channel check interval to ensure that minimum delay). In the below graph, the green triangles are the actual delay in econtag rtimer ticks, 2347 ticks = 125 milliseconds).
Finally, in real life, the transmission will not always be successful within one channel check interval. RF traffic or noise detected by the CCA can cause a tx delay and a missed rx window. Insufficient guard time will make that more likely, as well as increasing the failures from drift extrapolation. That will add additional check intervals to the delivery delay:
Of course, the timing could be more precise if everything was crystal-controlled. The Raven has a 32768 Hz watch crystal used for the 128 tick/second clock; however, the fast rtimer is clocked by the less stable 1284p internal RC oscillator. Conversely, the Econotag uses a 24 MHz crystal for the rtimer; and, clock ticks are obtained through a low-power ring oscillator that is calibrated at each start-up. The stability of all the oscillators is easy to measure using a host computer, e.g., by printing the times periodically in the main loop:
#define STAMPS 100 if ((clocktime%STAMPS)==0) { printf("%lu %u\n", clocktime, RTIMER_NOW()); }
and, using serial-log.pl to log the output to a file with host PC time-stamps:
$ ~/contiki/tools/serial-log.pl -s -l econotag Starting econotag.log on 12/04/2011 at 11:10:22 0009 30 622458 0019 40 811653 0029 50 1000860 0039 60 1190042 ...
Plotting and fitting the clock (red) and rtimer (blue) shows the low-power clock is slow by 540 ppm. That might change each start-up; but, does not matter for our purposes; it is the precise rtimer ticks that are used for radio turn-on. We pick 18897 ticks per second; the maximum accuracy we are going to get is ~0.5/18897 = 27 ppm since that is the tick spacing. We might want to change that up or down one depending on the observed drift between it and the Raven. Note the above used 18778 ticks/second; that was based on an erroneous comparison to the low-power clock.
A similar log shows the Raven watch crystal is 65 ppm fast. On the Raven, the rtimer can be phase-locked to the crystal, using negative feedback through the RC oscillator frequency (OSCCAL), e.g., once per second during the clock tick interrupt.
So, the rtimer has a similar long-term accuracy. Note the Raven 16-bit rtimer overflows every 8 seconds!
Now, we try the 100 pings:
The jags are undoubtedly the phase corrections on the Raven side. But, we know the Raven is phase-locked to a pretty good crystal; so, the downward drift suggests the Econotag is sampling too fast. Increasing RTIMER_ARCH_SECOND to 18898:
That is about as good as we can hope for. It corresponds to a drift of ~1/16 second over 100 seconds, about 650 ppm short-term.