Noise on ADC
DiverBob
Posts: 1,110
Still working on my motor control/ramping routines. The biggest problem I'm seeing right now is noise on the ADC causing eradic outputs to the Prop. I'm using a MCP3208 ADC and Jon's jm_mcp3208_ez object on a breadboard (which is another problem too!). I take an average of 8 samples which can have some fairly random values at times. I've hit this with a scope and I'm seeing +/- 20 to 140 mv variences in the signal line to the ADC chip that are coming in at random intervals. The linear actuator pot is 10k across 5 volts. The motor power leads and pot leads are in the same unshielded cable coming from the actuator. In general while watching the ADC output I see a fairly smooth change but then there comes a wild value that can throw the programming totally out of whack
I had hoped averaging would smooth things out but unfortunately it isn't enough. I'm experimenting with taking 10 values, dropping the high and low values, then averaging the remaining 8, but it got too late to complete that last night. I'm looking for circuit or programming suggestions. One thought just hit me is would slowing down the speed that the ADC is being read make a difference?
Thanks
Bob
I had hoped averaging would smooth things out but unfortunately it isn't enough. I'm experimenting with taking 10 values, dropping the high and low values, then averaging the remaining 8, but it got too late to complete that last night. I'm looking for circuit or programming suggestions. One thought just hit me is would slowing down the speed that the ADC is being read make a difference?
Thanks
Bob
Comments
That's the problem, you need to separate the sensitive signals away from the motor leads, you're coupling
switching transients directly into the signal wire.
The motor leads should be at least twisted pair, preferrably shielded twisted pair.
The signal lead from the pot should be shielded (should be the case for any analog sensor).
Add 10nF to ground at the ADC end of the cable.
Beside shielding the cables to avoid coupling between power and signal lines, if you have the possibility you can try to wire the pot in the field with one side to the cursor and the other to the +5v while inserting a resistor between the adc input and ground thus lowering the input impedance and forming a voltage divider of which one part is on the board and the other in the field but basically transforming your signal from voltage to a kind of current-loop that is less sensible to noise coupled from surrounding power leads.
I will research the mediane filter, not familiar with that one.
Thanks for the suggestions!
QuickMedian-Algorithm-in-Spin
If the response can be slow, an RC filter right at the Prop pin could smooth out much of the noise.
Marty
http://www.bot-thoughts.com/2013/07/oversampling-decimation-filtering.html
You could combine one or both with the median filtering.
I wonder if you might be lucky enough that the bandwidth of the noise is outside the bandwidth of the desired signal?
John Abshier
Huh? Leakage current 1nA, that's 10uV error from a 10k source resistance.
Taking one ADC sample involves charging up an internal capacitor to the input voltage and then discharging it back to ground via an internal charge DAC. The net effect is that every ADC sample charges and discharges approximately a 100pf cap. When sampling "quickly" (say ~30,000 samples per second) the load from the capacitor charging is similar to a 10K resistor. If you sample "slowly" (say less than 100Hz) and the signal source has significant capacitance (like 0.1uf or more) the average load current from the ADC input will approach the 1nA leakage spec.
Hook a digital multi-meter to one of the ADC inputs. With the 10K pots set to mid-scale, the DMM will read a different voltage when the ADC is sampling compared to when the ADC isn't sampling.
Marty
I want to try the median filter again, it may be that I didn't set it up correctly, I was getting some strange numbers out of it! I will probably attempt to re-write one on my own just so I'm sure of the operation.
This is basically the job done by a median filter. You define the number of samples, they are sorted and, if the number is odd the middle sample is picked, if the number is even the middle two are averaged. You can use your moving average of x samples, discard the 1,2,3 lower and higher values and average the others. The more samples you discard, the more median filter it is. The less values you discard, the more it is close to a moving average.
Here is the code of the ADC and sort routines. The GetADC routine runs on its own cog continuously updating three locations.
Here is a snippet from PST of the output from the code above:
Even the average value doesn't make sense when I review the values going into the calculation. Funny thing is that the other motor was working pretty good with this same code.
Bob
I did some more searching in the forum for other sorting options and found one by Tracey Allen that runs faster so I have decided to use that sort routine instead. Here is the code snippet:
After examining the output values I then average the middle 4 values as my ADC output. The robot leg movements have become much more predictable.
So long until the next problem!
Bob
So long as the source impedance is low enough for the sample cap (which is 20pF, not 100pF) to
charge to 12-bit accurate level (9 RC time constants) in the 1.5 clock sample window, it will read
accurate. Doesn't matter what the multimeter says, its averaging the re-charge spikes which are
not seen by the ADC (only the voltage at the end of the sample/hold window, when the cap is
fully charged).
Running at full whack for 5V, which is 2MHz clock, there is 0.75us available, meaning a source
impedance of ~5k or below is needed for full accuracy.
However it does seem that this chip does indeed discharge the sample cap as it digitizes it, which
isn't common for SAR ADC's which normally just compare the voltage with the successive
approximation.... Other chips have no need to recharge the sample cap for a DC input, unless
switching between input channels.
Ah, I'm glad someone read the datasheet. Mostly what I remember from my last reading is that the input loading was "significant" and that assuming it was a 10K resistor was a safe approximation.
Discharging the sample cap isn't that strange. It lets the chip use a much simpler single supply internal comparator instead of a rail to rail comparator. Additionally, the DAC inside this chip is a switched capacitor design. It looks like Microchip saved the area that would be used by a rail to rail buffer amp and sampling capacitor by using the DAC as the sampling capacitor.
Marty
The algorithm two posts back is an adaptation of one in Brandon Nimon's (Bob Fwed) obex object 556.
How are you acquiring the data that goes into the sort? It is not clear how data gets into the array for the call to insertionsort2(arrayAddr, arraylength)
It seems to me it would take at least a wrapper, or a different algorithm. The newest sample replaces the oldest sample in a circular buffer, following a pointer makes the rounds sequentially. It would not do to sort that buffer directly and in so doing to scramble the history.
One way to do it is to move the data to an auxiliary buffer and sort that.
Another way, one I prefer, is to use an auxiliary ranks table. The ranks table rather than the historical values table is sorted, making comparisons on values[rank[idx]]. Say there are 15 values. Then values[ranks[7]] is the median. When a new value is added to the historical buffer, sorting by ranks is fast, because there will only be one shift to put the new value in its place. The ranks[.] can usually be a byte variable, instead of a long or a word or a string (unless you have more than 256 entries in the main array!). You get one median output for each new data value put in.
Here is an snippet:
Optimizations are possible with larger tables, for example, by comparing the new value with the existing median and adjusting the sort order. Usually arrays for median filtering are rather small though. The median filter is robust against shot noise. Averaging the middle quartiles seems like a good idea too.
This is the code used to read 3 channels and the load the global variables. GetADC runs continuously in its own cog. I use jm_mcp3208_ez to run the ADC. I may look into combining these two items to save a cog since I'm using all 8 right now.
Bob
Hmm "tibia", "femur", "coxa". Humanoid?
With regard to ADC chips and input current errors. The effect is most evident when a muliplexer is involved, as in the MCP3208. You know the (Rinput*Csample)/Tsample is whack when the readings on one channel is affected by the reading on another channel.
Thanks for the suggestion, that may be possible although I'm looking at the floating point cog right now as a possible multi tasking cog.
The tibia, femur and Coxa are references for a large hexapod I've been developing for over 2 years. The code is for running a single leg. Servos rant strong enough for a 200 pound robot so I'm using linear actuators with potentiometer position feedback, hense the mcp3208 ADC. Each leg has its own prop board with a seperate central processor to control them. The project is documented over in the Parallax Robotics forum under "next large robot' if you are interested in more information. This has been my baby for a while and I'm committed to getting this thing walking sometime this year! So I will be back with more questions later! It's time to start developing the circuit boards next, haven't been able to find any out there that have the capabilities I'm looking for.
Bob
-use a linear array of longs
-the hi world have the sample value while the lower keeps the sample number
- in running condition the array is always sorted except for the last sample that is going to be inserted.
procedure
- first scan: search for lower loword (or lower sampleid to avoid a complete pass)
- replace the position found with the new sample (hiword)
- compare the new sample value with position-1 value
- start second scan (insertionsort/bubblesort just one pass) from the replaced position to one boundary or the other based on the previous comparison (or on the fact that the oldest sample id was found at one boundary or the other)
- during the sort scan you can compare hiwords or longs (being the value in the hi word) but always swap longs (to preserve sample age)
only two array scans, most of the times partial, independently of how many array elements. No nested loops, no additional buffers required. Easy to average the middle samples because the array is always sorted.