def derivative(self, src, vscale=1e6, voffset=0, autoscale=True): """ Derivative of waveform using subtraction of adjacent samples. If vscale and voffset are unitless, V/s are assumed. :param int,tuple src: Source, see info above :param float vscale: vertical units to display (V/s) :param float voffset: vertical offset (V/s) :param bool autoscale: auto scaling of vscale, voffset? """ src_str = _source(src) vscale = assume_units(vscale, u.V/u.s).rescale( u.V/u.s ).magnitude voffset = assume_units(voffset, u.V/u.s).rescale( u.V/u.s ).magnitude autoscale_str = 'OFF' if autoscale: autoscale_str = 'ON' send_str = "'DERI({})',VERSCALE,{},VEROFFSET,{}," \ "ENABLEAUTOSCALE,{}".format( src_str, vscale, voffset, autoscale_str) self._send_operator(send_str)
def wait_for_motion(self, poll_interval=0.01, max_wait=None): """ Blocks until all movement along this axis is complete, as reported by `~NewportESP301Axis.is_motion_done`. :param float poll_interval: How long (in seconds) to sleep between checking if the motion is complete. :param float max_wait: Maximum amount of time to wait before raising a `IOError`. If `None`, this method will wait indefinitely. """ # FIXME: make sure that the controller is not in # programming mode, or else this might not work. # In programming mode, the "WS" command should be # sent instead, and the two parameters to this method should # be ignored. poll_interval = float(assume_units(position,pq.s).rescale( pq.s).magnitude) max_wait = float(assume_units(position,pq.s).rescale( pq.s).magnitude) tic = time() while True: if self.is_motion_done: return else: if max_wait is None or (time() - tic) < max_wait: sleep(poll_interval) else: raise IOError("Timed out waiting for motion to finish.")
def trend(self, src, vscale=1, center=0, autoscale=True): """ Trend of the values of a paramter :param float vscale: vertical units to display (V) :param float center: center (V) """ src_str = _source(src) vscale = assume_units(vscale, u.V).rescale( u.V ).magnitude center = assume_units(center, u.V).rescale( u.V ).magnitude if autoscale: auto_str = 'ON' else: auto_str = 'OFF' send_str = "'TREND({})',VERSCALE,{},CENTER,{}," \ "AUTOFINDSCALE,{}".format(src_str, vscale, center, auto_str) self._send_operator(send_str)
def integral(self, src, multiplier=1, adder=0, vscale=1e-3, voffset=0): """ Integral of waveform. :param int,tuple src: Source, see info above :param float multiplier: 0 to 1e15 :param float adder: 0 to 1e15 :param float vscale: vertical units to display (Wb) :param float voffset: vertical offset (Wb) """ src_str = _source(src) vscale = assume_units(vscale, u.Wb).rescale( u.Wb ).magnitude voffset = assume_units(voffset, u.Wb).rescale( u.Wb ).magnitude send_str = "'INTG({}),MULTIPLIER,{},ADDER,{},VERSCALE,{}," \ "VEROFFSET,{}".format( src_str, multiplier, adder, vscale, voffset) self._send_operator(send_str)
def wait_for_motion(self, poll_interval=0.01, max_wait=None): """ Blocks until all movement along this axis is complete, as reported by `~NewportESP301Axis.is_motion_done`. :param float poll_interval: How long (in seconds) to sleep between checking if the motion is complete. :param float max_wait: Maximum amount of time to wait before raising a `IOError`. If `None`, this method will wait indefinitely. """ # FIXME: make sure that the controller is not in # programming mode, or else this might not work. # In programming mode, the "WS" command should be # sent instead, and the two parameters to this method should # be ignored. poll_interval = float(assume_units(poll_interval, u.s).rescale( u.s).magnitude) max_wait = float(assume_units(max_wait, u.s).rescale( u.s).magnitude) tic = time() while True: if self.is_motion_done: return else: if max_wait is None or (time() - tic) < max_wait: sleep(poll_interval) else: raise IOError("Timed out waiting for motion to finish.")
def user_offset(self): """Get / Set user offset. The user offset can be set unitful in watts or joules and set to the device. :return: User offset :rtype: u.Quantity :raises ValueError: Unit not supported or value for offset is out of range. Example: >>> import instruments as ik >>> inst = ik.gentec_eo.Blu.open_serial('/dev/ttyACM0') >>> inst.user_offset = 10 >>> inst.user_offset array(10.) * W """ if self._power_mode is None: _ = self.measure_mode # determine the power mode sleep(0.01) if self._power_mode: return assume_units(self._value_query("*GUO", tp=float), u.W) else: return assume_units(self._value_query("*GUO", tp=float), u.J)
def test_assume_units_correct(): m = u.Quantity(1, 'm') # Check that unitful quantities are kept unitful. assert assume_units(m, 'mm').rescale('mm').magnitude == 1000 # Check that raw scalars are made unitful. assert assume_units(1, 'm').rescale('mm').magnitude == 1000
def test_assume_units_correct(): m = pq.Quantity(1, 'm') # Check that unitful quantities are kept unitful. eq_(assume_units(m, 'mm').rescale('mm').magnitude, 1000) # Check that raw scalars are made unitful. eq_(assume_units(1, 'm').rescale('mm').magnitude, 1000)
def window(self, newval): newval_mag = assume_units(newval,pq.ns).rescale(pq.ns).magnitude if newval_mag < 0: raise ValueError("Window is too small.") if newval_mag >7: raise ValueError("Window is too big") self.sendcmd(":WIND {}".format(newval_mag))
def window(self, new_val): new_val_mag = int( assume_units(new_val, pq.ns).rescale(pq.ns).magnitude) if new_val_mag < 0 or new_val_mag > 7: raise ValueError("Window is out of range.") # window must be an integer! self.sendcmd(":WIND {}".format(new_val_mag))
def jog_low_velocity(self, newval): if newval is None: return newval = float( assume_units(newval, self._units / u.s).to(self._units / u.s).magnitude) self._newport_cmd("JW", target=self.axis_id, params=[newval])
def move(self, position, absolute=True, wait=False, block=False): """ :param position: Position to set move to along this axis. :type position: `float` or :class:`~quantities.Quantity` :param bool absolute: If `True`, the position ``pos`` is interpreted as relative to the zero-point of the encoder. If `False`, ``pos`` is interpreted as relative to the current position of this axis. :param bool wait: If True, will tell axis to not execute other commands until movement is finished :param bool block: If True, will block code until movement is finished """ position = float(assume_units(position, self._units).rescale( self._units).magnitude) if absolute: self._newport_cmd("PA", params=[position], target=self.axis_id) else: self._newport_cmd("PR", params=[position], target=self.axis_id) if wait: self.wait_for_position(position) if block: sleep(0.003) mot = self.is_motion_done while not mot: mot = self.is_motion_done
def max_acceleration(self, newval): if newval is None: return newval = float( assume_units(newval, self._units / (pq.s**2)).rescale( self._units / (pq.s**2)).magnitude) self._newport_cmd("AU", target=self.axis_id, params=[newval])
def window(self, newval): newval_mag = assume_units(newval, pq.ns).rescale(pq.ns).magnitude if newval_mag < 0: raise ValueError("Window is too small.") if newval_mag > 7: raise ValueError("Window is too big") self.sendcmd(":WIND {}".format(newval_mag))
def move(self, position, absolute=True,wait=False,block=False): """ :param position: Position to set move to along this axis. :type position: `float` or :class:`~quantities.Quantity` :param bool absolute: If `True`, the position ``pos`` is interpreted as relative to the zero-point of the encoder. If `False`, ``pos`` is interpreted as relative to the current position of this axis. :param bool wait: If True, will tell axis to not execute other commands until movement is finished :param bool block: If True, will block code until movement is finished """ position = float(assume_units(position,self._units).rescale( self._units).magnitude) # TODO: handle unit conversions here. if absolute: self._controller._newport_cmd("PA", params=[position], target=self.axis_id) else: self._controller._newport_cmd("PR", params=[position], target=self.axis_id) if wait: self.wait_for_position(position) if block: sleep(0.003) mot = self.is_motion_done while not mot: mot = self.is_motion_done
def deceleration(self, newval): if newval is None: return newval = float( assume_units(newval, self._units / (u.s**2)).to( self._units / (u.s**2)).magnitude) self._newport_cmd("AG", target=self.axis_id, params=[newval])
def max_voltage(self, newval): newval = assume_units(newval, pq.V).rescale(pq.V).magnitude if newval < 0: raise ValueError("Voltage is too low.") if newval > 25: raise ValueError("Voltage is too high") self.sendcmd("max={}".format(newval))
def frequency(self, newval): newval = assume_units(newval, pq.Hz).rescale(pq.Hz).magnitude if newval < 5: raise ValueError("Frequency is too low.") if newval >150: raise ValueError("Frequency is too high") self.sendcmd("freq={}".format(newval))
def delay(self, new_val): new_val = assume_units(new_val, u.ns).to(u.ns) if new_val < 0*u.ns or new_val > 14*u.ns: raise ValueError("New delay value is out of bounds.") if new_val.magnitude % 2 != 0: raise ValueError("New magnitude must be an even number") self.sendcmd(":DELA "+str(int(new_val.magnitude)))
def delay(self, new_val): new_val = assume_units(new_val, pq.ns).rescale(pq.ns) if new_val < 0*pq.ns or new_val > 14*pq.ns: raise ValueError("New delay value is out of bounds.") if new_val.magnitude % 2 != 0: raise ValueError("New magnitude must be an even number") self.sendcmd(":DELA "+str(int(new_val.magnitude)))
def homing_velocity(self, newval): if newval is None: return newval = float( assume_units(newval, self._units / pq.s).rescale(self._units / pq.s).magnitude) self._newport_cmd("OH", target=self.axis_id, params=[newval])
def full_step_resolution(self, newval): if newval is None: return newval = float(assume_units( newval, self._units ).rescale(self._units).magnitude) self._newport_cmd("FR", target=self.axis_id, params=[newval])
def error_threshold(self, newval): if newval is None: return newval = float(assume_units( newval, self._units ).rescale(self._units).magnitude) self._newport_cmd("FE", target=self.axis_id, params=[newval])
def freq(self, newval): # Rescale the input to millihertz as demanded by the signal # generator, then convert to an integer. newval = int(assume_units(newval, GHz).rescale(mHz).magnitude) # Write the integer to the serial port in ASCII-encoded # uppercase-hexadecimal format, with padding to 12 nybbles. self.sendcmd('0C{:012X}.'.format(newval))
def shut_time(self, newval): newval = int(assume_units(newval, pq.ms).rescale(pq.ms).magnitude) if newval < 0: raise ValueError("Time cannot be negative") if newval > 999999: raise ValueError("Duration is too long") self.sendcmd("shut={}".format(newval)) self.read()
def homing_velocity(self, newval): if newval is None: return newval = float(assume_units( newval, self._units / pq.s ).rescale(self._units / pq.s).magnitude) self._newport_cmd("OH", target=self.axis_id, params=[newval])
def shut_time(self, newval): newval = int(assume_units(newval, pq.ms).rescale(pq.ms).magnitude) if newval < 0: raise ValueError("Time cannot be negative") if newval >999999: raise ValueError("Duration is too long") self.sendcmd("shut={}".format(newval)) self.read()
def frequency(self, newval): # Rescale the input to millihertz as demanded by the signal # generator, then convert to an integer. newval = int(assume_units(newval, GHz).rescale(mHz).magnitude) # Write the integer to the serial port in ASCII-encoded # uppercase-hexadecimal format, with padding to 12 nybbles. self.sendcmd('0C{:012X}.'.format(newval))
def left_limit(self): """ Gets/sets the axis left travel limit :units: The limit in units :type: `~pint.Quantity` or `float` """ return assume_units( float(self._newport_cmd("SL?", target=self.axis_id)), self._units)
def error_threshold(self): """ Gets/sets the axis error threshold :units: units :type: `~quantities.Quantity` or `float` """ return assume_units( float(self._newport_cmd("FE?", target=self.axis_id)), self._units)
def right_limit(self): """ Gets/sets the axis right travel limit :units: units :type: `~quantities.Quantity` or `float` """ return assume_units( float(self._newport_cmd("SR?", target=self.axis_id)), self._units)
def _set_amplitude_(self, magnitude, units): if units == self._mhs.VoltageMode.peak_to_peak or \ units == self._mhs.VoltageMode.rms: magnitude = assume_units(magnitude, "V").rescale(pq.V).magnitude elif units == self._mhs.VoltageMode.dBm: raise NotImplementedError("Decibel units are not supported.") magnitude *= 100 query = ":s{0}a{1}".format(self._chan, int(magnitude)) self._mhs.sendcmd(query)
def load_resistance(self, newval): if isinstance(newval, self.LoadResistance): newval = newval.value else: newval = assume_units(newval, pq.ohm).rescale(pq.ohm).magnitude if (newval < 0) or (newval > 10000): raise ValueError( "Load resistance must be between 0 and 10,000") self.sendcmd("OUTP:LOAD {}".format(newval))
def field_control_params(self, newval): if not isinstance(newval, tuple): raise TypeError('Field control parameters must be specified as ' ' a tuple') newval = list(newval) newval[0] = float(newval[0]) newval[1] = float(newval[1]) unit = self.field_units / pq.minute newval[2] = float(assume_units(newval[2], unit).rescale(unit).magnitude) unit = pq.volt / pq.minute newval[3] = float(assume_units(newval[3], unit).rescale(unit).magnitude) self.sendcmd('CPARAM {},{},{},{}'.format(newval[0], newval[1], newval[2], newval[3], ))
def input_range(self, newval): current = self.query("CONF?") mode = self.Mode(self._mode_parse(current)) units = UNITS[mode] if isinstance(newval, self.InputRange): newval = newval.value else: newval = assume_units(newval, units).rescale(units).magnitude self.sendcmd("CONF:{} {}".format(mode.value, newval))
def _set_amplitude_(self, magnitude, units): if units == self._mhs.VoltageMode.peak_to_peak or \ units == self._mhs.VoltageMode.rms: magnitude = assume_units(magnitude, "V").to(u.V).magnitude elif units == self._mhs.VoltageMode.dBm: raise NotImplementedError("Decibel units are not supported.") magnitude *= 100 query = ":s{0}a{1}".format(self._chan, int(magnitude)) self._mhs.sendcmd(query)
def power(self, newval): # TODO: convert UnitPower Quantity instances to UnitLogPower. # That is, convert [W] to [dBm]. # The Phase Matrix unit speaks in units of centibel-milliwats, # so convert and take the integer part. newval = int(assume_units(newval, dBm).rescale(cBm).magnitude) # Command code 0x03, parameter length 2 bytes (4 nybbles) self.sendcmd('03{:04X}.'.format(newval))
def right_limit(self): """ Get the right travel limit :units: units :param limit: Set the travel limit :type: `~quantities.Quantity` or `float` """ return assume_units(float(self._controller._newport_cmd("SR?",target=self.axis_id)), self._units)
def timeout(self, newval): newval = assume_units(newval, pq.second) if self._version <= 4: newval = newval.rescale(pq.second) self._file.sendcmd('+t:{}'.format(newval.magnitude)) elif self._version >= 5: newval = newval.rescale(pq.millisecond) self._file.sendcmd("++read_tmo_ms {}".format(newval.magnitude)) self._file.timeout = newval.rescale(pq.second) self._timeout = newval.rescale(pq.second)
def error_threshold(self): """ Get and set the error threshold :units: units :param error_threshold: Set the travel limit :type: `~quantities.Quantity` or `float` """ return assume_units(float(self._controller._newport_cmd("FE?",target=self.axis_id)), self._units)
def voltage(self): """ Get and set the current :units: A :param voltage: Set the voltage :type: `~quantities.Quantity` or `float` """ return assume_units(float(self._controller._newport_cmd("QV?",target=self.axis_id)), self.V)
def desired_velocity(self): """ Gets desired velocity on axis in unit/s :units: As specified (if a `~quantities.Quantity`) or assumed to be of current newport unit/s :type: `~quantities.Quantity` or `float` """ return assume_units(float(self._controller._newport_cmd("DP?", target=self.axis_id)), self._units/pq.s)
def setter(self, newval): newval = assume_units(newval, default_units) if newval > max_getter(self) or newval < min_getter(self): raise ValueError("Value outside allowed bounds for this channel.") if newval.units not in allowed_units: newval = newval.rescale(default_units) self._sendcmd("{}:{}".format(base_name, newval))
def desired_position(self): """ Gets desired position on axis in units :units: As specified (if a `~quantities.Quantity`) or assumed to be of current newport unit :type: `~quantities.Quantity` or `float` """ return assume_units( float(self._newport_cmd("DP?", target=self.axis_id)), self._units)
def current(self): """ Get and set the current :units: A :param current: Set the current :type: `~quantities.Quantity` or `float` """ return assume_units(float(self._controller._newport_cmd("QI?",target=self.axis_id)), pq.A)
def position(self): """ Gets real position on axis in units :units: As specified (if a `~quantities.Quantity`) or assumed to be of current newport unit :type: `~quantities.Quantity` or `float` """ return assume_units(float(self._controller._newport_cmd("TP?", target=self.axis_id)), self._units)
def voltage(self): """ Gets/sets the axis voltage :units: As specified (if a `~quantities.Quantity`) or assumed to be of current newport :math:`\\text{V}` :type: `~quantities.Quantity` or `float` """ return assume_units( float(self._newport_cmd("QV?", target=self.axis_id)), pq.V)
def wait_for_position(self,position): """ Wait for axis to reach position before executing next command :param position: Position to wait for on axis :type position: float or :class:`~quantities.Quantity` """ position = float(assume_units(position,self._units).rescale( self._units).magnitude) self._controller._newport_cmd("WP",target=self.axis_id,params=[position])
def estop_deceleration(self): """ Gets estop_deceleration :units: As specified (if a `~quantities.Quantity`) or assumed to be of current newport :math:`\\frac{unit}{s^2}` :param decel: Sets deceleration :type decel: `~quantities.Quantity` or float """ return assume_units(float(self._controller._newport_cmd("AE?", target=self.axis_id)), self._units/(pq.s**2))
def max_base_velocity(self): """ Get the maximum base velocity for stepper motors :units: As specified (if a `~quantities.Quantity`) or assumed to be of current newport :math:`\\frac{unit}{s}` :param velocity: Sets the maximum velocity :type velocity: `~quantities.Quantity` or `float` """ return assume_units(float(self._controller._newport_cmd("VB?", target=self.axis_id)), self._units/pq.s)
def homing_velocity(self): """ Gets and sets the homing velocity :units: As specified (if a `~quantities.Quantity`) or assumed to be of current newport :math:`\\frac{unit}{s}` :param homing_velocity: Sets velocity :type homing_velocity: `~quantities.Quantity` or `float` """ return assume_units(float(self._controller._newport_cmd("OH?", target=self.axis_id)), self._units/(pq.s))
def home(self): """ Get home position :units: As specified (if a `~quantities.Quantity`) or assumed to be of current newport unit :param home: Sets home position of axis :type home: `~quantities.Quantity` or `float` """ return assume_units(float(self._controller._newport_cmd("DH?", target=self.axis_id)), self._units)