Skip to content
Jian Ding edited this page Sep 4, 2020 · 8 revisions

Welcome to the Agora wiki!

Overview

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).

overview

Flow Diagram for Baseband Processing

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.

code_flow_diagram

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
  • 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 (processing recip_block_size subcarriers in on function call)
  • Input: data size BS_ANT_NUM, data type: complex floats
    • calib_buffer
  • Output: data size BS_ANT_NUM, data type: complex float
    • recip_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 (processing zf_block_size subcarriers in on function call)
  • Input: data type: complex floats
    • csi_buffer: data size BS_ANT_NUM x UE_NUM (stored with partial transposed layout)
    • recip_buffer: data size BS_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
  • 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

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 (processing demul_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 size UE_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

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 with LDPC_config.cbCodewLen bits (saved as int8_t bytes)
  • Output: data_type uint8_t
    • decoded_buffer: decoded information bits with size LDPC_config.cbLen
  • Processing steps:
    • Set parameters of LDPC decoding and do decoding
Clone this wiki locally