Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 19 of 19

Thread: Potentiometer 'Debouncing' Revisited

  1. #1

    Potentiometer 'Debouncing' Revisited

    Thought this might be of use to some of you struggling w/ jumpy pots/MIDI cc values, etc. The twist is adding/subtracting a small % of the total raw value IN ADDITION to the usual fixed value. I noticed the fixed values just weren't enough at raw > 900, but increasing the fixed values then really screws up the pot 'feel' at low values. Haven't seen this approach before, but it doesn't mean it isn't out there ;-)

    You'll need to tune the values, but these work perfectly for me w/ a teensy 2.0, 10k pot, .1uf to ground on the wiper

    nn_MIDI-PotTest-01c.ino

  2. #2
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    14,233
    Very nice. I've added a link to this thread on the USB MIDI page.

    http://www.pjrc.com/teensy/td_midi.html

  3. #3
    Senior Member oddson's Avatar
    Join Date
    Feb 2013
    Location
    Vancouver Canada
    Posts
    440
    While making the threshold scale might sort out stability it seems it limits access to CC values near 127.

    If you max the pot so voltage = Vcc then the voltage reading should be 1023.
    As you turn it slowly into the voltage divider range the value the second OR clause becomes effective when the current value falls to 997 or lower. (2% margin = 20; plus constant 5 means you have to be 26 lower before it will send an new MIDI event.)

    When that gets bit-shifted to MIDI values it will be 124 so the intervening values could never be generated by lowering from above.

    Even in the middle it looks like you'd skip half the available CC values when you try to make a slow adjustment.

    Or am I getting this wrong?

    Code:
    // *************   function to convert pot to MIDI cc. Pass it the pin number, the cc to transmit, and the MIDI channel ***************
    void pot_to_cc(byte pinNum, byte PotCC, byte Ch ){ 
        int PotCurVal = analogRead(pinNum) ; // get the raw value
        int margin = PotPrevVal * .02; //  get 2% of the raw value.  Tune for lowest non-jitter value.
        /*
         * Next we add (or subtract...) the 'standard' fixed value to the previous reading. (PotPrevVal needs to be declared outside the function so it persists.)
         * Here's the twist: Since the jitter seems to be worse at high raw vals, we also add/subtract the 2% of total raw. Insignificantat on low 
         * raw vals, but enough to remove the jitter at raw >900 without wrecking linearity or adding 'lag', or slowing down the loop, etc.
         */
        if (PotCurVal > PotPrevVal + (4 + margin) || PotCurVal < PotPrevVal - (5 + margin)) { // a 'real' change in value? Tune the two numeric values for best results
              MIDI1.sendControlChange(PotCC,PotCurVal >> 3,Ch);  // scale to 0-127 and send the cc
          PotPrevVal = PotCurVal; // store valid raw val  for next comparison
          //Serial.print("PotCurVal-"); // uncomment to debug
          //Serial.println(PotCurVal); // uncomment to debug
        }    
    }

  4. #4
    Senior Member oddson's Avatar
    Join Date
    Feb 2013
    Location
    Vancouver Canada
    Posts
    440
    Also... if you put a cap between the wiper and the ground don't you end up with a low-pass where the cutoff frequency increases as you rotate the pot CW since the R in the RC circuit gets bigger and bigger.

    Couldn't this explain the higher noise observed on the upper end? The rising cutoff is letting more noise through?

    You could put a static low-pass in series with the wiper but I'm wondering if a discrete low-pass filter in the code couldn't be used in conjunction with 'change band' hysteresis.


    Just run the signal from the pin through the discrete low-pass before testing it
    y[i] := α * x[i] + (1-α) * y[i-1]

    ...and then use a 'change-band' technique to update the CC value when the filtered signal crosses the change threshold that corresponds to the 3 bits of headroom the ADC provides.

    The cutoff for this filter would not depend on the pot position and it could be fine-tuned in code.

  5. #5
    I'll caveat the following w/ the disclaimer that I'm no expert on this, lol.

    A couple of things, in no order. All of the solutions I found online for pot jitter where MIDI is concerned (i.e. you absolutely CAN NOT have the mcu transmitting cc's when no one is moving a control...) involve adding some kind of hysteresis or dead-band. I THINK (again, not sure) that if you use that approach, the tradeoff will always be A) Resolution, B) Worse with slower control movement (Paul, chime in any time, lol). In my (and I suspect other's) case, the tradeoff of not being able to hit 127 every time, or not being able to 'zero in' on an exact setting every time is an annoyance, but not a dealbreaker, since I'm generally using Teensy/Arduino-based pots (as opposed to switches) 'expressively' in pedals (think wah-wah pedal, etc), rather than for fine adjustments, which are better suited to my Lemur or Max-based touchscreens.

    re: the wiper cap to ground, it is the usual 'professional' recommendation in the threads where guys (like me) are whining about their inability to get a pot on an mcu gpio pin to "settle down"

    Of the various solutions I tried, this gave me the best result. Not nearly perfect, but closer than I was getting w/ dead-band, cap to ground, or a combo of the two.
    If you can test and post a solution that doesn't involve any of the tradeoffs of the other approaches, you'll make a lot of friends, starting w/ me, lol :-) :-)

  6. #6
    Senior Member Pensive's Avatar
    Join Date
    Aug 2014
    Location
    Basingstoke, UK
    Posts
    529
    This is a very interesting thread as the pot smoothing algorithm that is commonly used works, but introduces lag.

    I'll be nosing through this at a later date for my untztrument.

  7. #7
    Senior Member oddson's Avatar
    Join Date
    Feb 2013
    Location
    Vancouver Canada
    Posts
    440
    Quote Originally Posted by Pensive View Post
    This is a very interesting thread as the pot smoothing algorithm that is commonly used works, but introduces lag...


    But the lag should be negligible as long as the loop isn't using a delay (which you normally only use to get around this problem anyway).

    Can I ask what algorithm you mean when you say 'commonly used'?

    on a different note...

    I was wondering if a counter variable could track code cycles since the last MIDI event and prevent a new message until a 'time' threshold is passed.

    That is if you need to limit the rate that messages can be generated at but want/need to avoid code 'delays' (for a digital filter to run for example).

    But I'm hopeful the digital filter with and three-bit threshold for CC events will be stable enough with no limits on how fast the MIDI can fire.
    Last edited by oddson; 07-19-2016 at 07:20 PM. Reason: ...read 'eight-bit' threashold in error...

  8. #8
    Senior Member defragster's Avatar
    Join Date
    Feb 2015
    Posts
    4,262
    use ElapsedMillis or ElapsedMicros: td_timing_elaspedMillis.html

    Very AWESOME tool - even if you use it when you don't need to it is fun and harmless.

    <edit> ... Harmless compared to (mis)using delay()

    Here's a snip of my latest use -

    Code:
    elapsedMillis fftTime;
    uint32_t fftCount=0;
    
    void setup() {
      // ...
      Serial.print("\n\n  starting ....");
      fftTime = 0;
    }
    
    void loop() {
      // ...
      fftCount++;
      if ( fftTime >= 1000 ) {
        // Do something once a second
        // ... print the fftCount per second ...
        fftCount=0;
        fftTime = 0;
      }
      // ...
    }
    Last edited by defragster; 05-27-2016 at 03:48 AM.

  9. #9
    Senior Member Pensive's Avatar
    Join Date
    Aug 2014
    Location
    Basingstoke, UK
    Posts
    529
    Quote Originally Posted by oddson View Post
    But the lag should be negligible as long as the loop isn't using a delay (which you normally only use to get around this problem anyway).

    Can I ask what algorithm you mean when you say 'commonly used'?
    https://www.arduino.cc/en/Tutorial/Smoothing

    This one. It works but it actually introduces lag (this was noticed on an LC). Of course on could reduce the iterations and speed up the measurement intervals, I'm sure a reduction to 3 readings over a sensible period of time would serve the same purpose.

  10. #10
    Senior Member oddson's Avatar
    Join Date
    Feb 2013
    Location
    Vancouver Canada
    Posts
    440
    Thanks for the elapsedMillis/Micros thing. I guess I should read the documentation other than the MIDI section.

    It got me thinking about time and frequency calculations inside this kind of loop Ė which isnít really made for DSP filtering.

    Iíve also since noticed Paulís ĎTo Doí comment on digital filtering on the MIDI page. I wonder what he is planning.

    So I think I should try some actual work on this... and stop hijacking this thread for now.

  11. #11
    Quote Originally Posted by ForestCat View Post
    Thought this might be of use to some of you struggling w/ jumpy pots/MIDI cc values, etc. The twist is adding/subtracting a small % of the total raw value IN ADDITION to the usual fixed value. I noticed the fixed values just weren't enough at raw > 900, but increasing the fixed values then really screws up the pot 'feel' at low values. Haven't seen this approach before, but it doesn't mean it isn't out there ;-)

    You'll need to tune the values, but these work perfectly for me w/ a teensy 2.0, 10k pot, .1uf to ground on the wiper

    nn_MIDI-PotTest-01c.ino
    did you connect ground to agnd and the 'voltage' to aref?

    I'm struggling with a teensy 3.2 based midi-controller with neopixels, digital ins and analog inputs.
    The analog input is unstable, and plugging in an expression pedal distorts the leds (some leds turn blue all of a sudden)

  12. #12
    Junior Member
    Join Date
    Jun 2014
    Posts
    11
    In response to oddson and others wanting to filter a potentiometer. From the hardware side of things... to avoid having the potentiometer position affect the low-pass filter response, there needs to be another resistor that defines the filter and acts as a buffer. In short it needs to be much more than the variable resistance that precedes it.
    Click image for larger version. 

Name:	pot_filter.PNG 
Views:	153 
Size:	21.8 KB 
ID:	7330
    For this application with a typical potentiometer of 10k, roughly 5x more or around 50k works well enough. I've attached a circuit, and a plot of the time response of a 'noisy' signal added to an increase and decrease of the potentiometer value. The frequency response plot shows that the cutoff frequency Fc remains constant at ~700Hz. (The four lines are for different values of the potentiometer.) You can see that large noise pulses with sharp edges are knocked down pretty well without noticeably delaying the response.

    Click image for larger version. 

Name:	filtered_out_time_response.PNG 
Views:	86 
Size:	22.4 KB 
ID:	7328
    Click image for larger version. 

Name:	filtered_output.PNG 
Views:	79 
Size:	15.4 KB 
ID:	7329
    Last edited by David Smith; 06-09-2016 at 06:16 AM.

  13. #13
    Senior Member adrian's Avatar
    Join Date
    Oct 2015
    Location
    Wellington, NZ
    Posts
    503
    @David Smith thankyou for this. My experience is that there is only so much you can do in software without introducing lag or reducing resolution (although I haven't tried a proper digital filter yet for pots). I have come to the (personal) conclusion that a good hardware solution should probably be the starting point ...
    Last edited by adrian; 06-09-2016 at 09:22 PM.

  14. #14
    Senior Member Ben's Avatar
    Join Date
    Jul 2013
    Location
    Germany
    Posts
    381
    Quote Originally Posted by adrian View Post
    @David Smith thankyou for this. My experience is that there is only so much you can do in software without introducing lag or reducing resolution (although I haven't tried a proper digital filter yet for pots). I have come to the (personal) conclusion that a good hardware solution should probably be the starting point ...
    I kind of semi-agree. If the hardware solution tackles the source of the problem and inhibits the noise at its point of origin, yes, I'd favor the hardware solution. If the idea is to remove noise from the signal I'd prefer a software solution, because it is much more versatile and opens up possibilities such as adaptive and nonlinear filtering and per-input calibration of filter parameters.

  15. #15
    Senior Member
    Join Date
    Jun 2013
    Location
    So. Calif
    Posts
    2,828
    Hardware debounce often reduces but doesn't eliminate the false detections.
    There are several good ways to do this in software (firmware).
    My favorite is:
    Most MCU apps have a recurring timer interrupt, say 100 or 1,000 Hz.
    In the ISR for that, you read the switch bit(s) from GPIO. If a switch bit is true: increment a one byte counter (but not past 255). IF bit is false, decrement if not 0.
    If count is > x, switch is pressed. If less than y, switch is released.

  16. #16
    David,
    Thanks for this detailed example. I'm just learning LTSpice and this showed me many techniques I hadn't realized.

  17. #17
    Senior Member adrian's Avatar
    Join Date
    Oct 2015
    Location
    Wellington, NZ
    Posts
    503
    @stevech there are lots of killer good ways to debounce switches .... I use a similar method to the one you describe, using a very fast timer .... I have 4 bits, I shift them left one bit, read in the current GPIO bit. Then I check if the 4 bits = 0000 or = 1111. Depending on the previous state and active low/high, the check will give me the debounced leading edge, or the debounced trailing edge.

    Analog pots are a bit more difficult, I find.

  18. #18
    Senior Member oddson's Avatar
    Join Date
    Feb 2013
    Location
    Vancouver Canada
    Posts
    440
    Quote Originally Posted by David Smith View Post
    In response to oddson and others wanting to filter a potentiometer. From the hardware side of things... to avoid having the potentiometer position affect the low-pass filter response, there needs to be another resistor ...
    Thank you... that was my point... There are a lot of places on the web that suggest putting a cap between the wiper and ground... I think it's guitarists used to tone controls.

  19. #19
    Senior Member oddson's Avatar
    Join Date
    Feb 2013
    Location
    Vancouver Canada
    Posts
    440
    Quote Originally Posted by adrian View Post
    @David Smith thankyou for this. My experience is that there is only so much you can do in software without introducing lag or reducing resolution (although I haven't tried a proper digital filter yet for pots). I have come to the (personal) conclusion that a good hardware solution should probably be the starting point ...
    Hmm... I believe the lag is theoretically identical. I'm leaning towards software filtering (if/when needed) but I have a way to go before I can properly code a DSP loop for Teensy.

    EDIT - It occurs to me this theoretical equivalence only applies to the appropriate IIR filter but I don't think it alters my point and may even favor post-acquisition filtering.
    Last edited by oddson; 06-23-2016 at 04:53 AM. Reason: correction.

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •