def _transfer_steps(self, steps): """ Writes all sequence steps passed, potentially overwriting. Parameters ---------- steps : list of :class:`wavgen.utilities.Step` Sequence steps to write. """ verboseprint('Beginning transfer of Steps to Board memory') for step in steps: cur = step.CurrentStep seg = step.SegmentIndex loop = step.Loops nxt = step.NextStep tran = step.Transition reg_upper = int32(tran | loop) reg_lower = int32(nxt << 16 | seg) debugprint("\tStep %.2d: 0x%08x_%08x\n" % (cur, reg_upper.value, reg_lower.value)) spcm_dwSetParam_i64m(self.hCard, SPC_SEQMODE_STEPMEM0 + cur, reg_upper, reg_lower) if DEBUG: print("\nDump!:\n") for i in range(len(steps)): temp = uint64(0) spcm_dwGetParam_i64(self.hCard, SPC_SEQMODE_STEPMEM0 + i, byref(temp)) print("\tStep %.2d: 0x%08x_%08x\n" % (i, int32(temp.value >> 32).value, int32( temp.value).value)) print("\t\tAlso: %16x\n" % temp.value)
def load_sequence(self, waveforms=None, steps=None): """ Transfers sequence waveforms and/or transition steps to board. Parameters ---------- waveforms : list of :class:`~.waveform.Waveform`, list of (int, :class:`~wavgen.waveform.Waveform`) Waveform objects to each be written to a board segment. If each is paired with an index, then the corresponding segment indices are overwritten. You can only overwrite if an initial sequence is present on board. steps : list of :class:`~wavgen.utilities.Step` Transition steps which define looping & order of segment playback. See Also -------- :class:`wavgen.utilities.Step` Examples -------- Transferring an initial sequence:: hCard # Opened & configured Board handle myWaves = [wav0, wav2, wav3] mySteps = [step1, step3] # A hCard.load_sequence(myWaves, mySteps) hCard.load_sequence(myWaves) hCard.load_sequence(steps=mySteps) """ assert steps or waveforms, "No data given to load!" ## Card Configuration ## if not self.ChanReady: # Sets channels to default mode if no user setting self.setup_channels() if not self.Sequence: # Ensures the Card is set to Sequential Mode verboseprint("Setting Sequence mode") spcm_dwSetParam_i32(self.hCard, SPC_CARDMODE, SPC_REP_STD_SEQUENCE) ## Create default indices if none provided ## if isinstance(waveforms[0], tuple): indices = [i for i, _ in waveforms] waveforms = [wav for _, wav in waveforms] else: indices = np.arange(len(waveforms)) ## Transfers provided Data ## if waveforms: self._transfer_sequence(waveforms, indices) if steps: self._transfer_steps(steps) # Loads the sequence steps to card ## Wrap Up ## self._setup_clock() self._error_check() self.BufReady = True self.Sequence = True
def _transfer_sequence(self, wavs, indices): """ Tries to write each waveform, from a set, to an indicated board memory segment. Parameters ---------- wavs : list of :class:`~wavgen.waveform.Waveform` Waveforms to write. indices : list of int, None The segment indices corresponding to the waveforms. """ ## Checks the Board Memory's current division ## segs = int32(0) spcm_dwGetParam_i32(self.hCard, SPC_SEQMODE_MAXSEGMENTS, byref(segs)) segs = max(segs.value, 1) ## Re-Divides the Board Memory if necessary ## if segs <= max(indices): verboseprint("Dividing Board Memory") while segs < max(indices): segs *= 2 # Halves all segments, doubling available segments spcm_dwSetParam_i32(self.hCard, SPC_SEQMODE_MAXSEGMENTS, segs) spcm_dwSetParam_i32(self.hCard, SPC_SEQMODE_STARTSTEP, 0) ## Checks that each wave can fit in the allowed segments ## limit = MEM_SIZE / (segs * 2) # Segment capacity in samples max_wav = max([wav.SampleLength for wav in wavs]) assert max_wav <= limit, "%i waves limits each segment to %i samples." % ( len(wavs), limit) ## Sets up a local Software Buffer for Transfer to Board ## pv_buf = pvAllocMemPageAligned(NUMPY_MAX * 2) # Allocates space on PC pn_buf = cast(pv_buf, ptr16) # Casts pointer into something usable # Writes each waveform from the sequence to a corresponding segment on Board Memory ## verboseprint('Beginning Transfer of Waveform data to Board memory.') for itr, (idx, wav) in enumerate(zip(indices, wavs)): verboseprint( "\tTransferring Seg %d of size %d bytes to index %d..." % (itr, wav.SampleLength * 2, idx)) start = time() spcm_dwSetParam_i32(self.hCard, SPC_SEQMODE_WRITESEGMENT, int32(idx)) spcm_dwSetParam_i32(self.hCard, SPC_SEQMODE_SEGMENTSIZE, int32(wav.SampleLength)) self._error_check() self._write_segment([wav], pv_buf, pn_buf) self._error_check() verboseprint("\t\tAverage Transfer rate: %d bytes/second" % (wav.SampleLength * 2 // (time() - start))) verboseprint("Total Transfer %d%c" % (int(100 * (itr + 1) / len(wavs)), '%'))
def _setup_clock(self): """ Tries to achieve requested sampling frequency (see global parameter :data:`~wavgen.config.SAMP_FREQ`) """ spcm_dwSetParam_i32( self.hCard, SPC_CLOCKMODE, SPC_CM_INTPLL) # Sets out internal Quarts Clock For Sampling spcm_dwSetParam_i64(self.hCard, SPC_SAMPLERATE, int64(int(SAMP_FREQ))) # Sets Sampling Rate spcm_dwSetParam_i32(self.hCard, SPC_CLOCKOUT, 0) # Disables Clock Output check_clock = int64(0) spcm_dwGetParam_i64(self.hCard, SPC_SAMPLERATE, byref(check_clock)) # Checks Sampling Rate verboseprint("Achieved Sampling Rate: ", check_clock.value)
def __init__(self, sample_length, amp=1.0): """ Parameters ---------- sample_length : int Sets the `SampleLength`. amp : float, optional Amplitude of waveform relative to maximum output voltage. """ if sample_length % 32: verboseprint("Sample length is being truncated to align with 32 samples.") self.SampleLength = int(sample_length - sample_length % 32) self.Amplitude = amp self.PlotObjects = [] self.Latest = False self.FilePath = None self.DataPath = ''
def stabilize_intensity(self, wav, cam=None, which_cam=None): """ Balances power across traps. Applies an iterative update to the magnitude vector (corresponding to the trap array) upon image analysis. Converges to homogeneous intensity profile across traps. Example ------- You could access this algorithm by passing a waveform object:: myWave = Superposition([79, 80, 81]) # Define a waveform hCard.stabilize_intensity(myWave) # Pass it into the optimizer or through the :doc:`GUI <../how-to/gui>`, offering camera view during the process:: # Define a wave & load the board memory. hCard.wiggle_output(self, cam=True) # Use button on GUI Parameters ---------- wav : :class:`~wavgen.waveform.Superposition` The waveform object whose magnitudes will be optimized. which_cam : bool, optional `True` or `False` selects Pre- or Post- chamber cameras respectively. cam : :obj:`instrumental.drivers.cameras.uc480` The camera object opened by :obj:`instrumental` module. """ assert isinstance( wav, Superposition ), "Only Superpositions of pure tones can be optimized!" if cam is None: # If we're not in GUI mode cam = self._run_cam() # Retrieves a cam which_cam = 0 self.load_waveforms(wav) self.wiggle_output(block=False) # Outputs the given wave L = 0.2 # Correction Rate mags = wav.get_magnitudes() ntraps = len(mags) step_num, rel_dif = 0, 1 while step_num < 5: step_num += 1 verboseprint("Iteration ", step_num) trap_powers = analyze_image(which_cam, cam, ntraps, step_num) mean_power = trap_powers.mean() rel_dif = 100 * trap_powers.std() / mean_power verboseprint(f'Relative Power Difference: {rel_dif:.2f} %') ## Chain of performance thresholds ## if rel_dif < 0.1: debugprint("WOW") break elif rel_dif < 0.36: L = 0.001 elif rel_dif < 0.5: L = 0.01 elif rel_dif < 2: L = 0.05 elif rel_dif < 5: L = 0.1 deltaM = [(mean_power - P) / P for P in trap_powers] dmags = [L * dM / sqrt(abs(dM)) for dM in deltaM] wav.set_magnitudes(np.add(mags, dmags)) self._update_magnitudes(wav) for i in range(5): if rel_dif > 0.5: break sleep(2) # im = np.zeros(cam.latest_frame().shape) # for _ in range(10): # imm = cam.latest_frame() # for _ in range(9): # imm = np.add(imm, cam.latest_frame()) # imm = np.multiply(imm, 0.1) # # im = np.add(im, imm) # im = np.multiply(im, 0.1) trap_powers = analyze_image(which_cam, cam, ntraps) dif = 100 * trap_powers.std() / trap_powers.mean() verboseprint(f'Relative Power Difference: {dif:.2f} %') plot_image(which_cam, cam.latest_frame(), ntraps) cam.close()
def wiggle_output(self, duration=None, cam=None, block=True): """ Performs a Standard Output for configured settings. Parameters ---------- duration : int, float **straight mode only** Pass an integer to loop waveforms said number of times. Pass a float to loop waveforms for said number of milliseconds. Defaults to looping an infinite number of times. cam : bool, optional Indicates whether to use Camera GUI. *True* or *False* selects Pre- or Post- chamber cameras respectively. block : bool, optional Stops the card on function exit? Returns ------- None WAVES! (This function itself actually returns void) """ assert self.BufReady, "No Waveforms loaded to Buffer" assert not (duration and self.Sequence), "Duration cannot be set for sequences." ## Timed or Looped mode determination ## if self.Sequence: verboseprint("Initiating Sequence start...") else: msg = "infinity..." if isinstance(duration, float): # Timed Mode msg = str(duration / 1000) + " seconds..." spcm_dwSetParam_i32(self.hCard, SPC_TIMEOUT, int(duration)) elif isinstance(duration, int): # Looped Mode msg = str(duration) + " cycles..." spcm_dwSetParam_i64(self.hCard, SPC_LOOPS, int64(duration)) else: # Check for Invalid Option assert duration is None, "Invalid input for steps" verboseprint("Looping Signal for ", msg) ## Sets blocking command appropriately ## WAIT = M2CMD_CARD_WAITREADY if (duration and block and cam is None) else 0 ## Start card, try again if clock-not-locked ## dwError = spcm_dwSetParam_i32( self.hCard, SPC_M2CMD, M2CMD_CARD_START | M2CMD_CARD_ENABLETRIGGER | WAIT) count = 0 while dwError == ERR_CLOCKNOTLOCKED: verboseprint("Clock not Locked, giving it a moment to adjust...") count += 1 sleep(0.1) self._error_check(halt=False, print_err=False) dwError = spcm_dwSetParam_i32( self.hCard, SPC_M2CMD, M2CMD_CARD_START | M2CMD_CARD_ENABLETRIGGER | WAIT) if count == 10: break ## Special Cases GUI/blocking ## if cam is not None: # GUI Mode self._run_cam(cam) spcm_dwSetParam_i32(self.hCard, SPC_M2CMD, M2CMD_CARD_STOP) elif self.Sequence: verboseprint('Sequence running...') elif block: if not (self.Sequence or duration): # Infinite Looping until stopped easygui.msgbox('Stop Card?', 'Infinite Looping!') spcm_dwSetParam_i32(self.hCard, SPC_M2CMD, M2CMD_CARD_STOP) self._error_check()