Exercise: Input Hysteresis

Objective

Understand the application of a single state variable to produce hysteresis, the time-based dependence of a system’s output on present and past inputs.

Hysteresis arises in a process when internal state causes the output response to vary based on the history of the input. It can be a useful property to engineer into systems involving thresholds in order to avoid unwanted ambiguous behavior. For example, a thermostat typically turns on when the temperature drops somewhat below the target and keeps the furnace running until the temperature is somewhat above the target. This keeps the furnace from cycling on and off too rapidly.

However, the phenomenon can also interfere with control of mechanical systems. Most mechanical transmissions exhibit some degree of backlash, e.g. the slight gap between gear teeth, for which changing the direction of torque causes the contact to be lost and zero torque to be transmitted for a short displacement until load contact is re-established. The extra state variable is the relative position of the parts, which are ideally intended to have a fixed relationship. This can lead to motor chatter when trying to control an exact position with both positive and negative torques.

This example presents a simple light-responsive system which incorporates hysteresis. This might be a model for the behavior of a light-sensitive streetlight to allow it to turn off at dusk without oscillating in response to its own illumination.

State Transition Graph

This graph represents a set of discrete states modelled by the system. States are illustrated as ovals and transitions as arrows. Each state can have an associated output, in this case the LED. Transitions between states are defined by condition rules. There is no representation of time in this graph; transitions are assumed to trigger instantaneously.

// To compile:
// dot -T png input_hysteresis_state_transition_diagram.dot -o input_hysteresis_state_transition_diagram.png

digraph input_hysteresis {
	node [fontsize=10]
	edge [fontsize=8]
	dpi="72"
	size="5,5!"
	
	// declare all nodes
	IS_DARK [ label = "state IS_DARK\nLED is ON\n(waiting for light)", color="blue" ]
	IS_LIGHT  [ label = "state IS_LIGHT\nLED is OFF\n(waiting for dark)", color="#00ffff" ]

	// declare all edges with labels
	IS_LIGHT -> IS_DARK [ label = "transition rule:\nlight input < dark_threshold" ]
	IS_DARK -> IS_LIGHT [ label = "transition rule:\nlight input > light_threshold" ]

	label = "InputHysteresis\nState Transition Diagram"
}

The key requirement for this particular state machine to exhibit hysteresis is that the value of light_threshold is higher that the value of dark_threshold. (See the Wikipedia Schmitt trigger plot for an illustration of this.) So once the brightness input rises above the upper threshold, it has to fall back through the gap until it is below below the lower threshold. Inputs above the upper threshold will clearly be perceived as light, and below the lower threshold as dark, but inputs in the middle range are ambiguous by themselves, the perception depends on the recent history. In this way, small noise variations around a threshold level will not trigger a change, so the system more reliably detects meaningful variation.

Steps and observations

  1. Set up an Arduino UNO with a photoresistor between +5V and A0 and a 4.7K resistor between A0 and GND, e.g. a basic voltage divider to sense a varying light level using A0. Check with a DMM that the A0 voltage varies over a wide range with changes in light level. You may need to choose a different fixed resistor depending on your specific photoresistor.
  2. Upload the InputHysteresis sketch.
  3. Open the Serial Console and set to 115200 baud.
  4. Observe the console messages and the onboard LED. Can you observe the correct shadow and light levels to transition from off to on and back again? If it fails to transition, check that the A0 voltage is varying widely enough; you may need to adjust the values for light_threshold and dark_threshold.
  5. Compare the code against the state transition diagram shown above.

Comments

You may now recognize that the switch debouncing code introduced much earlier is a specific case of a finite-state machine implementing time-based hysteresis.

Optional Challenge

Can you introduce time measurements into the state graph? Adding intermediate wait states conditioned on elapsed time would be another way to improve the hysteresis.

Sketch Folder

  1. InputHysteresis.

See InputHysteresis Arduino Sketch for code documentation.

Table Of Contents

Previous topic

Exercise: Music Sequencer

Next topic

Exercise: Input Pattern Matching