From 48045fe89b487c94b854766c8799d418f42fc76b Mon Sep 17 00:00:00 2001 From: Mark Wolfman Date: Fri, 12 Jan 2024 12:45:46 -0600 Subject: [PATCH 01/11] Added pre-determined settling times to SRS570 pre-amp gain signals. --- apstools/devices/srs570_preamplifier.py | 160 +++++++++++++++++- .../devices/tests/test_srs570_preamplifier.py | 149 ++++++++++++++++ 2 files changed, 305 insertions(+), 4 deletions(-) create mode 100644 apstools/devices/tests/test_srs570_preamplifier.py diff --git a/apstools/devices/srs570_preamplifier.py b/apstools/devices/srs570_preamplifier.py index 7e839a875..6a9baabcf 100644 --- a/apstools/devices/srs570_preamplifier.py +++ b/apstools/devices/srs570_preamplifier.py @@ -21,12 +21,164 @@ import pint from ophyd import Component from ophyd import EpicsSignal +from ophyd.signal import DEFAULT_WRITE_TIMEOUT from .preamp_base import PreamplifierBaseDevice logger = logging.getLogger(__name__) +gain_units = ["pA/V", "nA/V", "uA/V", "mA/V"] +gain_values = ["1", "2", "5", "10", "20", "50", "100", "200", "500"] +gain_modes = ["LOW NOISE", "HIGH BW"] + +# Settling times measured from the 25-ID-C upstream I0 chamber's SR-570 +# (sensitivity_value, sensitivity_unit, gain_mode): settle_time +settling_times = { + # pA/V + ("1", "pA/V", "HIGH BW"): 2, + ("2", "pA/V", "HIGH BW"): 1.75, + ("5", "pA/V", "HIGH BW"): 1.5, + ("10", "pA/V", "HIGH BW"): 0.75, + ("20", "pA/V", "HIGH BW"): 0.3, + ("50", "pA/V", "HIGH BW"): 0.3, + ("100", "pA/V", "HIGH BW"): 0.3, + ("200", "pA/V", "HIGH BW"): 0.2, + ("500", "pA/V", "HIGH BW"): 0.2, + ("1", "pA/V", "LOW NOISE"): 2.0, + ("2", "pA/V", "LOW NOISE"): 1.75, + ("5", "pA/V", "LOW NOISE"): 1.5, + ("10", "pA/V", "LOW NOISE"): 1.25, + ("20", "pA/V", "LOW NOISE"): 1.0, + ("50", "pA/V", "LOW NOISE"): 1.0, + ("100", "pA/V", "LOW NOISE"): 1.0, + ("200", "pA/V", "LOW NOISE"): 0.3, + ("500", "pA/V", "LOW NOISE"): 0.3, +} +settling_times.update( + { + # nA/V + (gain_values[idx], "nA/V", "HIGH BW"): 0.2 + for idx in range(9) + } +) +settling_times.update( + { + # nA/V + ("1", "nA/V", "LOW NOISE"): 0.3, + ("2", "nA/V", "LOW NOISE"): 0.2, + ("5", "nA/V", "LOW NOISE"): 0.2, + ("10", "nA/V", "LOW NOISE"): 0.2, + ("20", "nA/V", "LOW NOISE"): 0.2, + ("50", "nA/V", "LOW NOISE"): 0.2, + ("100", "nA/V", "LOW NOISE"): 0.2, + ("200", "nA/V", "LOW NOISE"): 0.2, + ("500", "nA/V", "LOW NOISE"): 0.2, + } +) +settling_times.update( + { + # μA/V, high bandwidth + (gain_values[idx], "uA/V", "HIGH BW"): 0.15 + for idx in range(9) + } +) +settling_times.update( + { + # μA/V, low noise + (gain_values[idx], "uA/V", "LOW NOISE"): 0.15 + for idx in range(9) + } +) +settling_times.update( + { + ("1", "mA/V", "HIGH BW"): 0.15, + ("1", "mA/V", "LOW NOISE"): 0.15, + } +) + + +class GainSignal(EpicsSignal): + """A signal where the settling time depends on the pre-amp gain. + + Used to introduce a specific settle time when setting to account + for the amp's R–C relaxation time when changing gain. + + """ + @staticmethod + def _settle_time(gain_value: int, gain_unit: int, gain_mode: str): + """Determine the best settle time for a given combination of parameters. + + Parameters can be strings of indexes. + + """ + # Convert indexes to string values + try: + gain_value = gain_values[gain_value] + except (TypeError, IndexError): + pass + try: + gain_unit = gain_units[gain_unit] + except (TypeError, IndexError): + pass + try: + gain_mode = gain_modes[gain_mode] + except (TypeError, IndexError): + pass + # Get calibrated settle time, or None to use the Ophyd default + return settling_times.get((gain_value, gain_unit, gain_mode)) + + def set(self, value, *, timeout=DEFAULT_WRITE_TIMEOUT, settle_time="auto"): + """Set the value of the Signal and return a Status object. + + If put completion is used for this EpicsSignal, the status object will + complete once EPICS reports the put has completed. + + Otherwise the readback will be polled until equal to the set point (as + in `Signal.set`) + + Parameters + ---------- + value : any + timeout : float, optional + Maximum time to wait. + settle_time: float, optional + Delay after the set() has completed to indicate completion + to the caller. If "auto" (default), a reasonable settle + time will be chosen based on the gain mode on the pre-amp. + + Returns + ------- + st : Status + + See Also + -------- + Signal.set + EpicsSignal.set + + """ + # Determine optimal settling time. + if settle_time == "auto": + signals = [self.parent.sensitivity_value, self.parent.sensitivity_unit, self.parent.gain_mode] + args = [value if self is sig else sig.get() for sig in signals] + val, unit, mode = args + # Resolve string values to indices if provided + if val in gain_values: + val = gain_values.index(val) + if unit in gain_units: + unit = gain_units.index(unit) + if mode in gain_modes: + mode = gain_modes.index(mode) + # Low-drift mode uses the same settling times as low-noise mode + if mode == "LOW DRIFT": + mode = "LOW NOISE" + # Calculate settling time + _settle_time = self._settle_time(gain_value=val, gain_unit=unit, gain_mode=mode) + else: + _settle_time = settle_time + return super().set(value, timeout=timeout, settle_time=_settle_time) + + class SRS570_PreAmplifier(PreamplifierBaseDevice): """ Ophyd support for Stanford Research Systems 570 preamplifier from synApps. @@ -36,8 +188,8 @@ class SRS570_PreAmplifier(PreamplifierBaseDevice): # in the EPICS .db file. Must cast them to ``float()`` or ``int()`` # as desired. # see: https://github.com/epics-modules/ip/blob/master/ipApp/Db/SR570.db - sensitivity_value = Component(EpicsSignal, "sens_num", kind="config", string=True) - sensitivity_unit = Component(EpicsSignal, "sens_unit", kind="config", string=True) + sensitivity_value = Component(GainSignal, "sens_num", kind="config", string=True) + sensitivity_unit = Component(GainSignal, "sens_unit", kind="config", string=True) offset_on = Component(EpicsSignal, "offset_on", kind="config", string=True) offset_sign = Component(EpicsSignal, "offset_sign", kind="config", string=True) @@ -46,7 +198,7 @@ class SRS570_PreAmplifier(PreamplifierBaseDevice): offset_fine = Component(EpicsSignal, "off_u_put", kind="config", string=True) offset_cal = Component(EpicsSignal, "offset_cal", kind="config", string=True) - set_all = Component(EpicsSignal, "init.PROC", kind="config") + set_all = Component(GainSignal, "init.PROC", kind="config") bias_value = Component(EpicsSignal, "bias_put", kind="config", string=True) bias_on = Component(EpicsSignal, "bias_on", kind="config", string=True) @@ -55,7 +207,7 @@ class SRS570_PreAmplifier(PreamplifierBaseDevice): filter_lowpass = Component(EpicsSignal, "low_freq", kind="config", string=True) filter_highpass = Component(EpicsSignal, "high_freq", kind="config", string=True) - gain_mode = Component(EpicsSignal, "gain_mode", kind="config", string=True) + gain_mode = Component(GainSignal, "gain_mode", kind="config", string=True) invert = Component(EpicsSignal, "invert_on", kind="config", string=True) blank = Component(EpicsSignal, "blank_on", kind="config", string=True) diff --git a/apstools/devices/tests/test_srs570_preamplifier.py b/apstools/devices/tests/test_srs570_preamplifier.py new file mode 100644 index 000000000..115250c0f --- /dev/null +++ b/apstools/devices/tests/test_srs570_preamplifier.py @@ -0,0 +1,149 @@ +import pytest +from unittest import mock + +from apstools.devices.srs570_preamplifier import SRS570_PreAmplifier, GainSignal, DEFAULT_WRITE_TIMEOUT + +# Known settling times measured from the I0 SR-570 at 25-ID-C +settling_times = { + # (sensitivity_value, sensitivity_unit, gain_mode): settle_time + # pA/V + (0, 0, "HIGH BW"): 2, + (1, 0, "HIGH BW"): 1.75, + (2, 0, "HIGH BW"): 1.5, + (3, 0, "HIGH BW"): 0.75, + (4, 0, "HIGH BW"): 0.3, + (5, 0, "HIGH BW"): 0.3, + (6, 0, "HIGH BW"): 0.3, + (7, 0, "HIGH BW"): 0.2, + (8, 0, "HIGH BW"): 0.2, + # nA/V + (0, 1, "HIGH BW"): 0.2, + (1, 1, "HIGH BW"): 0.2, + (2, 1, "HIGH BW"): 0.2, + (3, 1, "HIGH BW"): 0.2, + (4, 1, "HIGH BW"): 0.2, + (5, 1, "HIGH BW"): 0.2, + (6, 1, "HIGH BW"): 0.2, + (7, 1, "HIGH BW"): 0.2, + (8, 1, "HIGH BW"): 0.2, + # μA/V + (0, 2, "HIGH BW"): 0.15, + (1, 2, "HIGH BW"): 0.15, + (2, 2, "HIGH BW"): 0.15, + (3, 2, "HIGH BW"): 0.15, + (4, 2, "HIGH BW"): 0.15, + (5, 2, "HIGH BW"): 0.15, + (6, 2, "HIGH BW"): 0.15, + (7, 2, "HIGH BW"): 0.15, + (8, 2, "HIGH BW"): 0.15, + # mA/V + (0, 3, "HIGH BW"): 0.15, + (1, 3, "HIGH BW"): None, + (2, 3, "HIGH BW"): None, + (3, 3, "HIGH BW"): None, + (4, 3, "HIGH BW"): None, + (5, 3, "HIGH BW"): None, + (6, 3, "HIGH BW"): None, + (7, 3, "HIGH BW"): None, + (8, 3, "HIGH BW"): None, + # pA/V + (0, 0, "LOW NOISE"): 2.0, + (1, 0, "LOW NOISE"): 1.75, + (2, 0, "LOW NOISE"): 1.5, + (3, 0, "LOW NOISE"): 1.25, + (4, 0, "LOW NOISE"): 1.0, + (5, 0, "LOW NOISE"): 1.0, + (6, 0, "LOW NOISE"): 1.0, + (7, 0, "LOW NOISE"): 0.3, + (8, 0, "LOW NOISE"): 0.3, + # nA/V + (0, 1, "LOW NOISE"): 0.3, + (1, 1, "LOW NOISE"): 0.2, + (2, 1, "LOW NOISE"): 0.2, + (3, 1, "LOW NOISE"): 0.2, + (4, 1, "LOW NOISE"): 0.2, + (5, 1, "LOW NOISE"): 0.2, + (6, 1, "LOW NOISE"): 0.2, + (7, 1, "LOW NOISE"): 0.2, + (8, 1, "LOW NOISE"): 0.2, + # μA/V + (0, 2, "LOW NOISE"): 0.15, + (1, 2, "LOW NOISE"): 0.15, + (2, 2, "LOW NOISE"): 0.15, + (3, 2, "LOW NOISE"): 0.15, + (4, 2, "LOW NOISE"): 0.15, + (5, 2, "LOW NOISE"): 0.15, + (6, 2, "LOW NOISE"): 0.15, + (7, 2, "LOW NOISE"): 0.15, + (8, 2, "LOW NOISE"): 0.15, + # mA/V + (0, 3, "LOW NOISE"): 0.15, + (1, 3, "LOW NOISE"): None, + (2, 3, "LOW NOISE"): None, + (3, 3, "LOW NOISE"): None, + (4, 3, "LOW NOISE"): None, + (5, 3, "LOW NOISE"): None, + (6, 3, "LOW NOISE"): None, + (7, 3, "LOW NOISE"): None, + (8, 3, "LOW NOISE"): None, +} + +gain_units = ["pA/V", "nA/V", "uA/V", "mA/V"] +gain_values = ["1", "2", "5", "10", "20", "50", "100", "200", "500"] +gain_modes = ["LOW NOISE", "HIGH BW"] + + +@pytest.mark.parametrize("gain_mode", gain_modes) +@pytest.mark.parametrize("gain_unit", gain_units) +@pytest.mark.parametrize("gain_value", gain_values) +@mock.patch("apstools.devices.srs570_preamplifier.EpicsSignal.set") +def test_preamp_gain_settling(mocked_setter, gain_value, gain_unit, gain_mode): + """The SR-570 Pre-amp voltage spikes when changing gain. + + One solution, tested here, is to add a dynamic settling time. + + """ + value_idx = gain_values.index(gain_value) + unit_idx = gain_units.index(gain_unit) + settle_time = settling_times[ + ( + value_idx, + unit_idx, + gain_mode, + ) + ] + # We need a real pre-amp device otherwise .set isn't in the MRO + preamp = SRS570_PreAmplifier("prefix:", name="preamp") + assert isinstance(preamp.sensitivity_unit, GainSignal) + assert isinstance(preamp.sensitivity_value, GainSignal) + status = preamp.sensitivity_unit.get = mock.MagicMock(return_value=gain_unit) + status = preamp.gain_mode.get = mock.MagicMock(return_value=gain_mode) + # Set the sensitivity based on value + status = preamp.sensitivity_value.set(gain_value) + # Check that the EpicsSignal's ``set`` was called with correct settle_time + mocked_setter.assert_called_with(gain_value, timeout=DEFAULT_WRITE_TIMEOUT, settle_time=settle_time) + # Set the sensitivity based on value + mocked_setter.reset_mock() + assert not mocked_setter.called + status = preamp.sensitivity_value.set(value_idx) + # Check that the EpicsSignal's ``set`` was called with correct settle_time + mocked_setter.assert_called_with(value_idx, timeout=DEFAULT_WRITE_TIMEOUT, settle_time=settle_time) + + +@mock.patch("apstools.devices.srs570_preamplifier.EpicsSignal.set") +def test_preamp_gain_mode_settling(mocked_setter): + """The SR-570 Pre-amp also has a low drift mode, whose settling + times are the same as the low noise mode. + """ + # We need a real pre-amp device otherwise .set isn't in the MRO + preamp = SRS570_PreAmplifier("prefix:", name="preamp") + gain_unit = "pA/V" + gain_value = "500" + settle_time = 0.3 + status = preamp.sensitivity_unit.get = mock.MagicMock(return_value=gain_unit) + status = preamp.sensitivity_value.get = mock.MagicMock(return_value=gain_value) + # Set the sensitivity based on value + status = preamp.gain_mode.set("LOW DRIFT") + # Check that the EpicsSignal's ``set`` was called with correct settle_time + mocked_setter.assert_called_with("LOW DRIFT", timeout=DEFAULT_WRITE_TIMEOUT, settle_time=settle_time) + From c8d6eecdf6eb90c74e390755fd156853558b05bf Mon Sep 17 00:00:00 2001 From: Mark Wolfman Date: Fri, 12 Jan 2024 14:49:06 -0600 Subject: [PATCH 02/11] Split the SRS-570 GainSignal into a signal and a mixin. --- apstools/devices/srs570_preamplifier.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/apstools/devices/srs570_preamplifier.py b/apstools/devices/srs570_preamplifier.py index 6a9baabcf..092c1383b 100644 --- a/apstools/devices/srs570_preamplifier.py +++ b/apstools/devices/srs570_preamplifier.py @@ -98,7 +98,7 @@ ) -class GainSignal(EpicsSignal): +class GainMixin(): """A signal where the settling time depends on the pre-amp gain. Used to introduce a specific settle time when setting to account @@ -179,6 +179,15 @@ def set(self, value, *, timeout=DEFAULT_WRITE_TIMEOUT, settle_time="auto"): return super().set(value, timeout=timeout, settle_time=_settle_time) +class GainSignal(GainMixin, EpicsSignal): + """A signal where the settling time depends on the pre-amp gain. + + Used to introduce a specific settle time when setting to account + for the amp's R–C relaxation time when changing gain. + + """ + + class SRS570_PreAmplifier(PreamplifierBaseDevice): """ Ophyd support for Stanford Research Systems 570 preamplifier from synApps. From f1e6bab5b7a6ff862f02a8af7182f1d53ae01006 Mon Sep 17 00:00:00 2001 From: Mark Wolfman Date: Wed, 17 Jan 2024 15:51:48 -0600 Subject: [PATCH 03/11] Black formatting. --- apstools/devices/srs570_preamplifier.py | 3 ++- apstools/devices/tests/test_srs570_preamplifier.py | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apstools/devices/srs570_preamplifier.py b/apstools/devices/srs570_preamplifier.py index 092c1383b..6e0f28325 100644 --- a/apstools/devices/srs570_preamplifier.py +++ b/apstools/devices/srs570_preamplifier.py @@ -98,13 +98,14 @@ ) -class GainMixin(): +class GainMixin: """A signal where the settling time depends on the pre-amp gain. Used to introduce a specific settle time when setting to account for the amp's R–C relaxation time when changing gain. """ + @staticmethod def _settle_time(gain_value: int, gain_unit: int, gain_mode: str): """Determine the best settle time for a given combination of parameters. diff --git a/apstools/devices/tests/test_srs570_preamplifier.py b/apstools/devices/tests/test_srs570_preamplifier.py index 115250c0f..ee1b9cffc 100644 --- a/apstools/devices/tests/test_srs570_preamplifier.py +++ b/apstools/devices/tests/test_srs570_preamplifier.py @@ -146,4 +146,3 @@ def test_preamp_gain_mode_settling(mocked_setter): status = preamp.gain_mode.set("LOW DRIFT") # Check that the EpicsSignal's ``set`` was called with correct settle_time mocked_setter.assert_called_with("LOW DRIFT", timeout=DEFAULT_WRITE_TIMEOUT, settle_time=settle_time) - From 735b13e6d8f719126ee635cb98f0152f4d9c9490 Mon Sep 17 00:00:00 2001 From: Mark Wolfman Date: Wed, 17 Jan 2024 20:13:04 -0600 Subject: [PATCH 04/11] Calculation for preamp gain settling time is now a separate function. --- apstools/devices/srs570_preamplifier.py | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/apstools/devices/srs570_preamplifier.py b/apstools/devices/srs570_preamplifier.py index 6e0f28325..841f60a6d 100644 --- a/apstools/devices/srs570_preamplifier.py +++ b/apstools/devices/srs570_preamplifier.py @@ -98,16 +98,7 @@ ) -class GainMixin: - """A signal where the settling time depends on the pre-amp gain. - - Used to introduce a specific settle time when setting to account - for the amp's R–C relaxation time when changing gain. - - """ - - @staticmethod - def _settle_time(gain_value: int, gain_unit: int, gain_mode: str): +def calculate_settle_time(gain_value: int, gain_unit: int, gain_mode: str): """Determine the best settle time for a given combination of parameters. Parameters can be strings of indexes. @@ -129,6 +120,17 @@ def _settle_time(gain_value: int, gain_unit: int, gain_mode: str): # Get calibrated settle time, or None to use the Ophyd default return settling_times.get((gain_value, gain_unit, gain_mode)) + +class GainMixin: + """A signal where the settling time depends on the pre-amp gain. + + Used to introduce a specific settle time when setting to account + for the amp's R–C relaxation time when changing gain. + + """ + + _settle_time = staticmethod(calculate_settle_time) + def set(self, value, *, timeout=DEFAULT_WRITE_TIMEOUT, settle_time="auto"): """Set the value of the Signal and return a Status object. From b12d6f65728b5eb00715777f7bf3343aee1e0e4c Mon Sep 17 00:00:00 2001 From: Sector 25 ID-C User Date: Thu, 18 Jan 2024 10:54:33 -0600 Subject: [PATCH 05/11] Updated the preamp gain settle times based on beamline testing. --- apstools/devices/srs570_preamplifier.py | 118 ++++++++++++------------ 1 file changed, 58 insertions(+), 60 deletions(-) diff --git a/apstools/devices/srs570_preamplifier.py b/apstools/devices/srs570_preamplifier.py index 841f60a6d..7e74799a7 100644 --- a/apstools/devices/srs570_preamplifier.py +++ b/apstools/devices/srs570_preamplifier.py @@ -36,89 +36,87 @@ # (sensitivity_value, sensitivity_unit, gain_mode): settle_time settling_times = { # pA/V - ("1", "pA/V", "HIGH BW"): 2, - ("2", "pA/V", "HIGH BW"): 1.75, - ("5", "pA/V", "HIGH BW"): 1.5, + ("1", "pA/V", "HIGH BW"): 3, + ("2", "pA/V", "HIGH BW"): 2.5, + ("5", "pA/V", "HIGH BW"): 2, ("10", "pA/V", "HIGH BW"): 0.75, - ("20", "pA/V", "HIGH BW"): 0.3, - ("50", "pA/V", "HIGH BW"): 0.3, - ("100", "pA/V", "HIGH BW"): 0.3, - ("200", "pA/V", "HIGH BW"): 0.2, - ("500", "pA/V", "HIGH BW"): 0.2, - ("1", "pA/V", "LOW NOISE"): 2.0, - ("2", "pA/V", "LOW NOISE"): 1.75, - ("5", "pA/V", "LOW NOISE"): 1.5, - ("10", "pA/V", "LOW NOISE"): 1.25, - ("20", "pA/V", "LOW NOISE"): 1.0, - ("50", "pA/V", "LOW NOISE"): 1.0, - ("100", "pA/V", "LOW NOISE"): 1.0, - ("200", "pA/V", "LOW NOISE"): 0.3, - ("500", "pA/V", "LOW NOISE"): 0.3, + ("20", "pA/V", "HIGH BW"): 0.75, + ("50", "pA/V", "HIGH BW"): 0.75, + ("100", "pA/V", "HIGH BW"): 0.75, + ("200", "pA/V", "HIGH BW"): 0.75, + ("500", "pA/V", "HIGH BW"): 0.75, + ("1", "pA/V", "LOW NOISE"): 3.0, + ("2", "pA/V", "LOW NOISE"): 2.5, + ("5", "pA/V", "LOW NOISE"): 2.0, + ("10", "pA/V", "LOW NOISE"): 2.0, + ("20", "pA/V", "LOW NOISE"): 1.75, + ("50", "pA/V", "LOW NOISE"): 1.5, + ("100", "pA/V", "LOW NOISE"): 1.25, + ("200", "pA/V", "LOW NOISE"): 0.75, + ("500", "pA/V", "LOW NOISE"): 0.75, + # nA/V + ("1", "nA/V", "HIGH BW"): 0.75, + ("2", "nA/V", "HIGH BW"): 0.75, + ("5", "nA/V", "HIGH BW"): 0.75, + ("10", "nA/V", "HIGH BW"): 0.75, + ("20", "nA/V", "HIGH BW"): 0.75, + ("50", "nA/V", "HIGH BW"): 0.75, + ("100", "nA/V", "HIGH BW"): 0.5, + ("200", "nA/V", "HIGH BW"): 0.5, + ("500", "nA/V", "HIGH BW"): 0.5, + ("1", "nA/V", "LOW NOISE"): 0.75, + ("2", "nA/V", "LOW NOISE"): 0.75, + ("5", "nA/V", "LOW NOISE"): 0.75, + ("10", "nA/V", "LOW NOISE"): 0.75, + ("20", "nA/V", "LOW NOISE"): 0.5, + ("50", "nA/V", "LOW NOISE"): 0.5, + ("100", "nA/V", "LOW NOISE"): 0.5, + ("200", "nA/V", "LOW NOISE"): 0.5, + ("500", "nA/V", "LOW NOISE"): 0.5, } -settling_times.update( - { - # nA/V - (gain_values[idx], "nA/V", "HIGH BW"): 0.2 - for idx in range(9) - } -) -settling_times.update( - { - # nA/V - ("1", "nA/V", "LOW NOISE"): 0.3, - ("2", "nA/V", "LOW NOISE"): 0.2, - ("5", "nA/V", "LOW NOISE"): 0.2, - ("10", "nA/V", "LOW NOISE"): 0.2, - ("20", "nA/V", "LOW NOISE"): 0.2, - ("50", "nA/V", "LOW NOISE"): 0.2, - ("100", "nA/V", "LOW NOISE"): 0.2, - ("200", "nA/V", "LOW NOISE"): 0.2, - ("500", "nA/V", "LOW NOISE"): 0.2, - } -) settling_times.update( { # μA/V, high bandwidth - (gain_values[idx], "uA/V", "HIGH BW"): 0.15 + (gain_values[idx], "uA/V", "HIGH BW"): 0.5 for idx in range(9) } ) settling_times.update( { # μA/V, low noise - (gain_values[idx], "uA/V", "LOW NOISE"): 0.15 + (gain_values[idx], "uA/V", "LOW NOISE"): 0.5 for idx in range(9) } ) settling_times.update( { - ("1", "mA/V", "HIGH BW"): 0.15, - ("1", "mA/V", "LOW NOISE"): 0.15, + ("1", "mA/V", "HIGH BW"): 0.5, + ("1", "mA/V", "LOW NOISE"): 0.5, } ) def calculate_settle_time(gain_value: int, gain_unit: int, gain_mode: str): - """Determine the best settle time for a given combination of parameters. + """Determine the best settle time for a given combination of parameters. - Parameters can be strings of indexes. + Parameters can be strings of indexes. - """ - # Convert indexes to string values - try: - gain_value = gain_values[gain_value] - except (TypeError, IndexError): - pass - try: - gain_unit = gain_units[gain_unit] - except (TypeError, IndexError): - pass - try: - gain_mode = gain_modes[gain_mode] - except (TypeError, IndexError): - pass - # Get calibrated settle time, or None to use the Ophyd default - return settling_times.get((gain_value, gain_unit, gain_mode)) + """ + # Convert indexes to string values + try: + gain_value = gain_values[gain_value] + except (TypeError, IndexError): + pass + try: + gain_unit = gain_units[gain_unit] + except (TypeError, IndexError): + pass + try: + gain_mode = gain_modes[gain_mode] + except (TypeError, IndexError): + pass + # Get calibrated settle time, or None to use the Ophyd default + return settling_times.get((gain_value, gain_unit, gain_mode)) class GainMixin: From cb653c9bc79153d16f806edba398a41478b37424 Mon Sep 17 00:00:00 2001 From: Sector 25 ID-C User Date: Thu, 18 Jan 2024 14:39:49 -0600 Subject: [PATCH 06/11] More updates to the preamp settling times. --- apstools/devices/srs570_preamplifier.py | 64 ++++++++++++------------- 1 file changed, 30 insertions(+), 34 deletions(-) diff --git a/apstools/devices/srs570_preamplifier.py b/apstools/devices/srs570_preamplifier.py index 7e74799a7..96a450db9 100644 --- a/apstools/devices/srs570_preamplifier.py +++ b/apstools/devices/srs570_preamplifier.py @@ -36,15 +36,16 @@ # (sensitivity_value, sensitivity_unit, gain_mode): settle_time settling_times = { # pA/V - ("1", "pA/V", "HIGH BW"): 3, - ("2", "pA/V", "HIGH BW"): 2.5, - ("5", "pA/V", "HIGH BW"): 2, - ("10", "pA/V", "HIGH BW"): 0.75, - ("20", "pA/V", "HIGH BW"): 0.75, - ("50", "pA/V", "HIGH BW"): 0.75, - ("100", "pA/V", "HIGH BW"): 0.75, - ("200", "pA/V", "HIGH BW"): 0.75, - ("500", "pA/V", "HIGH BW"): 0.75, + ("1", "pA/V", "HIGH BW"): 2.5, + ("2", "pA/V", "HIGH BW"): 2, + ("5", "pA/V", "HIGH BW"): 2., + ("10", "pA/V", "HIGH BW"): 0.5, + ("20", "pA/V", "HIGH BW"): 0.5, + ("50", "pA/V", "HIGH BW"): 0.5, + ("100", "pA/V", "HIGH BW"): 0.5, + ("200", "pA/V", "HIGH BW"): 0.3, + ("500", "pA/V", "HIGH BW"): 0.3, + ("1", "pA/V", "LOW NOISE"): 3.0, ("2", "pA/V", "LOW NOISE"): 2.5, ("5", "pA/V", "LOW NOISE"): 2.0, @@ -52,46 +53,41 @@ ("20", "pA/V", "LOW NOISE"): 1.75, ("50", "pA/V", "LOW NOISE"): 1.5, ("100", "pA/V", "LOW NOISE"): 1.25, - ("200", "pA/V", "LOW NOISE"): 0.75, - ("500", "pA/V", "LOW NOISE"): 0.75, - # nA/V - ("1", "nA/V", "HIGH BW"): 0.75, - ("2", "nA/V", "HIGH BW"): 0.75, - ("5", "nA/V", "HIGH BW"): 0.75, - ("10", "nA/V", "HIGH BW"): 0.75, - ("20", "nA/V", "HIGH BW"): 0.75, - ("50", "nA/V", "HIGH BW"): 0.75, - ("100", "nA/V", "HIGH BW"): 0.5, - ("200", "nA/V", "HIGH BW"): 0.5, - ("500", "nA/V", "HIGH BW"): 0.5, - ("1", "nA/V", "LOW NOISE"): 0.75, - ("2", "nA/V", "LOW NOISE"): 0.75, - ("5", "nA/V", "LOW NOISE"): 0.75, - ("10", "nA/V", "LOW NOISE"): 0.75, - ("20", "nA/V", "LOW NOISE"): 0.5, - ("50", "nA/V", "LOW NOISE"): 0.5, - ("100", "nA/V", "LOW NOISE"): 0.5, - ("200", "nA/V", "LOW NOISE"): 0.5, - ("500", "nA/V", "LOW NOISE"): 0.5, + ("200", "pA/V", "LOW NOISE"): 0.5, + ("500", "pA/V", "LOW NOISE"): 0.5, } +settling_times.update( + { + # nA/V, high bandwidth + (gain_values[idx], "nA/V", "HIGH BW"): 0.3 + for idx in range(9) + } +) +settling_times.update( + { + # nA/V, low noise + (gain_values[idx], "nA/V", "HIGH BW"): 0.3 + for idx in range(9) + } +) settling_times.update( { # μA/V, high bandwidth - (gain_values[idx], "uA/V", "HIGH BW"): 0.5 + (gain_values[idx], "uA/V", "HIGH BW"): 0.3 for idx in range(9) } ) settling_times.update( { # μA/V, low noise - (gain_values[idx], "uA/V", "LOW NOISE"): 0.5 + (gain_values[idx], "uA/V", "LOW NOISE"): 0.3 for idx in range(9) } ) settling_times.update( { - ("1", "mA/V", "HIGH BW"): 0.5, - ("1", "mA/V", "LOW NOISE"): 0.5, + ("1", "mA/V", "HIGH BW"): 0.3, + ("1", "mA/V", "LOW NOISE"): 0.3, } ) From 007bf4d91ae063733043602d9ab1f54d82a18fd0 Mon Sep 17 00:00:00 2001 From: Mark Wolfman Date: Thu, 18 Jan 2024 15:38:38 -0600 Subject: [PATCH 07/11] Fixed tests for new preamp settling times. --- apstools/devices/srs570_preamplifier.py | 5 +- .../devices/tests/test_srs570_preamplifier.py | 112 +++++++++--------- 2 files changed, 58 insertions(+), 59 deletions(-) diff --git a/apstools/devices/srs570_preamplifier.py b/apstools/devices/srs570_preamplifier.py index 96a450db9..aca009ddb 100644 --- a/apstools/devices/srs570_preamplifier.py +++ b/apstools/devices/srs570_preamplifier.py @@ -38,14 +38,13 @@ # pA/V ("1", "pA/V", "HIGH BW"): 2.5, ("2", "pA/V", "HIGH BW"): 2, - ("5", "pA/V", "HIGH BW"): 2., + ("5", "pA/V", "HIGH BW"): 2.0, ("10", "pA/V", "HIGH BW"): 0.5, ("20", "pA/V", "HIGH BW"): 0.5, ("50", "pA/V", "HIGH BW"): 0.5, ("100", "pA/V", "HIGH BW"): 0.5, ("200", "pA/V", "HIGH BW"): 0.3, ("500", "pA/V", "HIGH BW"): 0.3, - ("1", "pA/V", "LOW NOISE"): 3.0, ("2", "pA/V", "LOW NOISE"): 2.5, ("5", "pA/V", "LOW NOISE"): 2.0, @@ -66,7 +65,7 @@ settling_times.update( { # nA/V, low noise - (gain_values[idx], "nA/V", "HIGH BW"): 0.3 + (gain_values[idx], "nA/V", "LOW NOISE"): 0.3 for idx in range(9) } ) diff --git a/apstools/devices/tests/test_srs570_preamplifier.py b/apstools/devices/tests/test_srs570_preamplifier.py index ee1b9cffc..f6dee28df 100644 --- a/apstools/devices/tests/test_srs570_preamplifier.py +++ b/apstools/devices/tests/test_srs570_preamplifier.py @@ -7,37 +7,37 @@ settling_times = { # (sensitivity_value, sensitivity_unit, gain_mode): settle_time # pA/V - (0, 0, "HIGH BW"): 2, - (1, 0, "HIGH BW"): 1.75, - (2, 0, "HIGH BW"): 1.5, - (3, 0, "HIGH BW"): 0.75, - (4, 0, "HIGH BW"): 0.3, - (5, 0, "HIGH BW"): 0.3, - (6, 0, "HIGH BW"): 0.3, - (7, 0, "HIGH BW"): 0.2, - (8, 0, "HIGH BW"): 0.2, + (0, 0, "HIGH BW"): 2.5, + (1, 0, "HIGH BW"): 2.0, + (2, 0, "HIGH BW"): 2.0, + (3, 0, "HIGH BW"): 0.5, + (4, 0, "HIGH BW"): 0.5, + (5, 0, "HIGH BW"): 0.5, + (6, 0, "HIGH BW"): 0.5, + (7, 0, "HIGH BW"): 0.3, + (8, 0, "HIGH BW"): 0.3, # nA/V - (0, 1, "HIGH BW"): 0.2, - (1, 1, "HIGH BW"): 0.2, - (2, 1, "HIGH BW"): 0.2, - (3, 1, "HIGH BW"): 0.2, - (4, 1, "HIGH BW"): 0.2, - (5, 1, "HIGH BW"): 0.2, - (6, 1, "HIGH BW"): 0.2, - (7, 1, "HIGH BW"): 0.2, - (8, 1, "HIGH BW"): 0.2, + (0, 1, "HIGH BW"): 0.3, + (1, 1, "HIGH BW"): 0.3, + (2, 1, "HIGH BW"): 0.3, + (3, 1, "HIGH BW"): 0.3, + (4, 1, "HIGH BW"): 0.3, + (5, 1, "HIGH BW"): 0.3, + (6, 1, "HIGH BW"): 0.3, + (7, 1, "HIGH BW"): 0.3, + (8, 1, "HIGH BW"): 0.3, # μA/V - (0, 2, "HIGH BW"): 0.15, - (1, 2, "HIGH BW"): 0.15, - (2, 2, "HIGH BW"): 0.15, - (3, 2, "HIGH BW"): 0.15, - (4, 2, "HIGH BW"): 0.15, - (5, 2, "HIGH BW"): 0.15, - (6, 2, "HIGH BW"): 0.15, - (7, 2, "HIGH BW"): 0.15, - (8, 2, "HIGH BW"): 0.15, + (0, 2, "HIGH BW"): 0.3, + (1, 2, "HIGH BW"): 0.3, + (2, 2, "HIGH BW"): 0.3, + (3, 2, "HIGH BW"): 0.3, + (4, 2, "HIGH BW"): 0.3, + (5, 2, "HIGH BW"): 0.3, + (6, 2, "HIGH BW"): 0.3, + (7, 2, "HIGH BW"): 0.3, + (8, 2, "HIGH BW"): 0.3, # mA/V - (0, 3, "HIGH BW"): 0.15, + (0, 3, "HIGH BW"): 0.3, (1, 3, "HIGH BW"): None, (2, 3, "HIGH BW"): None, (3, 3, "HIGH BW"): None, @@ -47,37 +47,37 @@ (7, 3, "HIGH BW"): None, (8, 3, "HIGH BW"): None, # pA/V - (0, 0, "LOW NOISE"): 2.0, - (1, 0, "LOW NOISE"): 1.75, - (2, 0, "LOW NOISE"): 1.5, - (3, 0, "LOW NOISE"): 1.25, - (4, 0, "LOW NOISE"): 1.0, - (5, 0, "LOW NOISE"): 1.0, - (6, 0, "LOW NOISE"): 1.0, - (7, 0, "LOW NOISE"): 0.3, - (8, 0, "LOW NOISE"): 0.3, + (0, 0, "LOW NOISE"): 3.0, + (1, 0, "LOW NOISE"): 2.5, + (2, 0, "LOW NOISE"): 2.0, + (3, 0, "LOW NOISE"): 2.0, + (4, 0, "LOW NOISE"): 1.75, + (5, 0, "LOW NOISE"): 1.5, + (6, 0, "LOW NOISE"): 1.25, + (7, 0, "LOW NOISE"): 0.5, + (8, 0, "LOW NOISE"): 0.5, # nA/V (0, 1, "LOW NOISE"): 0.3, - (1, 1, "LOW NOISE"): 0.2, - (2, 1, "LOW NOISE"): 0.2, - (3, 1, "LOW NOISE"): 0.2, - (4, 1, "LOW NOISE"): 0.2, - (5, 1, "LOW NOISE"): 0.2, - (6, 1, "LOW NOISE"): 0.2, - (7, 1, "LOW NOISE"): 0.2, - (8, 1, "LOW NOISE"): 0.2, + (1, 1, "LOW NOISE"): 0.3, + (2, 1, "LOW NOISE"): 0.3, + (3, 1, "LOW NOISE"): 0.3, + (4, 1, "LOW NOISE"): 0.3, + (5, 1, "LOW NOISE"): 0.3, + (6, 1, "LOW NOISE"): 0.3, + (7, 1, "LOW NOISE"): 0.3, + (8, 1, "LOW NOISE"): 0.3, # μA/V - (0, 2, "LOW NOISE"): 0.15, - (1, 2, "LOW NOISE"): 0.15, - (2, 2, "LOW NOISE"): 0.15, - (3, 2, "LOW NOISE"): 0.15, - (4, 2, "LOW NOISE"): 0.15, - (5, 2, "LOW NOISE"): 0.15, - (6, 2, "LOW NOISE"): 0.15, - (7, 2, "LOW NOISE"): 0.15, - (8, 2, "LOW NOISE"): 0.15, + (0, 2, "LOW NOISE"): 0.3, + (1, 2, "LOW NOISE"): 0.3, + (2, 2, "LOW NOISE"): 0.3, + (3, 2, "LOW NOISE"): 0.3, + (4, 2, "LOW NOISE"): 0.3, + (5, 2, "LOW NOISE"): 0.3, + (6, 2, "LOW NOISE"): 0.3, + (7, 2, "LOW NOISE"): 0.3, + (8, 2, "LOW NOISE"): 0.3, # mA/V - (0, 3, "LOW NOISE"): 0.15, + (0, 3, "LOW NOISE"): 0.3, (1, 3, "LOW NOISE"): None, (2, 3, "LOW NOISE"): None, (3, 3, "LOW NOISE"): None, @@ -139,7 +139,7 @@ def test_preamp_gain_mode_settling(mocked_setter): preamp = SRS570_PreAmplifier("prefix:", name="preamp") gain_unit = "pA/V" gain_value = "500" - settle_time = 0.3 + settle_time = 0.5 status = preamp.sensitivity_unit.get = mock.MagicMock(return_value=gain_unit) status = preamp.sensitivity_value.get = mock.MagicMock(return_value=gain_value) # Set the sensitivity based on value From b9f6b8759a5face44e5e106a7b8c3e2d02c87e2a Mon Sep 17 00:00:00 2001 From: Mark Wolfman Date: Thu, 18 Jan 2024 15:43:55 -0600 Subject: [PATCH 08/11] Fixed flake8 issues. --- apstools/devices/tests/test_srs570_preamplifier.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/apstools/devices/tests/test_srs570_preamplifier.py b/apstools/devices/tests/test_srs570_preamplifier.py index f6dee28df..c850fc86a 100644 --- a/apstools/devices/tests/test_srs570_preamplifier.py +++ b/apstools/devices/tests/test_srs570_preamplifier.py @@ -116,16 +116,16 @@ def test_preamp_gain_settling(mocked_setter, gain_value, gain_unit, gain_mode): preamp = SRS570_PreAmplifier("prefix:", name="preamp") assert isinstance(preamp.sensitivity_unit, GainSignal) assert isinstance(preamp.sensitivity_value, GainSignal) - status = preamp.sensitivity_unit.get = mock.MagicMock(return_value=gain_unit) - status = preamp.gain_mode.get = mock.MagicMock(return_value=gain_mode) + preamp.sensitivity_unit.get = mock.MagicMock(return_value=gain_unit) + preamp.gain_mode.get = mock.MagicMock(return_value=gain_mode) # Set the sensitivity based on value - status = preamp.sensitivity_value.set(gain_value) + preamp.sensitivity_value.set(gain_value) # Check that the EpicsSignal's ``set`` was called with correct settle_time mocked_setter.assert_called_with(gain_value, timeout=DEFAULT_WRITE_TIMEOUT, settle_time=settle_time) # Set the sensitivity based on value mocked_setter.reset_mock() assert not mocked_setter.called - status = preamp.sensitivity_value.set(value_idx) + preamp.sensitivity_value.set(value_idx) # Check that the EpicsSignal's ``set`` was called with correct settle_time mocked_setter.assert_called_with(value_idx, timeout=DEFAULT_WRITE_TIMEOUT, settle_time=settle_time) @@ -140,9 +140,9 @@ def test_preamp_gain_mode_settling(mocked_setter): gain_unit = "pA/V" gain_value = "500" settle_time = 0.5 - status = preamp.sensitivity_unit.get = mock.MagicMock(return_value=gain_unit) - status = preamp.sensitivity_value.get = mock.MagicMock(return_value=gain_value) + preamp.sensitivity_unit.get = mock.MagicMock(return_value=gain_unit) + preamp.sensitivity_value.get = mock.MagicMock(return_value=gain_value) # Set the sensitivity based on value - status = preamp.gain_mode.set("LOW DRIFT") + preamp.gain_mode.set("LOW DRIFT") # Check that the EpicsSignal's ``set`` was called with correct settle_time mocked_setter.assert_called_with("LOW DRIFT", timeout=DEFAULT_WRITE_TIMEOUT, settle_time=settle_time) From 7eca36f568767ea81cdc983477047127a6def798 Mon Sep 17 00:00:00 2001 From: Mark Wolfman Date: Sat, 20 Jan 2024 13:59:05 -0600 Subject: [PATCH 09/11] Update apstools/devices/tests/test_srs570_preamplifier.py Co-authored-by: Pete R Jemian --- apstools/devices/tests/test_srs570_preamplifier.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apstools/devices/tests/test_srs570_preamplifier.py b/apstools/devices/tests/test_srs570_preamplifier.py index c850fc86a..95a9d434c 100644 --- a/apstools/devices/tests/test_srs570_preamplifier.py +++ b/apstools/devices/tests/test_srs570_preamplifier.py @@ -1,7 +1,7 @@ import pytest from unittest import mock -from apstools.devices.srs570_preamplifier import SRS570_PreAmplifier, GainSignal, DEFAULT_WRITE_TIMEOUT +from ..srs570_preamplifier import SRS570_PreAmplifier, GainSignal, DEFAULT_WRITE_TIMEOUT # Known settling times measured from the I0 SR-570 at 25-ID-C settling_times = { From b26b8a1d4b42f10f30735e876337e0c50b649497 Mon Sep 17 00:00:00 2001 From: Mark Wolfman Date: Tue, 23 Jan 2024 08:54:00 -0600 Subject: [PATCH 10/11] Added some comments to the SRS-570 tests. --- apstools/devices/tests/test_srs570_preamplifier.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/apstools/devices/tests/test_srs570_preamplifier.py b/apstools/devices/tests/test_srs570_preamplifier.py index 95a9d434c..2c52955d4 100644 --- a/apstools/devices/tests/test_srs570_preamplifier.py +++ b/apstools/devices/tests/test_srs570_preamplifier.py @@ -7,34 +7,34 @@ settling_times = { # (sensitivity_value, sensitivity_unit, gain_mode): settle_time # pA/V - (0, 0, "HIGH BW"): 2.5, + (0, 0, "HIGH BW"): 2.5, # 1 pA/V (1, 0, "HIGH BW"): 2.0, (2, 0, "HIGH BW"): 2.0, (3, 0, "HIGH BW"): 0.5, (4, 0, "HIGH BW"): 0.5, - (5, 0, "HIGH BW"): 0.5, + (5, 0, "HIGH BW"): 0.5, # 50 pA/V (6, 0, "HIGH BW"): 0.5, (7, 0, "HIGH BW"): 0.3, (8, 0, "HIGH BW"): 0.3, # nA/V (0, 1, "HIGH BW"): 0.3, - (1, 1, "HIGH BW"): 0.3, + (1, 1, "HIGH BW"): 0.3, # 2 nA/V (2, 1, "HIGH BW"): 0.3, (3, 1, "HIGH BW"): 0.3, (4, 1, "HIGH BW"): 0.3, (5, 1, "HIGH BW"): 0.3, - (6, 1, "HIGH BW"): 0.3, + (6, 1, "HIGH BW"): 0.3, # 100 nA/V (7, 1, "HIGH BW"): 0.3, (8, 1, "HIGH BW"): 0.3, # μA/V (0, 2, "HIGH BW"): 0.3, (1, 2, "HIGH BW"): 0.3, - (2, 2, "HIGH BW"): 0.3, + (2, 2, "HIGH BW"): 0.3, # 5 μA/V (3, 2, "HIGH BW"): 0.3, (4, 2, "HIGH BW"): 0.3, (5, 2, "HIGH BW"): 0.3, (6, 2, "HIGH BW"): 0.3, - (7, 2, "HIGH BW"): 0.3, + (7, 2, "HIGH BW"): 0.3, # 200 μA/V (8, 2, "HIGH BW"): 0.3, # mA/V (0, 3, "HIGH BW"): 0.3, From dc5bdc24dfcb2729d8f4e491ce59302f274211e6 Mon Sep 17 00:00:00 2001 From: Mark Wolfman Date: Tue, 23 Jan 2024 08:58:09 -0600 Subject: [PATCH 11/11] Removed SR-570 gain mixin class and just rolled everything up into GainSignal. --- apstools/devices/srs570_preamplifier.py | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/apstools/devices/srs570_preamplifier.py b/apstools/devices/srs570_preamplifier.py index aca009ddb..6d4912ef1 100644 --- a/apstools/devices/srs570_preamplifier.py +++ b/apstools/devices/srs570_preamplifier.py @@ -114,7 +114,7 @@ def calculate_settle_time(gain_value: int, gain_unit: int, gain_mode: str): return settling_times.get((gain_value, gain_unit, gain_mode)) -class GainMixin: +class GainSignal(EpicsSignal): """A signal where the settling time depends on the pre-amp gain. Used to introduce a specific settle time when setting to account @@ -122,8 +122,6 @@ class GainMixin: """ - _settle_time = staticmethod(calculate_settle_time) - def set(self, value, *, timeout=DEFAULT_WRITE_TIMEOUT, settle_time="auto"): """Set the value of the Signal and return a Status object. @@ -169,21 +167,12 @@ def set(self, value, *, timeout=DEFAULT_WRITE_TIMEOUT, settle_time="auto"): if mode == "LOW DRIFT": mode = "LOW NOISE" # Calculate settling time - _settle_time = self._settle_time(gain_value=val, gain_unit=unit, gain_mode=mode) + _settle_time = calculate_settle_time(gain_value=val, gain_unit=unit, gain_mode=mode) else: _settle_time = settle_time return super().set(value, timeout=timeout, settle_time=_settle_time) -class GainSignal(GainMixin, EpicsSignal): - """A signal where the settling time depends on the pre-amp gain. - - Used to introduce a specific settle time when setting to account - for the amp's R–C relaxation time when changing gain. - - """ - - class SRS570_PreAmplifier(PreamplifierBaseDevice): """ Ophyd support for Stanford Research Systems 570 preamplifier from synApps.