why are there odd spikes in the USB serial data transfer rates? I'm trying to use an Arduino for data collection, and hoping to get a consistent sampling rate.

I looked into the serial communication using the simplest program I could, but it produces odd results.  

void setup() { Serial.begin(9600); }
void loop() { Serial.println("00000"); }


I use a python script to read the data and create a text file and write the time in seconds before the five zeros.

Using the seconds as a marker, I then count the number of data lines for each second.  for example:

44 00000  // recorded at time 44 seconds
44 00000
44 00000
45 00000  // recorded at time 45 seconds, etc


I was expecting that there would be a somewhat stable value for this.  Using 10 bits per character, printing the 5 zeros should be able to be done about 190 times per second.  When analyzed, it turns out to be lower, which isn't surprising due to overhead, but also unexpectedly variable.

Collecting the zeros for 5000 seconds produced the following results:
most often, there were 137 sets of 00000 collected per second, followed by 138 sets of 00000.  This is easily explainable by not being equally spaced per second, and having one second with 137 followed by one second with 138.

What is harder to explain is when it jumps to 139, 140, 141 and 142 sets of 00000 per second.  

Out of the 5000 seconds of data, there were 25 seconds where 140 sets of 00000 were created.  That isn't too bad and could be due to timing.

But, out of the 5000 seconds, there were 203 seconds where 142 sets of 00000 were created.  

The percent breakdown is as follows:

137 sets of 00000:  79.15%
138 sets of 00000:  13.8%
139 sets of 00000:  0.39%
140 sets of 00000:  0.51%
141 sets of 00000:  2.05%
142 sets of 00000:  4.11%


the first 4 could be explainable with minor timing errors, the last ones are very hard to explain.  with 137 sets of 00000 there are 685 characters sent serially in one second.  

with 142 sets of 00000 there are 710 characters sent serially in one second.  

What I am trying to figure out is why the variability is so wide and also so consistent - as in the pattern, which can be seen in the graph.  




Is there any explanation for the variability?  

Because of the variability in the transfer, it is very hard to sync up data or filters or other uses when a constant sample rate is needed.  

I've also added delays in the main loop from 1ms to 7ms, 7ms was the maximum because that would not cause the loop to run slower than the free running speed at 142 loops/transmissions per second (1sec/7ms = 142.8 loops per second discounting all other overhead) and found the same patterns.  

Using a delay of 8ms produced another interesting result:
with a delay of 8ms, most of the data was transmitted at 123 or 124 sets of 00000 per second, but every 12 seconds there would be a burst of 128 sets of characters.  this makes sense because the delays add up to less than one second for 11 loops, then get an extra loop for that second, but that adds 15 characters, not just 5.  

After re-reading this, it dawned on me that there might be some loop timing/buffering errors, so instead of a delay, I used Serial.flush() to pause the loop until the data was sent.  

This resulted in a free-running result of 137 sets transmitted per second for the most common, followed by 138 sets.  The new issue is that every 25 seconds there is a drop down to 133 sets of characters transmitted per second, which seems to be the same issue only causing slowing instead of speeding up.  

I thought I found the answer with Serial.flush() but there is still something causing huge changes in the sent characters per second.  What could be causing this? and what can be done to make the transfer rates more constant?
While a serial port "kept busy" can potentially produce data with jitter comparable to its clock's jitter reduced by the number of clocks per word, a USB serial converter introduces a bunching of data into packets that is effectively entirely asynchronous.

As a result, once the data has gone through the USB, you really can't determine much of anything about the timing of its origin just by looking at the timing of its arrival.  That remains true even if you are claiming it via a serial-type API on the host, because the USB bus has already irreversibly de-synchronized it in transit.

A more meaningful experiment would be to timestamp the data at the source, ie, on the Arduino.  That could potentially be more regular, but if you use a high enough resolution timestamp, you will still find that it is irregular, as by default the Arduino's foreground thread of execution is periodically interrupted by the timer, which produces a brief delay.

If you are sending serial data into the Arduino or using other hardware peripherals, those may cause additional sporadic delay-inducing interrupts.