def __init__(self,
              name,
              trigger_device=None,
              trigger_connection=None,
              usbport='COM1'):
     PseudoClock.__init__(self, name, trigger_device, trigger_connection)
     self.BLACS_connection = usbport
Beispiel #2
0
 def __init__(self,
              name,
              ip_address,
              trigger_device=None,
              trigger_connection=None):
     PseudoClock.__init__(self, name, trigger_device, trigger_connection)
     self.BLACS_connection = ip_address
 def generate_code(self, hdf5_file):
     # Generate the hardware instructions
     hdf5_file.create_group('/devices/'+self.name)
     PseudoClock.generate_code(self, hdf5_file)
     dig_outputs, dds_outputs = self.get_direct_outputs()
     freqs, amps, phases = self.generate_registers(hdf5_file, dds_outputs)
     pb_inst, slow_clock_indices = self.convert_to_pb_inst(dig_outputs, dds_outputs, freqs, amps, phases)
     self.write_pb_inst_to_h5(pb_inst, slow_clock_indices, hdf5_file)
Beispiel #4
0
 def add_device(self, device):
     try:
         prefix, number = device.connection.split()
         assert int(number) in range(2)
         assert prefix == 'dds'
     except Exception:
         raise LabscriptError(
             'invalid connection string. Please use the format \'dds n\' with n 0 or 1'
         )
     PseudoClock.add_device(self, device)
 def __init__(self,name,trigger_device=None,trigger_connection=None,board_number=0,firmware = '', slow_clock_flag=1,fast_clock_flag=0):
     PseudoClock.__init__(self,name,trigger_device,trigger_connection)
     self.BLACS_connection = board_number
     # TODO: Implement capability checks based on firmware revision of PulseBlaster
     self.firmware_version = firmware
     
     # slow clock flag must be either the integer 0-11 to indicate a flag, or None to indicate not in use.
     if type(slow_clock_flag) == int:
         slow_clock_flag = [slow_clock_flag]
     if slow_clock_flag is not None:
         for flag in slow_clock_flag:
             if not self.flag_valid(flag):
                 raise LabscriptError('The slow clock flag(s) for Pulseblaster %s must either be an integer between 0-%d to indicate slow clock output'%(name, self.n_flags-1) +
                                      ' on that flag or None to indicate the suppression of the slow clock')
     self.slow_clock_flag = slow_clock_flag
         
         
     # if -1 < slow_clock_flag < self.n_flags or slow_clock_flag == None:
         # self.slow_clock_flag = slow_clock_flag
     # else:
         # raise LabscriptError('The slow clock flag for Pulseblaster %s must either be an integer between 0-11 to indicate slow clock output'%name +
                              # ' on that flag or None to indicate the suppression of the slow clock')
     
     # fast clock flag must be either the integer 0-11 to indicate a flag, or None to indicate not in use.
     if type(fast_clock_flag) == int:
         fast_clock_flag = [fast_clock_flag]
         
     self.extra_clocks = []
     if fast_clock_flag is not None:
         for flag in fast_clock_flag:
             if not self.flag_valid(flag) or (type(self.slow_clock_flag) == list and flag in self.slow_clock_flag):
                 raise LabscriptError('The fast clock flag for Pulseblaster %s must either be an integer between 0-%d to indicate fast clock output'%(name, self.n_flags-1) +
                                      ' on that flag orNone to indicate the suppression of the fast clock')
             self.extra_clocks.append('flag %d'%flag)
     self.fast_clock_flag = fast_clock_flag
         
     
     # if -1 < fast_clock_flag < self.n_flags or fast_clock_flag == None:
         # # the fast clock flag should not be the same as the slow clock flag
         # if fast_clock_flag == slow_clock_flag and fast_clock_flag != None:
             # raise LabscriptError('The fast clock flag for Pulseblaster %s must not be the same as the slow clock flag')
         # else:
             # self.fast_clock_flag = fast_clock_flag
     # else:
         # raise LabscriptError('The fast clock flag for Pulseblaster %s must either be an integer between 0-11 to indicate fast clock output'%name +
                              # ' on that flag orNone to indicate the suppression of the fast clock')
     
     # Only allow directly connected devices if we don't have a fast clock or a slow clock
     if slow_clock_flag == None and fast_clock_flag == None:
         self.allowed_children = [DDS,DigitalOut]
         self.description = 'PB-DDSII-300 [standalone]' #make the error messages make a little more sense
         self.has_clocks = False
     else:
         self.has_clocks = True
 def generate_code(self, hdf5_file):
     PseudoClock.generate_code(self, hdf5_file)
     group = hdf5_file['devices'].create_group(self.name)
     # Store the clock tick times:
     try:
         group.create_dataset('FAST_CLOCK',
                              compression=config.compression,
                              data=self.times[self.clock_type])
     except:
         import IPython
         IPython.embed()
     # compress clock instructions with the same period: This will
     # halve the number of instructions roughly, since the PineBlaster
     # does not have a 'slow clock':
     reduced_instructions = []
     for instruction in self.clock:
         if instruction == 'WAIT':
             # The following period and reps indicates a wait instruction
             reduced_instructions.append({'period': 0, 'reps': 1})
             continue
         reps = instruction['reps']
         # period is in quantised units:
         period = int(round(instruction['step'] / self.clock_resolution))
         if reduced_instructions and reduced_instructions[-1][
                 'period'] == period:
             reduced_instructions[-1]['reps'] += reps
         else:
             reduced_instructions.append({'period': period, 'reps': reps})
     # The following period and reps indicates a stop instruction:
     reduced_instructions.append({'period': 0, 'reps': 0})
     if len(reduced_instructions) > self.max_instructions:
         raise LabscriptError(
             "%s %s has too many instructions. It has %d and can only support %d"
             % (self.description, self.name, len(reduced_instructions),
                self.max_instructions))
     # Store these instructions to the h5 file:
     dtypes = [('period', int), ('reps', int)]
     pulse_program = np.zeros(len(reduced_instructions), dtype=dtypes)
     for i, instruction in enumerate(reduced_instructions):
         pulse_program[i]['period'] = instruction['period']
         pulse_program[i]['reps'] = instruction['reps']
     group.create_dataset('PULSE_PROGRAM',
                          compression=config.compression,
                          data=pulse_program)
     group.attrs['is_master_pseudoclock'] = self.is_master_pseudoclock
Beispiel #7
0
    def generate_code(self, hdf5_file):
        from rfblaster import caspr
        import rfblaster.rfjuice
        rfjuice_folder = os.path.dirname(rfblaster.rfjuice.__file__)

        import rfblaster.rfjuice.const as c
        from rfblaster.rfjuice.cython.make_diff_table import make_diff_table
        from rfblaster.rfjuice.cython.compile import compileD
        # from rfblaster.rfjuice.compile import compileD
        import tempfile
        from subprocess import Popen, PIPE

        # Generate clock and save raw instructions to the h5 file:
        PseudoClock.generate_code(self, hdf5_file)
        dtypes = [('time', float), ('amp0', float), ('freq0', float),
                  ('phase0', float), ('amp1', float), ('freq1', float),
                  ('phase1', float)]
        data = np.zeros(len(self.times[self.clock_type]), dtype=dtypes)
        data['time'] = self.times[self.clock_type]
        for dds in self.child_devices:
            prefix, connection = dds.connection.split()
            data['freq%s' % connection] = dds.frequency.raw_output
            data['amp%s' % connection] = dds.amplitude.raw_output
            data['phase%s' % connection] = dds.phase.raw_output
        group = hdf5_file['devices'].create_group(self.name)
        group.create_dataset('TABLE_DATA',
                             compression=config.compression,
                             data=data)

        # Quantise the data and save it to the h5 file:
        quantised_dtypes = [('time', np.int64), ('amp0', np.int32),
                            ('freq0', np.int32), ('phase0', np.int32),
                            ('amp1', np.int32), ('freq1', np.int32),
                            ('phase1', np.int32)]
        quantised_data = np.zeros(len(self.times[self.clock_type]),
                                  dtype=quantised_dtypes)
        quantised_data['time'] = np.array(c.tT * 1e6 * data['time'] + 0.5)
        for dds in range(2):
            # TODO: bounds checking
            # Adding 0.5 to each so that casting to integer rounds:
            quantised_data['freq%d' %
                           dds] = np.array(c.fF * 1e-6 * data['freq%d' % dds] +
                                           0.5)
            quantised_data['amp%d' % dds] = np.array((2**c.bitsA - 1) *
                                                     data['amp%d' % dds] + 0.5)
            quantised_data['phase%d' %
                           dds] = np.array(c.pP * data['phase%d' % dds] + 0.5)
        group.create_dataset('QUANTISED_DATA',
                             compression=config.compression,
                             data=quantised_data)
        # Generate some assembly code and compile it to machine code:
        assembly_group = group.create_group('ASSEMBLY_CODE')
        binary_group = group.create_group('BINARY_CODE')
        diff_group = group.create_group('DIFF_TABLES')
        # When should the RFBlaster wait for a trigger?
        quantised_trigger_times = np.array(
            [c.tT * 1e6 * t + 0.5 for t in self.trigger_times], dtype=np.int64)
        for dds in range(2):
            abs_table = np.zeros((len(self.times[self.clock_type]), 4),
                                 dtype=np.int64)
            abs_table[:, 0] = quantised_data['time']
            abs_table[:, 1] = quantised_data['amp%d' % dds]
            abs_table[:, 2] = quantised_data['freq%d' % dds]
            abs_table[:, 3] = quantised_data['phase%d' % dds]

            # split up the table into chunks delimited by trigger times:
            abs_tables = []
            for i, t in enumerate(quantised_trigger_times):
                subtable = abs_table[abs_table[:, 0] >= t]
                try:
                    next_trigger_time = quantised_trigger_times[i + 1]
                except IndexError:
                    # No next trigger time
                    pass
                else:
                    subtable = subtable[subtable[:, 0] < next_trigger_time]
                subtable[:, 0] -= t
                abs_tables.append(subtable)

            # convert to diff tables:
            diff_tables = [make_diff_table(tab) for tab in abs_tables]
            # Create temporary files, get their paths, and close them:
            with tempfile.NamedTemporaryFile(delete=False) as f:
                temp_assembly_filepath = f.name
            with tempfile.NamedTemporaryFile(delete=False) as f:
                temp_binary_filepath = f.name

            try:
                # Compile to assembly:
                with open(temp_assembly_filepath, 'w') as assembly_file:
                    for i, dtab in enumerate(diff_tables):
                        compileD(dtab,
                                 assembly_file,
                                 init=(i == 0),
                                 jump_to_start=(i == 0),
                                 jump_from_end=False,
                                 close_end=(i == len(diff_tables) - 1),
                                 local_loop_pre=str(i),
                                 set_defaults=(i == 0))
                # Save the assembly to the h5 file:
                with open(temp_assembly_filepath, ) as assembly_file:
                    assembly_code = assembly_file.read()
                    assembly_group.create_dataset('DDS%d' % dds,
                                                  data=assembly_code)
                    for i, diff_table in enumerate(diff_tables):
                        diff_group.create_dataset(
                            'DDS%d_difftable%d' % (dds, i),
                            compression=config.compression,
                            data=diff_table)
                # compile to binary:
                compilation = Popen(
                    [caspr, temp_assembly_filepath, temp_binary_filepath],
                    stdout=PIPE,
                    stderr=PIPE,
                    cwd=rfjuice_folder,
                    startupinfo=startupinfo)
                stdout, stderr = compilation.communicate()
                if compilation.returncode:
                    print stdout
                    raise LabscriptError(
                        'RFBlaster compilation exited with code %d\n\n' %
                        compilation.returncode +
                        'Stdout was:\n %s\n' % stdout +
                        'Stderr was:\n%s\n' % stderr)
                # Save the binary to the h5 file:
                with open(temp_binary_filepath, 'rb') as binary_file:
                    binary_data = binary_file.read()
                # has to be numpy.string_ (string_ in this namespace,
                # imported from pylab) as python strings get stored
                # as h5py as 'variable length' strings, which 'cannot
                # contain embedded nulls'. Presumably our binary data
                # must contain nulls sometimes. So this crashes if we
                # don't convert to a numpy 'fixes length' string:
                binary_group.create_dataset('DDS%d' % dds,
                                            data=np.string_(binary_data))
            finally:
                # Delete the temporary files:
                os.remove(temp_assembly_filepath)
                os.remove(temp_binary_filepath)