Potentiometer Jitter

Go To Last Post
27 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Potentiometer Jitter; Does anyone know how to prevent this?

I am ADC sampling the voltage from a simple potential divider formed using a potentiometer. My code will only update the stored value if the value has changed by 1 (5v/256)= 19.5mV (for 8 bit). Occasionally I get oscillations between two values... obvious why really.

I notice that a lot of professional systems using this technique don't suffer from jitter, does anyone know how this is corrected? I still need to detect a change of one l.s.b in 8 bits.

Many thanks

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

First of all ensure that everything about your ADC rardware/software is Ok.
Second if there is enough variability in your measurements, ensure that this is because of a real electrical jiter, because let's say of a bad (cheap) potentiometer.

If the problem occures because of an electrical jiter and you want to filter it (using a fast filter), then you could use a software rolling average of ADC measurements:

I post an example of this:

void read_battery(void){
	static UI voltage[8] = {0};
	UI average = 0;
	static UC i = 0;

	voltage[i] = adc_10_bit(ADC_CHANNEL_6);
	if (++i >= 8){
	    i = 0;
	}
	for (UC j = 0; j < 8; j++){
	    average += voltage[j];
        }
    if (average > .......){

      .....code.....

    }

}

Michael.

User of:
IAR Embedded Workbench C/C++ Compiler
Altium Designer

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You can always run into problems with jitter in the LSB, even after averaging and there is not alot that can be done. If the signal is right at the threshold between the two levels jitter can occur. Averaging can help but can not completely eliminate this.

Icarus has posted an example of a rolling of moving average filter. It appears he isn't actually averaging just summing, and I usually perfer to keep a sum instead of computing it each time the averaging is done. Just subtract the oldest value from the sum, insert the new value into the array and add the new value to the sum.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Great suggestions thank you, especially now seeing how this could be performed whilst maintaining the sample-rate.

I'll try this out, and post back.
:)

Thanks

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If you have taken the usual precautions with your PCB layout the ADC reading should be very stable. How long are the connections between the pot and the ADC input?

Leon

Leon Heller G1HSM

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You use averaging, and hysteresis. Your resolution still remains 8 bits, but you cannot detect a change of only the LSB, without an increase in resolution.

By increasing the resolution of the ADC samples, you can effectively push the hysteresis calculation below the 8 bits of resolution that you need for your result. Thus allowing you to retain that single LSB change detection. You will need to store the full ADC conversion though, and only update the value when the value changes by more than one LSB of the desired result width.

So say you use a 10 bit sample. You store the full 10 bits, but use only the upper 8 in the rest of your code. To test for a change, you subtract the new sample, from the stored one (at full 10 bit resolution) and if the absolute value of the change is greater than 2 LSB's do you store the new result.

This will remove any oscillation from conversion error, and border conditions. If you still see oscillation, then your circuit has too much noise in it.

[edit]

corrected some minor typos

Writing code is like having sex.... make one little mistake, and you're supporting it for life.

Last Edited: Tue. Aug 5, 2008 - 05:35 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Right now, I'm just prototyping on the STK500 using the ADC input. The cables are short, although very "rough".

Thinking about it, reducing any noise (including AC ripple) will not solve the problem however. An almost perfect DC signal from the pot with only nanovolts of instability could still sit between two quantisation levels it seems, and unless some hysteresis is introduced then we should see jitter I believe? I am not sure if any hysteresis is in existence with AVR ADC's.

I had also previously hoped a Low Pass Filter on the input would help, although this should make no difference (given the above).

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

No the ADC hardware does not perform any sort of hysteresis.

Writing code is like having sex.... make one little mistake, and you're supporting it for life.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Sample with 10 bit resolution, do the averaging with 10-bit values (for instance uint16_t can hold a sum of 64 readings), do the hysteresis etc there, and only at the final stage you truncate to 8 bits when you see from the 10-bit value that the 8 bit value should change. Also by oversampling you can get extra bits; every time sampling rate is increased by 4 times, you get 1 extra bit.

I hope you have good clean power supply with enough bypass caps, good clean filter on AVCC and/or VREF, and also cap or RC filter on the ADC pin too. I also hope your pot is less than 50k, as for best results the pot output impedance should be less than 10k.

Also slowing down the ADC conversion can make less noisy results, so use as low ADC clock as you can with the sampling rate you have to have.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
Thinking about it, reducing any noise (including AC ripple) will not solve the problem however.

I get perfectly adequate ADC results when everything is stable, down to the LSB. (Yes, it may wobble sometimes but not usually.) With a lash-up and undetermined amounts of ripple and noise throughout the signal chain, how can you expect "perfect" results?

Do you really have a "perfect" pot? Have you started there?

Quote:
I notice that a lot of professional systems using this technique don't suffer from jitter

How about just a few of the examples of "a lot" of systems? Are they using a 10-turn precision pot, and when you tweak them you make fine adjustments until the LSB jitter isn't there? Are they using endless encoder knobs as on my 'scope, with a digital quadrature signal?

The regular readers have seen many of these "darned AVR ADC isn't worth the sand it is made of" threads over the years. For those threads that have continued to a resolution, it almost always turns out to be instability in the levels provided to the AVR: reference, ground, power, signal. Also, are you ensuring that the recommended input impedance is being met?

In my experience a "stable" reading can almost always be attained by fairly simple averaging or addition as has been described. My norm is to "close the loop" with a new data set about every 500ms, and use 50 ADC readings for each channel and use the average of the total. If the sampling time happens to be in sync with the ripple the true RMS value may not end up being used--more samples may be taken in the peak or the valley. But if I see more instability than the LSB flicker then I check out the signal.

Lee

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Another option is to simply slow down the amount of samples, and add a .001uf capacitor at the wiper of the potentiometer. Thei way the cap/pot will soften the spikes. Another thought that came to mind is what value potentiometer are you using? 10k's are ok, but I get my best results with 1k's

Jim

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

 

"The critical shortage here is not stuff, but time." - Johan Ekdahl

 

"Step N is required before you can do step N+1!" - ka7ehk

 

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

 

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB, RSLogix user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
Icarus has posted an example of a rolling of moving average filter. It appears he isn't actually averaging just summing, and I usually perfer to keep a sum instead of computing it each time the averaging is done. Just subtract the oldest value from the sum, insert the new value into the array and add the new value to the sum.

Yes this is real. I forgot to write this:


average /= 8;

bwall, thnaks for the reminder.

Michael.

Michael.

User of:
IAR Embedded Workbench C/C++ Compiler
Altium Designer

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Or perform oversampling in software: sample eight times as fast as you need and keep an array of the previous eight samples. When each sample comes in, shift all the samples down one in the array, stuff the new one in on top, total the contents of the array (and add four for rounding) and divide the result by eight - that's your result.

Alternatively, a somewhat better LP filter is to let the new value be 7/8 of the previous eight values' average plus one eighth of the most recent value; then shift the array and stuff this newly calculated value on the top.

You could get into FIR or IIR filters but the effort is probably not worth it; you're into a lot of pain with multiply/accumulate cycles and fractional binary arithmetic to accommodate the necessary filter coefficients.

I'd repeat the advice about decoupling the ADC power, using a cap across the wiper, and indeed across the pot supply - but I'd point out that a one-bit change on a normal pot is only a move of a degree, and that there is indeed *no* way you can guarantee the accuracy sufficiently to avoid the quantisation steps.

If it's utterly important that you receive 256 stable steps from a rotary control, then your best choice is to use a rotary encoder of some kind; the detents will prevent jitter though of course you'll have to write the simple software that handles contact bounce if it's mechanical.

Neil

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

thorin92 wrote:
I notice that a lot of professional systems using this technique don't suffer from jitter, does anyone know how this is corrected?

No.

Professional equipment use always rotary encoders with direct digital output (gray code) but never potentiometers with ADC.

I fear, there exist no good solution with potentiometers, and thus professional equipment avoid it.

If you stick on potentiometers, you must insert a hysterese (dead range), which means, after increasing the value, the potentiometer must be decreased e.g. by 4 until it was accepted.
So the reading can change +/-2 without changing the displayed value.

Peter

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi,

Danni could you give some sample code for the hysteresis?
I couldn't found any.

Thanks

What kind of ADC filtering does manufactures use in Pro RC transmitters (Futaba, JR, Hitec..)?
Is it simple averaging or maybe hysteresis?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

mrx23dot wrote:
Hi,
Danni could you give some sample code for the hysteresis?

#define HYSTERESE       2

unsigned int val;

void update_val( unsigned int adc )     // adc = 0 .. 1023
{
  if( val > adc + HYSTERESE )
    val = adc + HYSTERESE;
  else
    if( val + HYSTERESE < adc )
      val = adc - HYSTERESE;
}

Not tested yet.

Peter

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Danni's code does more than normal hystersis, it is also limiting the rate of change of the input. You might or might not want this. The code I use for a standard moving average filter with hystersis is below:

#define FILTER_LENGTH 8
#define HYSTERSIS     2

unsigned int filter_input(unsigned int newValue)
{
   static unsigned int Sum;         
   static unsigned int Array[FILTER_LENGTH];
   static unsigned char Index;
   static unsigned int oldValue;

   Sum -= Array
; Array
= newValue; Sum += newValue; Index++; if (Index >= FILTER_LENGTH) { Index = 0; } newValue = Sum / FILTER_LENGTH; if ((newValue > (oldValue + HYSTERSIS) || (oldValue > (newValue + HYSTERSIS)) { oldValue = newValue; } return(oldValue); }

Make sure the size of Sum is big enough to hold FILTER_LENGTH * (max value of newValue). Set HYSTERSIS and FILTER_LENGTH to appropriate values for your input.

Edit: Code hasn't been compiled or tested

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

A very simple way to filter and add hysteresis is the following:

static unsigned int value;

  value = (value*8-value+ADC+(8/2))/8;
  // value is the filtered value to be used 
  // in further calculations

The amount of filtering and hysteresis can be changed by changing 8 to any other value (preferably power of two to use shifting whenever possible).
( I know that (value*8-value) is the same as (value*7) and this can be used if a hardware multiplier is available, but multiplying by 8 can be done by shifting and is the more general solution).

Jörg.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Definitely not a pro solution, but cheap and jitter free: midi keyboard with three slider pots for volume (and other stuff), pitch bend and vibrato. 14 bits comes out via midi, but I guess not all bits are used, and I can't remember what kind of ADCs are built in to Motorola 68HC11 controllers, but I'd suspect 8 bit converters.

- Jani

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

bwall wrote:
Danni's code does more than normal hystersis, it is also limiting the rate of change of the input.

It limit not the rate, it limit the range, e.g. from 0..1023 to 2..1021.
But typical a potentiometer limit the range already (nonlinear on both ends).

bwall wrote:

#define HYSTERSIS     2

   if ((newValue > (oldValue + HYSTERSIS) ||
       (oldValue > (newValue + HYSTERSIS))
   {
      oldValue = newValue;
   }

If I understand it right, then only changes of +/-3 or greater can occur.
You can not change newValue in steps of +/-1.
So you lost resolution.

Peter

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Not lost resolution, only lost sensitivity at low differentials. It still has the resolution of 1 count, but will only register a change when it becomes greater than a count of 2.

Writing code is like having sex.... make one little mistake, and you're supporting it for life.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

danni wrote:

It limit not the rate, it limit the range, e.g. from 0..1023 to 2..1021.
But typical a potentiometer limit the range already (nonlinear on both ends).

You're correct, it isn't limiting the rate of change but I am not sure why you add/subtract HYSTERESE instead of just accepting the new value.

danni wrote:

If I understand it right, then only changes of +/-3 or greater can occur.
You can not change newValue in steps of +/-1.
So you lost resolution.

As glitch mentions no resolution is lost. You could change newValue in steps of +/- 1, by setting HYSTERSIS to 0, but if you want to do this then you don't use hystersis at all.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi, thanks for your reponses.

I finally got around to fixing this. I implemented the moving average filter here and this worked nicely, however still jitter obviously.

My final working solution was to not only detect if the input sample was different to the last one, but also different to the one before that. Thus detecting jitter oscillations between two samples;

e.g. with a data-set of ADC readings from the potentiometer of:

78
79
78
79

My system would reject.

Here is the code for generating a MIDI message from a pot connected to the ADC input with no jitter :)

cur_data[i]=moving_average(i,ADC_read_input(i));//Sample the input	
if ((cur_data[i]!=p_data[i])&&(cur_data[i]!=pp_data[i])){//If input dif from last 2 samples
MIDI_cc_message((MIDICH-1),ctrl_ids[i],cur_data[i]);//Send a MIDICC
				pp_data[i]=p_data[i];//shift the previous value back one
				p_data[i]=cur_data[i];//shift the current value back one
			}

in code above "i" is the current channel because I am using many pots, whence also arrays rather than single variables.

Cheers

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

With 1 LSB is impossible,try with 3 LSB to define to potensiometer movement.
if((newvalue&0xf8)^(previousvalue&0xf8)){
//user has changed potensiometer value
}

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

geoelec wrote:
With 1 LSB is impossible,try with 3 LSB to define to potensiometer movement.
if((newvalue&0xf8)^(previousvalue&0xf8)){
//user has changed potensiometer value
}

Right, and how would that work if the movement is 1LSB, for example between 0xf8 and 0xf7?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

This only tests the movement by hand.Initially 3 LSBs needed,then set a flag and the display will updating normally with 1 LSB resolution.While is not moving after a short of time the flag will cleared and for new updating 3 LSBs needed again.Also 1 LSB resolution will be obtained using 10 turns potensiometer.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I don't see the big deal, even after all this time. Oversample. Or if the change in the LSB bothers you, oversample and discard low bits.

If I had to wager, then entire analog system isn't going to be squeaky clean. There is probably mV of noise and jitter and drift all over before the AVR actually gets a crack at the signal. Yet OP is worried about a fraction of a LSB on a device that has several LSB possible error according to the datasheet.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.