Source code for hardware.function_generators

"""
Function Generators
===================

.. module:: function_generators
   :platform: Windows, Linux, OSX
   :synopsis: Python wrappers for function generators

.. moduleauthor:: Jonathan Wheeler <jamwheel@stanford.edu>

This module provides support for controlling function generators with Python.
Arbitrary waveform generators and function generators can be imported by

>>> import hardware
>>> awg = hardware.function_generators.Agilent_33250A('GPIB0:...')

"""

import visa
import numpy as np


[docs]class Agilent_33250A(): """ Hardware wrapper for the Agilent 33250A Arbitrary Waveform Generator Parameters: visa_search_term (str): The address that is passed to ``visa.ResourceManager().open_resource()`` Attributes: frequency (float): The frequency in Hz. Also aliases to ``freq`` voltage (float): The peak-to-peak voltage in volts. Also aliases to `volt`` waveform (str): A string in the array ``['SIN', 'SQU', 'RAMP', 'PULS', 'NOIS', 'DC', 'USER' ]`` phase (float): The relative phase to other instruments synced through the 10 MHz reference clock. duty_cycle (float): The duty cycle of the square wave form in percent. """ def __init__(self, visa_search_term): rm = visa.ResourceManager() self.inst = rm.open_resource(visa_search_term)
[docs] def identify(self): """ Returns: str: the response from the ``*IDN?`` GPIB query. """ return self.inst.query('*IDN?')[:-1]
@property def frequency(self): f = self.inst.query('FREQ?') return float(f) @frequency.setter def frequency(self, val): self.inst.write('FREQ %i' % val) # alias freq = frequency @property def volt(self): return float(self.inst.query('VOLT?')) @volt.setter def volt(self, val): string = 'VOLT %f' % float(val) self.inst.write(string) # alias voltage = volt @property def phase(self): return float(self.inst.query('PHAS?')) @phase.setter def phase(self, val): self.inst.write('PHAS %f' % val) @property def duty_cycle(self): return float(self.inst.query('FUNCtion:SQUare:DCYCLe?')) @duty_cycle.setter def duty_cycle(self, val): self.inst.write('FUNCtion:SQUare:DCYCLe %f' % val) @property def waveform(self): wf = self.inst.query('FUNC?')[:-1] if wf == 'USER': return 'USER ' + self.inst.query('FUNC:USER?')[:-1] return wf @waveform.setter def waveform(self, val): waveform_list = [ 'SIN', 'SQU', 'RAMP', 'PULS', 'NOIS', 'DC', 'USER' ] if val.upper() in (waveform_list): return self.inst.write('FUNC %s' % val) elif val.upper()[0:4] == 'USER': return self.inst.write('FUNC:%s' % val) else: raise Exception('%s is not a recognized waveform' % val)
[docs] def upload(self, points_array): """ Uploads an array of points to the function generator volatile memory. Parameters: points_array (array-like): The waveform shape """ points_array = np.array(points_array) if points_array.dtype not in ['float64', 'int32']: raise Exception('Array is not numeric') if max(points_array) > 1 or min(points_array) < -1: raise Exception('Values should be floats between -1 and +1') values = ', '.join(map(str, points_array)) self.inst.write('DATA VOLATILE, %s' % values)
def set_duty_cycle(self, r, rise_time_over_cycle_time=0, fall_time_over_cycle_time=0): from pyfog.waveforms import square_pulse signal = square_pulse( 4e3, duty_cycle = r, rise_time_over_cycle_time = rise_time_over_cycle_time, fall_time_over_cycle_time = fall_time_over_cycle_time, ) __timeout = self.inst.timeout self.inst.timeout = 10e3 self.upload_as(signal, 'PULSEWAVEFORM') self.waveform = 'USER' self.waveform = 'USER PULSEWAVEFORM' self.inst.timeout = __timeout def set_double_gate(self, r1, r2, duty_cycle=.50, rise_time_over_cycle_time=0, fall_time_over_cycle_time=0): from pyfog.waveforms import square_pulse signal1 = square_pulse( 2e3, duty_cycle = r1, rise_time_over_cycle_time = rise_time_over_cycle_time, fall_time_over_cycle_time = fall_time_over_cycle_time, ) signal2 = square_pulse( 2e3, duty_cycle = r2, rise_time_over_cycle_time = rise_time_over_cycle_time, fall_time_over_cycle_time = fall_time_over_cycle_time, ) signal1=np.roll(signal1, -int(2e3*r1/2)) signal2=np.roll(signal2, -int(2e3*r2/2)) signal = np.concatenate([signal1, signal2]) __timeout = self.inst.timeout self.inst.timeout = 10e3 self.upload_as(signal, 'PULSEWAVEFORM') self.waveform = 'USER' # self.waveform = 'USER PULSEWAVEFORM' self.inst.timeout = __timeout def set_double_gate_no_roll(self, r1, r2, rise_time_over_cycle_time=0, fall_time_over_cycle_time=0): from pyfog.waveforms import square_pulse signal1 = square_pulse( 2e3, duty_cycle = r1, rise_time_over_cycle_time = rise_time_over_cycle_time, fall_time_over_cycle_time = fall_time_over_cycle_time, ) signal2 = square_pulse( 2e3, duty_cycle = r2, rise_time_over_cycle_time = rise_time_over_cycle_time, fall_time_over_cycle_time = fall_time_over_cycle_time, ) signal = np.concatenate([signal1, signal2]) __timeout = self.inst.timeout self.inst.timeout = 10e3 self.upload_as(signal, 'PULSEWAVEFORM') self.waveform = 'USER' # self.waveform = 'USER PULSEWAVEFORM' self.inst.timeout = __timeout def set_double_gate_and_notch(self, r1, r2, r3, phase, rise_time_over_cycle_time=0, fall_time_over_cycle_time=0): from pyfog.waveforms import square_pulse signal1 = square_pulse( 2e3, duty_cycle = r1, rise_time_over_cycle_time = rise_time_over_cycle_time, fall_time_over_cycle_time = fall_time_over_cycle_time, ) signal2 = square_pulse( 2e3, duty_cycle = r2, rise_time_over_cycle_time = rise_time_over_cycle_time, fall_time_over_cycle_time = fall_time_over_cycle_time, ) signal1=np.roll(signal1, -int(2e3*r1/2)) signal2=np.roll(signal2, -int(2e3*r2/2)) signal = np.concatenate([signal1, signal2]) signal3 = square_pulse( 4e3, duty_cycle=r3 ) signal3 = -np.roll(signal3, int(phase/360*4e3)) __timeout = self.inst.timeout self.inst.timeout = 10e3 self.upload_as(signal * signal3, 'PULSEWAVEFORM') self.waveform = 'USER' # self.waveform = 'USER PULSEWAVEFORM' self.inst.timeout = __timeout
[docs] def save_as(self, waveform_name): """ Saves the data in volatile memory as ``waveform_name`` Parameters: waveform_name (str): The name of the saved waveform """ self.inst.write('DATA:COPY %s' % waveform_name)
[docs] def upload_as(self, points_array, waveform_name): """ Uploads an array of points to the function generator, and saves them by name ``waveform_name`` Parameters: points_array (array-like): The waveform shape waveform_name (str): The variable name to store in the waveform generator. """ self.upload(points_array) self.save_as(waveform_name)
[docs]class SRS_DS345(): """ Hardware wrapper for the Stanford Research Systems DS345 Arbitrary Waveform Generator Parameters: visa_search_term (str): The address that is passed to ``visa.ResourceManager().open_resource()`` Attributes: frequency (float): The frequency in Hz. Also aliases to ``freq`` voltage (float): The peak-to-peak voltage in volts. Also aliases to ``volt`` waveform (str): A string in the array ``['SIN', 'SQU', 'RAMP', 'PULS', 'NOIS', 'DC', 'USER' ]`` phase (float): The relative phase to other instruments synced through the 10 MHz reference clock. duty_cycle (float): The duty cycle of the square wave form in percent. """ def __init__(self, visa_search_term): rm = visa.ResourceManager() self.inst = rm.open_resource(visa_search_term)
[docs] def identify(self): """ Returns: str: the response from the ``*IDN?`` GPIB query. """ return self.inst.query('*IDN?')[:-1]
@property def frequency(self): f = self.inst.query('FREQ?') return float(f) @frequency.setter def frequency(self, val): self.inst.write('FREQ %i' % val) # alias freq = frequency @property def voltage(self): return float(self.inst.query('AMPL?')[:-3]) @voltage.setter def voltage(self, val): self.inst.write('AMPL %f' % val) # alias volt = voltage @property def phase(self): return float(self.inst.query('PHSE?')) @phase.setter def phase(self, val): self.inst.write('PHSE %f' % val)
[docs]class HP_33120A(): """ Hardware wrapper for the HP 33120A Arbitrary Waveform Generator Parameters: visa_search_term (str): The address that is passed to ``visa.ResourceManager().open_resource()`` Attributes: frequency (float): The frequency in Hz. Also aliases to ``freq`` voltage (float): The peak-to-peak voltage in volts. Also aliases to `volt`` waveform (str): A string in the array ``['SIN', 'SQU', 'RAMP', 'PULS', 'NOIS', 'DC', 'USER' ]`` phase (float): The relative phase to other instruments synced through the 10 MHz reference clock. duty_cycle (float): The duty cycle of the square wave form in percent. """ def __init__(self, visa_search_term): rm = visa.ResourceManager() self.inst = rm.open_resource(visa_search_term)
[docs] def identify(self): """ Returns: str: the response from the ``*IDN?`` GPIB query. """ return self.inst.query('*IDN?')[:-1]
@property def frequency(self): f = self.inst.query('FREQ?') return float(f) @frequency.setter def frequency(self, val): self.inst.write('FREQ %i' % val) # alias freq = frequency @property def volt(self): return float(self.inst.query('VOLT?')) @volt.setter def volt(self, val): string = 'VOLT %f' % float(val) self.inst.write(string) # alias voltage = volt @property def phase(self): return float(self.inst.query('PHAS?')) @phase.setter def phase(self, val): self.inst.write('PHAS %f' % val) @property def duty_cycle(self): return float(self.inst.query('FUNCtion:SQUare:DCYCLe?')) @duty_cycle.setter def duty_cycle(self, val): self.inst.write('FUNCtion:SQUare:DCYCLe %f' % val) @property def waveform(self): wf = self.inst.query('FUNC?')[:-1] if wf == 'USER': return 'USER ' + self.inst.query('FUNC:USER?')[:-1] return wf @waveform.setter def waveform(self, val): waveform_list = [ 'SIN', 'SQU', 'RAMP', 'PULS', 'NOIS', 'DC', 'USER' ] if val.upper() in (waveform_list): return self.inst.write('FUNC %s' % val) elif val.upper()[0:4] == 'USER': return self.inst.write('FUNC:%s' % val) else: raise Exception('%s is not a recognized waveform' % val)
[docs] def upload(self, points_array): """ Uploads an array of points to the function generator volatile memory. Parameters: points_array (array-like): The waveform shape """ points_array = np.array(points_array) if points_array.dtype not in ['float64', 'int32']: raise Exception('Array is not numeric') if max(points_array) > 1 or min(points_array) < -1: raise Exception('Values should be floats between -1 and +1') values = ', '.join(map(str, points_array)) self.inst.write('DATA VOLATILE, %s' % values)
[docs] def save_as(self, waveform_name): """ Saves the data in volatile memory as ``waveform_name`` Parameters: waveform_name (str): The name of the saved waveform """ self.inst.write('DATA:COPY %s' % waveform_name)
[docs] def upload_as(self, points_array, waveform_name): """ Uploads an array of points to the function generator, and saves them by name ``waveform_name`` Parameters: points_array (array-like): The waveform shape waveform_name (str): The variable name to store in the waveform generator. """ self.upload(points_array) self.save_as(waveform_name)