def set_tone_bins(self, bins, nsamp, amps=None, load=True, normfact=None, phases=None, preset_norm=True): """ Set the stimulus tones by specific integer bins bins : array of bins at which tones should be placed For Heterodyne system, negative frequencies should be placed in cannonical FFT order If 2d, interpret as (nwaves,ntones) nsamp : int, must be power of 2 number of samples in the playback buffer. Frequency resolution will be fs/nsamp amps : optional array of floats, same length as bins array specify the relative amplitude of each tone. Can set to zero to read out a portion of the spectrum with no stimulus tone. load : bool (debug only). If false, don't actually load the waveform, just calculate it. """ if self.BYTES_PER_SAMPLE * nsamp > self.MEMORY_SIZE_BYTES: message = "Requested tone size ({:d} bytes) exceeds available memory ({:d} bytes)" raise ValueError(message.format(self.BYTES_PER_SAMPLE * nsamp, self.MEMORY_SIZE_BYTES)) if bins.ndim == 1: bins.shape = (1, bins.shape[0]) nwaves = bins.shape[0] spec = np.zeros((nwaves, nsamp), dtype='complex') self.tone_bins = bins.copy() self.tone_nsamp = nsamp #this is to make sure phases are correct shape since we are reusing phases if phases is None or phases.shape[0] != bins.shape[1]: phases = np.random.random(bins.shape[1]) * 2 * np.pi self.phases = phases.copy() if amps is None: amps = 1.0 self.amps = amps for k in range(nwaves): spec[k, bins[k, :]] = amps * np.exp(1j * phases) wave = np.fft.ifft(spec, axis=1) if preset_norm: self.wavenorm = calc_wavenorm(bins.shape[1], nsamp) else: self.wavenorm = np.abs(wave).max() if normfact is not None: wn = (2.0 / normfact) * len(bins) / float(nsamp) print "ratio of current wavenorm to optimal:", self.wavenorm / wn self.wavenorm = wn q_rwave = np.round((wave.real / self.wavenorm) * (2 ** 15 - 1024)).astype('>i2') q_iwave = np.round((wave.imag / self.wavenorm) * (2 ** 15 - 1024)).astype('>i2') q_iwave = np.roll(q_iwave, self.iq_delay, axis=1) q_rwave.shape = (q_rwave.shape[0] * q_rwave.shape[1],) q_iwave.shape = (q_iwave.shape[0] * q_iwave.shape[1],) self.q_rwave = q_rwave self.q_iwave = q_iwave if load: self.load_waveforms(q_rwave,q_iwave) self.save_state()
def add_tone_bins(self, bins, amps=None, preset_norm=True): nsamp = self.tone_nsamp spec = np.zeros((nsamp,), dtype='complex') self.tone_bins = np.vstack((self.tone_bins, bins)) phases = self.phases if amps is None: amps = 1.0 # self.amps = amps # TODO: Need to figure out how to deal with this spec[bins] = amps * np.exp(1j * phases) wave = np.fft.ifft(spec) if preset_norm: self.wavenorm = calc_wavenorm(self.tone_bins.shape[1], nsamp) else: self.wavenorm = np.abs(wave).max() q_rwave = np.round((wave.real / self.wavenorm) * (2 ** 15 - 1024)).astype('>i2') q_iwave = np.round((wave.imag / self.wavenorm) * (2 ** 15 - 1024)).astype('>i2') q_iwave = np.roll(q_iwave, self.iq_delay, axis=0) start_offset = self.tone_bins.shape[0] - 1 self.load_waveforms(q_rwave, q_iwave, start_offset=start_offset) self.save_state()
def add_tone_bins(self, bins, amps=None, preset_norm=True): nsamp = self.tone_nsamp spec = np.zeros((nsamp, ), dtype='complex') self.tone_bins = np.vstack((self.tone_bins, bins)) phases = self.phases if amps is None: amps = 1.0 # self.amps = amps # TODO: Need to figure out how to deal with this spec[bins] = amps * np.exp(1j * phases) wave = np.fft.ifft(spec) if preset_norm: self.wavenorm = calc_wavenorm(self.tone_bins.shape[1], nsamp) else: self.wavenorm = np.abs(wave).max() q_rwave = np.round( (wave.real / self.wavenorm) * (2**15 - 1024)).astype('>i2') q_iwave = np.round( (wave.imag / self.wavenorm) * (2**15 - 1024)).astype('>i2') q_iwave = np.roll(q_iwave, self.iq_delay, axis=0) start_offset = self.tone_bins.shape[0] - 1 self.load_waveforms(q_rwave, q_iwave, start_offset=start_offset) self.save_state()
def set_tone_bins(self, bins, nsamp, amps=None, load=True, normfact=None, phases=None, preset_norm=True): """ Set the stimulus tones by specific integer bins bins : array of bins at which tones should be placed For Heterodyne system, negative frequencies should be placed in cannonical FFT order If 2d, interpret as (nwaves,ntones) nsamp : int, must be power of 2 number of samples in the playback buffer. Frequency resolution will be fs/nsamp amps : optional array of floats, same length as bins array specify the relative amplitude of each tone. Can set to zero to read out a portion of the spectrum with no stimulus tone. load : bool (debug only). If false, don't actually load the waveform, just calculate it. """ if self.BYTES_PER_SAMPLE * nsamp > self.MEMORY_SIZE_BYTES: message = "Requested tone size ({:d} bytes) exceeds available memory ({:d} bytes)" raise ValueError( message.format(self.BYTES_PER_SAMPLE * nsamp, self.MEMORY_SIZE_BYTES)) if bins.ndim == 1: bins.shape = (1, bins.shape[0]) nwaves = bins.shape[0] spec = np.zeros((nwaves, nsamp), dtype='complex') self.tone_bins = bins.copy() self.tone_nsamp = nsamp #this is to make sure phases are correct shape since we are reusing phases if phases is None or phases.shape[0] != bins.shape[1]: phases = np.random.random(bins.shape[1]) * 2 * np.pi self.phases = phases.copy() if amps is None: amps = 1.0 self.amps = amps for k in range(nwaves): spec[k, bins[k, :]] = amps * np.exp(1j * phases) wave = np.fft.ifft(spec, axis=1) if preset_norm: self.wavenorm = calc_wavenorm(bins.shape[1], nsamp) else: self.wavenorm = np.abs(wave).max() if normfact is not None: wn = (2.0 / normfact) * len(bins) / float(nsamp) print "ratio of current wavenorm to optimal:", self.wavenorm / wn self.wavenorm = wn q_rwave = np.round( (wave.real / self.wavenorm) * (2**15 - 1024)).astype('>i2') q_iwave = np.round( (wave.imag / self.wavenorm) * (2**15 - 1024)).astype('>i2') q_iwave = np.roll(q_iwave, self.iq_delay, axis=1) q_rwave.shape = (q_rwave.shape[0] * q_rwave.shape[1], ) q_iwave.shape = (q_iwave.shape[0] * q_iwave.shape[1], ) self.q_rwave = q_rwave self.q_iwave = q_iwave if load: self.load_waveforms(q_rwave, q_iwave) self.save_state()