1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
|
#
# This file is part of the PyMeasure package.
#
# Copyright (c) 2013-2024 PyMeasure Developers
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
import math
import re
import logging
from pymeasure.instruments import Instrument
from pymeasure.instruments.validators import strict_range
log = logging.getLogger(__name__)
class AH2500A(Instrument):
""" Andeen Hagerling 2500A Precision Capacitance Bridge implementation
"""
# regular expression to extract measurement values
_reclv = re.compile(
r"[FHZ0-9.=\s]*C=\s*(-?[0-9.]+)\s*PF L=\s*(-?[0-9.]+)\s*NS V=\s*(-?[0-9.]+)\s*V")
_renumeric = re.compile(r'[-+]?(\d*\.?\d+)')
def __init__(self, adapter, name=None, timeout=3000,
write_termination="\n", read_termination="\n",
**kwargs):
super().__init__(
adapter,
name or "Andeen Hagerling 2500A Precision Capacitance Bridge",
write_termination=write_termination,
read_termination=read_termination,
timeout=timeout,
includeSCPI=False,
**kwargs
)
self._triggered = False
config = Instrument.measurement(
"SHOW",
"""Get the configuration.""",
)
caplossvolt = Instrument.measurement(
"Q",
"""Get the result of a single capacitance, loss measurement and return the
values in units of pF and nS. The used measurement voltage is returned
as third value.""",
# lambda function is needed here since AH2500A is otherwise undefined
get_process=lambda v: AH2500A._parse_reply(v),
)
vhighest = Instrument.control(
"SH V", "V %.4f",
"""Control maximum RMS value of the used measurement voltage. Values of up to
15 V are allowed. The device will select the best suiting range below
the given value.""",
validator=strict_range,
values=[0, 15],
# typical replies: "VOLTAGE HIGHEST= 15.0 V" or
# "VOLTAGE HIGHEST 1.00 V"
get_process=lambda v: float(AH2500A._renumeric.search(v).group(0)),
)
@classmethod
def _parse_reply(cls, string):
"""
parse reply string from Andeen Hagerling capacitance bridges.
:param string: reply string from the instrument. This commonly is:
2500A:
"C= 1.234567 PF L= 0.000014 NS V= 0.750 V"
2700A:
"F= 1000.00 HZ C= 4.20188 PF L=-0.0260 NS V= 15.0 V"
:returns: tuple with C, L, V values
"""
m = cls._reclv.match(string)
if m is not None:
values = tuple(map(float, m.groups()))
return values
# if an invalid string is returned ('EXCESS NOISE')
if string.strip() == "EXCESS NOISE":
log.warning("Excess noise, check your experiment setup")
return (math.nan, math.nan, math.nan)
else: # some unknown return string (e.g. misconfigured units)
raise Exception(f'Returned string "{string}" could not be parsed')
def trigger(self):
"""
Triggers a new measurement without blocking and waiting for the return
value.
"""
self.write("TRG")
self._triggered = True
def triggered_caplossvolt(self):
"""
reads the measurement value after the device was triggered by the
trigger function.
"""
if not self._triggered:
log.warning(
"Device not triggered, trigger manually for better timing")
self.trigger()
self._triggered = False
return AH2500A._parse_reply(self.read())
|