Skip to content

Instantly share code, notes, and snippets.

@theacodes
Created October 9, 2019 05:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save theacodes/0714d78c1356eee2b57ac024d436eac6 to your computer and use it in GitHub Desktop.
Save theacodes/0714d78c1356eee2b57ac024d436eac6 to your computer and use it in GitHub Desktop.
A helper library to setting a DAC to direct voltage values
# (c) 2019 Alethea Flowers
# Licensed under the MIT license.
"""A helper library to setting a DAC to direct voltage values.
That is, instead of setting a 16-bit integer value you can set the DAC to a
floating-point voltage value.
This requires information about the real-world DAC output and any output
scaling - this is called **calibration** data.
"""
import math
class VoltageOut:
"""Wraps an AnalogOut object to set voltage instead of 16-bit value.
Example::
vout = winterbloom_voltage_out.VoltageOut(board.A1)
vout.linear_calibration(3.3)
vout.voltage = 1.23
"""
def __init__(self, analog_out):
self._analog_out = analog_out
self._calibration = {}
def linear_calibration(self, max_voltage):
"""Determines intermediate calibration values using the given
maximum output voltage (assumes the minimum is 0). This is the
simplest way to calibrate the output. It assumes that the DAC
and any output scaling op amps have an exactly linear response.
Example::
vout.linear_calibration(10.26)
"""
self._calibration = {
voltage: int((voltage * 65535) / max_voltage)
for voltage
in range(math.ceil(max_voltage) + 1)
}
print(self._calibration)
def direct_calibration(self, calibration):
"""Allows you to set the calibration values directly. Generally
you'll do this by driving the DAC to each integral voltage in
the output range and recording the 16-bit DAC value. Then, you
can pass these integrals and associated values into this function.
Example::
vout.direct_calibration({
0: 0,
1: 1000,
2: 2000,
3: 3000,
...
})
"""
self._calibration.update(calibration)
def _calibrated_value_for_voltage(self, voltage):
# TODO: Use a function like take_nearest to allow this to work on non-integral,
# non-continuos calibration data.
root = int(math.floor(voltage))
next_root = root + 1
offset = voltage - root
root_val = self._calibration[root]
next_val = self._calibration[next_root]
lerped = int(root_val + ((next_val - root_val) * offset))
print(voltage, root, root_val, lerped)
return min(lerped, 65535)
def _set_voltage(self, voltage):
value = self._calibrated_value_for_voltage(voltage)
print("Voltage: ", voltage, "Value: ", value)
self._analog_out.value = value
voltage = property(None, _set_voltage)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment