...
 
Commits (3)
......@@ -210,8 +210,8 @@ elseif chan_type == "iris"
node_bs.sdrrxsetup();
tdd_sched_index = 1; % for uplink only one frame schedule is sufficient
node_bs.set_tddconfig(1, tdd_sched_index); % configure the BS: schedule etc.
node_ue.set_tddconfig(0, tdd_sched_index);
node_bs.set_tddconfig(1, bs_param.tdd_sched(tdd_sched_index)); % configure the BS: schedule etc.
node_ue.set_tddconfig(0, ue_param.tdd_sched(tdd_sched_index));
node_bs.sdr_setupbeacon(); % Burn beacon to the BS(1) RAM
......
......@@ -22,25 +22,25 @@ classdef iris_py < handle
use_hub = 0;
py_obj_hub;
% Parameters to feed python (pun very intended!)
serial_ids;
n_sdrs; % number of Iris boards in a chain
sample_rate;
tx_freq;q
rx_freq;
bw;
tx_gain;
rx_gain;
n_samp;
tdd_sched;
n_zpad_samp; %number of zero-padding samples
serial_ids = [];
n_sdrs = 0; % number of Iris boards in a chain
sample_rate = 0;
tx_freq = 0;
rx_freq = 0;
bw = 0;
tx_gain = 0;
rx_gain = 0;
n_samp = 0;
tdd_sched = "";
n_zpad_samp = 0; %number of zero-padding samples
n_frame = 10;
is_bs = 1;
end
methods
function obj = iris_py(sdr_params, hub_id) % User must put 0 in hub_params in case hub is not used!
if nargin > 0
if ~isempty(hub_id)
if ~isempty(hub_id)
disp('Using hub with ID:');
id_str = convertStringsToChars(hub_id);
obj.py_obj_hub = py.hub_py.Hub_py( pyargs('serial_id',id_str));
......@@ -62,25 +62,28 @@ classdef iris_py < handle
obj.n_zpad_samp = sdr_params.n_zpad_samp;
for ipy=1:obj.n_sdrs
id_str = convertStringsToChars( obj.serial_ids(ipy));
id_str = convertStringsToChars(obj.serial_ids(ipy));
py_obj = py.iris_py.Iris_py( pyargs('serial_id',id_str,...
'tx_freq', obj.tx_freq, 'rx_freq', obj.rx_freq,...
'tx_gain',obj.tx_gain,'rx_gain',obj.rx_gain,...
'sample_rate',obj.sample_rate, 'n_samp', obj.n_samp) );%,...
%'max_frames',obj.n_frame) );
'sample_rate',obj.sample_rate, 'n_samp', obj.n_samp) );
obj.py_obj_array(ipy,:) = {py_obj};
end
end
end
function sdr_set_n_frame(obj, n_frame)
obj.n_frame = n_frame;
end
% NB: Need to redefine py_obj as array to be parsed in all the
% functions that follow
function sdrtrigger(obj, trig)
function sdrtrigger(obj)
if ~obj.use_hub
obj.py_obj_array{1}.set_trigger(pyargs('trig',trig)); % The trigger is set only on the fist node
obj.py_obj_array{1}.set_trigger(); % The trigger is set only on the fist node
else
obj.py_obj_hub.set_trigger(pyargs('trig',trig));
obj.py_obj_hub.set_trigger();
end
end
......@@ -106,57 +109,62 @@ classdef iris_py < handle
function sdr_setupbeacon(obj)
% Assume Beacon only from the first Iris board in the BS array
obj.py_obj_array{1}.burn_beacon();
for ipy = 1:obj.n_sdrs
obj.py_obj_array{ipy}.burn_beacon();
end
end
function set_tddconfig(obj, is_bs, index)
sched = convertStringsToChars(obj.tdd_sched(index));
function set_tddconfig(obj, is_bs, tdd_sched)
obj.is_bs = is_bs;
sched = convertStringsToChars(tdd_sched);
for ipy = 1:obj.n_sdrs
obj.py_obj_array{ipy}.config_sdr_tdd( pyargs('tdd_sched',sched, ...
'is_bs', is_bs, 'prefix_len', obj.n_zpad_samp));
obj.py_obj_array{ipy}.config_sdr_tdd( pyargs('tdd_sched', sched, ...
'is_bs', is_bs, 'prefix_len', obj.n_zpad_samp, 'max_frames', obj.n_frame));
end
end
function sdrrxsetup(obj)
function set_tddconfig_single(obj, is_bs, tdd_sched, index)
sched = convertStringsToChars(tdd_sched);
obj.py_obj_array{index}.config_sdr_tdd( pyargs('tdd_sched', sched, ...
'is_bs', is_bs, 'prefix_len', obj.n_zpad_samp, 'max_frames', obj.n_frame));
end
function sdrrxsetup(obj)
for ipy = 1:obj.n_sdrs
obj.py_obj_array{ipy}.setup_stream_rx();
end
end
end
function sdr_activate_rx(obj)
function sdr_activate_rx(obj)
for ipy=1:obj.n_sdrs
obj.py_obj_array{ipy}.activate_stream_rx();
end
end
end
%Assume same data is Tx-ed from all memebers of the array
function sdrtx(obj, data)
re = real(data).';
im = imag(data).';
for ipy = 1:obj.n_sdrs
obj.py_obj_array{ipy}.burn_data( pyargs('data_r', re, 'data_i', im) );
obj.py_obj_array{ipy}.burn_data( pyargs('data_r', real(data), 'data_i', imag(data)) );
end
end
function sdrtx_single(obj, data, index)
re = real(data).';
im = imag(data).';
obj.py_obj_array{index}.burn_data( pyargs('data_r', re, 'data_i', im) );
obj.py_obj_array{index}.burn_data( pyargs('data_r', real(data), 'data_i', imag(data)) );
end
% Read n_frame x n_samp data
function [data, len] = sdrrx(obj, n_samp)
data_raw = zeros(obj.n_sdrs, obj.n_frame*n_samp); % Change this to max frame!
data_raw = zeros(obj.n_sdrs, obj.n_frame * n_samp); % Change this to max frame!
for jf=1:obj.n_frame
%trigger beacon TX
trig = 1;
if ~obj.use_hub
obj.py_obj_array{1}.set_trigger(pyargs('trig',trig)); % The trigger is set only on the fist node
else
obj.py_obj_hub.set_trigger(pyargs('trig',trig));
disp('trig hub!!!!')
%trigger base station
if obj.is_bs
if ~obj.use_hub
obj.py_obj_array{1}.set_trigger(); % The trigger is set only on the fist node
else
obj.py_obj_hub.set_trigger();
disp('trig hub!!!!')
end
end
for ipy = 1:obj.n_sdrs
......
......@@ -88,7 +88,6 @@ class Iris_py:
bw=None,
sample_rate=None,
n_samp=None, # Total number of samples, including zero-pads
max_frames=1,
both_channels=False,
agc_en=False,
):
......@@ -107,7 +106,7 @@ class Iris_py:
self.agc_en = agc_en
self.both_channels = both_channels
self.max_frames = int(max_frames)
self.max_frames = 1
### Setup channel rates, ports, gains, and filters ###
info = self.sdr.getHardwareInfo()
......@@ -161,23 +160,19 @@ class Iris_py:
self.sdr.writeSetting(SOAPY_SDR_TX, 1, 'ENABLE_CHANNEL', 'false')
# Set trigger:
def set_trigger(self, trig=False):
if bool(trig) is True:
self.sdr.writeSetting("TRIGGER_GEN", "")
def set_trigger(self):
self.sdr.writeSetting("TRIGGER_GEN", "")
def set_corr(self):
'''enable the correlator, with inputs from adc'''
self.sdr.writeSetting("CORR_START", "A")
def config_sdr_tdd(self, tdd_sched=None, is_bs=True, prefix_len=0):
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')
if tdd_sched is not None:
self.tdd_sched = tdd_sched
else:
self.tdd_sched = "G"
max_frames = self.max_frames
self.tdd_sched = tdd_sched
self.max_frames = int(max_frames)
if bool(is_bs):
conf_str = {"tdd_enabled": True,
"frame_mode": "free_running",
......@@ -393,7 +388,7 @@ if __name__ == '__main__':
siso_bs.activate_stream_rx()
siso_ue.set_corr()
siso_bs.set_trigger(True)
siso_bs.set_trigger()
wave_rx_a_bs_mn = siso_bs.recv_stream_tdd()
......
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Author(s): C. Nicolas Barati nicobarati@rice.edu
% Rahman Doost-Mohamamdy: doost@rice.edu
%
%---------------------------------------------------------------------
% Original code copyright Mango Communications, Inc.
% Distributed under the WARP License http://warpproject.org/license
% Copyright (c) 2018-2019, Rice University
% RENEW OPEN SOURCE LICENSE: http://renew-wireless.org/license
% ---------------------------------------------------------------------
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
clear
close all;
[version, executable, isloaded] = pyversion;
if ~isloaded
pyversion /usr/bin/python
py.print() %weird bug where py isn't loaded in an external script
end
% Params:
WRITE_PNG_FILES = 0; % Enable writing plots to PNG
%Iris params:
USE_HUB = 0;
TX_FRQ = 3.6e9;
RX_FRQ = TX_FRQ;
TX_GN = 70;
RX_GN = 50;
SMPL_RT = 5e6;
N_FRM = 1;
bs_ids = string.empty();
bs_sched = string.empty();
% Waveform params
% OFDM params
SC_IND_PILOTS = [8 22 44 58]; % Pilot subcarrier indices
SC_IND_DATA = [2:7 9:21 23:27 39:43 45:57 59:64]; % Data subcarrier indices
SC_IND_DATA_PILOT = [2:27 39:64]';
N_SC = 64; % Number of subcarriers
CP_LEN = 16; % Cyclic prefix length
N_SYM_SAMP = N_SC + CP_LEN; % Number of samples that will go over the air
N_ZPAD_PRE = 100; % Zero-padding prefix for Iris
N_ZPAD_POST = 76; % Zero-padding postfix for Iris
N_OFDM_SYM = floor((4096 - N_ZPAD_PRE - N_ZPAD_POST) / N_SYM_SAMP);% Number of OFDM symbols for burst, it needs to be less than 47
% Rx processing params
FFT_OFFSET = 16; % Number of CP samples to use in FFT (on average)
%% Define the preamble
% LTS for fine CFO and channel estimation
lts_f = [0 1 -1 -1 1 1 -1 1 -1 1 -1 -1 -1 -1 -1 1 1 -1 -1 1 -1 1 -1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 ...
1 1 -1 -1 1 1 -1 1 -1 1 1 1 1 1 1 -1 -1 1 1 -1 1 -1 1 1 1 1];
lts_t = ifft(lts_f, 64); %time domain
%% Init Iris nodes
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Set up the Iris experiment
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Create BS Hub and UE objects. Note: BS object is a collection of Iris
% nodes.
if USE_HUB
hub_id = "FH4A000002";
else
hub_id = [];
end
bs_ids = ["RF3E000208", "RF3E000636", "RF3E000632", "RF3E000568", "RF3E000558", "RF3E000633", "RF3E000566", "RF3E000635"];
bs_sched = ["PGRG", "RGPG"]; % All BS schedule, Ref Schedule
N_BS_NODE = length(bs_ids);
REF_ANT = floor(N_BS_NODE/2);
sched_id = ones(1, N_BS_NODE);
sched_id(REF_ANT) = 2;
lts = [lts_t(49:64) lts_t];
N_BS = N_BS_NODE - 1;
DATA_REP = floor(N_OFDM_SYM / N_BS);
data_len = N_BS * DATA_REP * N_SYM_SAMP;
preamble = zeros(N_BS_NODE, data_len);
for jp = 1:N_BS
nid = jp + (jp >= REF_ANT);
for rp = 1:DATA_REP
start_index = ((rp - 1) + (jp - 1) * DATA_REP) * N_SYM_SAMP;
preamble(nid, start_index + 1: start_index + N_SYM_SAMP) = lts;
preamble(REF_ANT, start_index + 1: start_index + N_SYM_SAMP) = lts;
end
end
n_samp = N_ZPAD_PRE + data_len + N_ZPAD_POST;
payload_rx = zeros(N_BS_NODE, data_len);
rx_fft = zeros(N_BS, N_SC);
rx_fft_ref = zeros(N_BS, N_SC);
cal_mat = zeros(N_BS, N_SC);
% Iris nodes' parameters
bs_sdr_params = struct(...
'id', bs_ids, ...
'n_sdrs', N_BS_NODE, ...
'txfreq', TX_FRQ, ...
'rxfreq', RX_FRQ, ...
'txgain', TX_GN, ...
'rxgain', RX_GN, ...
'sample_rate', SMPL_RT, ...
'n_samp', n_samp, ... % number of samples per frame time.
'n_frame', 1, ...
'tdd_sched', bs_sched, ... % number of zero-paddes samples
'n_zpad_samp', N_ZPAD_PRE ...
);
node_bs = iris_py(bs_sdr_params, hub_id); % initialize BS
node_bs.sdrsync(); % synchronize delays only for BS
node_bs.sdrrxsetup();
for i=1:N_BS_NODE
node_bs.set_tddconfig_single(1, bs_sched(sched_id(i)), i); % configure the BS: schedule etc.
tx_data = [zeros(1, N_ZPAD_PRE) preamble(i, :) zeros(1, N_ZPAD_POST)];
node_bs.sdrtx_single(tx_data, i); % Burn data to the UE RAM
end
node_bs.sdr_activate_rx(); % activate reading stream
[rx_vec_iris, data0_len] = node_bs.sdrrx(n_samp); % read data
% process received reciprocity pilots
a = 1;
unos = ones(size(conj(lts)));
for ibs = 1:N_BS_NODE
% Correlation through filtering
v0 = filter(fliplr(conj(preamble(REF_ANT, end - DATA_REP * N_SYM_SAMP: end))), a, rx_vec_iris(ibs, end - DATA_REP * N_SYM_SAMP: end));
v1 = filter(unos, a, abs(rx_vec_iris(ibs, end - DATA_REP * N_SYM_SAMP: end)) .^ 2);
lts_corr = (abs(v0) .^ 2) ./ v1; % normalized correlation
% position of the last peak
[~, max_idx] = max(abs(lts_corr));
rx_data_start = max_idx + (n_samp - DATA_REP * N_SYM_SAMP) - data_len
if rx_data_start < 0
display('bad receive!');
break;
end
payload_rx(ibs, :) = rx_vec_iris(ibs, rx_data_start: rx_data_start + data_len - 1);
for sid = 1:N_BS
for rid = 1:DATA_REP
% nid = sid + (sid >= REF_ANT);
start_index = CP_LEN + ((rid - 1) + (sid - 1) * DATA_REP) * N_SYM_SAMP;
if (ibs == REF_ANT)
rx_fft_ref(sid, :) = rx_fft_ref(sid, :) + fft(payload_rx(ibs, 1 + start_index : start_index + N_SC), N_SC);
else
rx_fft(sid, :) = rx_fft(sid, :) + fft(payload_rx(ibs, 1 + start_index : start_index + N_SC), N_SC);
end
end
end
end
for sid = 1:N_BS
cal_mat(sid, :) = (rx_fft_ref(sid, :) / DATA_REP) ./ (rx_fft(sid, :) / (N_BS * DATA_REP));
end
node_bs.sdr_close();
cf = 0;
cf = cf + 1;
figure(cf);clf;
for i = 1:N_BS
subplot(N_BS, 1, i);
plot(-32:1:31, abs(cal_mat(i, :)));
axis([-40 40 0 5])
grid on;
title('Calibration MAGNITUDE');
end
cf = cf + 1;
figure(cf);clf;
for i = 1:N_BS
subplot(N_BS, 1, i);
plot(-32:1:31, angle(cal_mat(i, :)));
axis([-40 40 -pi pi])
grid on;
title('Calibration ANGLE');
end
This diff is collapsed.