예제 #1
0
    def add_AO_funcgen_channel(self,
                               ao,
                               name=None,
                               func=None,
                               fsamp=None,
                               amp=None,
                               offset='0V'):
        """ Adds an analog output funcgen channel (or channels) to the task """
        ao_name = "{}/ao{}".format(self.dev.name, ao).encode('ascii')
        ch_name = 'ao{}'.format(ao) if name is None else name
        ch_name = ch_name.encode('ascii')
        self.AOs.append(ch_name)
        if fsamp is None or amp is None:
            raise Exception("Must include fsamp, and amp")
        fsamp_mag = float(Q_(fsamp).to('Hz').magnitude)
        amp_mag = float(Q_(amp).to('V').magnitude)
        off_mag = float(Q_(offset).to('V').magnitude)

        func_map = {
            'sin': mx.DAQmx_Val_Sine,
            'tri': mx.DAQmx_Val_Triangle,
            'squ': mx.DAQmx_Val_Square,
            'saw': mx.DAQmx_Val_Sawtooth
        }
        func = func_map[func]
        self.t.CreateAOFuncGenChan(ao_name, ch_name, func, fsamp_mag, amp_mag,
                                   off_mag)
예제 #2
0
    def read_AI_scalar(self, timeout=-1.0):
        if timeout != -1.0:
            timeout = float(Q_(timeout).to('s').magnitude)

        value = c_double()
        self.t.ReadAnalogScalarF64(timeout, byref(value), None)
        return Q_(value.value, 'V')
예제 #3
0
    def read_AI_channels(self, samples=-1, timeout=-1.0):
        """ Returns a dict containing the AI buffers. """
        samples = int(samples)
        if timeout != -1.0:
            timeout = float(Q_(timeout).to('s').magnitude)

        if samples == -1:
            buf_size = self.get_buf_size() * len(self.AIs)
        else:
            buf_size = samples * len(self.AIs)

        data = np.zeros(buf_size, dtype=np.float64)
        num_samples_read = c_int32()
        self.t.ReadAnalogF64(samples, timeout, mx.DAQmx_Val_GroupByChannel,
                             data, len(data), byref(num_samples_read), None)

        num_samples_read = num_samples_read.value
        res = {}
        for i, ch_name in enumerate(self.AIs):
            start = i * num_samples_read
            stop = (i + 1) * num_samples_read
            res[ch_name] = Q_(data[start:stop], 'V')
        res['t'] = Q_(
            np.linspace(0,
                        num_samples_read / self.fsamp,
                        num_samples_read,
                        endpoint=False), 's')
        return res
예제 #4
0
def take_measure(COUNTER, POWERMETER, Vthresh, integration_time):
    '''
		Collect counts during integration_time and measures power

		Input Parameters:
		COUNTER: frequency counter object
		POWERMETER: powermeter object
		Vthres: threshold voltage for frequency counter

		Returns: (cps, int_power)
		cps: counts per second
		power: average optical power during measurement returned as pint.Measurement object
	'''
    with visa_timeout_context(COUNTER._rsrc, 60000):  # timeout of 60,000 msec
        COUNTER.Vthreshold = Q_(Vthresh, 'V')
        COUNTER.write('INIT')  # Initiate couting
        COUNTER.write('*WAI')

        if POWERMETER is not None:
            power = POWERMETER.measure(n_samples=int(
                integration_time / 0.003))  # each sample about 3ms
        else:
            power = Q_(0.0, 'W').plus_minus(Q_(0.0, 'W'))
        num_counts = float(COUNTER.query('FETC?'))

        cps = num_counts / integration_time

    return (cps, power)
예제 #5
0
 def _handle_minmax_AO(self, min_val, max_val):
     if min_val is None or max_val is None:
         min_mag, max_mag = self.dev.get_AO_max_range()
     else:
         min_mag = Q_(min_val).to('V').magnitude
         max_mag = Q_(max_val).to('V').magnitude
     return min_mag, max_mag
예제 #6
0
    def write_sequence(self,
                       data,
                       duration=None,
                       reps=None,
                       fsamp=None,
                       freq=None,
                       onboard=True):
        """Write an array of samples to the digital output channel

        Outputs a buffered digital waveform, writing each value in sequence at
        the rate determined by `duration` and `fsamp` or `freq`. You must
        specify either `fsamp` or `freq`.

        This function blocks until the output sequence has completed.

        Parameters
        ----------
        data : array or list of ints or bools
            The sequence of samples to output. For a single-line DO channel,
            samples can be bools.
        duration : Quantity, optional
            How long the entirety of the output lasts, specified as a
            second-compatible Quantity. If `duration` is longer than a single
            period of data, the waveform will repeat. Use either this or
            `reps`, not both. If neither is given, waveform is output once.
        reps : int or float, optional
            How many times the waveform is repeated. Use either this or
            `duration`, not both. If neither is given, waveform is output once.
        fsamp: Quantity, optional
            This is the sample frequency, specified as a Hz-compatible
            Quantity. Use either this or `freq`, not both.
        freq : Quantity, optional
            This is the frequency of the *overall waveform*, specified as a
            Hz-compatible Quantity. Use either this or `fsamp`, not both.
        onboard : bool, optional
            Use only onboard memory. Defaults to True. If False, all data will
            be continually buffered from the PC memory, even if it is only
            repeating a small number of samples many times.
        """
        if (fsamp is None) == (freq is None):
            raise Exception("Need one and only one of 'fsamp' or 'freq'")
        if fsamp is None:
            fsamp = Q_(freq) * len(data)
        else:
            fsamp = Q_(fsamp)

        if (duration is not None) and (reps is not None):
            raise Exception(
                "Can use at most one of `duration` or `reps`, not both")
        if duration is None:
            duration = (reps or 1) * len(data) / fsamp
        fsamp, n_samples = _handle_timing_params(duration, fsamp, len(data))

        with self.dev.create_task() as t:
            t.add_DO_channel(self._get_name())
            t.set_DO_only_onboard_mem(self._get_name(), onboard)
            t.config_timing(fsamp, n_samples, clock='')
            t.write_DO_channels({self.name: data}, [self])
            t.t.WaitUntilTaskDone(-1)
예제 #7
0
    def set_low(self, low, channel=1):
        """ Set the low voltage level of the current waveform.

        This changes the low level while keeping the high level fixed.

        Parameters
        ----------
        low : pint.Quantity
            The new low level in volt-compatible units
        """
        low = Q_(low)
        mag = low.to('V').magnitude
        self.inst.write('source{}:voltage:low {}V'.format(channel, mag))
예제 #8
0
    def set_offset(self, offset, channel=1):
        """ Set the voltage offset of the current waveform.

        This changes the offset while keeping the amplitude fixed.

        Parameters
        ----------
        offset : pint.Quantity
            The new voltage offset in volt-compatible units
        """
        offset = Q_(offset)
        mag = offset.to('V').magnitude
        self.inst.write('source{}:voltage:offset {}V'.format(channel, mag))
예제 #9
0
def bring_down_from_breakdown(SOURCEMETER, Vbd):
    Vstep = Q_(5.0, 'V')
    Vinit = Vbd - Vstep

    while (Vinit > Q_(0, 'V')):
        # SOURCEMETER.write(':SOUR1:VOLT {}'.format(Vinit))
        # SOURCEMETER.write(':OUTP ON')
        SOURCEMETER.set_voltage(Vinit)
        Vinit = Vinit - Vstep
        time.sleep(0.5)

    SOURCEMETER.set_voltage(Q_(0, 'V'))
    print('Sourcemeter at 0V')
예제 #10
0
def _handle_timing_params(duration, fsamp, n_samples):
    if duration:
        duration = Q_(duration).to('s')
        if fsamp:
            fsamp = Q_(fsamp).to('Hz')
            n_samples = int((duration*fsamp).to(''))  # Exclude endpoint
        else:
            n_samples = int(n_samples or 1000.)
            fsamp = n_samples / duration
    elif fsamp:
        fsamp = Q_(fsamp).to('Hz')
        n_samples = int(n_samples or 1000.)
    return fsamp, n_samples
예제 #11
0
    def set_high(self, high, channel=1):
        """ Set the high voltage level of the current waveform.

        This changes the high level while keeping the low level fixed.

        Parameters
        ----------
        high : pint.Quantity
            The new high level in volt-compatible units
        """
        high = Q_(high)
        mag = high.to('V').magnitude
        self.inst.write('source{}:voltage:high {}V'.format(channel, mag))
예제 #12
0
    def output_pulses(self,
                      freq,
                      duration=None,
                      reps=None,
                      idle_high=False,
                      delay=None,
                      duty_cycle=0.5):
        """Generate digital pulses using the counter.

        Outputs digital pulses with a given frequency and duty cycle.

        This function blocks until the output sequence has completed.

        Parameters
        ----------
        freq : Quantity
            This is the frequency of the pulses, specified as a Hz-compatible Quantity.
        duration : Quantity, optional
            How long the entirety of the output lasts, specified as a second-compatible
            Quantity. Use either this or `reps`, not both. If neither is given, only one pulse is
            generated.
        reps : int, optional
            How many pulses to generate. Use either this or `duration`, not both. If neither is
            given, only one pulse is generated.
        idle_high : bool, optional
            Whether the resting state is considered high or low. Idles low by default.
        delay : Quantity, optional
            How long to wait before generating the first pulse, specified as a second-compatible
            Quantity. Defaults to zero.
        duty_cycle : float, optional
            The width of the pulse divided by the pulse period. The default is a 50% duty cycle.
        """
        idle_state = mx.High if idle_high else mx.Low
        delay = 0 if delay is None else Q_(delay).to('s').magnitude
        freq = Q_(freq).to('Hz').magnitude

        if (duration is not None) and (reps is not None):
            raise Exception(
                "Can use at most one of `duration` or `reps`, not both")
        if reps is None:
            if duration is None:
                reps = 1
            else:
                reps = int(Q_(duration).to('s').magnitude * freq)

        with self.dev.create_task() as t:
            t.t.CreateCOPulseChanFreq(self.fullname, None, mx.Hz, idle_state,
                                      delay, freq, duty_cycle)
            t.t.CfgImplicitTiming(mx.FiniteSamps, reps)
            t.t.StartTask()
            t.t.WaitUntilTaskDone(-1)
예제 #13
0
    def set_phase(self, phase, channel=1):
        """ Set the phase offset of the current waveform.

        Parameters
        ----------
        phase : pint.Quantity or number
            The new low level in radian-compatible units. Unitless numbers are
            treated as radians.
        """
        phase = Q_(phase)  # This also accepts dimensionless numbers as rads
        if phase < -u.pi or phase > +u.pi:
            raise Exception("Phase out of range. Must be between -pi and +pi")
        mag = phase.to('rad').magnitude
        self.inst.write('source{}:phase {}rad'.format(channel, mag))
예제 #14
0
def bring_to_breakdown(SOURCEMETER, Vbd):
    Vinit = Q_(0, 'V')
    Vstep = Q_(5.0, 'V')

    while (Vinit < Vbd):
        # SOURCEMETER.write(':SOUR1:VOLT {}'.format(Vinit))
        # SOURCEMETER.write(':OUTP ON')
        SOURCEMETER.set_voltage(Vinit)
        Vinit = Vinit + Vstep
        time.sleep(0.5)

    SOURCEMETER.set_voltage(Vbd)
    time.sleep(5.0)
    print('Sourcemeter at breakdown voltage {}'.format(Vbd))
예제 #15
0
    def sweep_end_frequency(self, val=None):
        """
        Sets the end frequency of a sweep.

        Sets the ending frequency for subsequent sweeps. If no value
        is specified, the current ending frequency setting is returned.

        Parameters
        ----------
        val : float, optional
            The ending value of the frequency sweep in THz.
            Step: 0.00001 (THz)

        Returns
        -------
        Quantity
            The current sweep end frequency in THz, and its units.

        >>> laser.sweep_end_frequency()
        <Quantity(183.92175, 'terahertz')>
        >>> laser.sweep_end_frequency(185.5447)
        <Quantity(185.5447, 'terahertz')>
        """

        return Q_(float(self._set_var("FF", 5, val)), 'THz')
예제 #16
0
    def sweep_end_wavelength(self, val=None):
        """
        Sets the end wavelength of a sweep.

        Sets the ending wavelength for subsequent sweeps. If no value
        is specified, the current ending wavelength setting is returned.

        Parameters
        ----------
        val : float, optional
            The ending value of the wavelength sweep in nanometers.
            Step: 0.0001 (nm)

        Returns
        -------
        Quantity
            The current sweep end wavelength in nm, and its units.

        >>> laser.sweep_end_wavelength()
        <Quantity(1630.0, 'nanometer')>
        >>> laser.sweep_end_wavelength(1618)
        <Quantity(1618.0, 'nanometer')>
        """

        return Q_(float(self._set_var("SE", 4, val)), 'nm')
예제 #17
0
def test():
    ps = MyPowerSupply()
    ps.voltage = '12V'
    assert ps.voltage == Q_(12, 'volts')

    with pytest.raises(DimensionalityError):
        ps.voltage = '200 mA'
예제 #18
0
    def sweep_start_frequency(self, val=None):
        """
        Sets the start frequency of a sweep.

        Sets the starting frequency for subsequent sweeps. If no value
        is specified, the current starting frequency setting is returned.

        Parameters
        ----------
        val : float, optional
            The starting value of the frequency sweep in terahertz.
            Step: 0.00001 (THz)

        Returns
        -------
        Quantity
            The current sweep start frequency in THz, and its units.

        >>> laser.sweep_start_frequency()
        <Quantity(199.86164, 'terahertz')>
        >>> laser.sweep_start_frequency(196)
        <Quantity(195.99999, 'terahertz')>
        """

        return Q_(float(self._set_var("FS", 5, val)), 'THz')
예제 #19
0
    def wavelength(self, val=None):
        """
        Sets the output wavelength. If a value is not specified, returns the currently set wavelength.

        Parameters
        ----------
        val : float, optional
            The wavelength the laser will be set to in nanometers.
            Step: 0.0001 (nm)

        Returns
        -------
        Quantity
            The currently set wavelength in nanometers, and its units.

        You can get the current wavelength by calling without arguments.

        >>> laser.wavelength()
        <Quantity(1630.0, 'nanometer')>

        The following sets the output wavelength to 1560.123 nanometers.

        >>> laser.wavelength(1560.123)
        <Quantity(1630.0, 'nanometer')> # Bug returns the last set wavelength
        """

        return Q_(float(self._set_var("WA", 4, val)), 'nm')
예제 #20
0
    def sweep_step_frequency(self, val=None):
        """
        Set the size of each step in the stepwise sweep when constant
        frequency intervals are enabled. If a new value is not
        provided, the current one will be returned. Units: THz

        Parameters
        ----------
        val : float, optional
            The step size of each step in the stepwise sweep in terahertz.
            Range: 0.00002 - 19.76219 (THz)
            Step: 0.00001 (THz)

        Returns
        -------
        Quantity
            The set step size in THz, and its units.

        >>> laser.sweep_step_frequency()
        <Quantity(0.1, 'terahertz')>
        >>> laser.sweep_step_frequency(0.24)
        <Quantity(0.24, 'terahertz')>
        """

        return Q_(float(self._set_var("WF", 5, val)), 'THz')
예제 #21
0
    def read_measurement_stats(self, num):
        """
        Read the value and statistics of a measurement.

        Parameters
        ----------
        num : int
            Number of the measurement to read from, from 1-4

        Returns
        -------
        stats : dict
            Dictionary of measurement statistics. Includes value, mean, stddev,
            minimum, maximum, and nsamps.
        """
        prefix = 'measurement:meas{}'.format(num)

        if not self.are_measurement_stats_on():
            raise Exception("Measurement statistics are turned off, "
                            "please turn them on.")

        # Potential issue: If we query for all of these values in one command,
        # are they guaranteed to be taken from the same statistical set?
        # Perhaps we should stop_acquire(), then run_acquire()...
        keys = ['value', 'mean', 'stddev', 'minimum', 'maximum']
        res = self.inst.query(
            prefix +
            ':value?;mean?;stddev?;minimum?;maximum?;units?').split(';')
        units = res.pop(-1).strip('"')
        stats = {k: Q_(rval + units) for k, rval in zip(keys, res)}

        num_samples = int(self.inst.query('measurement:statistics:weighting?'))
        stats['nsamps'] = num_samples
        return stats
예제 #22
0
 def write_AO_channels(self, data, timeout=-1.0, autostart=True):
     if timeout != -1.0:
         timeout = float(Q_(timeout).to('s').magnitude)
     arr = np.concatenate([data[ao].to('V').magnitude for ao in self.AOs]).astype(np.float64)
     samples = data.values()[0].magnitude.size
     samples_written = c_int32()
     self.t.WriteAnalogF64(samples, autostart, timeout,
                           mx.DAQmx_Val_GroupByChannel, arr,
                           byref(samples_written), None)
예제 #23
0
 def _write_AO_channels(self, data):
     task = self._mxtasks['AO']
     ao_names = [name for (name, ch) in self.channels.items() if ch.type == 'AO']
     arr = np.concatenate([Q_(data[ao]).to('V').magnitude for ao in ao_names])
     arr = arr.astype(np.float64)
     samples = data.values()[0].magnitude.size
     samples_written = c_int32()
     task.WriteAnalogF64(samples, False, -1.0,
                         mx.DAQmx_Val_GroupByChannel, arr,
                         byref(samples_written), None)
예제 #24
0
 def config_analog_trigger(self,
                           source,
                           trig_level,
                           rising=True,
                           pretrig_samples=2):
     source_name = self._handle_ai(source)
     level_mag = float(Q_(trig_level).to('V').magnitude)
     slope = mx.DAQmx_Val_RisingSlope if rising else mx.DAQmx_Val_FallingSlope
     self.t.CfgAnlgEdgeStartTrig(source_name, slope, level_mag,
                                 pretrig_samples)
예제 #25
0
    def write_DO_channels(self, data, channels, timeout=-1.0, autostart=True):
        if timeout != -1.0:
            timeout = float(Q_(timeout).to('s').magnitude)

        arr = self._make_DO_array(data, channels)
        n_samples = arr.size
        n_samples_written = c_int32()
        self.t.WriteDigitalU32(n_samples, autostart, timeout,
                               mx.DAQmx_Val_GroupByChannel, arr,
                               byref(n_samples_written), None)
예제 #26
0
    def _read_AI_channels(self):
        """ Returns a dict containing the AI buffers. """
        task = self._mxtasks['AI']

        bufsize_per_chan = c_uint32()
        task.GetBufInputBufSize(byref(bufsize_per_chan))
        buf_size = bufsize_per_chan.value * len(self.AIs)

        data = np.zeros(buf_size, dtype=np.float64)
        num_samples_read = c_int32()
        task.ReadAnalogF64(-1, -1.0, mx.DAQmx_Val_GroupByChannel,
                           data, len(data), byref(num_samples_read), None)

        num_samples_read = num_samples_read.value
        res = {}
        for i, ch in enumerate(self.AIs):
            start = i*num_samples_read
            stop = (i+1)*num_samples_read
            res[ch.name] = Q_(data[start:stop], 'V')
        res['t'] = Q_(np.linspace(0, float(num_samples_read-1)/self.fsamp, num_samples_read), 's')
        return res
예제 #27
0
    def set_sweep_center(self, center, channel=1):
        """ Set the sweep frequency center.

        This sets the sweep center frequency while keeping the sweep frequency
        span fixed. The start and stop frequencies will be changed.

        Parameters
        ----------
        center : pint.Quantity
            The center frequency of the sweep in Hz-compatible units
        """
        val = Q_(center).to('Hz').magnitude
        self.inst.write('source{}:freq:center {}Hz'.format(channel, val))
예제 #28
0
    def set_sweep_hold_time(self, time, channel=1):
        """ Set the hold time of the sweep.

        The hold time is the amount of time that the frequency is held constant
        after reaching the stop frequency.

        Parameters
        ----------
        time : pint.Quantity
            The hold time in second-compatible units
        """
        val = Q_(time).to('s').magnitude
        self.inst.write('source{}:sweep:htime {}s'.format(channel, val))
예제 #29
0
    def set_am_depth(self, depth, channel=1):
        """ Set depth of amplitude modulation.

        Parameters
        ----------
        depth : number
            Depth of modulation in percent. Must be between 0.0% and 120.0%.
            Has resolution of 0.1%.
        """
        val = Q_(depth).magnitude
        if not (0.0 <= val <= 120.0):
            raise Exception("Depth must be between 0.0 and 120.0")
        self.inst.write('source{}:am:depth {:.1f}pct'.format(channel, val))
예제 #30
0
def tune_SHG(lm,
             wait=False,
             n_temp_samples=10,
             temp_timeout=30 * u.minute,
             temp_max_err=Q_(0.05, u.degK)):
    shg_data = load_newest_SHG_calibration()
    poling_region = get_poling_region(lm)
    if poling_region:
        T_set = Q_(
            np.asscalar(shg_data[poling_region]['phase_match_model'](lm)),
            u.degC)
        print('tuning SHG:')
        print('\tpoling region: {}, LM={:2.4f}um'.format(
            current_poling_region, LM_cov[current_poling_region].magnitude))
        print('\tset temperature: {:4.1f}C'.format(T_set.magnitude))
        if wait:
            oc.set_temp_and_wait(T_set,
                                 max_err=temp_max_err,
                                 n_samples=n_temp_samples,
                                 timeout=temp_timeout)
        else:
            oc.set_set_temp(T_set)
예제 #31
0
 def _set_amplitude(self, val, units, channel):
     val = Q_(val)
     mag = val.to('V').magnitude
     self.inst.write('source{}:voltage {}{}'.format(channel, mag, units))