-
Notifications
You must be signed in to change notification settings - Fork 32
Home
Agora is a high-performance system for massive-MIMO baseband processing. Agora uses a queue-based master-worker model. A master thread is responsible for scheduling tasks and a pool of worker threads are responsible for executing tasks. The communication between the master thread worker threads are achieved through single-producer multi-consumer or multi-producer single-consumer shared memory FIFO queues (concurrentqueue).
As shown in the figure below, Agora has a socket interface to communicate with remote radio unit (RRU) and a MAC interface to communicate with upper layer. Baseband processing blocks are implemented as Doer functions.
DoFFT does FFT of an OFDM symbol to convert data from time domain to frequency domain.
(OFDM_CA_NUM
: number of subcarriers in an OFDM symbol, BS_ANT_NUM
: number of base station antennas, fft_block_size
: task granularity of FFT, values are given in config.cpp)
- Data dimension: antenna-parallel
- Number of unit tasks: number of base station antennas
BS_ANT_NUM
per symbol - Task granularity is controlled by
fft_block_size
- Input: data size:
OFDM_CA_NUM
, data type: 2-bytes integer (2 bytes for I and 2 bytes for Q)socket_buffer
- Output: data size:
OFDM_CA_NUM
, data type: complex float (4 bytes for I and 4 bytes for Q)- Pilot symbols:
data_buffer
- Uplink data symbols:
data_buffer
- Reciprocity calibration symbols:
calib_buffer
- Pilot symbols:
- Processing steps:
- Convert 2-bytes integers to floats
- Compute FFT
- Only for pilot symbols, do channel estimation
- Save results in a partial transposed data layout
DoRecip calculates the reciprocal calibration matrix.
(BS_ANT_NUM
: number of base station antennas, OFDM_DATA_NUM
: number of data subcarriers in an OFDM symbol, recip_block_size
: task granularity of Recip, values are given in config.cpp)
- Data dimension: subcarrier-parallel
- Number of unit tasks: number of data subcarriers
OFDM_DATA_NUM
per reciprocity calibration symbol - Task granularity is controlled by
recip_block_size
(processingrecip_block_size
subcarriers in on function call) - Input: data size
BS_ANT_NUM
, data type: complex floatscalib_buffer
- Output: data size
BS_ANT_NUM
, data type: complex floatrecip_buffer
- Processing steps:
- Calculates the reciprocal calibration matrix
DoZF does precoder calculation to get precoder matrix from CSI matrix with Zeroforcing method.
(BS_ANT_NUM
: number of base station antennas, UE_NUM
: number of users, OFDM_DATA_NUM
: number of data subcarriers in an OFDM symbol, zf_block_size
: task granularity of ZF, values are given in config.cpp)
- Data dimension: subcarrier-parallel
- Number of unit tasks: number of data subcarriers
OFDM_DATA_NUM
per pilot symbol - Task granularity is controlled by
zf_block_size
(processingzf_block_size
subcarriers in on function call) - Input: data type: complex floats
-
csi_buffer
: data sizeBS_ANT_NUM x UE_NUM
(stored with partial transposed layout) -
recip_buffer
: data sizeBS_ANT_NUM
, used for reciprocal calibration to get downlink precoder matrix
-
- Output: data size
UE_NUM x BS_ANT_NUM
, data type: complex float- Uplink:
ul_zf_buffer
- Downlink:
dl_zf_buffer
- Uplink:
- Processing steps:
- Gather data from csi_buffer which has partial transposed data layout into
csi_gather_buffer
for CSI matrix with continuous layout - Compute matrix pseudo-inverse to get uplink precoder matrix
- If there are downlink symbols in a frame, do reciprocal calibration to get downlink precoder matrix
- Gather data from csi_buffer which has partial transposed data layout into
DoDemul does equalization and demodulation to get log-likelihood ratios (LLRs), which are the input to soft-decision decoding.
(BS_ANT_NUM
: number of base station antennas, UE_NUM
: number of users, OFDM_DATA_NUM
: number of data subcarriers in an OFDM symbol, demul_block_size
: task granularity of Demul, values are given in config.cpp)
- Data dimension: subcarrier-parallel
- Number of unit tasks: number of data subcarriers
OFDM_DATA_NUM
per uplink data symbol - Task granularity is controlled by
demul_block_size
(processingdemul_block_size
subcarriers in on function call) - Input: data type: complex float
-
data_buffer
: data vector with data size:BS_ANT_NUM x 1
(stored with partial transposed layout) -
ul_zf_buffer
: precoder matrix with data sizeUE_NUM x BS_ANT_NUM
-
- Output: data_type
int8_t
-
demod_soft_buffer
: LLRs vector with data size:UE_NUM x 1
-
- Processing steps:
- Gather data vector from data_buffer which has partial transposed data layout into
smp_buffer
with continuous layout - Do equalization (matrix multiplication) to get demultiplexed user data
- Do demodulation to get LLRs, which are the input to soft-decision decoding
- Gather data vector from data_buffer which has partial transposed data layout into
DoDecode does LDPC decoding.
(UE_NUM
: number of users, LDPC_config.cbCodewLen
: number of encoded bits in a code block, LDPC_config.cbLen
: number of information bits in a code block, LDPC_config.nblocksInSymbol
: number of code blocks in a symbol, values are given in config.cpp)
- Data dimension: user-parallel, code block parallel
- Number of unit tasks: number of code blocks
UE_NUM * LDPC_config.nblocksInSymbol
in a symbol - Task granularity is always 1 since decoding has high computational overhead
- Input: data type:
int8_t
-
demod_soft_buffer
: LLR vector withLDPC_config.cbCodewLen
bits (saved as int8_t bytes)
-
- Output: data_type
uint8_t
-
decoded_buffer
: decoded information bits with sizeLDPC_config.cbLen
-
- Processing steps:
- Set parameters of LDPC decoding and do decoding