def config_sdr_tdd(self, is_bs=True, tdd_sched="G", prefix_len=0, max_frames=1): '''Configure the TDD schedule and functionality when unchained. Set up the correlator.''' global corr_threshold, beacon coe = cfloat2uint32(np.conj(beacon), order='QI') self.tdd_sched = tdd_sched self.max_frames = int(max_frames) if bool(is_bs): conf_str = { "tdd_enabled": True, "frame_mode": "free_running", "symbol_size": self.n_samp, "max_frame": max_frames, "beacon_start": prefix_len, "beacon_stop": prefix_len + len(beacon), "frames": [self.tdd_sched] } self.sdr.writeSetting("TDD_CONFIG", json.dumps(conf_str)) print("TDD schedule of BS node {}: {}".format( self.serial_id, tdd_sched)) else: conf_str = { "tdd_enabled": True, "frame_mode": "triggered", "symbol_size": self.n_samp, "frames": [self.tdd_sched] } self.sdr.writeSetting("TDD_CONFIG", json.dumps(conf_str)) #Correlator stuff: corr_conf = { "corr_enabled": True, "corr_threshold": corr_threshold } self.sdr.writeSetting("CORR_CONFIG", json.dumps(corr_conf)) if coe is not None: self.sdr.writeRegisters("CORR_COE", 0, coe.tolist()) else: print("No coe was passed into config_sdr_tdd() \n") # DEV: ueTrigTime = 153 (prefix_length=0), CBRS: ueTrigTime = 235 (prefix_length=82), tx_advance=prefix_length, corr delay is 17 cycles ueTrigTime = len(beacon) + 200 sf_start = int(ueTrigTime // (self.n_samp)) sp_start = int(ueTrigTime % (self.n_samp)) print( "config_sdr_tdd: UE starting symbol and sample count (%d, %d)" % (sf_start, sp_start)) # make sure to set this after TDD mode is enabled "writeSetting("TDD_CONFIG", ..." self.sdr.setHardwareTime( SoapySDR.ticksToTimeNs((sf_start << 16) | sp_start, self.sample_rate), "TRIGGER") print("TDD schedule of UE node {}: {}".format( self.serial_id, tdd_sched)) self.sdr.writeSetting("TX_SW_DELAY", str(30)) self.sdr.writeSetting("TDD_MODE", "true")
def config_sdr_tdd(self, tdd_sched=None, is_bs=True): '''Configure the TDD schedule and functionality when unchained. Set up the correlator.''' global tx_advance, corr_threshold, beacon len_beacon_zpad = len(beacon) + self.n_zpad_samp coe = cfloat2uint32(np.conj(beacon), order='QI') if tdd_sched is not None: self.tdd_sched = tdd_sched else: self.tdd_sched = "G" print(tdd_sched) max_frames = self.max_frames if bool(is_bs): conf_str = { "tdd_enabled": True, "frame_mode": "free_running", "symbol_size": self.n_samp, "max_frame": max_frames, "frames": [self.tdd_sched] } self.sdr.writeSetting("TDD_CONFIG", json.dumps(conf_str)) else: conf_str = { "tdd_enabled": True, "frame_mode": "triggered", "symbol_size": self.n_samp, "frames": [self.tdd_sched] } self.sdr.writeSetting("TDD_CONFIG", json.dumps(conf_str)) #Correlator stuff: self.sdr.writeRegister("IRIS30", CORR_CONF, int( "00004001", 16)) # enable the correlator, with zeros as inputs for i in range(128): self.sdr.writeRegister("ARGCOE", i * 4, 0) time.sleep(0.1) self.sdr.writeRegister("IRIS30", CORR_RST, 0x1) # reset corr self.sdr.writeRegister("IRIS30", CORR_RST, 0x0) # unrst corr self.sdr.writeRegister("IRIS30", CORR_THRESHOLD, int(corr_threshold)) if coe is not None: for i in range(128): self.sdr.writeRegister("ARGCOE", i * 4, int(coe[i])) else: print("No coe was passed into config_sdr_tdd() \n") # DEV: ueTrigTime = 153 (prefix_length=0), CBRS: ueTrigTime = 235 (prefix_length=82), tx_advance=prefix_length, corr delay is 17 cycles ueTrigTime = 17 + tx_advance + len_beacon_zpad sf_start = int(ueTrigTime // (self.n_samp)) sp_start = int(ueTrigTime % (self.n_samp)) print( "config_sdr_tdd: UE starting symbol and sample count (%d, %d)" % (sf_start, sp_start)) self.sdr.setHardwareTime( SoapySDR.ticksToTimeNs((sf_start << 16) | sp_start, self.sample_rate), "TRIGGER" ) # make sure to set this after TDD mode is enabled "writeSetting("TDD_CONFIG", ..." self.sdr.writeSetting("TX_SW_DELAY", str(30)) self.sdr.writeSetting("TDD_MODE", "true")
def rx(self, nsamps, rx_delay=57, delay=10000000, ts=None): '''Receive nsamps on rxsdr at timestamp ts, if provided, otherwise waits delay ns.''' if self.rxsdr is None: print('Error: No RX SDR provided!') return nsamps = int(nsamps) rx_delay_ns = SoapySDR.ticksToTimeNs(rx_delay, self.rate) hw_time = self.trig_sdr.getHardwareTime() ts = hw_time + delay + rx_delay_ns if ts is None else ts + rx_delay_ns sampsRecv = np.empty(nsamps, dtype=np.complex64) rxFlags = SOAPY_SDR_HAS_TIME | SOAPY_SDR_END_BURST # GM note: if nsamps is greater than some threshold, an error will print to terminal self.rxsdr.activateStream(self.rxStream, rxFlags, ts, nsamps) # GM uncommented these added first line print( "hwtime, delay, rx_delay_ns, ts \n [sdr.getHardwareTime() for sdr in self.sdrs]" ) print(hw_time, delay, rx_delay_ns, ts) print([sdr.getHardwareTime() for sdr in self.sdrs]) #time.sleep((ts - hw_time)/1e9) # GM documentation on device.readStream is not great, # can't find a function definition anywhere beyond an error code, not on github sr = self.rxsdr.readStream(self.rxStream, [sampsRecv], nsamps, timeoutUs=int(1e6)) if sr.ret != nsamps: print("Bad read!!!") # GM print("nsamps, sr.ret, [sampsRecv]") print(nsamps) print(sr.ret) # GM print as list, so it all prints #print(sampsRecv.tolist()[:150]) # GM attempting to invert signal back into integers # for reference (from below): # sig = np.exp(s_time_vals*1j*2*np.pi*s_freq).astype(np.complex64)*.5 decoded = np.log( sampsRecv[:150] * 2) / 1j / 2 / np.pi / 500e3 # s_freq = 500e3 # decoded = np.log((sampsRecv*2).astype(float)) /1j /2 /np.pi /500e3 # s_freq = 500e3 ints = np.arange(150) ints = ints - 100 #samp buff #GM estimating CSI csi = decoded / ints # csi = sampsRecv[:150] / ints # GM print expected, raw data from buffer, inverted function for i in range(150): print("expected: ", ints[i], "\nraw: ", sampsRecv[i], "\nval: ", decoded[i], "\nCSI: ", csi[i]) return sampsRecv
def Process_RxActivate_WriteFlagToRxStream_UseHasTime(self, rx_delay=57): rx_delay_ns = SoapySDR.ticksToTimeNs(rx_delay, self.rate) if rx_delay != 0 else 0 ts = self.ts + rx_delay_ns # rx is a bit after tx flags = SOAPY_SDR_HAS_TIME | SOAPY_SDR_END_BURST # activate all receive stream for r, rxStream in enumerate(self.rxStreams): serial_ant = self.rx_serials_ant[r] serial, ant = Format_SplitSerialAnt(serial_ant) sdr = self.sdrs[serial] sdr.activateStream(rxStream, flags, ts, len(self.sampsRecv[r][0]))
def rx(self, nsamps, rx_delay=57, delay=10000000, ts=None): '''Receive nsamps on rxsdr at timestamp ts, if provided, otherwise waits delay ns.''' if self.rxsdr is None: print('Error: No RX SDR provided!') return nsamps = int(nsamps) rx_delay_ns = SoapySDR.ticksToTimeNs(rx_delay,self.rate) hw_time = self.trig_sdr.getHardwareTime() ts = hw_time + delay + rx_delay_ns if ts is None else ts + rx_delay_ns sampsRecv = np.empty(nsamps, dtype=np.complex64) rxFlags = SOAPY_SDR_HAS_TIME | SOAPY_SDR_END_BURST self.rxsdr.activateStream(self.rxStream, rxFlags, ts, nsamps) #print(hw_time,delay,rx_delay_ns,ts) #print([sdr.getHardwareTime() for sdr in self.sdrs]) time.sleep((ts - hw_time)/1e9) sr = self.rxsdr.readStream(self.rxStream, [sampsRecv], nsamps, timeoutUs=int(1e6)) if sr.ret != nsamps: print("Bad read!!!") return sampsRecv
def setupUE(args, serial, rate, freq, txgain, rxgain, numSamps, numSyms, pilotSymbol, txSymbol, txSymNum, threshold, tx_advance, prefix_length, postfix_length, cp, calibrate, both_channels, wait_trigger, auto_tx_gain): global msdr, txStreamM, rxStreamM msdr = SoapySDR.Device(dict(serial=serial)) #some default sample rates for sdr in [msdr]: info = sdr.getHardwareInfo(); print("%s settings" % info["frontend"]) for ch in [0,1]: sdr.setSampleRate(SOAPY_SDR_TX, ch, rate) sdr.setSampleRate(SOAPY_SDR_RX, ch, rate) #sdr.setFrequency(SOAPY_SDR_TX, ch, freq) #sdr.setFrequency(SOAPY_SDR_RX, ch, freq) sdr.setFrequency(SOAPY_SDR_TX, ch, 'RF', freq-.75*rate) sdr.setFrequency(SOAPY_SDR_RX, ch, 'RF', freq-.75*rate) sdr.setFrequency(SOAPY_SDR_TX, ch, 'BB', .75*rate) sdr.setFrequency(SOAPY_SDR_RX, ch, 'BB', .75*rate) if ("CBRS" in info["frontend"]): sdr.setGain(SOAPY_SDR_TX, ch, 'ATTN', 0) #[-18,0] by 3 sdr.setGain(SOAPY_SDR_TX, ch, 'PA1', 15) #[0|15] sdr.setGain(SOAPY_SDR_TX, ch, 'PA2', 0) #[0|15] sdr.setGain(SOAPY_SDR_TX, ch, 'PA3', 30) #[0|30] if ("UHF" in info["frontend"]): sdr.setGain(SOAPY_SDR_TX, ch, 'ATTN', 0) #[-18,0] by 3 sdr.setGain(SOAPY_SDR_TX, ch, 'IAMP', 0) #[0,12] sdr.setGain(SOAPY_SDR_TX, ch, 'PAD', txgain) #[0,52] if ("CBRS" in info["frontend"]): sdr.setGain(SOAPY_SDR_RX, ch, 'ATTN', 0) #[-18,0] sdr.setGain(SOAPY_SDR_RX, ch, 'LNA1', 30) #[0,33] sdr.setGain(SOAPY_SDR_RX, ch, 'LNA2', 17) #[0,17] if ("UHF" in info["frontend"]): sdr.setGain(SOAPY_SDR_RX, ch, 'ATTN1', -6) #[-18,0] sdr.setGain(SOAPY_SDR_RX, ch, 'ATTN2', -12) #[-18,0] sdr.setGain(SOAPY_SDR_RX, ch, 'LNA', rxgain) #[0,30] sdr.setGain(SOAPY_SDR_RX, ch, 'TIA', 0) #[0,12] sdr.setGain(SOAPY_SDR_RX, ch, 'PGA', 0) #[-12,19] sdr.setAntenna(SOAPY_SDR_RX, ch, "TRX") #sdr.setBandwidth(SOAPY_SDR_TX, ch, 30e6) #sdr.setBandwidth(SOAPY_SDR_RX, ch, 30e6) sdr.setDCOffsetMode(SOAPY_SDR_RX, ch, True) if calibrate: for ch in [0,1]: sdr.writeSetting(SOAPY_SDR_RX, ch, "CALIBRATE", 'SKLK') sdr.writeSetting(SOAPY_SDR_TX, ch, "CALIBRATE", 'SKLK') #if not both_channels: # sdr.writeSetting("SPI_TDD_MODE", "SISO") # sdr.writeSetting(SOAPY_SDR_RX, 1, 'ENABLE_CHANNEL', 'false') # sdr.writeSetting(SOAPY_SDR_TX, 1, 'ENABLE_CHANNEL', 'false') #else: # sdr.writeSetting("SPI_TDD_MODE", "MIMO") sdr.writeRegister("IRIS30", RF_RST_REG, (1<<29) | 0x1) sdr.writeRegister("IRIS30", RF_RST_REG, (1<<29)) sdr.writeRegister("IRIS30", RF_RST_REG, 0) msdr.writeRegister("ARGCOR", CORR_RST, 0x1) # reset corr msdr.writeRegister("IRIS30", TX_GAIN_CTRL, 0) minfo = msdr.getHardwareInfo() #packet size symSamp = numSamps + prefix_length + postfix_length print("symSamp = %d"%symSamp) print("txSymNum = %d"%txSymNum) upsample = 1 # preambles to be sent from BS and correlated against in UE preambles_bs, highest_peak_to_second_ratio_bs = Preambles.getPreambles('gold_ifft', 128, 0, upsample=1) #the base station may upsample, but the mobiles won't preambles = preambles_bs[:,::upsample] #the correlators can run at lower rates, so we only need the downsampled signal. beacon = preambles[0,:]*.25 coe = cfloat2uint32(np.conj(beacon), order='QI') # FPGA correlator takes coefficients in QI order ltsSym = lts.genLTS(upsample=upsample,cp=1 if cp else 0) pad1 = np.array([0]*(prefix_length), np.complex64) # to comprensate for front-end group delay pad2 = np.array([0]*(postfix_length), np.complex64) # to comprensate for rf path delay wb_pilot = np.tile(ltsSym,numSamps/len(ltsSym)).astype(np.complex64)*.5 wbz = np.array([0]*(symSamp), np.complex64) wb_pilot1 = np.concatenate([pad1,wb_pilot,pad2]) wb_pilot2 = wb_pilot1 if both_channels else wbz Ts = 1/rate s_freq = 1e6 s_time_vals = np.array(np.arange(0,symSamp)).transpose()*Ts nb_data = np.exp(s_time_vals*1j*2*np.pi*s_freq).astype(np.complex64)*.25 rand_data = [1,0,1,1,0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, \ 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, \ 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0 ,1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, \ 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1 ,0, 1, 0, 0, \ 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, \ 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, \ 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1] #data_16qam = genDATA(np.random.randint(2, size=64*4),0) data_16qam = ofdm.genDATAQPSK(rand_data,0) if not cp: data_16qam[16:] wb_data = np.tile(data_16qam,numSamps/len(data_16qam)).astype(np.complex64)*.5 wb_data = np.concatenate([pad1,wb_data,pad2]) if txSymNum > 0: txStreamM = msdr.setupStream(SOAPY_SDR_TX, SOAPY_SDR_CF32, [0, 1]) rxStreamM = msdr.setupStream(SOAPY_SDR_RX, SOAPY_SDR_CS16, [0, 1]) msdr.writeRegister("IRIS30", CORR_CONF, int("00004001", 16)) # enable the correlator, with zeros as inputs for i in range(128): msdr.writeRegister("ARGCOE", i*4, 0) time.sleep(0.1) msdr.writeRegister("ARGCOR", CORR_THRESHOLD, int(threshold)) msdr.writeRegister("ARGCOR", CORR_RST, 0x1) # reset corr msdr.writeRegister("ARGCOR", CORR_RST, 0x0) # unrst corr for i in range(128): msdr.writeRegister( "ARGCOE", i*4, int(coe[i])) if auto_tx_gain: max_gain = int(txgain) min_gain = max(0, max_gain-15) gain_reg = 0xF000 | (max_gain & 0x3F) << 6 | (min_gain & 0x3F) print("gain reg 0x%X" % gain_reg) msdr.writeRegister("IRIS30", TX_GAIN_CTRL, gain_reg) # [15] en, [14] mode, [13:12] step, [11:6] stop, [5:0] start if both_channels: pilotSymNum = 2 msched = ''.join("G"*(pilotSymbol-2))+"PP" else: pilotSymNum = 1 msched = ''.join("G"*(pilotSymbol-2))+"P" if txSymNum > 0: msched += ''.join("G"*(txSymbol-pilotSymbol-pilotSymNum))+''.join("T"*txSymNum)+''.join("G"*(numSyms-txSymNum-txSymbol)) msched = "GR" + msched else: msched += ''.join("G"*(numSyms-pilotSymbol-pilotSymNum)) msched = "GG" + msched print("Client schedule %s " % msched) mconf = {"tdd_enabled": True, "trigger_out": True, "wait_trigger": True, "dual_pilot": both_channels, "symbol_size" : symSamp, "frames": [msched]} msdr.writeSetting("TDD_CONFIG", json.dumps(mconf)) # DEV: ueTrigTime = 153 (prefix_length=0), CBRS: ueTrigTime = 235 (prefix_length=82), tx_advance=prefix_length ueTrigTime = prefix_length + len(beacon) + postfix_length + 17 + tx_advance sf_start = ueTrigTime/symSamp sp_start = ueTrigTime%symSamp print("UE starting symbol and sample count (%d, %d)" % (sf_start, sp_start)) msdr.setHardwareTime(SoapySDR.ticksToTimeNs((sf_start<<16) | sp_start, rate),"TRIGGER") # make sure to set this after TDD mode is enabled "writeSetting("TDD_CONFIG", ..." for sdr in [msdr]: sdr.writeSetting("TX_SW_DELAY", str(30)) msdr.writeSetting("TDD_MODE", "true") replay_addr = 0 if both_channels: msdr.writeRegisters("TX_RAM_A", replay_addr+(pilotSymbol%2)*2048, cfloat2uint32(wb_pilot1, order='QI').tolist()) msdr.writeRegisters("TX_RAM_B", replay_addr+((pilotSymbol+1)%2)*2048, cfloat2uint32(wb_pilot1, order='QI').tolist()) else: msdr.writeRegisters("TX_RAM_A", replay_addr, cfloat2uint32(wb_pilot1, order='QI').tolist()) msdr.writeRegisters("TX_RAM_B", replay_addr, cfloat2uint32(wb_pilot2, order='QI').tolist()) #pdb.set_trace() msdr.writeRegister("IRIS30", CORR_CONF, int("00004011", 16)) # enable the correlator, with inputs from adc signal.signal(signal.SIGINT, partial(signal_handler, rate, numSyms, txSymNum)) if txSymNum>0: txth = threading.Thread(target=tx_thread, args=(msdr, rate, txStreamM, rxStreamM, wb_data, symSamp, numSyms, txSymNum, txSymbol)) txth.start() #signal.pause() num_trig = 0 while True: time.sleep(0.25) t = SoapySDR.timeNsToTicks(msdr.getHardwareTime(""),rate) >> 32 #trigger count is top 32 bits. print("%d new triggers, %d total" % (t - num_trig, t)) num_trig = t
def siso_sounder(serial1, serial2, rate, freq, txgain, rxgain, bw, numSamps, numSyms, txSymNum, threshold, tx_advance, prefix_length, postfix_length, both_channels, wait_trigger, calibrate, record, use_trig, auto_tx_gain): global bsdr, msdr, txStreamM, rxStreamB print("setting %s as eNB and %s as UE" % (serial1, serial2)) bsdr = SoapySDR.Device(dict(serial=serial1)) msdr = SoapySDR.Device(dict(serial=serial2)) #some default sample rates for i, sdr in enumerate([bsdr, msdr]): info = sdr.getHardwareInfo() print("%s settings on device %d" % (info["frontend"], i)) for ch in [0, 1]: sdr.setSampleRate(SOAPY_SDR_TX, ch, rate) sdr.setSampleRate(SOAPY_SDR_RX, ch, rate) #sdr.setFrequency(SOAPY_SDR_TX, ch, freq) #sdr.setFrequency(SOAPY_SDR_RX, ch, freq) sdr.setFrequency(SOAPY_SDR_TX, ch, 'RF', freq - .75 * rate) sdr.setFrequency(SOAPY_SDR_RX, ch, 'RF', freq - .75 * rate) sdr.setFrequency(SOAPY_SDR_TX, ch, 'BB', .75 * rate) sdr.setFrequency(SOAPY_SDR_RX, ch, 'BB', .75 * rate) if ("CBRS" in info["frontend"]): sdr.setGain(SOAPY_SDR_TX, ch, 'ATTN', 0) #[-18,0] by 3 sdr.setGain(SOAPY_SDR_TX, ch, 'PA1', 15) #[0,15] sdr.setGain(SOAPY_SDR_TX, ch, 'PA2', 0) #[0,15] sdr.setGain(SOAPY_SDR_TX, ch, 'PA3', 30) #[0,30] sdr.setGain(SOAPY_SDR_TX, ch, 'IAMP', 12) #[0,12] sdr.setGain(SOAPY_SDR_TX, ch, 'PAD', txgain) #[-52,0] if ("CBRS" in info["frontend"]): sdr.setGain(SOAPY_SDR_RX, ch, 'ATTN', 0) #[-18,0] sdr.setGain(SOAPY_SDR_RX, ch, 'LNA1', 30) #[0,33] sdr.setGain(SOAPY_SDR_RX, ch, 'LNA2', 17) #[0,17] sdr.setGain(SOAPY_SDR_RX, ch, 'LNA', rxgain) #[0,30] sdr.setGain(SOAPY_SDR_RX, ch, 'TIA', 0) #[0,12] sdr.setGain(SOAPY_SDR_RX, ch, 'PGA', 0) #[-12,19] sdr.setAntenna(SOAPY_SDR_RX, ch, "TRX") #sdr.setBandwidth(SOAPY_SDR_RX, ch, bw) #sdr.setBandwidth(SOAPY_SDR_TX, ch, bw) sdr.setDCOffsetMode(SOAPY_SDR_RX, ch, True) for ch in [0, 1]: if calibrate: sdr.writeSetting(SOAPY_SDR_RX, ch, "CALIBRATE", 'SKLK') sdr.writeSetting(SOAPY_SDR_TX, ch, "CALIBRATE", '') sdr.writeRegister("IRIS30", RF_RST_REG, (1 << 29) | 0x1) sdr.writeRegister("IRIS30", RF_RST_REG, (1 << 29)) sdr.writeRegister("IRIS30", RF_RST_REG, 0) if not both_channels: sdr.writeSetting("SPI_TDD_MODE", "SISO") sdr.writeSetting(SOAPY_SDR_RX, 1, 'ENABLE_CHANNEL', 'false') sdr.writeSetting(SOAPY_SDR_TX, 1, 'ENABLE_CHANNEL', 'false') else: sdr.writeSetting("SPI_TDD_MODE", "MIMO") #pdb.set_trace() msdr.writeRegister("IRIS30", TX_GAIN_CTRL, 0) if use_trig: bsdr.writeSetting("SYNC_DELAYS", "") #bsdr.writeSetting("FPGA_DIQ_MODE", "PATTERN") else: msdr.writeRegister("ARGCOR", CORR_RST, 0x1) # reset corr #packet size symSamp = numSamps + prefix_length + postfix_length print("numSamps = %d" % symSamp) print("txSymNum = %d" % txSymNum) upsample = 1 Ts = 1 / rate s_freq = 1e6 s_time_vals = np.array(np.arange(0, numSamps)).transpose() * Ts nb_data = np.exp(s_time_vals * 1j * 2 * np.pi * s_freq).astype( np.complex64) * .25 #create streams rxStreamM = msdr.setupStream(SOAPY_SDR_RX, SOAPY_SDR_CS16, [0, 1]) txStreamM = msdr.setupStream(SOAPY_SDR_TX, SOAPY_SDR_CF32, [0, 1]) if record: rxStreamB = bsdr.setupStream(SOAPY_SDR_RX, SOAPY_SDR_CS16, [0, 1]) # preambles to be sent from BS and correlated against in UE preambles_bs, highest_peak_to_second_ratio_bs = Preambles.getPreambles( 'gold_ifft', 128, 0, upsample=1) #the base station may upsample, but the mobiles won't preambles = preambles_bs[:, :: upsample] #the correlators can run at lower rates, so we only need the downsampled signal. beacon = preambles[0, :] * .25 coe = cfloat2uint32( np.conj(beacon), order='QI') # FPGA correlator takes coefficients in QI order ltsSym = lts.genLTS(upsample=1, cp=0) pad1 = np.array([0] * (prefix_length), np.complex64) # to comprensate for front-end group delay pad2 = np.array([0] * (postfix_length), np.complex64) # to comprensate for rf path delay wb_pilot = np.tile(ltsSym, numSamps / len(ltsSym)).astype( np.complex64) * .5 wbz = np.array([0] * (symSamp), np.complex64) wb_pilot1 = np.concatenate([pad1, wb_pilot, pad2]) wb_pilot2 = wbz #wb_pilot1 if both_channels else wbz bcnz = np.array([0] * (symSamp - prefix_length - len(beacon)), np.complex64) beacon1 = np.concatenate([pad1, beacon, bcnz]) beacon2 = wbz #beacon1 if both_channels else wbz bsched = "PGR" + ''.join("G" * (numSyms - txSymNum - 4)) + ''.join( "R" * txSymNum) + "G" msched = "GGP" + ''.join("G" * (numSyms - txSymNum - 4)) + ''.join( "T" * txSymNum) + "G" if both_channels: bsched = "PGRR" + ''.join("G" * (numSyms - txSymNum - 5)) + ''.join( "R" * txSymNum) + "G" msched = "GGPP" + ''.join("G" * (numSyms - txSymNum - 5)) + ''.join( "T" * txSymNum) + "G" print("Node 1 schedule %s " % bsched) print("Node 2 schedule %s " % msched) bconf = { "tdd_enabled": True, "trigger_out": False, "symbol_size": symSamp, "frames": [bsched] } mconf = { "tdd_enabled": True, "trigger_out": not use_trig, "wait_trigger": wait_trigger, "dual_pilot": both_channels, "symbol_size": symSamp, "frames": [msched] } #mconf = {"tdd_enabled": True, "trigger_out": not use_trig, "wait_trigger": True, "symbol_size" : symSamp, "frames": [msched]} bsdr.writeSetting("TDD_CONFIG", json.dumps(bconf)) msdr.writeSetting("TDD_CONFIG", json.dumps(mconf)) for sdr in [bsdr, msdr]: sdr.writeSetting("TX_SW_DELAY", str(30)) if not use_trig: msdr.writeRegister("IRIS30", CORR_CONF, int( "00004001", 16)) # enable the correlator, with zeros as inputs for i in range(128): msdr.writeRegister("ARGCOE", i * 4, 0) time.sleep(0.1) msdr.writeRegister("ARGCOR", CORR_THRESHOLD, int(threshold)) msdr.writeRegister("ARGCOR", CORR_RST, 0x1) # reset corr msdr.writeRegister("ARGCOR", CORR_RST, 0x0) # unrst corr for i in range(128): msdr.writeRegister("ARGCOE", i * 4, int(coe[i])) if auto_tx_gain: max_gain = int(txgain) min_gain = max(0, max_gain - 15) gain_reg = 0xF000 | (max_gain & 0x3F) << 6 | (min_gain & 0x3F) print("gain reg 0x%X" % gain_reg) msdr.writeRegister( "IRIS30", TX_GAIN_CTRL, gain_reg ) # [15] en, [14] mode, [13:12] step, [11:6] stop, [5:0] start # DEV: ueTrigTime = 153 (prefix_length=0), CBRS: ueTrigTime = 235 (prefix_length=82), tx_advance=prefix_length, corr delay is 17 cycles ueTrigTime = prefix_length + len( beacon) + postfix_length + 17 + tx_advance sf_start = ueTrigTime / symSamp sp_start = ueTrigTime % symSamp print("UE starting symbol and sample count (%d, %d)" % (sf_start, sp_start)) msdr.setHardwareTime( SoapySDR.ticksToTimeNs((sf_start << 16) | sp_start, rate), "TRIGGER" ) # make sure to set this after TDD mode is enabled "writeSetting("TDD_CONFIG", ..." msdr.writeSetting("TDD_MODE", "true") bsdr.writeSetting("TDD_MODE", "true") replay_addr = 0 bsdr.writeRegisters("TX_RAM_A", replay_addr, cfloat2uint32(beacon1, order='IQ').tolist()) bsdr.writeRegisters("TX_RAM_B", replay_addr, cfloat2uint32(beacon2, order='IQ').tolist()) msdr.writeRegisters("TX_RAM_A", replay_addr, cfloat2uint32(wb_pilot1, order='IQ').tolist()) msdr.writeRegisters("TX_RAM_B", replay_addr, cfloat2uint32(wbz, order='IQ').tolist()) if both_channels: msdr.writeRegisters("TX_RAM_A", replay_addr + 2048, cfloat2uint32(wbz, order='IQ').tolist()) msdr.writeRegisters("TX_RAM_B", replay_addr + 2048, cfloat2uint32(wb_pilot2, order='IQ').tolist()) if not use_trig: msdr.writeRegister("IRIS30", CORR_CONF, int( "00004011", 16)) # enable the correlator, with inputs from adc signal.signal(signal.SIGINT, partial(signal_handler, rate, numSyms)) bsdr.writeSetting("TRIGGER_GEN", "") txth = threading.Thread(target=tx_thread, args=(msdr, rate, txStreamM, rxStreamM, nb_data, symSamp, numSyms, txSymNum, numSyms - txSymNum - 1)) txth.start() if record: rxth = threading.Thread(target=rx_thread, args=(bsdr, rxStreamB, symSamp, txSymNum, both_channels)) rxth.start() signal.pause()
def siso_sounder(hub, serial1, serial2, rate, freq, txgain, rxgain, numSamps, numSyms, txSymNum, threshold, tx_advance, prefix_length, postfix_length, both_channels, wait_trigger, calibrate, record, use_trig, tx_power_loop, agc_en): global bsdr, msdr, txStreamM, rxStreamB print("setting %s as eNB and %s as UE" % (serial1, serial2)) bsdr = SoapySDR.Device(dict(serial=serial1)) msdr = SoapySDR.Device(dict(serial=serial2)) if hub != "": trig_dev = SoapySDR.Device(dict(serial=hub, driver="remote")) else: trig_dev = bsdr # Some default sample rates for i, sdr in enumerate([bsdr, msdr]): info = sdr.getHardwareInfo() print("%s settings on device %d" % (info["frontend"], i)) for ch in [0, 1]: sdr.setBandwidth(SOAPY_SDR_TX, ch, 2.5*rate) sdr.setBandwidth(SOAPY_SDR_RX, ch, 2.5*rate) sdr.setSampleRate(SOAPY_SDR_TX, ch, rate) sdr.setSampleRate(SOAPY_SDR_RX, ch, rate) #sdr.setFrequency(SOAPY_SDR_TX, ch, freq) #sdr.setFrequency(SOAPY_SDR_RX, ch, freq) sdr.setFrequency(SOAPY_SDR_TX, ch, 'RF', freq-.75*rate) sdr.setFrequency(SOAPY_SDR_RX, ch, 'RF', freq-.75*rate) sdr.setFrequency(SOAPY_SDR_TX, ch, 'BB', .75*rate) sdr.setFrequency(SOAPY_SDR_RX, ch, 'BB', .75*rate) sdr.setAntenna(SOAPY_SDR_RX, ch, "TRX") sdr.setDCOffsetMode(SOAPY_SDR_RX, ch, True) if "CBRS" in info["frontend"]: # Set gains to high val (initially) if agc_en: rxgain = 100 sdr.setGain(SOAPY_SDR_TX, ch, txgain) sdr.setGain(SOAPY_SDR_RX, ch, rxgain) else: # No CBRS board gains, only changing LMS7 gains # AGC only supported for CBRS boards agc_en = False sdr.setGain(SOAPY_SDR_TX, ch, "PAD", txgain) # [0:1:42] sdr.setGain(SOAPY_SDR_TX, ch, "IAMP", 0) # [-12:1:3] sdr.setGain(SOAPY_SDR_RX, ch, "LNA", rxgain) # [0:1:30] sdr.setGain(SOAPY_SDR_RX, ch, "TIA", 0) # [0, 3, 9, 12] sdr.setGain(SOAPY_SDR_RX, ch, "PGA", -10) # [-12:1:19] # Read initial gain settings readLNA = sdr.getGain(SOAPY_SDR_RX, 0, 'LNA') readTIA = sdr.getGain(SOAPY_SDR_RX, 0, 'TIA') readPGA = sdr.getGain(SOAPY_SDR_RX, 0, 'PGA') print("INITIAL GAIN - LNA: {}, \t TIA:{}, \t PGA:{}".format(readLNA, readTIA, readPGA)) for ch in [0, 1]: if calibrate: sdr.writeSetting(SOAPY_SDR_RX, ch, "CALIBRATE", 'SKLK') sdr.writeSetting("RESET_DATA_LOGIC", "") # pdb.set_trace() if use_trig: trig_dev.writeSetting("SYNC_DELAYS", "") # Packet size symSamp = numSamps + prefix_length + postfix_length print("numSamps = %d" % symSamp) print("txSymNum = %d" % txSymNum) upsample = 1 Ts = 1/rate s_freq = 1e6 s_time_vals = np.array(np.arange(0, numSamps)).transpose()*Ts nb_data = np.exp(s_time_vals*1j*2*np.pi*s_freq).astype(np.complex64)*.25 # Create streams rxStreamM = msdr.setupStream(SOAPY_SDR_RX, SOAPY_SDR_CS16, [0, 1]) txStreamM = msdr.setupStream(SOAPY_SDR_TX, SOAPY_SDR_CF32, [0, 1]) if record: rxStreamB = bsdr.setupStream(SOAPY_SDR_RX, SOAPY_SDR_CS16, [0, 1]) tpc_conf = {"tpc_enabled" : False} msdr.writeSetting("TPC_CONFIG", json.dumps(tpc_conf)) agc_conf = {"agc_enabled" : agc_en} msdr.writeSetting("AGC_CONFIG", json.dumps(agc_conf)) # preambles to be sent from BS and correlated against in UE # the base station may upsample, but the mobiles won't preambles_bs = generate_training_seq(preamble_type='gold_ifft', seq_length=128, cp=0, upsample=1) # the correlators can run at lower rates, so we only need the downsampled signal. preambles = preambles_bs[:, ::upsample] ampl = 0.5 beacon = preambles[0, :] coe = cfloat2uint32(np.conj(beacon), order='QI') # FPGA correlator takes coefficients in QI order ltsSym, lts_f = generate_training_seq(preamble_type='lts', cp=32, upsample=1) # ltsSym = lts.genLTS(upsample=1, cp=0) pad1 = np.array([0]*(prefix_length), np.complex64) # to comprensate for front-end group delay pad2 = np.array([0]*(postfix_length), np.complex64) # to comprensate for rf path delay wb_pilot = np.tile(ltsSym, numSamps//len(ltsSym)).astype(np.complex64)*ampl wbz = np.array([0]*(symSamp), np.complex64) wb_pilot1 = np.concatenate([pad1, wb_pilot, pad2]) wb_pilot2 = wbz # wb_pilot1 if both_channels else wbz bcnz = np.array([0]*(symSamp-prefix_length-len(beacon)), np.complex64) if both_channels: beacon_weights = hadamard(2) else: beacon_weights = np.eye(2, dtype=np.uint32) beacon_weights = beacon_weights.astype(np.uint32) bsched = "BGR"+''.join("G"*(numSyms-txSymNum-4))+''.join("R"*txSymNum)+"G" msched = "GGP"+''.join("G"*(numSyms-txSymNum-4))+''.join("T"*txSymNum)+"G" if both_channels: bsched = "BGRR"+''.join("G"*(numSyms-txSymNum-5))+''.join("R"*txSymNum)+"G" msched = "GGPP"+''.join("G"*(numSyms-txSymNum-5))+''.join("T"*txSymNum)+"G" print("Iris 1 schedule %s " % bsched) print("Iris 2 schedule %s " % msched) bconf = {"tdd_enabled": True, "frame_mode": "free_running", "symbol_size": symSamp, "frames": [bsched], "beacon_start" : prefix_length, "beacon_stop" : prefix_length+len(beacon), "max_frame" : 0} mconf = {"tdd_enabled": True, "frame_mode": "free_running" if use_trig else "triggered" if wait_trigger else "continuous_resync", "dual_pilot": both_channels, "symbol_size" : symSamp, "frames": [msched], "max_frame" : 0} bsdr.writeSetting("TDD_CONFIG", json.dumps(bconf)) msdr.writeSetting("TDD_CONFIG", json.dumps(mconf)) bsdr.writeRegisters("BEACON_RAM", 0, cfloat2uint32(beacon, order='QI').tolist()) bsdr.writeRegisters("BEACON_RAM_WGT_A", 0, beacon_weights[0].tolist()) bsdr.writeRegisters("BEACON_RAM_WGT_B", 0, beacon_weights[1].tolist()) numAnt = 2 if both_channels else 1 bsdr.writeSetting("BEACON_START", str(numAnt)) for sdr in [bsdr, msdr]: sdr.writeSetting("TX_SW_DELAY", str(30)) sdr.writeSetting("TDD_MODE", "true") if not use_trig: corr_conf = {"corr_enabled" : True, "corr_threshold" : threshold} msdr.writeSetting("CORR_CONFIG", json.dumps(corr_conf)) msdr.writeRegisters("CORR_COE", 0, coe.tolist()) # DEV: ueTrigTime = 153 (prefix_length=0), CBRS: ueTrigTime = 235 (prefix_length=82), tx_advance=prefix_length, # corr delay is 17 cycles ueTrigTime = len(beacon) + 200 # prefix_length + len(beacon) + postfix_length + 17 + tx_advance + 150 sf_start = ueTrigTime // symSamp sp_start = ueTrigTime % symSamp print("UE starting symbol and sample count (%d, %d)" % (sf_start, sp_start)) # make sure to set this after TDD mode is enabled "writeSetting("TDD_CONFIG", ..." msdr.setHardwareTime(SoapySDR.ticksToTimeNs((sf_start << 16) | sp_start, rate), "TRIGGER") if tx_power_loop: tcp_conf = {"tpc_enabled" : True, "max_gain" : int(tx_gain), "min_gain" : max(0, max_gain-12)} msdr.writeSetting("TPC_CONFIG", json.dumps(tpc_conf)) msdr.writeRegisters("TX_RAM_A", 0, cfloat2uint32(wb_pilot1, order='QI').tolist()) if both_channels: msdr.writeRegisters("TX_RAM_B", 0, cfloat2uint32(wb_pilot2, order='QI').tolist()) if not use_trig: msdr.writeSetting("CORR_START", "A") signal.signal(signal.SIGINT, partial(signal_handler, rate, numSyms, use_trig)) trig_dev.writeSetting("TRIGGER_GEN", "") txth = threading.Thread(target=tx_thread, args=(msdr, rate, txStreamM, rxStreamM, nb_data, symSamp, numSyms, txSymNum, numSyms-txSymNum-1)) txth.start() if record: rxth = threading.Thread(target=rx_thread, args=(bsdr, rxStreamB, symSamp, txSymNum, both_channels)) rxth.start() num_trig = 0 while True: time.sleep(1) t = SoapySDR.timeNsToTicks(msdr.getHardwareTime(""),rate) >> 32 #trigger count is top 32 bits. print("%d new triggers, %d total" % (t - num_trig, t)) num_trig = t
def init(hub, bnodes, cnodes, ref_ant, ampl, rate, freq, txgain, rxgain, cp, plotter, numSamps, prefix_length, postfix_length, tx_advance, mod_order, threshold, use_trig): if hub != "": hub_dev = SoapySDR.Device(dict(driver="remote", serial = hub)) # device that triggers bnodes and ref_node bsdrs = [SoapySDR.Device(dict(driver="iris", serial = serial)) for serial in bnodes] # base station sdrs csdrs = [SoapySDR.Device(dict(driver="iris", serial = serial)) for serial in cnodes] # client sdrs # assume trig_sdr is part of the master nodes trig_dev = None if hub != "": trig_dev = hub_dev else: trig_dev = bsdrs[0] #set params on both channels for sdr in bsdrs+csdrs: info = sdr.getHardwareInfo() print("%s settings on device" % (info["frontend"])) for ch in [0, 1]: sdr.setBandwidth(SOAPY_SDR_TX, ch, 2.5*rate) sdr.setBandwidth(SOAPY_SDR_RX, ch, 2.5*rate) sdr.setSampleRate(SOAPY_SDR_TX, ch, rate) sdr.setSampleRate(SOAPY_SDR_RX, ch, rate) # sdr.setFrequency(SOAPY_SDR_TX, ch, freq) # sdr.setFrequency(SOAPY_SDR_RX, ch, freq) sdr.setFrequency(SOAPY_SDR_TX, ch, 'RF', freq-.75*rate) sdr.setFrequency(SOAPY_SDR_RX, ch, 'RF', freq-.75*rate) sdr.setFrequency(SOAPY_SDR_TX, ch, 'BB', .75*rate) sdr.setFrequency(SOAPY_SDR_RX, ch, 'BB', .75*rate) sdr.setAntenna(SOAPY_SDR_RX, ch, "TRX") sdr.setDCOffsetMode(SOAPY_SDR_RX, ch, True) sdr.setGain(SOAPY_SDR_TX, ch, 'PAD', txgain) sdr.setGain(SOAPY_SDR_RX, ch, 'LNA', rxgain) if "CBRS" in info["frontend"]: sdr.setGain(SOAPY_SDR_TX, ch, 'ATTN', -6) sdr.setGain(SOAPY_SDR_RX, ch, 'LNA2', 14) if freq < 3e9: sdr.setGain(SOAPY_SDR_RX, ch, 'ATTN', -12) else: sdr.setGain(SOAPY_SDR_RX, ch, 'ATTN', 0) # Read initial gain settings readLNA = sdr.getGain(SOAPY_SDR_RX, 0, 'LNA') readTIA = sdr.getGain(SOAPY_SDR_RX, 0, 'TIA') readPGA = sdr.getGain(SOAPY_SDR_RX, 0, 'PGA') print("INITIAL GAIN - LNA: {}, \t TIA:{}, \t PGA:{}".format(readLNA, readTIA, readPGA)) sdr.writeSetting("RESET_DATA_LOGIC", "") sdr.writeSetting(SOAPY_SDR_RX, 1, 'ENABLE_CHANNEL', 'false') sdr.writeSetting(SOAPY_SDR_TX, 1, 'ENABLE_CHANNEL', 'false') trig_dev.writeSetting("SYNC_DELAYS", "") sym_samps = numSamps + prefix_length + postfix_length print("numSamps = %d"%sym_samps) M = len(bsdrs) K = len(csdrs) N = 64 D = 1 # number of downlink symbols pad1 = np.array([0]*(prefix_length), np.complex64) # to comprensate for front-end group delay pad2 = np.array([0]*(postfix_length), np.complex64) # to comprensate for rf path delay wbz = np.array([0]*(sym_samps), np.complex64) # OFDM object ofdm_obj = ofdmTxRx() #### Generate Pilot cp_len = 32 if cp else 0 ofdm_len = 2*N + cp_len lts_rep = numSamps//(ofdm_len) zeros = np.array([0]*(numSamps-ofdm_len)) lts_sym, lts_f = generate_training_seq(preamble_type='lts', cp=cp_len, upsample=1) pilot = np.concatenate((lts_sym, zeros)) wb_pilot = ampl * pilot wb_pilot1 = np.concatenate([pad1, wb_pilot, pad2]) lts_t = lts_sym[-64:] lts_t_cp = np.concatenate((lts_t[len(lts_t) - 16:], lts_t)) #### Generate Beacon and hadamard weights upsample = 1 preambles_bs = generate_training_seq(preamble_type='gold_ifft', seq_length=128, cp=0, upsample=upsample) preambles = preambles_bs[:,::upsample] beacon = preambles[0,:] coe = cfloat2uint32(np.conj(beacon), order='QI') bcnz = np.array([0]*(sym_samps-prefix_length-len(beacon)), np.complex64) beacon1 = np.concatenate([pad1,beacon*.5,bcnz]) beacon2 = wbz possible_dim = [] possible_dim.append(2**(np.ceil(np.log2(M)))) h_dim = min(possible_dim) hadamard_matrix = hadamard(h_dim) beacon_weights = hadamard_matrix[0:M, 0:M] beacon_weights = beacon_weights.astype(np.uint32) #### Generate Data data_cp_len = 16 if cp else 0 data_ofdm_len = N + data_cp_len n_ofdm_syms = (numSamps // data_ofdm_len) sig_t, data_const, tx_data, sc_idx_all, pilots_matrix = \ ofdm_obj.generate_data(n_ofdm_syms - 2, mod_order, cp_length=data_cp_len) data_sc = sc_idx_all[0] pilot_sc = sc_idx_all[1] tx_dl_data = np.zeros((N, n_ofdm_syms, K)).astype(complex) for k in range(K): tx_dl_data[data_sc, 2:, k] = data_const tx_dl_data[pilot_sc, 2:, k] = pilots_matrix tx_dl_data[:, 0, k] = lts_f tx_dl_data[:, 1, k] = lts_f tx_dl_ifft = np.zeros((M, n_ofdm_syms, N)).astype(complex) print("n_ofdm_syms %d, data_ofdm_len %d"%(n_ofdm_syms, data_ofdm_len)) # received data params lts_thresh = 0.8 n_data_ofdm_syms = n_ofdm_syms - 2 payload_len = n_data_ofdm_syms * data_ofdm_len lts_len = 2 * data_ofdm_len fft_offset = 0 #### Configure tdd mode guardSize = (len(csdrs)) % 2 + 1 frameLen = len(csdrs) + len(bsdrs)*2 + 4 + guardSize # BS frame config for i,sdr in enumerate(bsdrs): beacon_sch = "BG" if i == ref_ant: ref_ul_pilot_sch = "PG" ref_dl_pilot_sch = ''.join("RG" * (M - 1)) ul_pilot_sch = ''.join("R" * K) else: ref_ul_pilot_sch = "RG" new_i = i - (i > ref_ant) ref_dl_pilot_sch = ''.join("GG" * new_i) + "PG" + ''.join("GG" * (M-(new_i+2))) ul_pilot_sch = ''.join("R" * K) frame_sch1 = beacon_sch + ref_ul_pilot_sch + ref_dl_pilot_sch + ul_pilot_sch + 'G' dl_data_sch = "PG" + ''.join("G" * (2 * M + K - (2 * D))) frame_sch2 = beacon_sch + dl_data_sch + 'G' print("BS node %d frame schedule (%s, %s)" % (i, frame_sch1, frame_sch2)) bconf = {"tdd_enabled": True, "frame_mode": "triggered", "symbol_size" : sym_samps, "frames": [frame_sch1, frame_sch2], "beacon_start" : prefix_length, "beacon_stop" : prefix_length+len(beacon), "max_frame" : 2} sdr.writeSetting("TDD_CONFIG", json.dumps(bconf)) sdr.writeSetting("TDD_MODE", "true") # Client frame config for i, sdr in enumerate(csdrs): det_sch = "GG" ref_pilot_sch = ''.join("GG" * M) ul_pilot_sch = ''.join("G" * i) + "P" + ''.join("G" * (K-(i+1))) frame_sch1 = det_sch + ref_pilot_sch + ul_pilot_sch + 'G' dl_data_sch = "RG" * D + ''.join("G" * (2 * M + K - (2 * D))) frame_sch2 = det_sch + dl_data_sch + 'G' print("Client %d frame schedule (%s, %s)"%(i, frame_sch1, frame_sch2)) cconf = {"tdd_enabled": True, "frame_mode": "triggered", "symbol_size" : sym_samps, "frames": [frame_sch1, frame_sch2], "max_frame" : 0} sdr.writeSetting("TDD_CONFIG", json.dumps(cconf)) sdr.writeSetting("TDD_MODE", "true") for sdr in bsdrs+csdrs: sdr.writeSetting("TX_SW_DELAY", str(30)) if not use_trig: for sdr in csdrs: # enable the correlator, with zeros as inputs corr_conf = {"corr_enabled" : True, "corr_threshold" : 1} sdr.writeSetting("CORR_CONFIG", json.dumps(corr_conf)) sdr.writeRegisters("CORR_COE", 0, coe.tolist()) # DEV: ueTrigTime = 153 (prefix_length=0), # CBRS: ueTrigTime = 235 (prefix_length=82), tx_advance=prefix_length, # corr delay is 17 cycles #cl_trig_time = prefix_length + len(beacon) + postfix_length + 17 + postfix_length cl_trig_time = 256 + 250 sf_start = cl_trig_time // sym_samps sp_start = cl_trig_time % sym_samps print("UE starting symbol and sample count (%d, %d)" % (sf_start, sp_start)) # make sure to set this after TDD mode is enabled "writeSetting("TDD_CONFIG", ..." sdr.setHardwareTime(SoapySDR.ticksToTimeNs((sf_start << 16) | sp_start, rate), "TRIGGER") else: for sdr in csdrs: sdr.setHardwareTime(0, "TRIGGER") for i,sdr in enumerate(bsdrs): sdr.setHardwareTime(0, "TRIGGER") replay_addr = 0 pilot_uint = cfloat2uint32(wb_pilot1, order='QI').tolist() beacon_uint = cfloat2uint32(beacon1, order='QI').tolist() zero_uint = cfloat2uint32(wbz, order='QI').tolist() for i, sdr in enumerate(bsdrs): sdr.writeRegisters("BEACON_RAM", 0, beacon_uint) sdr.writeRegisters("BEACON_RAM_WGT_A", 0, beacon_weights[i].tolist()) sdr.writeSetting("BEACON_START", str(M)) for sdr in csdrs: sdr.writeRegisters("TX_RAM_A", replay_addr, pilot_uint) sdr.writeRegisters("TX_RAM_B", replay_addr, zero_uint) # Create and activate streams rx_stream_ul = [sdr.setupStream(SOAPY_SDR_RX, SOAPY_SDR_CF32, [0, 1]) for sdr in bsdrs] rx_stream_dl = [sdr.setupStream(SOAPY_SDR_RX, SOAPY_SDR_CF32, [0, 1]) for sdr in csdrs] flags = 0 for i, sdr in enumerate(bsdrs): sdr.activateStream(rx_stream_ul[i], flags, 0) for i, sdr in enumerate(csdrs): sdr.activateStream(rx_stream_dl[i], flags, 0) ############# #initialize array and matrixes to hold rx and processed data ############# calib_rx_dl = [np.array([1]*sym_samps).astype(np.complex64) for m in range(M)] calib_rx_ul = [np.array([1]*sym_samps).astype(np.complex64) for m in range(M)] data_rx_dl = [[np.array([0]*sym_samps).astype(np.complex64) for k in range(K)] for m in range(D)] pilot_rx_ul = [[np.array([0]*sym_samps).astype(np.complex64) for m in range(M)] for k in range(K)] dummy_rx = np.array([0]*sym_samps).astype(np.complex64) ul_cal_offset = np.array([0]*M, np.int32) dl_cal_offset = np.array([0]*M, np.int32) ul_offset = [np.array([0]*K, np.int32) for m in range(M)] dl_offset = [np.array([0]*K, np.int32) for m in range(M)] ul_csi_mat = np.empty([K, M, N], dtype=np.complex64) rx_f_cal_dl = np.empty([M, N], dtype=np.complex64) rx_f_cal_ul = np.empty([M, N], dtype=np.complex64) w_zf_dl = np.empty([M, K, N], dtype=np.complex64) w_conj_dl = np.empty([M, K, N], dtype=np.complex64) calib = np.empty((M, N)).astype(np.complex64) rxSymbols_mat = np.empty([len(data_sc), D * n_data_ofdm_syms, K], dtype=np.complex64) cont_plotter = plotter if cont_plotter: fig1, axes1 = plt.subplots(nrows=M, ncols=2, figsize=(9, 12)) axes1[0, 0].set_title('Pilot Uplink (Re)') axes1[0, 1].set_title('Pilot Uplink (Im)') for m in range(M): axes1[m, 0].set_xlim(0, sym_samps) axes1[m, 0].set_ylim(-1, 1) if m == ref_ant: axes1[m, 0].set_ylabel('Ant %d (ref)'%m) else: axes1[m, 0].set_ylabel('Ant %d'%m) axes1[m, 0].legend(fontsize=10) axes1[m, 1].set_xlim(0, sym_samps) axes1[m, 1].set_ylim(-1, 1) axes1[m, 1].legend(fontsize=10) lines11 = [[axes1[m, 0].plot(range(sym_samps), np.real(pilot_rx_ul[k][m]), label="User %d (real)"%k)[0] for k in range(K)] for m in range(M)] lines12 = [[axes1[m, 1].plot(range(sym_samps), np.imag(pilot_rx_ul[k][m]), label="User %d (imag)"%k)[0] for k in range(K)] for m in range(M)] fig1.show() fig2, axes2 = plt.subplots(nrows=M, ncols=2, figsize=(9, 12)) axes2[0, 0].set_title('Calibration Downlink') axes2[0, 1].set_title('Calibration Uplink') for m in range(M): axes2[m, 0].set_xlim(0, sym_samps) axes2[m, 0].set_ylim(-1, 1) if m == ref_ant: axes2[m, 0].set_ylabel('Ant %d (ref)'%m) else: axes2[m, 0].set_ylabel('Ant %d'%m) axes2[m, 0].legend(fontsize=10) axes2[m, 1].set_xlim(0, sym_samps) axes2[m, 1].set_ylim(-1, 1) axes2[m, 1].legend(fontsize=10) lines20 = [axes2[m, 0].plot(range(sym_samps), calib_rx_dl[m][:sym_samps])[0] for m in range(M)] lines21 = [axes2[m, 1].plot(range(sym_samps), calib_rx_ul[m][:sym_samps])[0] for m in range(M)] lines24 = [axes2[m, 0].plot(range(sym_samps), calib_rx_dl[m][:sym_samps])[0] for m in range(M)] lines25 = [axes2[m, 1].plot(range(sym_samps), calib_rx_ul[m][:sym_samps])[0] for m in range(M)] fig2.show() fig3, axes3 = plt.subplots(nrows=K, ncols=1, figsize=(6, 6)) for k in range(K): if K == 1: ax3 = axes3 else: ax3 = axes3[k] ax3.grid(True) ax3.set_title('TX/RX Constellation') ax3.set_xlabel('') ax3.set_ylabel('') ax3.set_ylim(-5.5, 5.5) ax3.set_xlim(-5.8, 5.8) ax3.legend(fontsize=10) if K == 1: line31, = axes3.plot([], [], 'ro', label='TXSym') line32, = axes3.plot([], [], 'bx', label='RXSym') else: line31 = [axes3[k].plot([], [], 'ro', label='TXSym')[0] for k in range(K)] line32 = [axes3[k].plot([], [], 'bx', label='RXSym')[0] for k in range(K)] fig3.show() fig4, axes4 = plt.subplots(nrows=K, ncols=1, figsize=(6, 6)) for k in range(K): if K == 1: ax4 = axes4 else: ax4 = axes4[k] ax4.grid(True) ax4.set_title('Received Downlink') ax4.set_xlabel('') ax4.set_ylabel('') ax4.set_ylim(-1, 1) ax4.set_xlim(0, sym_samps) ax4.legend(fontsize=10) if K == 1: line41, = axes4.plot(range(sym_samps), data_rx_dl[0][0], label='RX Downlink') line42, = axes4.plot(range(sym_samps), data_rx_dl[0][0]) else: line41 = [axes4[k].plot(range(sym_samps), data_rx_dl[0][k], label='RX Downlink')[0] for k in range(K)] line42 = [axes4[k].plot(range(sym_samps), data_rx_dl[0][k])[0] for k in range(K)] fig4.show() cur_frame = 0 signal.signal(signal.SIGINT, signal_handler) tstart = datetime.datetime.now() while(RUNNING): ## disarm correlator in the clients if not use_trig: for i, sdr in enumerate(csdrs): sdr.writeSetting("CORR_CONFIG", json.dumps({"corr_enabled": False})) bad_recip_read = False bad_frame = False ## arm correlator in the clients, inputs from adc if not use_trig: for i, sdr in enumerate(csdrs): sdr.writeSetting("CORR_START", "A") for i, sdr in enumerate(bsdrs): sdr.writeRegisters("TX_RAM_A", 0, pilot_uint) sdr.writeRegisters("TX_RAM_B", 0, zero_uint) trig_dev.writeSetting("TRIGGER_GEN", "") ## collect reciprocity pilots from antenna m for m in range(M): if bad_recip_read: break if m != ref_ant: sr = bsdrs[m].readStream(rx_stream_ul[m], [calib_rx_ul[m], dummy_rx], sym_samps) if sr.ret < sym_samps: print("Calib: m %d ret %d"%(m,sr.ret)) bad_recip_read = True for m in range(M): if bad_recip_read: break if m != ref_ant: sr = bsdrs[ref_ant].readStream(rx_stream_ul[ref_ant], [calib_rx_dl[m], dummy_rx], sym_samps) if sr.ret < sym_samps: print("Calib: m %d ret %d"%(m,sr.ret)) bad_recip_read = True if bad_recip_read: print("BAD RECIPROCAL PILOT READ... CONTINUE! ") continue ## collect uplink pilots bad_pilot_read = False for k in range(K): if bad_pilot_read: break for m in range(M): sr = bsdrs[m].readStream(rx_stream_ul[m], [pilot_rx_ul[k][m], dummy_rx], sym_samps) if sr.ret < sym_samps: print("PilotUP: k: %d, m %d ret %d"%(k,m,sr.ret)) bad_pilot_read = True if bad_pilot_read: print("BAD PILOT READ... CONTINUE! ") continue ## process downlink signal # processing the received calibration samples print("frame %d"%(cur_frame)) for m in range(M): if ref_ant == m: calib[m,:] = np.array([1]*N, np.complex64) #continue rx_f_cal_dl[m,:] = np.array([0]*N, np.complex64) rx_f_cal_ul[m,:] = np.array([0]*N, np.complex64) continue calib_rx_dl[m] -= np.mean(calib_rx_dl[m]) calib_rx_ul[m] -= np.mean(calib_rx_ul[m]) best_peak_dl, _, _ = find_lts(calib_rx_dl[m], thresh=LTS_THRESH) best_peak_ul, _, _ = find_lts(calib_rx_ul[m], thresh=LTS_THRESH) dl_cal_offset[m] = 0 if not best_peak_dl else best_peak_dl - len(lts_sym) + cp_len ul_cal_offset[m] = 0 if not best_peak_ul else best_peak_ul - len(lts_sym) + cp_len if (dl_cal_offset[m] < 150 or ul_cal_offset[m] < 150): bad_frame = True lts_dn_1 = calib_rx_dl[m][dl_cal_offset[m]:dl_cal_offset[m]+N] lts_dn_2 = calib_rx_dl[m][dl_cal_offset[m]+N:dl_cal_offset[m]+2*N] lts_up_1 = calib_rx_ul[m][ul_cal_offset[m]:ul_cal_offset[m]+N] lts_up_2 = calib_rx_ul[m][ul_cal_offset[m]+N:ul_cal_offset[m]+2*N] rx_f_cal_dl1 = np.fft.fftshift(np.fft.fft(lts_dn_1, N, 0), 0) rx_f_cal_dl2 = np.fft.fftshift(np.fft.fft(lts_dn_2, N, 0), 0) rx_f_cal_ul1 = np.fft.fftshift(np.fft.fft(lts_up_1, N, 0), 0) rx_f_cal_ul2 = np.fft.fftshift(np.fft.fft(lts_up_2, N, 0), 0) rx_f_cal_dl[m, :] = (rx_f_cal_dl1 + rx_f_cal_dl2)/2 rx_f_cal_ul[m, :] = (rx_f_cal_ul1 + rx_f_cal_ul2)/2 calib[m,:] = np.divide(rx_f_cal_dl[m,:], rx_f_cal_ul[m,:]) # processing uplink pilot received samples for k in range(K): for m in range(M): pilot_rx_ul[k][m] -= np.mean(pilot_rx_ul[k][m]) best_peak, _, _ = find_lts(pilot_rx_ul[k][m], thresh=LTS_THRESH) ul_offset[m][k] = 0 if not best_peak else (best_peak - len(lts_sym) + cp_len) if ul_offset[m][k] < 150: bad_frame = True lts_ul_1 = pilot_rx_ul[k][m][ul_offset[m][k]:ul_offset[m][k]+N] lts_ul_2 = pilot_rx_ul[k][m][ul_offset[m][k]+N:ul_offset[m][k]+2*N] rx_f_ul1 = np.fft.fftshift(np.fft.fft(lts_ul_1, N, 0), 0) rx_f_ul2 = np.fft.fftshift(np.fft.fft(lts_ul_2, N, 0), 0) ul_csi_mat[k,m,:] = (rx_f_cal_ul1 + rx_f_cal_ul2) * lts_f / 2 # processing beamforming vectors and downlink transmit data for l in range(n_ofdm_syms): for n in range(N): dl_csi = np.matmul(ul_csi_mat[:, :, n], np.diag(calib[:, n])) w_zf_dl[:, :, n] = np.linalg.pinv(dl_csi) tx_dl_ifft[:, l, n] = np.matmul(w_zf_dl[:, :, n], tx_dl_data[n, l, :]) tx_sym = np.fft.ifft(tx_dl_ifft, axis=2) tx_sym = np.concatenate((tx_sym[:,:,-data_cp_len:], tx_sym), axis=2) # send downlink signal for i, sdr in enumerate(bsdrs): tx_sig = np.reshape(tx_sym[i, :, :], (1, n_ofdm_syms * data_ofdm_len)) tx_sig = np.concatenate([pad1, tx_sig[0, :], pad2]) sdr.writeRegisters("TX_RAM_A", 0, cfloat2uint32(tx_sig, order='QI').tolist()) sdr.writeRegisters("TX_RAM_B", 0, zero_uint) trig_dev.writeSetting("TRIGGER_GEN", "") # collect downlink data from antenna k bad_dl_read = False for d in range(D): if bad_dl_read: break for k in range(K): sr = csdrs[k].readStream(rx_stream_dl[k], [data_rx_dl[d][k], dummy_rx], sym_samps) if sr.ret < sym_samps: print("DL DATA: symbol %d, k %d, ret %d"%(d, k, sr.ret)) bad_dl_read = True if bad_dl_read: print("BAD DL READ... CONTINUE! ") continue # DC removal # Find LTS peaks (in case LTSs were sent) bad_dl_data = False for k in range(K): if bad_dl_data: break for d in range(D): data_rx_dl[d][k] -= np.mean(data_rx_dl[d][k]) best_peak_dl, b, peaks0 = find_lts(data_rx_dl[d][k], thresh=lts_thresh, flip=True, lts_seq=lts_t_cp) if use_trig: dl_offset[k] = 163 + 160 #0 if not best_peak_dl else best_peak_dl else: dl_offset[k] = 0 if not best_peak_dl else best_peak_dl if dl_offset[k] < lts_len: bad_dl_data = True print("NO VALID DOWNLINK... CONTINUE! ") break payload_start = dl_offset[k] payload_end = payload_start + payload_len # Payload_len == (n_ofdm_syms * (num_sc + data_cp_len)) lts_start = payload_start - lts_len # where LTS-CP start lts = data_rx_dl[d][k][lts_start: payload_start] if len(lts) < lts_len: print("BAD DOWNLINK PILOT... CONTINUE! ") bad_dl_data = True break lts_1 = lts[16 + -fft_offset + np.array(range(0, 64))] lts_2 = lts[96 + -fft_offset + np.array(range(0, 64))] # Average 2 LTS symbols to compute channel estimate tmp = np.fft.ifftshift(lts_f) chan_est = np.fft.ifftshift(lts_f) * (np.fft.fft(lts_1) + np.fft.fft(lts_2))/2 if len(data_rx_dl[d][k]) >= payload_end: # Retrieve payload symbols payload_samples = data_rx_dl[d][k][payload_start: payload_end] else: bad_dl_data = True print("TOO LATE (payload_end %d)... CONTINUE! "%payload_end) break payload_samples_mat_cp = np.reshape(payload_samples, (data_ofdm_len, n_data_ofdm_syms), order="F") # Remove cyclic prefix payload_samples_mat = payload_samples_mat_cp[data_cp_len - fft_offset + np.array(range(0, N)), :] # FFT rxSig_freq = np.fft.fft(payload_samples_mat, n=N, axis=0) # Equalizer chan_est_tmp = chan_est.reshape(len(chan_est), 1, order="F") rxSig_freq_eq = rxSig_freq / np.matlib.repmat(chan_est_tmp, 1, n_data_ofdm_syms) phase_error = ofdm_obj.phase_correction(rxSig_freq_eq, pilot_sc, pilots_matrix) phase_corr_tmp = np.matlib.repmat(phase_error, N, 1) phase_corr = np.exp(-1j * phase_corr_tmp) rxSig_freq_eq_phase = rxSig_freq_eq * phase_corr rxSymbols_mat[:, d * n_data_ofdm_syms : (d + 1) * n_data_ofdm_syms, k] = rxSig_freq_eq_phase[data_sc, :] if bad_dl_data: continue evm_mat = np.power(np.abs(rxSymbols_mat - np.tile(tx_dl_data[data_sc, 2:, :], (1, D, 1))), 2) evm_per_user = np.mean(np.reshape(evm_mat, (len(data_sc) * n_data_ofdm_syms * D, K)), axis=0) evm_per_user_db = 10 * np.log10(evm_per_user) print('EVM (dB) per user') print([ "{:2.2f}".format(x) for x in evm_per_user_db ]) print('') cur_frame += 1 if cur_frame >= TOT_FRAMES: break if cont_plotter: for m in range(M): if m == ref_ant: lines20[m].set_ydata(np.real(wb_pilot1)) lines21[m].set_ydata(np.real(wb_pilot1)) continue lines20[m].set_ydata(np.real(calib_rx_dl[m])) lines21[m].set_ydata(np.real(calib_rx_ul[m])) lines24[m].set_data(dl_cal_offset[m], np.linspace(-1.0, 1.0, num=100)) lines25[m].set_data(ul_cal_offset[m], np.linspace(-1.0, 1.0, num=100)) for m in range(M): for k in range(K): lines11[m][k].set_ydata(np.real(pilot_rx_ul[k][m])) lines12[m][k].set_ydata(np.imag(pilot_rx_ul[k][m])) if K == 1: txSyms_all = tx_dl_data[data_sc, 2:, 0].flatten() rxSyms_all = rxSymbols_mat[:, :, 0].flatten() line31.set_data(np.real(txSyms_all), np.imag(txSyms_all)) line32.set_data(np.real(rxSyms_all), np.imag(rxSyms_all)) line41.set_data(range(sym_samps), np.real(data_rx_dl[0][0])) line42.set_data(dl_offset[0], np.linspace(-1.0, 1.0, num=100)) else: for k in range(K): txSyms_all = tx_dl_data[data_sc, 2:, k].flatten() rxSyms_all = rxSymbols_mat[:, :, k].flatten() line31[k].set_data(np.real(txSyms_all), np.imag(txSyms_all)) line32[k].set_data(np.real(rxSyms_all), np.imag(rxSyms_all)) line41[k].set_data(range(sym_samps), np.real(data_rx_dl[0][k])) line42[k].set_data(dl_offset[k], np.linspace(-1.0, 1.0, num=100)) fig1.canvas.draw() fig1.show() fig2.canvas.draw() fig2.show() fig3.canvas.draw() fig3.show() fig4.canvas.draw() fig4.show() tend = datetime.datetime.now() c = tend - tstart print("Elapsed %d (secs)"%c.total_seconds()) # clear up fpga states tdd_conf = {"tdd_enabled" : False} corr_conf = {"corr_enabled" : False} for sdr in csdrs: if not use_trig: sdr.writeSetting("CORR_CONFIG", json.dumps(corr_conf)) for sdr in bsdrs+csdrs: sdr.writeSetting("TDD_CONFIG", json.dumps(tdd_conf)) sdr.writeSetting("TDD_MODE", "false") sdr.writeSetting("RESET_DATA_LOGIC", "") # close streams and exit for i, sdr in enumerate(bsdrs): sdr.closeStream(rx_stream_ul[i]) for i, sdr in enumerate(csdrs): sdr.closeStream(rx_stream_dl[i])
def setup(self): # BS for i, sdr in enumerate(self.bsdrs): sched_main = "PG" + ''.join( "G" * i * self.sdr_ant) + "T" * self.sdr_ant + ''.join( "G" * (self.num_ants - (i + 1) * self.sdr_ant)) + "G" + ''.join( "R" * (len(self.csdrs))) + "G" #print("BS node %d"%i) #print("sched_main %s"%(sched_main)) bconf = { "tdd_enabled": True, "frame_mode": "free_running", "symbol_size": self.symSamp, "frames": [sched_main], "max_frame": 1 } sdr.writeSetting("TDD_CONFIG", json.dumps(bconf)) sdr.writeSetting("TDD_MODE", "true") # Client for i, sdr in enumerate(self.csdrs): sched_main = "GG" + ''.join("R" * self.num_bsdrs) + "G" + ''.join( "G" * i) + "P" + ''.join("G" * (self.num_csdrs - (i + 1))) + "G" #print("Client node %d"%i) #print("sched_main %s"%(sched_main)) cconf = { "tdd_enabled": True, "frame_mode": "triggered", "symbol_size": self.symSamp, "frames": [sched_main], "max_frame": 0 } sdr.writeSetting("TDD_CONFIG", json.dumps(cconf)) sdr.writeSetting("TDD_MODE", "true") for sdr in self.bsdrs + self.csdrs: sdr.writeSetting("TX_SW_DELAY", str(30)) z = np.empty(self.symSamp).astype(np.complex64) if self.ota_trig: coe = cfloat2uint32( np.conj(self.coeffs), order='IQ') # FPGA correlator takes coefficients in QI order for sdr in self.csdrs: sdr.writeRegister("IRIS30", CORR_CONF, int( "00004001", 16)) # enable the correlator, with zeros as inputs for i in range(128): sdr.writeRegister("ARGCOE", i * 4, 0) time.sleep(0.1) sdr.writeRegister("IRIS30", CORR_RST, 0x1) # reset corr sdr.writeRegister("IRIS30", CORR_RST, 0x0) # unrst corr sdr.writeRegister("IRIS30", CORR_THRESHOLD, 1) for i in range(128): sdr.writeRegister("ARGCOE", i * 4, int(coe[i])) sf_start = self.rf_roundtrip // self.symSamp sp_start = self.rf_roundtrip % self.symSamp #print("UE starting symbol and sample count (%d, %d)" % (sf_start, sp_start)) # make sure to set this after TDD mode is enabled "writeSetting("TDD_CONFIG", ..." sdr.setHardwareTime( SoapySDR.ticksToTimeNs((sf_start << 16) | sp_start, self.rate), "TRIGGER") else: for sdr in self.csdrs: sdr.setHardwareTime(0, "TRIGGER") replay_addr = 0 for i, sdr in enumerate(self.bsdrs): sdr.writeRegisters("TX_RAM_A", replay_addr, cfloat2uint32(self.beacon, order='IQ').tolist()) if self.beacon_weights is not None: sdr.writeRegisters( "TX_RAM_B", replay_addr, cfloat2uint32(self.beacon, order='IQ').tolist()) sdr.writeRegisters( "TX_RAM_WGT_A", replay_addr, self.beacon_weights[self.sdr_ant * i].tolist()) if self.sdr_ant == 2: sdr.writeRegisters( "TX_RAM_WGT_B", replay_addr, self.beacon_weights[self.sdr_ant * i + 1].tolist()) sdr.writeRegister("RFCORE", 156, int(self.num_ants)) sdr.writeRegister("RFCORE", 160, 1) # enable beamsweeping else: break # if beamsweep is not active, only send pilot from the first antenna sdr.setHardwareTime(0, "TRIGGER") for sdr in self.csdrs: sdr.writeRegisters("TX_RAM_A", replay_addr, cfloat2uint32(self.pilot, order='IQ').tolist()) sdr.writeRegisters("TX_RAM_B", replay_addr, cfloat2uint32(z, order='IQ').tolist()) ret = 0 dummy = np.empty(self.symSamp).astype(np.complex64) dummy2 = np.empty(self.symSamp).astype(np.complex64) for r, sdr in enumerate(self.bsdrs): #if r != m: while ret >= 0: sr = sdr.readStream(self.rxBsStream[r], [dummy, dummy2], self.symSamp, timeoutUs=0) ret = sr.ret ret = 0 for r, sdr in enumerate(self.csdrs): #if r != m: while ret >= 0: sr = sdr.readStream(self.rxBsStream[r], [dummy, dummy2], self.symSamp, timeoutUs=0) ret = sr.ret ret = 0 # arm correlator in the clients if self.ota_trig: for i, sdr in enumerate(self.csdrs): sdr.writeRegister("IRIS30", CORR_CONF, int( "00004011", 16)) # enable the correlator, with inputs from adc