PUSCH#

Physical Uplink Shared Channel processing pipeline for 5G NR.

Overview#

The PUSCH runtime module provides a complete processing pipeline for Physical Uplink Shared Channel (PUSCH) in 5G NR systems. It consists of a TensorRT-accelerated inner receiver stage for signal processing and an outer receiver stage with LDPC channel decoding to transform received uplink signals into decoded transport blocks.

The pipeline consists of the following modules organized into two stages:

  • Inner Receiver: TensorRT-based signal processing that performs channel estimation, noise estimation, equalization, and soft demapping

  • Outer Receiver: Channel decoding chain that performs derate matching, LDPC decode, and CRC check

The inner receiver module uses TensorRT for GPU-accelerated neural network inference, while the outer receiver uses the LDPC library modules for channel decoding. All modules implement the pipeline::IModule interface from the pipeline library, enabling standardized configuration, memory management, and execution patterns.

Key Features#

  • TensorRT Inner Receiver: GPU-accelerated signal processing with TensorRT

  • Channel Decoding: LDPC decoder with derate matching and CRC validation

  • Pipeline Architecture: Modular design with factory-based module creation

  • Execution Modes: Support for both stream and CUDA graph execution

  • Memory Management: Efficient memory allocation and reuse across iterations

Core Concepts#

Pipeline Architecture#

The PUSCH pipeline processes uplink signals through two stages:

Inner Receiver Stage

The inner receiver module (InnerRxModule) performs signal processing on received time-frequency samples:

  1. Channel Estimation: Estimates channel response using DMRS (Demodulation Reference Signals)

  2. Noise Estimation: Estimates noise covariance matrix for equalization

  3. Equalization: Compensates for channel effects using estimated channel

  4. Soft Demapping: Generates Log-Likelihood Ratios (LLRs) from equalized symbols

This stage is implemented using TensorRT for optimized GPU execution.

Outer Receiver Stage

The outer receiver consists of three LDPC library modules:

  1. LDPC Derate Match Module: Reverses rate matching to prepare LLRs for LDPC decoding

  2. LDPC Decoder Module: Performs iterative LDPC decoding on LLRs to produce hard-decision bits

  3. CRC Decoder Module: Validates CRC checksums and concatenates code blocks into transport blocks

Each module implements the IModule interface from the pipeline library and can be created using the factory pattern.

Module Factory#

The PuschModuleFactory creates all module types used in the pipeline:

// Create a module factory for PUSCH pipeline
auto factory = std::make_unique<PuschModuleFactory>();

// Check supported module types
const bool supports_inner_rx = factory->supports_module_type("inner_rx_module");
const bool supports_ldpc = factory->supports_module_type("ldpc_decoder_module");

Module Configuration#

Modules are configured using static parameters at creation time:

// Configure physical layer parameters
PhyParams phy_params{};
phy_params.num_rx_ant = 4;
phy_params.num_prb = 273;
phy_params.bandwidth = 100;

// Configure inner_rx module parameters
const InnerRxModule::StaticParams params{
        .phy_params = phy_params, .execution_mode = pipeline::ExecutionMode::Stream};

// Create the inner_rx module
auto module = std::make_unique<InnerRxModule>("inner_rx_0", params);

Physical layer parameters include antenna configuration, PRB count, and bandwidth configuration.

Pipeline Specification#

Pipeline behavior is defined using PipelineSpec:

// Create pipeline specification
pipeline::PipelineSpec spec;
spec.pipeline_name = "PuschPipeline";
spec.execution_mode = pipeline::ExecutionMode::Stream;

// Configure physical layer parameters
PhyParams phy_params{};
phy_params.num_rx_ant = 4;
phy_params.num_prb = 273;

// Add inner receiver (inner_rx) module to specification
const InnerRxModule::StaticParams inner_rx_params{
        .phy_params = phy_params, .execution_mode = spec.execution_mode};

spec.modules.emplace_back(pipeline::ModuleCreationInfo{
        .module_type = "inner_rx_module",
        .instance_id = "inner_rx_0",
        .init_params = std::any(inner_rx_params)});

// Add outer receiver modules (derate match, LDPC decoder, CRC decoder)
const LdpcDerateMatchModule::StaticParams derate_params{
        .max_num_tbs = ran::common::MAX_NUM_TBS,
        .max_num_cbs_per_tb = ran::common::MAX_NUM_CBS_PER_TB,
        .max_num_rm_llrs_per_cb = ran::ldpc::MAX_NUM_RM_LLRS_PER_CB,
        .max_num_ue_grps = ran::common::MAX_NUM_UE_GRPS};

spec.modules.emplace_back(pipeline::ModuleCreationInfo{
        .module_type = "ldpc_derate_match_module",
        .instance_id = "ldpc_derate_match_0",
        .init_params = std::any(derate_params)});

const LdpcDecoderModule::StaticParams decoder_params{
        .clamp_value = ran::ldpc::LDPC_CLAMP_VALUE,
        .max_num_iterations = ran::ldpc::LDPC_MAX_ITERATIONS,
        .max_num_cbs_per_tb = ran::common::MAX_NUM_CBS_PER_TB,
        .max_num_tbs = ran::common::MAX_NUM_TBS,
        .normalization_factor = ran::ldpc::LDPC_NORMALIZATION_FACTOR,
        .max_iterations_method = ran::ldpc::LdpcMaxIterationsMethod::Fixed,
        .max_num_ldpc_het_configs = ran::ldpc::LDPC_MAX_HET_CONFIGS};

spec.modules.emplace_back(pipeline::ModuleCreationInfo{
        .module_type = "ldpc_decoder_module",
        .instance_id = "ldpc_decoder_0",
        .init_params = std::any(decoder_params)});

const CrcDecoderModule::StaticParams crc_params{
        .max_num_cbs_per_tb = ran::common::MAX_NUM_CBS_PER_TB,
        .max_num_tbs = ran::common::MAX_NUM_TBS};

spec.modules.emplace_back(pipeline::ModuleCreationInfo{
        .module_type = "crc_decoder_module",
        .instance_id = "crc_decoder_0",
        .init_params = std::any(crc_params)});

Module Introspection#

Modules provide introspection APIs for discovering ports and tensor information:

// Create inner_rx module
PhyParams phy_params{};
phy_params.num_rx_ant = 4;
phy_params.num_prb = 273;

const InnerRxModule::StaticParams params{
        .phy_params = phy_params, .execution_mode = pipeline::ExecutionMode::Stream};

auto module = std::make_unique<InnerRxModule>("inner_rx_0", params);

// Inspect module ports
const auto input_ports = module->get_input_port_names();
const auto output_ports = module->get_output_port_names();

Execution Flow#

A typical PUSCH processing iteration follows these steps:

Pipeline Setup#

Setup allocates memory and initializes all modules:

// Setup pipeline
pipeline_->setup();

This is called once during initialization before any processing begins.

Configure and Execute#

For each slot, configure the pipeline with dynamic parameters:

// Configure I/O with dynamic parameters
pipeline_->configure_io(params, external_inputs_, external_outputs_, stream.get());

// Warmup pipeline
pipeline_->warmup(stream.get());

The configure_io() method sets up input/output ports and prepares internal state based on transport block parameters. The warmup() method prepares execution paths (called once after setup).

Then execute the pipeline:

// Execute based on pipeline mode
if (pipeline_->get_execution_mode() == pipeline::ExecutionMode::Stream) {
    pipeline_->execute_stream(stream.get());
} else {
    pipeline_->execute_graph(stream.get());
}

The execute_stream() or execute_graph() method runs the complete pipeline processing on the provided CUDA stream.

Dynamic parameters change per slot and include UE-specific configuration like MCS, PRB allocation, and HARQ parameters.

Additional Examples#

For complete working examples with full setup and validation, see:

  • ran/runtime/pusch/tests/pusch_pipeline_runner.cpp - Pipeline runner implementation for benchmarks and tests

  • ran/runtime/pusch/tests/pusch_pipeline_test.cpp - Complete pipeline test with TensorRT integration

  • ran/runtime/pusch/tests/pusch_sample_tests.cpp - Documentation examples

API Reference#

constexpr uint32_t ran::pusch::NUM_PUSCH_MODULES = 4#

Number of PUSCH modules.

constexpr std::size_t ran::pusch::NUM_EXTERNAL_INPUTS = 1#

Number of external input ports.

constexpr std::size_t ran::pusch::NUM_EXTERNAL_OUTPUTS = 4#

Number of external output ports.

ran::pusch::DECLARE_LOG_COMPONENT(
PuschComponent,
PuschPipeline,
PuschModuleFactory,
InnerRxModuleFactory,
InnerRxModule,
)#

PUSCH logging components

ran::pusch::DECLARE_LOG_EVENT(
PuschPipelineEvent,
CreatePipeline,
CreateModules,
PipelineSetup,
PipelineWarmup,
PipelineConfigureIo,
PipelineExecuteStream,
PipelineBuildGraph,
PipelineExecuteGraph,
ModuleSetupMemory,
ModuleSetInputs,
ModuleWarmup,
ModuleConfigureIo,
ModuleGetOutputs,
ModuleExecute,
ModuleAddNodeToGraph,
)#

PUSCH pipeline event logging identifiers

ran::pusch::DECLARE_LOG_EVENT(
PuschErrorEvent,
InvalidParam,
InvalidState,
)#

PUSCH error event logging identifiers

bool ran::pusch::init_ran_trt_plugins() noexcept#

Initialize RAN TensorRT plugins

Uses an internal static TensorRT logger that forwards all messages to RT_LOG. Thread-safe and only initializes once.

Returns:

true if plugins initialized successfully

std::string ran::pusch::get_trt_engine_path()#

Get TRT engine file path from environment variable

Reads the full path to the TRT engine file from the RAN_TRT_ENGINE_PATH environment variable and verifies the file exists.

Throws:

std::runtime_error – if RAN_TRT_ENGINE_PATH not set or file doesn’t exist

Returns:

Full path to TRT engine file

std::vector<framework::memory::UniqueDevicePtr<std::byte>> ran::pusch::prepare_pusch_inputs(
std::vector<pipeline::PortInfo> &inputs,
const ran::common::PhyParams &phy_params,
const ran::aerial_tv::CuphyPuschTestVector &test_vector,
cudaStream_t stream,
)#
template<typename T>
std::vector<T> ran::pusch::tensor_to_host_vector(
const tensor::TensorInfo &tensor_info,
const void *device_ptr,
cudaStream_t stream,
)#

Copy device tensor data to host vector using stream-aware async copy

Computes number of elements from tensor_info, creates a std::vector<T> with that capacity, and copies data from device_ptr to the vector using cudaMemcpyAsync on the specified stream for proper synchronization.

Parameters:
  • tensor_info[in] Tensor information containing dimensions

  • device_ptr[in] Device pointer to tensor data

  • stream[in] CUDA stream to use for async memory copy (ensures proper ordering)

Returns:

Vector containing the copied data

pipeline::PipelineSpec ran::pusch::create_pusch_pipeline_spec(
const std::string &instance_id,
const ran::common::PhyParams &phy_params,
const pipeline::ExecutionMode execution_mode,
)#

Create PUSCH pipeline specification for testing/benchmarking

Parameters:
  • instance_id[in] Instance identifier for the pipeline

  • phy_params[in] Physical layer parameters

  • execution_mode[in] Execution mode (Stream or Graph)

Returns:

Pipeline specification with all module configurations

BenchmarkStatistics ran::pusch::compute_benchmark_statistics(
const std::vector<double> &times,
)#

Compute statistics from benchmark timing samples

Parameters:

times[in] Vector of timing measurements

Returns:

Computed statistics

std::vector<framework::memory::UniqueDevicePtr<std::byte>> ran::pusch::prepare_pusch_inputs(
std::vector<framework::pipeline::PortInfo> &inputs,
const ran::common::PhyParams &phy_params,
const ran::aerial_tv::CuphyPuschTestVector &test_vector,
cudaStream_t stream,
)#

Prepare PUSCH inputs with managed memory using stream-aware copy

Parameters:
  • inputs[out] Input ports

  • phy_params[in] Physical layer parameters

  • test_vector[in] Test vector

  • stream[in] CUDA stream for async memory copy

Returns:

Managed device pointers (memory freed automatically via RAII)

struct BenchmarkStatistics#
#include <pusch_test_utils.hpp>

Benchmark timing statistics

Public Members

double min = {}#

Minimum value.

double max = {}#

Maximum value.

double mean = {}#

Arithmetic mean.

double median = {}#

Median value (50th percentile)

double stddev = {}#

Standard deviation.

double p95 = {}#

95th percentile

std::size_t count = {}#

Number of samples.

class InnerRxModule : public framework::pipeline::IModule, public framework::pipeline::IAllocationInfoProvider, public framework::pipeline::IGraphNodeProvider, public framework::pipeline::IStreamExecutor#
#include <inner_rx_module.hpp>

Inner Rx Module

Generic front-end processing module template. Can be customized for specific front-end processing tasks.

Configuration:

  • Configurable input/output ports

  • Support for both stream and graph execution modes

Public Functions

InnerRxModule(std::string instance_id, const StaticParams &params)#

Construct module with instance ID and parameters

Parameters:
  • instance_id[in] Unique identifier for this module instance

  • params[in] Static configuration parameters

~InnerRxModule() override = default#

Destructor

InnerRxModule(const InnerRxModule&) = delete#
InnerRxModule &operator=(const InnerRxModule&) = delete#
InnerRxModule(InnerRxModule&&) = delete#
InnerRxModule &operator=(InnerRxModule&&) = delete#
inline virtual std::string_view get_type_id() const override#

Get module type identifier

Returns:

Module type ID

inline virtual std::string_view get_instance_id() const override#

Get module instance identifier

Returns:

Module instance ID

virtual framework::pipeline::IStreamExecutor *as_stream_executor(
) override#

Get stream executor interface

Returns:

Pointer to stream executor interface

virtual framework::pipeline::IGraphNodeProvider *as_graph_node_provider(
) override#

Get graph node provider interface

Returns:

Pointer to graph node provider interface

virtual std::vector<std::string> get_input_port_names(
) const override#

Get list of input port names

Returns:

Vector of input port names

virtual std::vector<std::string> get_output_port_names(
) const override#

Get list of output port names

Returns:

Vector of output port names

virtual std::vector<framework::tensor::TensorInfo> get_input_tensor_info(
std::string_view port_name,
) const override#

Get tensor information for input port

Parameters:

port_name[in] Input port name

Throws:

std::invalid_argument – if port name is unknown

Returns:

Vector of tensor information

virtual std::vector<framework::tensor::TensorInfo> get_output_tensor_info(
std::string_view port_name,
) const override#

Get tensor information for output port

Parameters:

port_name[in] Output port name

Throws:

std::invalid_argument – if port name is unknown

Returns:

Vector of tensor information

virtual framework::pipeline::InputPortMemoryCharacteristics get_input_memory_characteristics(
std::string_view port_name,
) const override#

Get input port memory characteristics

Parameters:

port_name[in] Input port name

Throws:

std::invalid_argument – if port name is unknown

Returns:

Memory characteristics for the port

virtual framework::pipeline::OutputPortMemoryCharacteristics get_output_memory_characteristics(
std::string_view port_name,
) const override#

Get output port memory characteristics

Parameters:

port_name[in] Output port name

Throws:

std::invalid_argument – if port name is unknown

Returns:

Memory characteristics for the port

virtual void set_connection_copy_mode(
std::string_view port_name,
framework::pipeline::ConnectionCopyMode mode,
) override#

Configure connection copy mode for an input port

Parameters:
  • port_name[in] Input port name

  • mode[in] Connection copy mode (Copy or ZeroCopy)

Throws:

std::invalid_argument – if port name is unknown

virtual framework::pipeline::ModuleMemoryRequirements get_requirements(
) const override#

Get module memory requirements

Returns:

Memory requirements for this module

virtual void setup_memory(
const framework::pipeline::ModuleMemorySlice &memory_slice,
) override#

Setup module memory

Parameters:

memory_slice[in] Memory slice allocated for this module

virtual void set_inputs(
std::span<const framework::pipeline::PortInfo> inputs,
) override#

Configure input port connections

Parameters:

inputs[in] Input port information containing data pointers

Throws:

std::invalid_argument – if required inputs are missing or port names don’t match with expected inputs

virtual void warmup(cudaStream_t stream) override#

Warmup execution

Parameters:

stream[in] CUDA stream for warmup

Throws:

std::runtime_error – if warmup is called before setup_memory() and set_inputs() have been called, or if the TRT engine setup() or warmup() fails

virtual void configure_io(
const framework::pipeline::DynamicParams &params,
cudaStream_t stream,
) override#

Configure I/O for current iteration

Parameters:
  • params[in] Dynamic parameters for this iteration

  • stream[in] CUDA stream for async operations during configuration

Throws:

std::runtime_error – if input ports are not set before configure_io()

virtual std::vector<framework::pipeline::PortInfo> get_outputs(
) const override#

Get output port information

Returns:

Vector of output port information

virtual void execute(cudaStream_t stream) override#

Execute module on stream

Parameters:

stream[in] CUDA stream for execution

Throws:

std::runtime_error – if the TRT engine run() fails

virtual std::span<const CUgraphNode> add_node_to_graph(
gsl_lite::not_null<framework::pipeline::IGraph*> graph,
std::span<const CUgraphNode> deps,
) override#

Add processing node to CUDA graph

Parameters:
  • graph[in] Graph interface for node creation

  • deps[in] Dependency nodes that must complete before this node

Throws:

std::runtime_error – if warmup() is not called before add_node_to_graph(), or if the graph capturer is not in capture mode, or if the captured TensorRT graph is not available

Returns:

Span of created graph node handle (single TensorRT node)

virtual void update_graph_node_params(
CUgraphExec exec,
const framework::pipeline::DynamicParams &params,
) override#

Update graph node parameters

Parameters:
  • exec[in] Graph executable to update

  • params[in] Dynamic parameters for the update

struct StaticParams#
#include <inner_rx_module.hpp>

Static parameters for module construction

Public Members

ran::common::PhyParams phy_params = {}#

Physical layer parameters.

framework::pipeline::ExecutionMode execution_mode = {framework::pipeline::ExecutionMode::Graph}#

Module execution mode.

class InnerRxModuleFactory : public framework::pipeline::IModuleFactory#
#include <pusch_module_factories.hpp>

Factory for creating InnerRxModule instances

Supports module type: “inner_rx_module” Accepts InnerRxModule::StaticParams via std::any in create_module()

Public Functions

InnerRxModuleFactory() = default#

Default constructor

~InnerRxModuleFactory() override = default#

Destructor

InnerRxModuleFactory(const InnerRxModuleFactory&) = delete#
InnerRxModuleFactory &operator=(const InnerRxModuleFactory&) = delete#
InnerRxModuleFactory(InnerRxModuleFactory &&other) = default#

Move constructor

Parameters:

other[inout] Source factory to move from

InnerRxModuleFactory &operator=(
InnerRxModuleFactory &&other,
) = default#

Move assignment operator

Parameters:

other[inout] Source factory to move from

Returns:

Reference to this object

virtual std::unique_ptr<framework::pipeline::IModule> create_module(
std::string_view module_type,
const std::string &instance_id,
const std::any &static_params,
) override#

Create a InnerRxModule instance

Parameters:
  • module_type[in] The type of module to create (must be “inner_rx_module”)

  • instance_id[in] Unique identifier for this module instance

  • static_params[in] Type-erased InnerRxModule::StaticParams

Throws:
  • std::invalid_argument – if module_type is not “inner_rx_module”

  • std::bad_any_cast – if static_params type doesn’t match

Returns:

Unique pointer to the created module

virtual bool supports_module_type(
std::string_view module_type,
) const override#

Check if a module type is supported

Parameters:

module_type[in] The type of module to check

Returns:

true if module_type is “inner_rx_module”, false otherwise

class InnerRxModuleRunner#
#include <inner_rx_module_runner.hpp>

InnerRx module execution helper for benchmarks and tests

Encapsulates inner_rx module setup, configuration, and execution. Follows RAII - module is fully initialized upon construction.

Public Functions

InnerRxModuleRunner(
const std::string &test_vector_path,
framework::pipeline::ExecutionMode execution_mode,
)#

Construct and initialize inner_rx module with test vector

Parameters:
  • test_vector_path[in] Full path to H5 test vector file

  • execution_mode[in] Execution mode (Stream or Graph)

~InnerRxModuleRunner() = default#
InnerRxModuleRunner(const InnerRxModuleRunner&) = delete#
InnerRxModuleRunner &operator=(const InnerRxModuleRunner&) = delete#
InnerRxModuleRunner(InnerRxModuleRunner&&) noexcept = default#

Move constructor

InnerRxModuleRunner &operator=(
InnerRxModuleRunner&&,
) noexcept = default#

Move assignment operator

Returns:

Reference to this object

void configure(const framework::utils::CudaStream &stream)#

Configure I/O and dynamic parameters

Call once before execute_once() or after parameter changes. Note: This method includes an initial warmup call.

Parameters:

stream[in] CUDA stream for execution

void warmup(const framework::utils::CudaStream &stream)#

Warmup module execution paths

Optional: Additional warmup can be performed by calling this method or by executing the module multiple times before benchmarking.

Parameters:

stream[in] CUDA stream for warmup

void execute_once(const framework::utils::CudaStream &stream)#

Execute one iteration of the module

Only performs execute() or launch_graph() call.

Parameters:

stream[in] CUDA stream for execution

inline framework::pipeline::ExecutionMode get_execution_mode() const#

Get module execution mode

Returns:

Execution mode (Stream or Graph)

std::vector<framework::pipeline::PortInfo> get_outputs() const#

Get module outputs after execution

Returns:

Vector of output port information

inline const ran::common::PhyParams &get_phy_params() const#

Get PhyParams

Returns:

Physical layer parameters

inline const ran::aerial_tv::CuphyPuschTestVector &get_test_vector(
) const#

Get test vector

Returns:

Test vector used for module configuration

struct PuschDynamicParams#
#include <pusch_defines.hpp>

PUSCH dynamic parameters data structure

This structure contains the dynamic parameters for the PUSCH pipeline. It is used to pass the dynamic parameters to the PUSCH pipeline.

Param inner_rx_params:

[in] InnerRx parameters

Param outer_rx_params:

[in] OuterRx parameters

Public Members

PuschInnerRxRxParams inner_rx_params#

InnerRx parameters.

ran::ldpc::PuschOuterRxParams outer_rx_params#

OuterRx parameters.

struct PuschInnerRxRxParams#
#include <pusch_defines.hpp>

InnerRx parameters structure

struct PuschInput#
#include <pusch_defines.hpp>

PUSCH Input Data

Contains all input parameters and data for PUSCH processing.

Public Functions

inline bool check_bounds() const#

Check if indices are within bounds

Returns:

true if indices are within valid ranges

Public Members

std::vector<PuschUeParams> ue_params#

UE parameters.

uint32_t ue_params_index = {}#

UE parameters index.

std::vector<std::vector<int8_t>> ue_group_idx_map#

map between ue params index and ue group index. ue_group_idx_map is sized by number of ue groups each slot. ue_group_idx_map[ue_group_idx] contains the indexes into ue_params for the UE which belong to this group.

uint32_t ue_group_idx_index = {}#

UE group index index.

std::vector<float> xtf#

XTF data (real/imag interleaved)

class PuschModuleFactory : public framework::pipeline::IModuleFactory#
#include <pusch_module_factories.hpp>

Combined factory for all PUSCH pipeline modules

Aggregates InnerRxModuleFactory and LDPC module factories. Supports module types: “inner_rx_module”, “ldpc_decoder_module”, “ldpc_derate_match_module”, “crc_decoder_module”

This factory delegates to the appropriate sub-factory based on module type.

Public Functions

PuschModuleFactory()#

Constructor - initializes sub-factories

~PuschModuleFactory() override = default#

Destructor

PuschModuleFactory(const PuschModuleFactory&) = delete#
PuschModuleFactory &operator=(const PuschModuleFactory&) = delete#
PuschModuleFactory(PuschModuleFactory &&other) = default#

Move constructor

Parameters:

other[inout] Source factory to move from

PuschModuleFactory &operator=(PuschModuleFactory &&other) = default#

Move assignment operator

Parameters:

other[inout] Source factory to move from

Returns:

Reference to this object

virtual std::unique_ptr<framework::pipeline::IModule> create_module(
std::string_view module_type,
const std::string &instance_id,
const std::any &static_params,
) override#

Create a module instance

Delegates to the appropriate sub-factory based on module_type.

Parameters:
  • module_type[in] The type of module to create

  • instance_id[in] Unique identifier for this module instance

  • static_params[in] Type-erased module static parameters

Throws:
  • std::invalid_argument – if module_type is not supported

  • std::bad_any_cast – if static_params type doesn’t match module requirements

Returns:

Unique pointer to the created module

virtual bool supports_module_type(
std::string_view module_type,
) const override#

Check if a module type is supported

Parameters:

module_type[in] The type of module to check

Returns:

true if supported by any sub-factory, false otherwise

struct PuschOutput#
#include <pusch_defines.hpp>

PUSCH Output Data

Contains all output results from PUSCH processing.

Public Members

std::vector<std::uint32_t> tb_crcs#

Transport block CRCs.

std::vector<std::uint8_t*> tb_payloads#

Transport block payloads.

void *d_tb_payloads = {}#

pointer to device memory containing Transport block payloads

std::vector<float> post_eq_noise_var_db#

Post-EQ noise variance db.

std::vector<float> post_eq_sinr_db#

Post-EQ SINR db.

class PuschPipeline : public framework::pipeline::IPipeline#
#include <pusch_pipeline.hpp>

PUSCH Pipeline

Pipeline for PUSCH processing:

  • External Inputs ─→ InnerRx module (TensorRT) ─→ LDPC derate match module (CUDA) ─→ LDPC decoder module ─→ CRC decoder module ─→ External Outputs

Features:

  • The full pipeline for PUSCH processing

  • InnerRx module: TensorRT-based processing

  • Channel decoding chain modules: CUDA-based LDPC decoding

  • Stream and graph execution modes

  • External input/output handling

  • Memory management

Public Functions

explicit PuschPipeline(
std::string pipeline_id,
gsl_lite::not_null<framework::pipeline::IModuleFactory*> module_factory,
const framework::pipeline::PipelineSpec &spec,
)#

Construct PUSCH pipeline using factory pattern

Creates all modules via the provided factory and configures the pipeline according to the PipelineSpec.

Parameters:
  • pipeline_id[in] Unique identifier for pipeline instance

  • module_factory[in] Factory for creating modules (non-owning pointer)

  • spec[in] Pipeline specification with module configurations

Throws:
  • std::invalid_argument – if spec doesn’t have exactly 4 modules

  • std::runtime_error – if module creation fails

~PuschPipeline() override = default#
PuschPipeline(const PuschPipeline&) = delete#
PuschPipeline &operator=(const PuschPipeline&) = delete#
PuschPipeline(PuschPipeline&&) = delete#
PuschPipeline &operator=(PuschPipeline&&) = delete#
inline virtual std::string_view get_pipeline_id() const override#

Get pipeline identifier

Returns:

Pipeline ID string

inline virtual std::size_t get_num_external_inputs() const override#

Get number of external inputs

Returns:

Number of external input ports

inline virtual std::size_t get_num_external_outputs() const override#

Get number of external outputs

Returns:

Number of external output ports

inline framework::pipeline::ExecutionMode get_execution_mode() const#

Get pipeline execution mode

Returns:

Execution mode (Stream or Graph)

virtual void setup() override#

Setup pipeline and modules

Allocates memory and initializes all modules

virtual void warmup(cudaStream_t stream) override#

Warmup pipeline execution

Parameters:

stream[in] CUDA stream for warmup

virtual void configure_io(
const framework::pipeline::DynamicParams &params,
std::span<const framework::pipeline::PortInfo> external_inputs,
std::span<framework::pipeline::PortInfo> external_outputs,
cudaStream_t stream,
) override#

Configure pipeline I/O for the current iteration.

Routes external inputs to modules and calls configure_io() on each module. Copies dynamic kernel descriptors to device and synchronizes stream. Routes module outputs to external outputs.

Parameters:
  • params[in] Dynamic parameters for this iteration

  • external_inputs[in] External input port information

  • external_outputs[out] External output port information to populate

  • stream[in] CUDA stream for any necessary operations

Throws:

std::invalid_argument – if dynamic parameters are invalid

virtual void execute_stream(cudaStream_t stream) override#

Execute pipeline in stream mode

Parameters:

stream[in] CUDA stream for execution

virtual void execute_graph(cudaStream_t stream) override#

Execute pipeline in graph mode

Parameters:

stream[in] CUDA stream for execution

Throws:
  • std::runtime_error – if not in graph mode or if graph build fails

  • std::runtime_error – if graph execution fails

class PuschPipelineRunner#
#include <pusch_pipeline_runner.hpp>

Pipeline execution helper for benchmarks and tests

Encapsulates pipeline setup, configuration, and execution for benchmarking. Follows RAII - pipeline is fully initialized upon construction.

Public Functions

PuschPipelineRunner(
const std::string &test_vector_path,
framework::pipeline::ExecutionMode execution_mode,
)#

Construct and initialize pipeline with test vector

Parameters:
  • test_vector_path[in] Full path to H5 test vector file

  • execution_mode[in] Execution mode (Stream or Graph)

~PuschPipelineRunner() = default#
PuschPipelineRunner(const PuschPipelineRunner&) = delete#
PuschPipelineRunner &operator=(const PuschPipelineRunner&) = delete#
PuschPipelineRunner(PuschPipelineRunner&&) noexcept = default#

Move constructor

PuschPipelineRunner &operator=(
PuschPipelineRunner&&,
) noexcept = default#

Move assignment operator

Returns:

Reference to this object

void configure(const framework::utils::CudaStream &stream)#

Configure I/O and dynamic parameters

Call once before execute_once() or after parameter changes.

Parameters:

stream[in] CUDA stream for execution

void warmup(cudaStream_t stream)#

Warmup pipeline execution paths

Parameters:

stream[in] CUDA stream for warmup

void execute_once(const framework::utils::CudaStream &stream)#

Execute one iteration of the pipeline

Only performs execute_stream() or execute_graph() call.

Parameters:

stream[in] CUDA stream for execution

framework::pipeline::ExecutionMode get_execution_mode() const#

Get pipeline execution mode

Returns:

Execution mode (Stream or Graph)

std::size_t get_num_external_outputs() const#

Get number of external outputs

Returns:

Count of external output ports

inline const std::vector<framework::pipeline::PortInfo> &get_external_outputs(
) const#

Get external outputs after execution

Returns:

Vector of external output port information

inline const ran::common::PhyParams &get_phy_params() const#

Get PhyParams

Returns:

Physical layer parameters

inline const ran::aerial_tv::CuphyPuschTestVector &get_test_vector(
) const#

Get test vector

Returns:

Test vector used for pipeline configuration

struct PuschUeParams#
#include <pusch_defines.hpp>

PUSCH UE parameters structure

Public Members

uint16_t cell_id = {}#

Cell ID (0-65535)

uint16_t sfn = {}#

System Frame Number (0-1023)

uint16_t rnti = {}#

Radio Network Temporary Identifier (0-65535)

uint32_t handle = {}#

Handle for UL indication.

uint16_t target_code_rate = {}#

Target code rate.

uint8_t qam_mod_order = {}#

QAM modulation order (2,4,6,8 for TP disabled; 1,2,4,6,8 for TP enabled)

uint8_t mcs_index = {}#

MCS index (0-31)

uint8_t mcs_table = {}#

MCS table index (0-4)

uint8_t transform_precoding = {}#

Transform precoding (0-1)

uint16_t data_scrambling_id = {}#

Data scrambling ID (0-65535)

uint8_t num_layers = {}#

Number of layers (1-4)

uint16_t dmrs_sym_pos_bmsk = {}#

DMRS symbol position bitmask.

uint8_t num_dmrs_cdm_grps_no_data = {}#

Number of DMRS CDM groups without data.

uint16_t start_prb = {}#

Start physical resource block for RA type 1.

uint16_t num_prb = {}#

Number of physical resource blocks for RA type 1.

uint8_t num_symbols = {}#

Number of symbols.

uint8_t start_symbol_index = {}#

Start symbol index.

uint8_t rv_index = {}#

Redundancy version index (0-3)

uint8_t harq_process_id = {}#

HARQ process ID (0-15)

uint8_t ndi = {}#

New data indicator (0-1)

uint32_t tb_size = {}#

Transport block size in bytes.