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 canonical 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 // 2 + 1), dtype='complex') self.tone_bins = bins.copy() self.tone_nsamp = nsamp if phases is None: 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.irfft(spec, axis=1) if preset_norm and not normfact: self.wavenorm = tools.calc_wavenorm(bins.shape[1], nsamp, baseband=True) else: self.wavenorm = np.abs(wave).max() if normfact is not None: wn = (2.0 / normfact) * len(bins) / float(nsamp) logger.debug( "Using user provide waveform normalization resulting in wavenorm %f versus optimal %f. " "Ratio is %f" % (wn, self.wavenorm, self.wavenorm / wn)) self.wavenorm = wn qwave = np.round((wave / self.wavenorm) * (2**15 - 1024)).astype('>i2') qwave.shape = (qwave.shape[0] * qwave.shape[1], ) self.qwave = qwave if load: self.load_waveform(qwave) 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 canonical 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 // 2 + 1), dtype='complex') self.tone_bins = bins.copy() self.tone_nsamp = nsamp if phases is None: 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.irfft(spec, axis=1) if preset_norm and not normfact: self.wavenorm = tools.calc_wavenorm(bins.shape[1], nsamp, baseband=True) else: self.wavenorm = np.abs(wave).max() if normfact is not None: wn = (2.0 / normfact) * len(bins) / float(nsamp) logger.debug("Using user provide waveform normalization resulting in wavenorm %f versus optimal %f. " "Ratio is %f" % (wn,self.wavenorm,self.wavenorm/wn)) self.wavenorm = wn qwave = np.round((wave / self.wavenorm) * (2 ** 15 - 1024)).astype('>i2') qwave.shape = (qwave.shape[0] * qwave.shape[1],) self.qwave = qwave if load: self.load_waveform(qwave) self.save_state()
def add_tone_bins(self, bins, amps=None, preset_norm=True): nsamp = self.tone_nsamp spec = np.zeros((nsamp // 2 + 1,), 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.irfft(spec) if preset_norm: self.wavenorm = tools.calc_wavenorm(self.tone_bins.shape[1], nsamp, baseband=True) else: self.wavenorm = np.abs(wave).max() qwave = np.round((wave / self.wavenorm) * (2 ** 15 - 1024)).astype('>i2') # self.qwave = qwave # TODO: Deal with this, if we ever use it start_offset = self.tone_bins.shape[0] - 1 self.load_waveform(qwave, 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 // 2 + 1, ), 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.irfft(spec) if preset_norm: self.wavenorm = tools.calc_wavenorm(self.tone_bins.shape[1], nsamp, baseband=True) else: self.wavenorm = np.abs(wave).max() qwave = np.round((wave / self.wavenorm) * (2**15 - 1024)).astype('>i2') # self.qwave = qwave # TODO: Deal with this, if we ever use it start_offset = self.tone_bins.shape[0] - 1 self.load_waveform(qwave, start_offset=start_offset) self.save_state()