Go Down

Topic: Hysteresis (Read 2482 times) previous topic - next topic

lastchancename

A red herring...
Debouncing has very little or nothing to do with hysteresis.

Contact chatter won't be affected by hysteresis. 
High is high, and low is low.
Only rarely would the voltages wander undecisively, unless there was some capacitance hanging off there.
Experienced responders have a nose for laziness, (they were beginners once)... expecting the poster to contribute to the learning experience.

GoForSmoke

i would suggest
"Hysteresis - why you need to debounce"

We debounce sparks jumping across switch contacts too.
1) http://gammon.com.au/blink  <-- tasking Arduino 1-2-3
2) http://gammon.com.au/serial <-- techniques howto
3) http://gammon.com.au/interrupts
Your sketch can sense ongoing process events in time.
Your sketch can make events to control it over time.

Robin2

i would suggest
"Hysteresis - why you need to debounce"

Hysteresis is very different from bouncing.

Hysteresis is usually useful. Bouncing never is - apart from when you need to get a baby to sleep.

...R
Two or three hours spent thinking and reading documentation solves most programming problems.

larryd

Quote
apart from when you need to get a baby to sleep
Are you implying a debounced baby is a unhappy baby?



No technical PMs.
The last thing you did is where you should start looking.

Robin2

Are you implying a debounced baby is a unhappy baby?
No. I believe your logic is flawed.

Petrol (gas) will help a fire burn better, but the absence of petrol does not mean that the fire won't burn.

...R
Two or three hours spent thinking and reading documentation solves most programming problems.

BabyGeezer

Hysteresis is very different from bouncing.

Hysteresis is usually useful. Bouncing never is - apart from when you need to get a baby to sleep.

...R
yes - i have recently learned about Schmitt triggers in more detail, having previously only heard of it in a Jeremy Blum tutorial video as a "hardware solution to debouncing".

i suppose it just adds to the confusion, i was following your intention to "attract newbies" though.

GoForSmoke

Use a 1 uF cap to debounce switches in hardware. A .1 uF cap might do.

This has nothing to do with ADC dither.
1) http://gammon.com.au/blink  <-- tasking Arduino 1-2-3
2) http://gammon.com.au/serial <-- techniques howto
3) http://gammon.com.au/interrupts
Your sketch can sense ongoing process events in time.
Your sketch can make events to control it over time.

Grumpy_Mike

I used to describe hysteresis to my students as being like a town with a one way system of roads. Your route into town is always different from your route out of town.

But then in the UK a one way system is common, maybe it is not where you are.

BabyGeezer

But then in the UK a one way system is common, maybe it is not where you are.
nope - here, the *one* way system is MY/YOUR way, and the other guy's way is the WRONG way ! :P

GoForSmoke

We have President Dunning-Kreuger, if that's any indication.
1) http://gammon.com.au/blink  <-- tasking Arduino 1-2-3
2) http://gammon.com.au/serial <-- techniques howto
3) http://gammon.com.au/interrupts
Your sketch can sense ongoing process events in time.
Your sketch can make events to control it over time.

6v6gt

#25
Apr 17, 2018, 09:12 pm Last Edit: Apr 22, 2018, 07:08 pm by 6v6gt Reason: HowTo added.
I've now reworked the example in the OP using a class  to generalise it also borrowing some of the ideas which have been discussed in this thread and recently in similar 'potentiometer flicker' threads.  It is very simple to use and scales up well to multiple potentiometers (or other analog sources).
The documentation is in the .h file.
To use this, simply copy the files HystFilter.h and HystFilter.cpp to the same folder as your sketch, then reopen the sketch in the IDE to see the new files.


HystFilter.h :

Code: [Select]

/*
 * Class: HystFilter [Hysteresis filter].
 * Apply hysteresis to an input value and deliver a lower resolution, stabilised output value.
 *
 */


#ifndef HystFilter_h
#define HystFilter_h

#include <Arduino.h>


class HystFilter
{
  public:

    HystFilter( uint16_t inputValues, uint16_t outputValues, uint16_t margin  ) ;

    // constructor

    // inputValues:  the total number of discrete values delivered by the input.
    //               For example, a 10 bit ADC delivers 1024 values.
    //               8 bit ADC = 256, 9 bit ADC = 512, 10 bit ADC = 1024, 11 bit ADC = 2048, 12 bit ADC = 4096 etc.

    // outputValues: the number of discrete output values delivered. This governs the resolution of the function.
    //               For example a 6 bit resolution yields 64 values. This should ideally be no higher that the input resolution
    //               minus 3 bits. For example if the input resolution is 10 bits (1024), this should not exceed 7 bits (128)

    // margin:       margin sets the 'stickyness' of the hysteresis or the reluctance to leave the current state.
    //               It is measured in units of the the input level. As a general rule, this should be about 10% to 25% of the
    //               range of input values that map to 1 output value. For example, if the inputValues is 1024 and the outputValues
    //               is 128, then 8 input values map to 1 output value so the margin should be 2 (25% of 8 ).
    //               Probably a value of 2 is OK. For low resolutions or noisy environments, it can be higher. Don't make it too high
    //               or ranges overlap and some output values become unreachable.


    uint16_t getOutputLevel( uint16_t inputLevel )  ;

    // converts an input level (eg in the range 0 to 1023 to an aoutput value of 1 to 127 with hyteresis.

  private:
    uint16_t _inputValues ;
    uint16_t _outputValues ;
    uint16_t _margin ;
    uint16_t _currentOutputLevel ;
} ;

#endif




HystFilter.cpp :

Code: [Select]

#include "HystFilter.h"


HystFilter::HystFilter( uint16_t inputValues, uint16_t outputValues, uint16_t margin  ) :
  _inputValues( inputValues ) ,
  _outputValues(  outputValues ) ,
  _margin(  margin ) ,
  _currentOutputLevel( 0  )
{  }


uint16_t HystFilter::getOutputLevel( uint16_t inputLevel ) {

  // get lower and upper bounds for currentOutputLevel
  uint16_t lb =   (float) ( (float) _inputValues / _outputValues ) * _currentOutputLevel  ;
  if ( _currentOutputLevel > 0 ) lb -= _margin  ;   // subtract margin

  uint16_t ub =   ( (  (float) ( (float) _inputValues / _outputValues ) * ( _currentOutputLevel + 1 )  )  - 1 )  ;
  if ( _currentOutputLevel < _outputValues ) ub +=  _margin  ;  // add margin
  // now test if input is outside the outer margins for current output value
  // If so, caclulate new output level.
  if ( inputLevel < lb || inputLevel > ub ) {
    // determine new output level
    _currentOutputLevel =   (  ( (float) inputLevel * (float) _outputValues ) /  _inputValues ) ;
  }
  return _currentOutputLevel ;
}




example usage sketch:

Code: [Select]

/*

   HystFilter class [Hysteresis]

   This code example shows obtaining values 0-64 from one potentiometer wired
   as a voltage divider and 0-10 from another.
  
   These values remain stable even if the potentiometer
   is set on a border point between two values.

   The same principle could be used to set the brightness of a display
   dependent on the ambient light, but free from flicker or switching a heater
   on based on a thermostat etc.

   6v6gt 17.apr.2018

   ver 0.01 03.02.2018 Original verson with table to represent range end points
   ver 0.02 13.04.2018 Original verson with calculation to determine range end points.
   ver 0.04 17.03.2018 Class implementation for multiple potentiometers (or other analog sources)

*/




#include "HystFilter.h"

HystFilter potA( 1024, 64, 3 ) ;  // 10 bit ADC = 1024, 64 discrete output values required, margin = 3 units (of 1024)
HystFilter potB( 1024, 10, 5 ) ;  // 10 bit ADC = 1024, 10 discrete output values required, margin = 5 units (of 1024)


void setup() {
  Serial.begin( 9600 ) ;
}

void loop() {
  
  Serial.print("potA:  " ) ;
  Serial.print(  potA.getOutputLevel( analogRead(A0) ) ) ;
  Serial.print("  " ) ;
  Serial.println( analogRead(A0) ) ;

  Serial.print("potB:  " ) ;
  Serial.print(  potB.getOutputLevel( analogRead(A1) ) ) ;
  Serial.print("  " ) ;
  Serial.println( analogRead(A1) ) ;
  Serial.println("  " ) ;
  

  delay ( 500 ) ;
}




edmcguirk

Sorry if I am misunderstanding the concept of your program but it seems to me that you are overcomplicating this.

If there is some function that calculates the output value from a new measurement, Then all you need to know is the current displayed output, the new measurement, and the margin. If the new measurement plus or minus the margin delivers an output value equal to the current displayed output, then keep the current displayed output else change the current displayed output.

The margin can be a constant or it can be calculated dynamically based on the new measurement if the scale is nonlinear. It should not be necessary to know how many different output values are possible unless you need to base the margin dynamically on the currently displayed output value.

If you wanted to get fancy, you could start the margin at a largish value which narrows to a smaller value if the displayed output remains unchanged over time to have both reduced flicker and increased accuracy.

GoForSmoke

Maybe because hysteresis is not debouncing and this is supposed to be about hysteresis.

1) http://gammon.com.au/blink  <-- tasking Arduino 1-2-3
2) http://gammon.com.au/serial <-- techniques howto
3) http://gammon.com.au/interrupts
Your sketch can sense ongoing process events in time.
Your sketch can make events to control it over time.

edmcguirk

How would my reply have anything to do with debouncing? My reply clearly has to do with changing output when the new value is close to a boundary, thus preventing unwanted flickering between two output values.

lastchancename

Let's just say that hysteresis has less to do with TIME than it has to do with levels.
Experienced responders have a nose for laziness, (they were beginners once)... expecting the poster to contribute to the learning experience.

Go Up