Saturday, December 15, 2012

How Many Bits is enough

Back when I was doing my Engineering Masters degree I had to build an active suspension setup, simulate it in software, and then test it in real life. That was a difficult proposition and my 300+ page thesis took 4 months to review instead of the 3 weeks costing me about a thousand dollars in tuition. However, I was using about 6 MCP3201’s tied to a Spartan FPGA that was running at about 50000 samples per second and then averaged down to 512 sample/second with an artificial 16 bits created by summing and averaging the 12 bits. Suffice to say, this did actually help when it came to differentiating the positions for velocities, but it was honestly a mess.
I’ve done some experimenting in order to determine why I can’t get stable numbers with it sitting on a table while I simulate high RPM (120 RPM +/- 40). 60 – 90 RPM seem acceptably stable at 0 watts, but at 200 RPM it could erroneously read high, up to 26 watts I’ve seen. 26 watts error is flat out unacceptable!
So I’m back to basics. Read out the samples as fast as the fake serial port can allow and I come up with a few graphs. So what I am doing is summing up so many samples and then dividing them by the count, so averaging out over so many samples. This will be referred to as Samples/Report.
At 2000 samples/report things look very good! Less than 1 bit of appreciable noise getting though this crude filtering technique. But things quickly go bleak.
At 200 samples/report we have about 3 LSB of noise almost. My 16bit ADC is now barely a 13 bit ADC.
At 20 samples / report things just get very very very bad. We are at 4 – 5 LSB of noise! This means I’m down to MCP3201 territory with 11-12 bit.
This wouldn’t be so bad, but with so much time spent doing floating point math, at 160 RPM the code is struggling to make 200 samples before it has to update the calculations. This is skewed because I’m slowing it down a lot by sending data over USB. However it’s much slower than I can actually read out. Keep in mind that this is reading two sets of data.
So what is the problem? It’s now ratiometric so it should be more tolerant of voltage fluctuations. I’ve tested to see if I am causing any spikes in voltage due to magnets passing over it, that’s proven to not be a problem. I think it’s one of two things, the voltage regulator isn’t great causing some additional noise, or a higher quality ADC with more bits is needed.
Let’s look at one of the other problems mentioned, time calculating versus time reading. I’ve had the serial output tell me the running time before the zeroL and before and after zeroR. This is seen below.
Speed Time (Absolute)
Start Zero L Zero R
4mhz 8017 8914 9699
2mhz 8019 9037 9943
1mhz 8017 9277 10424
Well this seems peculiar, as the time only seems marginally affected by the SPI bus speed… also, the ADS8321 should not be run at higher than 2 Mhz, but seemed to function at 4 Mhz. I won’t do it again in case of damage, but it survived and I haven’t seen any anomalies.
Speed Time (relative) Time Reading  Time Calculating
Zero L Zero R Zero L Zero R
4mhz 897 785 121 776 664
2mhz 1018 906 242 776 664
1mhz 1260 1147 484 776 663
At 2 Mhz I’m spending 3 times as long to calculate as I am to read! So what is my code! Below is the zero command. I am summing to a “Long” from a short and then after 20000 reads it averages it out.
short zeroadcL()
   long adcl = 0;  //initialize a long variable
   for (int i=0; i < 20000; i++){adcl += long(readadcL());}
//     Serial.print(adcl);
//     Serial.print(",");
//     Serial.println(i);} //Read 1000 times
   return (short((adcl/20000))); //Output the average

I think this is a limitation of two things 8 bit and 8 Mhz microcontrollers. However, it puts me back on another issue; I need the microcontroller to spend more time sleeping. If I have to bump to 16Mhz on an 8 bit AVR type chip then I might as well hold off until I can move to the nRF51 which is 32bit and shouldn’t require so many commands to sum.

A lot to think about.

No comments:

Post a Comment