Exemple #1
0
    def __init__(self, port='ao0', saver=None):
        self.port = port
        self.saver = saver
        self.daq = DAQ(DAQ.ANALOG_OUT, ports=[self.port])
        self.trig = Trigger(5.0, dtype=np.float64)
        self.end_trig = Trigger(0.0, dtype=np.float64)

        self.is_on = False
Exemple #2
0
def main():
    global event_q
    event_q = queue.Queue(maxsize=10)

    # Here we import the ENV variables from docker
    olympus_env_settings = {
        "rate": int(environ['rate']),
        "samples_per_channel": int(environ['samples_per_channel']),
        "low_channel": int(environ['low_channel']),
        "high_channel": int(environ['high_channel']),
        "serial": environ['serial'],
        "db_path": environ['db_path'],
        "input_mode": environ['input_mode'],
        "range": environ['volts']
    }

    # Instantiate the custom DAQ module
    daq = DAQ(olympus_env_settings, event_callback)

    try:
        # Configure the hardware with our ENV variables
        daq.configure_mode(olympus_env_settings['input_mode'])
        # Initialize the DAQ
        daq.initialize()
        # Start the background acquisition process
        daq.begin_acquisition()

        # Olympus Event Loop
        try:
            while True:
                # event_q holds the data coming in from the DAQ hardware
                if event_q.qsize() > 0:
                    # Each iteration of the loop pulls the data off the FIFO
                    data_sample = event_q.get_nowait()
                    # Save the data from the FIFO
                    save = Save(data_sample.formatted_buffer(),
                                olympus_env_settings['db_path'])
                    save.record()

        except KeyboardInterrupt:
            pass

    except Exception as e:
        print('\n', e)

    finally:
        # Stop the acquisition if it is still running.
        if daq.status.RUNNING:
            daq.ai_device.scan_stop()
        if daq.daq_device.is_connected():
            daq.daq_device.disconnect()
        daq.daq_device.release()
Exemple #3
0
class Light(object):
    OFF,ON = 0,1
    def __init__(self, port='ao0', saver=None):
        self.port = port
        self.saver = saver
        self.daq = DAQ(DAQ.ANALOG_OUT, ports=[self.port])
        self.trig = Trigger(5.0, dtype=np.float64)
        self.end_trig = Trigger(0.0, dtype=np.float64)

        self.is_on = False
    def on(self):
        if self.is_on:
            return
        
        self.daq.trigger(self.trig, clear=False)
        if self.saver:
            self.saver.write('light', [self.ON])
        self.is_on = True
    def off(self):
        if not self.is_on:
            return

        self.daq.trigger(self.end_trig, clear=False)
        if self.saver:
            self.saver.write('light', [self.OFF])
        self.is_on = False
    def end(self):
        self.daq.release()
Exemple #4
0
    def __init__(
        self, ports=["ai0", "ai1", "ai5", "ai6"], runtime_ports=[0, 1], saver=None, lick_thresh=6.0, holding_thresh=1.0
    ):
        # IMPORTANT: NUMBER OF PORTS MUST MATCH VALUE IN EXPTS/DTYPES.PY
        self.ports = ports
        self.runtime_ports = runtime_ports  # to be used in accumulator and lick/holding variable
        self.saver = saver
        self.thresh = lick_thresh
        self.daq = DAQ(DAQ.ANALOG_IN, ports=self.ports, read_buffer_size=self.READ_BUF_SIZE)
        self.holding_thresh = int(holding_thresh * self.daq.sample_rate)

        # runtime vars
        self.licked_ = np.zeros(len(self.runtime_ports))
        self.accum = np.zeros((len(self.runtime_ports), self.ACCUM_SIZE))
        self.holding = np.array([False, False])
        self.lock = threading.Lock()
        self.accum_lock = threading.Lock()
        self.SAVING = False
        self.start()
Exemple #5
0
	parser.add_argument('-g', '--graphical', action="store_true",
	help="Erzeuge eine grafische Darstellung von Messreihen. Wenn diese Option \
			nicht gesetzt ist wird einfach das Ergebnis einer Messung im Terminal ausgegeben.")

	return parser.parse_args()


if __name__ == '__main__':
	"""Dies ist die main Methode des Skripts, d.h. diese wird ausgefuehrt wenn
	man das Skript direkt mit `python muonrate.py` startet."""

	opt = argumente()

	# Hier erzeugen wir ein Objekt namens daqcard vom Typ DAQ
	daqcard = DAQ(opt.device)

	# Schwellenspannungen und Trigger setzen
	daqcard.set_thresholds(*opt.schwellen)
	daqcard.set_trigger(opt.trigger)

	if not opt.graphical:
		# Messung starten
		t, outputlist = daqcard.measure(opt.time)

		# Ergebnisse ausgeben
		print "\nErgebnis nach %.2f Sekunden Messzeit:" % t
		for i in range(3):
			print "Kanal %s: %.0f Ereignisse" % (i+1, outputlist[i])
		print "Trigger:   %.0f Ereignisse" % outputlist[4], "  Stat. Fehler: %.0f Ereignisse" % math.sqrt(outputlist[4])
		print "\nTriggerrate: %.2f +- %.2f  Hz" % ((outputlist[4]/t), (math.sqrt(outputlist[4])/t))
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""Example data logger that saves DAQ data to a CSV file in real-time"""

import csv
from time import time
from daq import DAQ

d = DAQ()

try:
    dataFile = open('data.csv', 'w+')  # overwrite data file if it exists
    writer = csv.writer(dataFile, quoting=csv.QUOTE_ALL)
    writer.writerow(['date'] + d.source_labels)  # table headers
    while True:  # kill/interrupt script to end program
        data = [time()] + d.data()
        print(data)
        writer.writerow(data)
finally:  # close/release everything
    d.close()
    dataFile.close()
Exemple #7
0
class AnalogReader(object):
    READ_BUF_SIZE = 10
    ACCUM_SIZE = 1000

    def __init__(
        self, ports=["ai0", "ai1", "ai5", "ai6"], runtime_ports=[0, 1], saver=None, lick_thresh=6.0, holding_thresh=1.0
    ):
        # IMPORTANT: NUMBER OF PORTS MUST MATCH VALUE IN EXPTS/DTYPES.PY
        self.ports = ports
        self.runtime_ports = runtime_ports  # to be used in accumulator and lick/holding variable
        self.saver = saver
        self.thresh = lick_thresh
        self.daq = DAQ(DAQ.ANALOG_IN, ports=self.ports, read_buffer_size=self.READ_BUF_SIZE)
        self.holding_thresh = int(holding_thresh * self.daq.sample_rate)

        # runtime vars
        self.licked_ = np.zeros(len(self.runtime_ports))
        self.accum = np.zeros((len(self.runtime_ports), self.ACCUM_SIZE))
        self.holding = np.array([False, False])
        self.lock = threading.Lock()
        self.accum_lock = threading.Lock()
        self.SAVING = False
        self.start()

    def start(self):
        # begin reading
        self.on = True
        th = threading.Thread(target=self.continuous_read)
        th.start()

    def get_accum(self):
        with self.accum_lock:
            return self.accum.copy()

    def continuous_read(self):
        while self.on:

            # read new data
            with self.accum_lock:
                self.accum = np.roll(self.accum, -self.READ_BUF_SIZE, axis=1)
                newdat_ts, newdat = (
                    self.daq.get()
                )  # important that "get" function locks thread, otherwise update line below would repeat logic on identical data
                assert newdat.shape == (len(self.ports), self.READ_BUF_SIZE)
                self.accum[:, -self.READ_BUF_SIZE :] = newdat[self.runtime_ports, :]

            # update logic
            with self.lock:
                self.licked_ += np.any(
                    newdat[self.runtime_ports, :] >= self.thresh, axis=1
                )  # is this really picking up the number of licks? no, it really represents the number of times this class queried and received a "at least 1 lick" response
                self.holding = np.all(self.accum[:, -self.holding_thresh :] > self.thresh, axis=1)

            if not self.on:  # b/c session can end b/t start of this loop iteration and this point
                break
            if self.saver and self.SAVING:
                self.saver.write("analogreader", newdat, ts=newdat_ts)
        self.release()

    def begin_saving(self):
        self.SAVING = True

    def licked(self):
        with self.lock:
            ret = self.licked_.copy()
            self.licked_ = np.zeros(len(self.runtime_ports))
            return ret

    def end(self):
        self.SAVING = False
        self.on = False

    def release(self):
        self.daq.release()
Exemple #8
0
        switch_type = self._setup['naming']['control']
        return site_name + switch_type + target.get('location',
                                                    '') + target['domain']

    def _get_t1_dp_name(self, domain):
        site_name = self._site['site_name']
        switch_type = self._setup['naming']['tier1']
        t1_conf = self._site['tier1']['domains'][domain]
        return site_name + switch_type + t1_conf.get('location', '') + domain

    def _get_t2_dp_name(self, t2_conf):
        site_name = self._site['site_name']
        switch_type = self._setup['naming']['tier2']
        return site_name + switch_type + t2_conf.get('location',
                                                     '') + t2_conf['domain']

    def _make_vlans(self):
        return {
            self._setup['vlan']['name']: {
                'description': self._setup['vlan']['description'],
                'vid': self._site['vlan_id']
            }
        }

    def _make_dps(self, domain):
        return {**self._make_t1_dps(domain), **self._make_t2_dps(domain)}


if __name__ == '__main__':
    sys.exit(TopologyGenerator(DAQ(sys.argv)).process())
Exemple #9
0
def main():
    """
    Main file to be executed for the vibration DAQ used for CUTE
    It imports the DAQ and Scope classes and modifies their behaviour using multiple threads
    This file handles path related things so that the script can be called and the appropriate configuration and log files are found.
    It parses command line arguments that can modify the DAQ and Scope functionality
    It creates the DAQ object, starts its run method in a seperate thread.
    Passes the DAQ object to the user_input function and starts that process in another thread.
    The Scope object is managed in the main thread as GUI components must be in the main thread.
    When the quit option is passed to the main thread all the threads join.
    """

#----------------    Path Related Things    ----------------#

    #make the relavent full paths
    cwd = os.getcwd()
    daq_path = sys.path[0]
    data_path = os.path.join(daq_path, 'data')
    vib_path = os.path.join(data_path, 'vib')
    psd_path = os.path.join(data_path, 'psd')

    #create the paths if they dont already exist
    if not os.path.exists(data_path):
        os.mkdir(data_path)
    if not os.path.exists(vib_path):
        os.mkdir(vib_path)
    if not os.path.exists(psd_path):
        os.mkdir(psd_path)

#----------------    Parse CLi Arguments    ----------------#

    try:
        opts, args = getopt.getopt(sys.argv[1:], 'hsa:p:', ['help','scope','address=','port='])

    except getopt.GetoptError:
        usage()
        sys.exit(2)

    #initialize default args
    address = ''
    port = ''
    scope_on = False
    scope = None

    #loop through all of the arguments
    for opt, arg in opts:

        #help option
        if opt in ('-h','--help'):
            usage()
            sys.exit(0)

        #address option
        elif opt in ('-a','--address'):
            address = arg

        #port option
        elif opt in ('-p','--port'):
            try:
                port = int(arg)
            except:
                raise

        #scope functionality option
        elif opt in ('-s','--scope'):
            scope_on = True

#-----------------    Setup the Logger    -----------------#

    #create logger
    logger = logging.getLogger('vib_daq')
    logger.setLevel(logging.DEBUG)

    #create file handler
    log_file = os.path.join(daq_path,'vib_daq.log')
    fh = logging.FileHandler(log_file)
    fh.setLevel(logging.DEBUG)

    #create stream handler
    ch = logging.StreamHandler()
    ch.setLevel(logging.ERROR)

    #create formatter
    formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')

    #add formatter to the handlers
    fh.setFormatter(formatter)
    ch.setFormatter(formatter)

    #add handlers to the logger
    logger.addHandler(fh)
    logger.addHandler(ch)

#-----------------    Read Config File    -----------------#

    #set up config parser
    config = configparser.ConfigParser()
    config.optionxform = str    #preserve case on import
    cfg_file = os.path.join(daq_path,'vib_daq.cfg')
    config.read(cfg_file)

    #conversion parameters
    convert = None
    if 'convert' in config.sections():
        convert = {key:config['convert'].getfloat(key) for key in config['convert']}

    #network parameters
    if not address:
        address = config['network'].get('IPv4')
    if not port:
        port = config['network'].getint('Port')

#-----------------    Start the DAQ    -----------------#

    #create queue for the scope
    q = queue.Queue()

    #create DAQ instance
    daq = DAQ(address, port, q, scope_on=scope_on, convert=convert)

    #create daq thread so console input can be received without blocking
    daq_thread = threading.Thread(target=daq.run)
    inpt_thread = threading.Thread(target=user_input,args=(daq,))

    #start the threads
    daq_thread.start()
    inpt_thread.start()

#-----------------    Control Scope    -----------------#

    while daq.take_data:

        if daq.scope_on:

            if scope is None:
                #create the scope
                scope = Scope(daq.fs, daq.n_frames)

            if not q.empty():
                traces = q.get()
                scope.draw(traces)
        else:
            if scope is not None:
                scope.close()
                scope = None

#-----------------    Join Threads    -----------------#

    #wait for the process to complete, blocks the main process
    inpt_thread.join()
    daq_thread.join()

#-----------------    Clean Up Files    -----------------#

    #loop through the files in the daq directory, moving csv files with the correct formatting to the data directory
    files = os.listdir(cwd)
    for f in files:
        if f.startswith('vib_') and f.endswith('.csv'):
            src = os.path.join(cwd,f)
            dst = os.path.join(vib_path,f)
            os.rename(src,dst)
        elif f.startswith('psd_') and f.endswith('.csv'):
            src = os.path.join(cwd,f)
            dst = os.path.join(psd_path,f)
            os.rename(src,dst)
Exemple #10
0
class MyFrame(wx.Frame):
    def __init__(self, parent, id, title):
        wx.Frame.__init__(
            self, parent, id, title, wx.DefaultPosition, (300, 150))
        self.panel = wx.Panel(self, -1)

        vbox = wx.BoxSizer(wx.VERTICAL)
        hbox = wx.BoxSizer(wx.HORIZONTAL)

        self.floatspin = FS.FloatSpin(
            self.panel, -1, pos=(50, 50), min_val=0, max_val=10,
            increment=0.1, value=5, agwStyle=FS.FS_CENTRE)
        self.floatspin.SetFormat("%f")
        self.floatspin.SetDigits(2)

        btn1 = wx.Button(self.panel, 8, 'Adjust')
        btn2 = wx.Button(self.panel, 9, 'Close')

        self.Bind(wx.EVT_CLOSE, self.OnClose)
        btn1.Bind(wx.EVT_BUTTON, self.on_adjust)
        btn2.Bind(wx.EVT_BUTTON, self.OnClose)
        
        vbox.Add(self.floatspin, 1, wx.ALIGN_CENTRE | wx.ALL, 10)
        hbox.Add(btn1, 1, wx.RIGHT, 10)
        hbox.Add(btn2, 1)
        vbox.Add(hbox, 0, wx.ALIGN_CENTRE | wx.ALL, 10)
        self.panel.SetSizer(vbox)
        self.initialize_daq()

    def on_adjust(self, event):
        change_voltage = self.floatspin.GetValue()
        print change_voltage
        self.daq.voltage[:, 2] = change_voltage
        print self.daq.voltage[:, 2]
    def OnClose(self, event):
        self.daq_timer.Stop()
        self.daq.stop_scan()
        self.daq.close()
        print "DAQ Closing"
        self.Destroy()

    def on_daq_timer(self, event):
        this_time = time.clock()
        print "Interval:", this_time - self.last_daq_time
        self.last_daq_time = this_time
        self.daq.write_voltage()

    def initialize_daq(self):
        rotations_per_second = 150
        facets_per_rotation = 10
        points_per_second = 500000

        """
        This logic assumes we can get away with an integer number of
        triggers per write; if we end up using a mirror with an odd
        number of sides, or if the mirror isn't perfectly regular, we
        might have to always use an integer number of rotations per
        write, not an integer number of triggers per write.
        """
        triggers_per_rotation = 2
        triggers_per_second = triggers_per_rotation * rotations_per_second
        points_per_trigger = points_per_second * (1.0 / triggers_per_second)
        facets_per_second = rotations_per_second * facets_per_rotation
        points_per_facet = points_per_second * (1.0 / facets_per_second)
        print
        print "Desired points per rotation:",
        print points_per_trigger * triggers_per_rotation
        print "Desired points per facet:", points_per_facet
        points_per_facet = int(round(points_per_facet))
        points_per_trigger = int(points_per_facet *
                                 facets_per_rotation *
                                 (1.0 / triggers_per_rotation))
        print "Actual points per rotation:",
        print points_per_trigger * triggers_per_rotation
        print "Actual points per facet:", (points_per_trigger *
                                           triggers_per_rotation *
                                           (1.0 / facets_per_rotation))
        print
        print "Desired rotations per second:", rotations_per_second
        rotations_per_second = (
            points_per_second *
            (1.0 / (points_per_trigger * triggers_per_rotation)))
        print "Actual rotations per second:", rotations_per_second
        print 
        points_per_write = points_per_second // 3
        print "Desired write length:", points_per_write
        rotations_per_write = points_per_write * 1.0 / (points_per_trigger *
                                                        triggers_per_rotation)
        rotations_per_write = int(round(rotations_per_write))
        points_per_write = (points_per_trigger *
                            triggers_per_rotation *
                            rotations_per_write)
        print "Actual write length:", points_per_write
        print "Rotations per write:", rotations_per_write
        triggers_per_write = triggers_per_rotation * rotations_per_write
        print "Triggers per write:", triggers_per_write
        print
        self.daq = DAQ(rate=points_per_second, write_length=points_per_write)

        wheel_signal = np.zeros(self.daq.write_length, dtype=np.float64)
        for i in range(triggers_per_write):
            start = i * points_per_trigger
            stop = start + points_per_trigger // 2
            wheel_signal[start:stop] = 6
        wheel_brake_signal = np.zeros(self.daq.write_length, dtype=np.float64)

        laser_signal = np.zeros(self.daq.write_length, dtype=np.float64)
        laser_duration = 1
        print "Laser duration:", laser_duration * 1.0 / points_per_second,
        print "seconds"
        ##Positive is up
        laser_lag = 65
        for i in range(rotations_per_write):
            for n in range(1):
                start = (i * points_per_trigger * triggers_per_rotation +
                         n * points_per_facet + 
                         laser_lag)
                stop = start + laser_duration
                laser_signal[start:stop] = 10

        voltage = np.zeros_like(self.daq.voltage)
        voltage[:, 0] = wheel_signal
        voltage[:, 1] = wheel_brake_signal
        voltage[:, 2] = 5 #focusing objective
        voltage[:, 3] = 0 #murrrcle
        voltage[:, 6] = laser_signal
        voltage[:, 7] = laser_signal
        self.daq.set_voltage(voltage)
        self.seconds_per_write = self.daq.write_length * 1.0 / self.daq.rate
        print "Seconds per write:", self.seconds_per_write

        TIMER_ID = 100
        self.daq_timer = wx.Timer(self.panel, TIMER_ID)
        self.daq_timer.Start(round(self.seconds_per_write * 1000 * 0.95))
        wx.EVT_TIMER(self.panel, TIMER_ID, self.on_daq_timer)
        self.last_daq_time = 0
        self.daq.scan()
Exemple #11
0
    def initialize_daq(self):
        rotations_per_second = 150
        facets_per_rotation = 10
        points_per_second = 500000

        """
        This logic assumes we can get away with an integer number of
        triggers per write; if we end up using a mirror with an odd
        number of sides, or if the mirror isn't perfectly regular, we
        might have to always use an integer number of rotations per
        write, not an integer number of triggers per write.
        """
        triggers_per_rotation = 2
        triggers_per_second = triggers_per_rotation * rotations_per_second
        points_per_trigger = points_per_second * (1.0 / triggers_per_second)
        facets_per_second = rotations_per_second * facets_per_rotation
        points_per_facet = points_per_second * (1.0 / facets_per_second)
        print
        print "Desired points per rotation:",
        print points_per_trigger * triggers_per_rotation
        print "Desired points per facet:", points_per_facet
        points_per_facet = int(round(points_per_facet))
        points_per_trigger = int(points_per_facet *
                                 facets_per_rotation *
                                 (1.0 / triggers_per_rotation))
        print "Actual points per rotation:",
        print points_per_trigger * triggers_per_rotation
        print "Actual points per facet:", (points_per_trigger *
                                           triggers_per_rotation *
                                           (1.0 / facets_per_rotation))
        print
        print "Desired rotations per second:", rotations_per_second
        rotations_per_second = (
            points_per_second *
            (1.0 / (points_per_trigger * triggers_per_rotation)))
        print "Actual rotations per second:", rotations_per_second
        print 
        points_per_write = points_per_second // 3
        print "Desired write length:", points_per_write
        rotations_per_write = points_per_write * 1.0 / (points_per_trigger *
                                                        triggers_per_rotation)
        rotations_per_write = int(round(rotations_per_write))
        points_per_write = (points_per_trigger *
                            triggers_per_rotation *
                            rotations_per_write)
        print "Actual write length:", points_per_write
        print "Rotations per write:", rotations_per_write
        triggers_per_write = triggers_per_rotation * rotations_per_write
        print "Triggers per write:", triggers_per_write
        print
        self.daq = DAQ(rate=points_per_second, write_length=points_per_write)

        wheel_signal = np.zeros(self.daq.write_length, dtype=np.float64)
        for i in range(triggers_per_write):
            start = i * points_per_trigger
            stop = start + points_per_trigger // 2
            wheel_signal[start:stop] = 6
        wheel_brake_signal = np.zeros(self.daq.write_length, dtype=np.float64)

        laser_signal = np.zeros(self.daq.write_length, dtype=np.float64)
        laser_duration = 1
        print "Laser duration:", laser_duration * 1.0 / points_per_second,
        print "seconds"
        ##Positive is up
        laser_lag = 65
        for i in range(rotations_per_write):
            for n in range(1):
                start = (i * points_per_trigger * triggers_per_rotation +
                         n * points_per_facet + 
                         laser_lag)
                stop = start + laser_duration
                laser_signal[start:stop] = 10

        voltage = np.zeros_like(self.daq.voltage)
        voltage[:, 0] = wheel_signal
        voltage[:, 1] = wheel_brake_signal
        voltage[:, 2] = 5 #focusing objective
        voltage[:, 3] = 0 #murrrcle
        voltage[:, 6] = laser_signal
        voltage[:, 7] = laser_signal
        self.daq.set_voltage(voltage)
        self.seconds_per_write = self.daq.write_length * 1.0 / self.daq.rate
        print "Seconds per write:", self.seconds_per_write

        TIMER_ID = 100
        self.daq_timer = wx.Timer(self.panel, TIMER_ID)
        self.daq_timer.Start(round(self.seconds_per_write * 1000 * 0.95))
        wx.EVT_TIMER(self.panel, TIMER_ID, self.on_daq_timer)
        self.last_daq_time = 0
        self.daq.scan()
Exemple #12
0
print 
points_per_write = points_per_second // 10
print "Desired write length:", points_per_write
rotations_per_write = points_per_write * 1.0 / (points_per_trigger *
                                                triggers_per_rotation)
rotations_per_write = int(round(rotations_per_write))
points_per_write = (points_per_trigger *
                    triggers_per_rotation *
                    rotations_per_write)
print "Actual write length:", points_per_write
print "Rotations per write:", rotations_per_write
triggers_per_write = triggers_per_rotation * rotations_per_write
print "Triggers per write:", triggers_per_write
print

daq = DAQ(rate=points_per_second, write_length=points_per_write)

wheel_signal = np.zeros(daq.write_length, dtype=np.float64)
for i in range(triggers_per_write):
    start = i * points_per_trigger
    stop = start + points_per_trigger // 2
    wheel_signal[start:stop] = 6
wheel_brake_signal = np.zeros(daq.write_length, dtype=np.float64)

laser_signal = np.zeros(daq.write_length, dtype=np.float64)
laser_duration = 1
print "Laser duration:", laser_duration * 1.0 / points_per_second, "seconds"
##Positive is up
laser_lag = 65
for i in range(rotations_per_write):
    for n in range(1):
Exemple #13
0
print "Actual rotations per second:", rotations_per_second
print
points_per_write = points_per_second // 10
print "Desired write length:", points_per_write
rotations_per_write = points_per_write * 1.0 / (points_per_trigger *
                                                triggers_per_rotation)
rotations_per_write = int(round(rotations_per_write))
points_per_write = (points_per_trigger * triggers_per_rotation *
                    rotations_per_write)
print "Actual write length:", points_per_write
print "Rotations per write:", rotations_per_write
triggers_per_write = triggers_per_rotation * rotations_per_write
print "Triggers per write:", triggers_per_write
print

daq = DAQ(rate=points_per_second, write_length=points_per_write)

wheel_signal = np.zeros(daq.write_length, dtype=np.float64)
for i in range(triggers_per_write):
    start = i * points_per_trigger
    stop = start + points_per_trigger // 2
    wheel_signal[start:stop] = 6
wheel_brake_signal = np.zeros(daq.write_length, dtype=np.float64)

laser_signal = np.zeros(daq.write_length, dtype=np.float64)
laser_duration = 1
print "Laser duration:", laser_duration * 1.0 / points_per_second, "seconds"
##Positive is up
laser_lag = 65
for i in range(rotations_per_write):
    for n in range(1):