NR SA CSI Report
The purpose of this tutorial is to show you how to configure CSI-RS and Report configuration. This would be the most complicated configuration in 5G NR and many parameters are involved in Amarisoft configuration as well. Main purpose of this tutorial is to show how each of the configuration parameter in enb.cfg is associated with RRC Configuration for CSI Report.
Amarisoft gNB provides two different ways of configuring CSI RS/CSI Report as listed below :
- Manual Configuration : This is the way you should configure every details of RRC configuration required for CSI Report and CSI RS. This is the only option if you are using the gNB software before 2022-06-17. You still can use this option even after 2022-06-17 if you want to control all the detailed parameters (like periodicity and position of all the necessary CSI RS) and you exactly understand what you should do.
- Auto Configuration : This is the way you just configure a few most fundamental parameters (e.g, CSI Report Quantity) and gNB software configure all other parameters which are necessary to enable the specified Report. In order to use this feature, you need to use the release 2022-06-17 or later.
Table of Contents
- NR SA CSI Report
- Introduction
- Summary of the Tutorial
- Test Procedure Summary
- For those frustrated with 5G CSI
- Plan before Doing
- Test Setup
- Key Configuration Parameters
- Reference Configuration : Auto CSI Configuration
- Test 1 : Periodic CSI Report
- Configuration
- Log Analysis
- Sub Test 1 : RI-PMI-CQI
- Sub Test 2 : RI-CQI
- Sub Test 3 : RI-CQI with non-PMI-PortIndication
- Sub Test 4 : RSRP
- Sub Test 5 : RI-PMI-CQI with ri-restriction
- Sub Test 6 : ssb-RSRP
- Test 2 : Aperiodic CSI Report
- Test 3 : TCI
- Test 4 : CSI RS p32 - Periodic
- Test 5 : CSI RS and Physical Antenna Mapping - TRS
- RRC / NAS Signaling
- Tips
Introduction
Channel State Information Reference Signals (CSI-RS) play a pivotal role in the performance optimization and link adaptation mechanisms of 5G New Radio (NR) systems. CSI-RS are specialized downlink reference signals transmitted by the gNB (next-generation NodeB or 5G base station) to enable the User Equipment (UE) to accurately assess channel conditions and report this information back to the network. Such measurements are essential for closed-loop operations like beam management, mobility, and advanced MIMO (Multiple-Input Multiple-Output) techniques. The configuration of CSI-RS and their corresponding reporting mechanisms is inherently complex due to the extensive parameterization available in 5G NR, including aspects such as resource mapping, periodicity, frequency-domain positioning, and report quantization. Amarisoft’s gNB software provides a flexible and robust framework for configuring CSI-RS and CSI reporting, supporting both detailed manual configuration and streamlined auto-configuration modes. Understanding the mapping between high-level configuration files, such as enb.cfg, and the underlying RRC (Radio Resource Control) configurations is critical for network engineers seeking to optimize network performance, troubleshoot issues, or implement custom measurement strategies. This tutorial offers a comprehensive technical guide to configuring CSI-RS and CSI reporting in Amarisoft gNB, elucidating the interplay between configuration parameters and the resulting network behavior, while ensuring compatibility across software releases and deployment scenarios.
-
Context and Background
- 5G NR introduces advanced channel estimation and reporting mechanisms to support features such as massive MIMO, beamforming, and dynamic spectrum utilization.
- CSI-RS serve as the foundation for precise channel quality measurements, enabling UEs to provide feedback that drives adaptive transmission strategies.
- Amarisoft’s gNB software aligns with 3GPP standards, offering granular control over CSI-RS configuration for both pre- and post-2022-06-17 software releases.
-
Relevance and Importance
- Correct configuration of CSI-RS and reporting mechanisms is crucial for maximizing spectral efficiency and ensuring reliable UE connectivity in real-world deployments.
- This tutorial addresses the practical challenges of mapping configuration file parameters to RRC signaling, especially in the context of Amarisoft deployments.
- Understanding both manual and auto-configuration workflows empowers engineers to tailor network behavior to specific scenarios, balancing ease-of-use with fine-grained control.
-
Learning Objectives
- Comprehend the architectural role of CSI-RS in 5G NR and its impact on channel measurements and reporting.
- Gain hands-on familiarity with Amarisoft’s dual-mode (manual and auto) configuration paradigms for CSI-RS and reporting.
- Learn to associate enb.cfg parameters with RRC-level configurations for effective network tuning and troubleshooting.
- Acquire practical knowledge for maintaining compatibility with evolving Amarisoft software releases and leveraging new features efficiently.
-
Prerequisite Knowledge
- Familiarity with 5G NR concepts, especially radio protocol stack layers, reference signals, and measurement reporting.
- Basic understanding of Amarisoft gNB software usage and configuration file structure.
- Awareness of RRC signaling principles and general network configuration workflows.
-
Scope and Approach
- This tutorial focuses on high-level configuration strategies, parameter associations, and architectural context rather than raw message formats or ASN.1 definitions.
- It is designed to be accessible to radio engineers, system integrators, and advanced users aiming for optimal 5G NR network performance using Amarisoft gNB.
Summary of the Tutorial
This tutorial provides detailed procedures for configuring and testing various Channel State Information (CSI) reporting scenarios in a 5G NR Standalone (SA) environment using Amarisoft gNB. The focus is on configuration methodologies, verification steps, and test execution for both simple and advanced CSI use cases. Below are the summarized test procedures and methodologies as described in the tutorial:
-
General Test Preparation
- gNB configuration changes are required; default MME and IMS configurations can be kept.
- Key configuration steps include selecting duplex mode (TDD/FDD), DL antennas, band, frequency, and bandwidth.
- CSI configuration can be automatic (using resource_auto) for simplicity, or fully manual for advanced control.
- Verification of configuration is performed via logs, focusing on RRC Setup and CSI reporting via PUCCH.
-
Reference (Auto CSI) Configuration
- Use default gnb-sa.cfg with resource_auto to enable CSI RS and reporting with minimal parameter settings.
- Duplex mode, TDD pattern, bandwidth, and antenna settings are defined in the configuration file.
- AutoCSI simplifies configuration by automating resource and report setup; detailed configuration is possible with manual methods.
- Verification involves checking the log for proper auto-generation of CSI RS, resource sets, and report configuration.
-
Test 1: Periodic CSI Report (Manual Configuration)
- Manual configuration using gnb-sa-rq-ri-pmi-cqi.cfg allows full flexibility in defining CSI RS, resource sets, and reporting.
- Physical resources (CSI RS and TRS) are configured according to antenna setup and TDD pattern, ensuring non-collision with SSB and other signals.
- Resource grouping and assignment are managed through nzp_csi_rs_resource_set and csi_resource_config.
- Subtests demonstrate configuration changes in report_quantity (e.g., RI-PMI-CQI, RI-CQI, RSRP), inclusion of non_pmi_port_indication, and use of ri_restriction bits.
- For SSB-based RSRP reporting, csi_ssb_resource_set is configured and registered.
- Test execution involves:
- Starting gNB service and running cell phy and cell commands.
- Collecting logs from the attach process (using t command before UE power on).
- Validating CSI reports received on PUCCH at configured intervals.
- For some subtests, channel conditions are manipulated (e.g., using tx_gain) to observe RI adaptation.
-
Test 2: Aperiodic CSI Report
- Configured by setting report_config_type to "aperiodic" in csi_report_config, with other configurations similar to periodic tests.
- Verification includes checking that aperiodic reporting is scheduled via DCI and reported through PUSCH, with appropriate k2 slot offset.
- Test steps are similar to periodic tests, focusing on DCI and PUSCH log validation.
-
Test 3: TCI (Transmission Configuration Indication)
- TCI configuration is demonstrated for both PDCCH and PDSCH using tci_states_pdcch and tci_states parameters.
- Multiple TCI states are set: for SSB only, CSI RS only, and both SSB and CSI RS.
- Verification includes checking RRC logs for TCI state configuration and ensuring no fatal issues on UE.
- Test execution follows standard procedure, with PUCCH CSI report monitoring.
-
Test 4: CSI RS p32 - Periodic
- Demonstrates configuration of 32-port CSI RS (n_ports=32) using resource_auto, even if the number of logical CSI ports exceeds physical antennas.
- Highlights the limitation that cdm_type and some other parameters are fixed in resource_auto.
- Verification involves checking that the UE accepts the configuration and that signaling is as expected.
-
Test 5: CSI RS and Physical Antenna Mapping - TRS
- Manual configuration of TRS using four CSI RS, each mapped to specific physical antennas via the precoding_matrix parameter.
- Mapping logic is internal to the Amarisoft gNB and not signaled in protocol logs; logs are used to confirm TRS resource configuration.
-
Resource Collision Avoidance Tips
- Draw time domain resource allocation maps to visualize and avoid collisions between CSI RS, SSB, PDSCH DMRS, and other signals.
- Adjust parameters such as ssb_pos_bitmap, dmrs_type_a_pos, dmrs_add_pos, and first_symb to resolve conflicts.
- If unresolved, distribute CSI RS across non-overlapping slots using period and offset, or adjust frequency allocation with bitmap.
-
Additional Configuration and Logging Tips
- When configuring n1 and n2 in codebook_config, associate them with CSI RS ports, not physical antennas.
- Codebook settings may be omitted from RRC if only one CSI port is configured.
- Enable decoded CSI reporting in logs using phy.csi=1 or via the WebGUI for easier analysis.
By following these procedures and configuration methodologies, users can conduct comprehensive CSI reporting tests (both periodic and aperiodic), manage resource allocation, and validate results using Amarisoft’s configuration and logging tools.
Test Procedure Summary
This test requires gNB configuration change only and you can keep mme, ims configuration as in default.
Step 1 : Set TDD/FDD(NR_TDD). number of DL Antenna(N_ANTENNA_DL), Band(band) and Frequency(dl_nr_arfcn) and Bandwidth(NR_BANDWIDTH) as you want
Step 2 : Configure csi_re parameter as per your test requirement. If you don't have any specific requirement and just want to have csi report, you can use resource_auto, but if you have any specific requirement of your own you need to configure nzp_csi_rs_resource, nzp_csi_rs_resource_set, csi_im_resource, csi_im_resource_set, zp_csi_rs_resource, p_zp_csi_rs_resource_set, csi_resource_config, csi_report_config as you like.
Step 3 : Run the test
Step 4 : Verify the result with Log. Check RRC Setup message and see if all the configuration is configured as intended and Check if gNB is getting CSI report via PUCCH.
For those frustrated with 5G CSI
If you are so struggling with 5G CSI, don't get frustrated. You are not the only one. I think almost everybody would be in same situation to some degree. Even those who is working in this specific technical area (in development or verification), they would need to turn to 3GPP documents or other documents every time when there is details they need to figure out.
The frustration that I personally have are
- Understanding the full details of 3GPP about CSI is difficult
- Configuring those details into RRC message is even more difficult
This frustration would persist with testing this feature. Too simple or Too complex situation happens here again with most of test system
- Too Simple : Some test system allow you to configure CSI stuffs just by turning on/off a toggle switch. This may be convenient if you just want to enable / disable CSI in order to get some basic CSI report and don't care much about the detailed configuration. However if the task you have to deal with is to test CSI feature itself and you need complete controll over every detailed elements of CSI configuration.
- Too Complex : Some test system allow you to configure each and every details of CSI configuration like giving you the access to every information elements in the RRC messages and even the access to the physical configuration (like physical antenna configuration) that are associated with the RRC. It is perfect in terms of flexibility and controlability, but it is nightmare in terms of user friendliness. You would understand what this mean right away if you try yourself with configuring just a few CSI RS resources, resource sets, resource configuration and report configuration in RRC message.. make a small mistake and get error ... pulling hairs trying to figure out where the error comes from .. and fix it and try again... doing this over and over. In most case, the ASN editor used for the configuration does not allow Copy & Paste of a certain IE(Information Elements) at a branch level. So even if you have multiple CSI Resource configuration which are similar to each other, you would not be able to configure them just by copy & paste and a little bit of modification. You need to configure them all one by one.
How Amarisoft does ?
Can Amarisoft provides anything simple and flexible ? To be honest, No. but 'simple and flexible' is mutually exclusive. I haven't seen any solution with 'simple and flexible at the same time'. A kind of trade off that Amarisoft takes is to provide both simple way and complex way to gether so that user can choose depending on their necessity. Amarisoft provide the options as follows :
- Simple : Amarisoft provide a special configuration parameter called resource_auto. With this parameter, you can enable or disable CSI RS configuration almost like flipping a toggle switch. It is super simple to configure CSI RS/CSI Report with this parameter, but you don't have full controllability/flexibility in terms of detailed configuration.
- Complex : Amarisoft allows directly configuring each CSI RS resource one-by-one for maximum control. You can set the number of ports, number of resources per port, exact position of CSI resources, CSI RS types, reporting configurations, and other advanced parameters. This provides full flexibility to customize the CSI RS setup to your specific needs. Even with this flexibility, this would not as difficult as editing RRC with ASN Editor. Amarisoft configuration is done in JSON format and you can do copy&paste of the partial or entire cofnguration from one configuration to another and just modify a little bit to create a new configuration.
Plan before Doing
At 10000 feet view, CSI report configuration follows along a long and winding path of configurations : CSI Resource --> CSI Resource Set --> CSI Resource Config --> CSI Report. The first hurdle is to understand all the details of these configuration in terms of 3GPP. But let's assume that you get the full understandins on the configuration itself. However the fact that you have full understanding does not necessarily mean that you can start writing configuration and testing without any prep. There are two major check points (preparation) that I want to suggest
- Write down on the exact purpose of the CSI resources : Is this for Report or TRS ? If it is for Report, is it persistent or semi-persistent ? antenna pannel type ? structure of the panel ? measurement quantity ? etc
- Draw the details of physical resource allocation on the resource grid on paper or excel spreadsheet or whatever you think is convenient. Which OFDM symbols in a resource grid ? Periodicity ? Frequency span in PRBs ? etc
First step would be done relatively easy and it may be done in your head, but the second step would not go as easy unless you have done a lot of practice. The best way would be to draw with your hand first and have some imagination on how it would look like when they are really transmitted. One example of final image you can think of would be something as below. Of course, you would not get the exact details of every possible physical signal shown below since some of these signal is dynamically allocated and would vary depending on the situation, but you should get the clear image about CSI RS since they are static or semi-static.

Image captured by Amarisoft sdr_spectrum
Other form of imagination can be as follows. If you can plot this kind of image for each of the symbols in your brain, you are ready to go with the real configuration and test.

Image captured by Amarisoft sdr_spectrum
Test Setup
Test setup for this tutorial is as shown below. This is just for low layer testing, you may not need any complicated IP layer setup.
- SIM Card used in this tutorial is the one delivered with the system as it is.
- If you want to change the configuration, The tutorial Configuration Guide would help

Key Configuration Parameters
Followings are important configuration parameters for this tutorial. You may click on the items for the descriptions from Amarisoft documents.
- csi_report_config : In this link, you can find the descriptions for all the parameters below.
- resource_for_channel_measurement
- csi_im_resources_for_interference
- report_config_type
- period
- report_quantity
- codebook_config: In this link, you can find the descriptions for all the parameters below.
- non_pmi_port_indication
- cqi_table
- subband_size
- pdcch
- pdsch
- tci_states: In this link, you can find the descriptions for all the parameters below.
- tci_state_id
- qcl_type1
- reference_signal
- ssb_index
- csi_rs_index
- qcl_type
- ssb_pos_bitmap
- csi_rs
- nzp_csi_rs_resource : In this link, you can find the descriptions for all the parameters below.
- csi_rs_id
- n_ports
- frequency_domain_allocation
- cdm_type
- density
- first_symb
- first_symb2
- rb_start
- l_crb
- period
- offset
- qcl_info_periodic_csi_rs
- csi_im_resource : In this link, you can find the descriptions for all the parameters below.
- csi_im_id
- pattern
- subcarrier_location
- symbol_location
- rb_start
- l_crb
- period
- offset
- zp_csi_rs_resource : In this link, you can find the descriptions for all the parameters below.
- csi_rs_id
- n_ports
- frequency_domain_allocation
- cdm_type
- density
- first_symb
- first_symb2
- rb_start
- l_crb
- period
- offset
- nzp_csi_rs_resource_set : In this link, you can find the descriptions for all the parameters below.
- csi_rs_set_id
- nzp_csi_rs_resources
- repetition
- trs_info
- csi_im_resource_set : In this link, you can find the descriptions for all the parameters below.
- csi_im_set_id
- csi_im_resources
- resource_auto : In this link, you can find the descriptions for all the parameters below.
- nzp_csi_rs_period
- n_ports
- trs_presence
- trs_period
- exclude_slot_sib1
- exclude_slot_ssb
- power_control_offset
- dl_bwp_list
Reference Configuration : Auto CSI Configuration
Configuration
Since this is a reference test, I just used a default reference configuration gnb-sa.cfg.

In the configuration file, you can select any specific tdd pattern with the parameter NR_TDD_CONFIG. To apply TDD configuration, you first need to configure the duplex mode (NR_TDD) to 1 (TDD). And then I set NR_TDD_CONFIG to 2 which is one of default sample configuration provided by Amarisoft sample configuration. And I set the channel bandwidth (NR_BANDWIDTH) to 20Mhz and 2x2 MIMO (N_ANTENNA_DL = 2)

Here you can enable csi_rs simply by sing resource_auto and specify a couple of simple setting like nzp_csi_rs_period and trs_presence in stead of configuring all the complicated individual csi resources and csi resource sets.
This shows a "minimal-touch" way to enable CSI-RS for downlink channel measurement. Instead of defining individual CSI-RS resources and CSI resource sets one by one, you turn on csi_rs.resource_auto, and the gNB automatically generates a reasonable NZP-CSI-RS setup that matches the current carrier, numerology, and PDSCH settings. You mainly control the measurement cadence with nzp_csi_rs_period (here, 80), which determines how often the NZP-CSI-RS is transmitted so the UE can track channel quality over time. The trs_presence flag controls whether TRS-related signaling is considered in the auto-generated CSI-RS behavior (here it is disabled, and the snippet hints it may be handled differently for FR2). On top of the reference signal generation, csi_report_config is set to a simple periodic report with the same period: 80, so the UE sends CSI feedback at a regular interval aligned with the CSI-RS transmission rhythm. Overall, the intent is to get a working CSI measurement + reporting loop with only a couple of high-level parameters, while leaving the detailed resource mapping to the automatic generator.

Following table shows an example of csi configuration that just configures a single set of TRS and one csi-report. You would notice how simple it get with auto CSI configuration.
|
Configuration without AutoCSI |
Configuration with AutoCSI |
| This is the configuration in gnb-sa.cfg before AutoCSI feature is supported | This is the configuration in gnb-sa.cfg after AutoCSI feature is supported |
|
csi_rs: { nzp_csi_rs_resource: [ { csi_rs_id: 0, #if N_ANTENNA_DL == 1 n_ports: 1, frequency_domain_allocation: "row2", bitmap: "100000000000", cdm_type: "no_cdm", #elif N_ANTENNA_DL == 2 n_ports: 2, frequency_domain_allocation: "other", bitmap: "100000", cdm_type: "fd_cdm2", #elif N_ANTENNA_DL == 4 n_ports: 4, frequency_domain_allocation: "row4", bitmap: "100", cdm_type: "fd_cdm2", #elif N_ANTENNA_DL == 8 n_ports: 8, frequency_domain_allocation: "other", bitmap: "110011", cdm_type: "fd_cdm2", #else #error unsupported number of DL antennas #endif density: 1, first_symb: 4, rb_start: 0, l_crb: -1, / -1 means from rb_start to the end of the bandwidth / power_control_offset: 0, / dB / power_control_offset_ss: 0, / dB / period: 80, offset: 1, / != 0 to avoid collision with SSB / qcl_info_periodic_csi_rs: 0, }, #if FR2 == 0 #define USE_TRS #endif #ifdef USE_TRS / TRS : period of 40 ms, slots 1 & 2, symbols 4 and 8 / { csi_rs_id: 1, n_ports: 1, frequency_domain_allocation: "row1", bitmap: "0001", cdm_type: "no_cdm", density: 3, first_symb: 4, rb_start: 0, l_crb: -1, / -1 means from rb_start to the end of the bandwidth / power_control_offset: 0, / dB / power_control_offset_ss: 0, / dB / period: 40, offset: 11, qcl_info_periodic_csi_rs: 0, }, { csi_rs_id: 2, n_ports: 1, frequency_domain_allocation: "row1", bitmap: "0001", cdm_type: "no_cdm", density: 3, first_symb: 8, rb_start: 0, l_crb: -1, / -1 means from rb_start to the end of the bandwidth / power_control_offset: 0, / dB / power_control_offset_ss: 0, / dB / period: 40, offset: 11, qcl_info_periodic_csi_rs: 0, }, { csi_rs_id: 3, n_ports: 1, frequency_domain_allocation: "row1", bitmap: "0001", cdm_type: "no_cdm", density: 3, first_symb: 4, rb_start: 0, l_crb: -1, / -1 means from rb_start to the end of the bandwidth / power_control_offset: 0, / dB / power_control_offset_ss: 0, / dB / period: 40, offset: 12, qcl_info_periodic_csi_rs: 0, }, { csi_rs_id: 4, n_ports: 1, frequency_domain_allocation: "row1", bitmap: "0001", cdm_type: "no_cdm", density: 3, first_symb: 8, rb_start: 0, l_crb: -1, / -1 means from rb_start to the end of the bandwidth / power_control_offset: 0, / dB / power_control_offset_ss: 0, / dB / period: 40, offset: 12, qcl_info_periodic_csi_rs: 0, }, #endif ], nzp_csi_rs_resource_set: [ { csi_rs_set_id: 0, nzp_csi_rs_resources: [ 0 ], repetition: false, }, #ifdef USE_TRS { csi_rs_set_id: 1, nzp_csi_rs_resources: [ 1, 2, 3, 4 ], repetition: false, trs_info: true, }, #endif ],
csi_im_resource: [ { csi_im_id: 0, pattern: 1, subcarrier_location: 8, symbol_location: 8, rb_start: 0, l_crb: -1, / -1 means from rb_start to the end of the bandwidth / period: 80, offset: 1, / != 0 to avoid collision with SSB / }, ], csi_im_resource_set: [ { csi_im_set_id: 0, csi_im_resources: [ 0 ], } ], / ZP CSI-RS to set the CSI-IM REs to zero / zp_csi_rs_resource: [ { csi_rs_id: 0, frequency_domain_allocation: "row4", bitmap: "100", n_ports: 4, cdm_type: "fd_cdm2", first_symb: 8, density: 1, rb_start: 0, l_crb: -1, / -1 means from rb_start to the end of the bandwidth / period: 80, offset: 1, }, ], p_zp_csi_rs_resource_set: [ { zp_csi_rs_resources: [ 0 ], }, ],
csi_resource_config: [ { csi_rsc_config_id: 0, nzp_csi_rs_resource_set_list: [ 0 ], resource_type: "periodic", }, { csi_rsc_config_id: 1, csi_im_resource_set_list: [ 0 ], resource_type: "periodic", }, #ifdef USE_TRS { csi_rsc_config_id: 2, nzp_csi_rs_resource_set_list: [ 1 ], resource_type: "periodic", }, #endif ], csi_report_config: [ { resources_for_channel_measurement: 0, csi_im_resources_for_interference: 1, report_config_type: "periodic", period: 80, report_quantity: "CRI_RI_PMI_CQI", #if N_ANTENNA_DL > 1 codebook_config: { codebook_type: "type1", sub_type: "typeI_SinglePanel", #if N_ANTENNA_DL == 2 #elif N_ANTENNA_DL == 4 n1: 2, n2: 1, codebook_mode: 1, #elif N_ANTENNA_DL == 8 n1: 4, n2: 1, codebook_mode: 1, #endif }, #endif cqi_table: 2, subband_size: "value1", }, ], }, |
csi_rs: { resource_auto: { nzp_csi_rs_period: 80, #if FR2 trs_presence: false, #endif }, csi_report_config: [ { report_config_type: "periodic", period: 80, }, ], },
|
Log Analysis
This is just for showing the association between the configuration shown above and IE (Information Elements) in RRC.
First check out zp-CSI-RS-ResourceToAddModList in pdsch-Config. All the detailed IEs within the configuration was set automatically by the resource_auto configuration parameter.
In this step, you verify that the CSI-RS was not only enabled at the high level, but also materialized into real RRC IEs inside pdsch-Config. The easiest place to confirm this is nzp-CSI-RS-ResourceToAddModList, because this list shows the concrete NZP-CSI-RS resource(s) that the UE will actually measure. In the decoded RRC view on the right, you can see that the gNB has automatically created zp-CSI-RS-ResourceId 0 and filled in all the low-level mapping details that you normally would have to configure manually. For example, it defines the CSI-RS RE pattern through resourceMapping, including the frequency-domain allocation (freqDomainAllocation row4: '100'B) and the time-domain location (firstOFDMSymbolInTimeDomain 4). It also selects the CDM behavior (cdm-Type cdm2), and it decides the bandwidth and placement by setting the starting RB and RB span (startingRB 0, nrofRBs 52, with freqBand 0). Finally, it gives the resource its periodic transmission pattern via periodicityAndOffset slots80: 1, which matches the simple period-based intent you provided in the configuration. The key point is that these values were not hand-crafted in your config; they appear because resource_auto generated a complete, standards-compliant NZP-CSI-RS resource definition, and then injected it into the RRC configuration under pdsch-Config so the UE can measure and report CSI without you having to build the full CSI-RS resource and resource-set structures yourself.

After confirming the single NZP-CSI-RS entry under pdsch-Config, the next validation point is csi-MeasConfig, because this is where the UE is told what CSI-RS resources exist for measurement and how they are grouped for reporting. In the right-side decode view, you can see nzp-CSI-RS-ResourceToAddModList populated with multiple entries, which means the gNB did not stop at creating only one "PDSCH-side" resource. It also generated a measurement-oriented set of NZP-CSI-RS resources that the UE can use for CSI acquisition. Here, five NZP-CSI-RS resources are created, typically with IDs 0 to 4. Each entry has its own resourceMapping parameters, such as the frequency-domain allocation pattern (for example the row/bitmap style allocation), the firstOFDMSymbolInTimeDomain (so the CSI-RS appears in a specific OFDM symbol), and the CDM type. They also include RB placement information like startingRB and nrofRBs, so the UE knows exactly where in frequency the CSI-RS is located. Even though these resources share a common "shape" (same bandwidth and similar mapping rules), they are differentiated by timing, especially through periodicityAndOffset. In the capture, you can see the periodicity is based on an 80-slot rhythm, but the offset values vary across resources, which effectively spreads CSI-RS occasions over time instead of transmitting everything in the same slot.


After you confirm that nzp-CSI-RS-ResourceToAddModList contains five NZP-CSI-RS resources, the next step is to look at nzp-CSI-RS-ResourceSetToAddModList. This list tells you how the gNB groups those individual resources into "resource sets," because the UE does not use every CSI-RS for the same purpose. The grouping is the key that explains the intent of each CSI-RS transmission.
In this log, you can see two NZP-CSI-RS resource sets. One set contains only NZP-CSI-RS resource 0. This is the CSI-RS that will be referenced by CSI reporting, so it becomes the main measurement anchor for periodic CSI feedback. The other set contains NZP-CSI-RS resources 1, 2, 3, and 4. This set has trs-info true, which indicates that this group is treated as TRS-oriented. In other words, those four CSI-RS resources are grouped together to act like tracking reference signals, so the UE can use them for time/frequency tracking and channel tracking behavior rather than for the "main CSI report" measurement.
In the same csi-MeasConfig area, you also see csi-IM-ResourceToAddModList. CSI-IM resources are a different type of measurement resource. They are not NZP-CSI-RS, and they do not carry reference symbols for channel estimation. Instead, they define where the UE should measure interference (IM = interference measurement). So when you see CSI-IM resources configured, it means the gNB is giving the UE explicit measurement occasions to observe interference power on specific REs, which can then be combined with NZP-CSI-RS measurements to produce more complete CSI (for example, separating signal and interference conditions).

By looking at csi-ResourceConfigToAddModList, you can see how the gNB packages the measurement resources into "CSI resource configurations" that the UE will actually use for reporting. This is the step where the configuration stops being "a list of CSI-RS resources" and becomes "a reportable group" with a clear measurement purpose. In this log, you can see that the periodic reporting is built by combining two types of resources. The first one is the NZP-CSI-RS side. Here the configuration points to NZP-CSI-RS Resource Set 0, which is the set you identified earlier as the CSI-report set. This tells the UE which NZP-CSI-RS occasion it should measure to derive channel quality and PMI/RI style information for the periodic report.
The second one is the interference side. You can see CSI-IM Resource Set 0 included as well. This means the UE is not only measuring the signal reference (NZP-CSI-RS), but also measuring interference on the CSI-IM locations, so the report can reflect a more realistic SINR-like condition instead of only reference-signal strength.
In addition to CSI-RS/CSI-IM, SSB is also included for periodic reporting in this configuration. This provides an extra measurement source that is always available and robust, so the UE can base some periodic measurements on SSB as well, depending on the report configuration and what the gNB requests.
So the key point of csi-ResourceConfigToAddModList is that it defines the exact "input set" for the periodic CSI pipeline. It ties together the NZP-CSI-RS set for channel measurement, the CSI-IM set for interference measurement, and the SSB measurement option, all under periodic reporting behavior.

At the final stage, csi-ReportConfigToAddModList shows the actual CSI reporting "contract" that the UE must follow, using the resources and groupings that were built in the earlier steps. This is where the gNB decides what the UE reports, how often it reports, and which measurement inputs (NZP-CSI-RS / CSI-IM / SSB) are tied to that report.
In the highlighted block, you can see a periodic report configuration is created and linked to the previously defined measurement setup. The report points to a CSI resource configuration for channel measurement (csi-ResourceConfigChannelMeasurement) and also references the interference side (csi-IM-ResourcesForInterference). This means the periodic CSI report is based on the NZP-CSI-RS resource set you identified for CSI reporting, combined with the CSI-IM resource set used for interference measurement. The reporting type is set to periodic, and the periodicity is explicitly defined (in this capture it is slots80: 9), so the UE will generate CSI feedback every 80 slots with the given offset.
The report also specifies the payload format and quantity of feedback. You can see it is configured for wideband reporting (csi-ReportQuantity / wideband style selection), and it includes the usual CSI content that maps to rank and precoder selection behavior. The codebook section is also present, which tells the UE what PMI codebook restrictions apply and how the UE should interpret the report in terms of MIMO layer/precoding assumptions. Finally, the configuration indicates how the report is carried (PUCCH resource linkage appears in the same block), meaning the UE knows the uplink control resource to use when it sends the periodic CSI.
So, csi-ReportConfigToAddModList is the point where everything "clicks together." The earlier lists define what exists (CSI-RS resources, CSI-IM resources, resource sets). The resource config defines which groups are used for measurement. The report config defines what the UE must report and on what schedule, and ties it to the exact measurement inputs and uplink reporting mechanism.

Test 1 : Periodic CSI Report
In this test, I will show you how to configure manually the periodic CSI report and validate it. Obviously manual configuration is much more complicated than the auto configuration, but you will have full flexibility for the configuration.
Configuration
The configuration shown here is common configuration for all the subtests belonging to Test 1 and I will not show this configuration repeatedly for every subtest.
I have used gnb-sa-rq-ri-pmi-cqi.cfg which is copied and modified from gnb-sa.cfg

I am using the default mme, ims config as shown below.

In gnb-sa-rq-ri-pmi-cqi.cfg, it is configured as follows.
In the configuration file, you can select any specific tdd pattern with the parameter NR_TDD_CONFIG. To apply TDD configuration, you first need to configure the duplex mode (NR_TDD) to 1 (TDD). And then I set NR_TDD_CONFIG to 2 which is one of default sample configuration provided by Amarisoft sample configuration. And I set the channel bandwidth (NR_BANDWIDTH) to 20Mhz and 2x2 MIMO (N_ANTENNA_DL = 2)

Here the band is set to n78 which is a TDD band. The important part is ssb_pos_bitmap. In this test, only ssb 0 is enabled and all the csi-rs is configured not to collide with the ssb 0 symbols. If you want to change this part, you may need to change CSI-RS symbols accordingly not to collide the changed ssb burst position.

Here comes the difficult parts which is about configuring all the physical resources. The first physical resource is configured for CSI report. Applying different csi port depending on the number of DL antenna. This configurations are related to 38.211-Table 7.4.1.5.3-1.
One important thing for you to pay attention to especially for TDD is to make it sure that this configuration should fall into DL slots/symbols in TDD UL/DL common configuration and should not collide with other physical resources like SSB, PDCCH or PDSCH DMRS etc.
This configuration shows a manual NZP-CSI-RS resource definition where the CSI-RS "shape" is selected automatically based on the number of downlink antenna ports (N_ANTENNA_DL). The idea is that you keep one csi_rs_id and one resource block of common timing/frequency settings, but you switch the port count and RE pattern so the CSI-RS matches the MIMO capability of the cell.
For each N_ANTENNA_DL option, the config sets n_ports and then chooses the corresponding frequency-domain allocation type and bitmap. Those choices control where CSI-RS REs are placed inside the resource grid, and they also determine what CDM structure is used (cdm_type). The comment points to 3GPP TS 38.211 Table 7.4.1.5.3-1, which is the reference table that enumerates valid CSI-RS resource mappings for different numbers of antenna ports. In practice, this is why the 1-port case uses a simpler mapping with no_cdm, while multi-port cases use FD-CDM (fd_cdm2) to multiplex multiple ports in the same time/frequency region.
Below the port-dependent section, the resource timing and placement are fixed. first_symb decides in which OFDM symbol CSI-RS appears, density controls how many REs are used within the mapping, and rb_start plus l_crb define the bandwidth portion where the CSI-RS spans (with l_crb = -1 meaning "from rb_start to the end of the carrier"). period and offset define the periodic transmission pattern, and these are the parameters you must align with your TDD pattern and other always-on signals. The note about collision with SSB is important: if first_symb, period, or offset place CSI-RS in the same symbols/slots as SSB (or other DL signals you care about), you may need to move the CSI-RS occasion to avoid overlap. The power control offsets are included to let you bias CSI-RS power relative to other signals if needed, but the main purpose of this block is to ensure the CSI-RS mapping is valid and consistent with the configured DL antenna port count.


Following is the simplified configuration
|
csi_rs: { nzp_csi_rs_resource: [ { csi_rs_id: 0,
// Pick one port option that matches your DL antenna ports n_ports: 4, // 1 / 2 / 4 / 8
// Matching RE pattern for the selected n_ports (example for 4 ports) frequency_domain_allocation: "row4", bitmap: "100", cdm_type: "fd_cdm2",
// Common placement/timing density: 1, first_symb: 4, rb_start: 0, l_crb: -1, // -1 = from rb_start to end of bandwidth
// Periodic transmission period: 80, offset: 1 // adjust to avoid SSB collision } ] } |
Now four csi resources are configured to define TRS in such a way to meet 3GPP requirement.
Again One important thing for you to pay attention to especially for TDD is to make it sure that this configuration should fall into DL slots/symbols in TDD UL/DL common configuration and should not collide with other physical resources like SSB, PDCCH or PDSCH DMRS etc.
This configuration adds an optional TRS-style CSI-RS group on top of the normal NZP-CSI-RS used for CSI reporting. When USE_TRS is enabled, the gNB defines four additional NZP-CSI-RS resources with csi_rs_id 1 to 4. These TRS resources always use n_ports: 1, regardless of how many DL antenna ports the cell supports, because the goal is stable tracking rather than multi-port CSI estimation. Each TRS resource uses a simple mapping (frequency_domain_allocation: "row1", bitmap: "0001", cdm_type: "no_cdm") with higher density (density: 3) so the UE gets reliable reference symbols for time/frequency tracking. The resources are split across two OFDM symbols (first_symb: 4 and first_symb: 8) and two slot offsets (offset: 11 and offset: 12) with a period: 40, which is meant to place TRS occasions at specific, repeating time locations. Because these placements directly interact with your TDD pattern and other DL signals, the important knobs to revisit when you tune the pattern are first_symb, period, and offset.
The resource-set section shows the intended usage clearly. csi_rs_set_id: 0 includes only resource 0, so that single NZP-CSI-RS resource is the one used as the CSI-report anchor. When USE_TRS is enabled, csi_rs_set_id: 1 groups resources [1, 2, 3, 4] and sets trs_info: true, which marks this set as TRS-oriented. In other words, resource 0 is kept for periodic CSI reporting, while resources 1-4 are transmitted as a coordinated group to support UE tracking behavior.



Following is the simplified configuration
|
// Enable only if you want TRS-style CSI-RS (tracking) #define USE_TRS
#ifdef USE_TRS // ---- TRS-style NZP-CSI-RS (always 1 port) ---- // Two symbols (4 and 8), two offsets (11 and 12) -> total 4 resources { csi_rs_id: 1, n_ports: 1, frequency_domain_allocation: "row1", bitmap: "0001", cdm_type: "no_cdm", density: 3, first_symb: 4, rb_start: 0, l_crb: -1, period: 40, offset: 11 },
{ csi_rs_id: 2, n_ports: 1, frequency_domain_allocation: "row1", bitmap: "0001", cdm_type: "no_cdm", density: 3, first_symb: 8, rb_start: 0, l_crb: -1, period: 40, offset: 11 },
{ csi_rs_id: 3, n_ports: 1, frequency_domain_allocation: "row1", bitmap: "0001", cdm_type: "no_cdm", density: 3, first_symb: 4, rb_start: 0, l_crb: -1, period: 40, offset: 12 },
{ csi_rs_id: 4, n_ports: 1, frequency_domain_allocation: "row1", bitmap: "0001", cdm_type: "no_cdm", density: 3, first_symb: 8, rb_start: 0, l_crb: -1, period: 40, offset: 12 }, #endif ],
// ---- Resource sets (how UE uses them) ---- nzp_csi_rs_resource_set: [ { csi_rs_set_id: 0, nzp_csi_rs_resources: [0], repetition: false }, // for CSI report
#ifdef USE_TRS { csi_rs_set_id: 1, nzp_csi_rs_resources: [1,2,3,4], repetition: false, trs_info: true }, // for TRS #endif ] } |
Next step is to group the nzp csi resource defined above as per usage (purpose). This is done by nzp_csi_rs_resource_set configuration parameter. Here two group (two sets) are defined. The first group is the one with only one elements in nzp_csi_rs_resources array which will be used for CSI report and the second group (set) is the one with 4 elements in nzp_csi_rs_resources array which will be used for TRS.
csi_rs_set_id: 0 contains only nzp_csi_rs_resources: [0]. This makes resource 0 the dedicated CSI-RS used for CSI reporting. The UE measures this CSI-RS and uses it as the channel measurement input for the periodic CSI report configuration.
When USE_TRS is enabled, an additional set is created with csi_rs_set_id: 1. This set bundles nzp_csi_rs_resources: [1, 2, 3, 4] and sets trs_info: true. With trs_info enabled, the gNB is marking this set as TRS-oriented. The UE treats these CSI-RS occasions as tracking references, so they are used mainly for time/frequency tracking and channel tracking behavior rather than as the primary CSI-report measurement resource.

Last part of the csi resource configuration in this test is for the resources for interference measurement, which are IM resources and ZP CSI resources shown here. CSI IM is configured by the parameter csi_im_resources and ZP CSI resources is configured by zp_csi_rs_resources. Again and Again, one important thing for you to pay attention to especially for TDD is to make it sure that this configuration should fall into DL slots/symbols in TDD UL/DL common configuration and should not collide with other physical resources like SSB, PDCCH or PDSCH DMRS etc.
csi_im_resource defines where the UE should measure interference. It does not transmit a reference signal. Instead, it specifies a fixed RE pattern in time/frequency using pattern, subcarrier_location, and symbol_location. In your example, the CSI-IM measurement points are placed at subcarrier 8 and symbol 8, over the bandwidth region starting at rb_start: 0 and extending to the end with l_crb: -1. The measurement occasion repeats with period: 80 and offset: 1.
csi_im_resource_set then groups the CSI-IM resources. Here, csi_im_set_id: 0 contains just resource [0], so this becomes the single interference-measurement set that the report configuration can reference later.
The comment ZP CSI-RS to set the CSI-IM REs to zero explains the practical pairing that usually comes with CSI-IM. A ZP-CSI-RS is not transmitted energy either; it is a muting pattern that tells the UE those REs are reserved/blank. By defining a ZP-CSI-RS with the same kind of periodic timing (period: 80, offset: 1) and a specific mapping (frequency_domain_allocation, bitmap, first_symb, etc.), the gNB ensures the REs used for CSI-IM are kept free of PDSCH and other transmissions. That way, when the UE measures on the CSI-IM locations, it is measuring interference and noise, not a mix of interference plus your own data.
So the flow is: CSI-IM defines where to measure interference, CSI-IM set defines the group used by reporting, and ZP-CSI-RS defines muted REs so the interference measurement is clean and repeatable.

Following is the simplified configuration
|
csi_im_resource: [ { csi_im_id: 0, pattern: 1, subcarrier_location: 8, symbol_location: 8, rb_start: 0, l_crb: -1, // to end of bandwidth period: 80, offset: 1 // shift to avoid SSB / collisions } ],
csi_im_resource_set: [ { csi_im_set_id: 0, csi_im_resources: [0] } ],
// ZP-CSI-RS (muting) for CSI-IM REs zp_csi_rs_resource: [ { csi_rs_id: 0, frequency_domain_allocation: "row4", bitmap: "100", n_ports: 4, cdm_type: "fd_cdm2", first_symb: 8, density: 1, rb_start: 0, l_crb: -1, period: 80, offset: 1 } ] |
One step above the physical resource grouping (i.e, csi rs resource set) is csi resource config (csi_resource_config) which groups the resource sets (it is a kind of super group with the restpect of csi resource) and assign a specific type (resource_type) to the group. In this test, all the resources sets are set to periodic.
This shows how the "muting" resources and the measurement resources are tied together into CSI resource configurations, and it also makes clear that this test is built around periodic operation.
p_zp_csi_rs_resource_set groups the ZP-CSI-RS resources. Here it contains only zp_csi_rs_resources: [0], meaning ZP-CSI-RS resource 0 is the single muting pattern used in the test. This set is what higher-level CSI configuration can reference when it needs a ZP-CSI-RS resource by set rather than by individual ID.
csi_resource_config then defines the measurement "packages" that will be referenced by CSI reporting. Each entry has its own csi_rsc_config_id, points to a particular resource set list, and declares resource_type: "periodic". In this default setup, you see one config (id: 0) that references the NZP-CSI-RS resource set list [0], so this is the periodic channel-measurement input for CSI reporting. Another config (id: 1) references the CSI-IM resource set list [0], so this is the periodic interference-measurement input. If USE_TRS is enabled, an additional config (id: 2) references NZP-CSI-RS resource set list [1], which is the TRS-marked resource set you created earlier.
The key point is that CSI reporting does not directly point to individual CSI-RS or CSI-IM resources. Instead, the report configuration references these csi_resource_config entries. By setting everything to periodic, the UE is instructed to perform these measurements on a repeating schedule (as defined by each resource’s period and offset) and then use them as inputs for periodic CSI reports.

Following is the simplified configuration
|
p_zp_csi_rs_resource_set: [ { zp_csi_rs_resources: [0] } // ZP-CSI-RS set for muting ],
csi_resource_config: [ { csi_rsc_config_id: 0, nzp_csi_rs_resource_set_list: [0], // NZP-CSI-RS set used for CSI report resource_type: "periodic" }, { csi_rsc_config_id: 1, csi_im_resource_set_list: [0], // CSI-IM set used for interference meas resource_type: "periodic" },
#ifdef USE_TRS { csi_rsc_config_id: 2, nzp_csi_rs_resource_set_list: [1], // TRS-marked NZP-CSI-RS set resource_type: "periodic" }, #endif ] |
Log Analysis
This is just for showing the association between the configuration shown above and IE (Information Elements) in RRC.
In this specific test, it is not so important but it is worth noting that at least one tci-state gets configured in RRC even when you didn't configure anything in configuration file. Here, you see one tci-State assciated with ssb 0 is configured in tci-StatesToAddModList of pdsch-Config. Regarding the TCI/QCL, you may refer to this note.
In this test, you don’t explicitly configure any TCI states in the cell configuration, but the RRC still ends up carrying at least one default TCI state. You can confirm this by checking tci-StatesToAddModList inside pdsch-Config. In the decoded view, a single tci-StateId 0 appears even though tci_states was not set in the config file.
This default entry is basically a "baseline" association so the UE has at least one valid TCI/QCL reference for PDSCH reception. In the shown example, the state references SSB 0 (referenceSignal ssb:0) and provides the QCL type information (for example qcl-Type typeD). That means the UE can treat the SSB as the reference for the spatial/beam and tracking assumptions used when it receives downlink data. So even in a simplified CSI-RS test where TCI is not the focus, the stack still injects a minimal TCI configuration to keep the RRC configuration complete and the PDSCH reception behavior well-defined.

Now let's take a look into csi configuration that is under pdsch-Config. It is zp-CSI-RS-ResourceToAddModList IE in pdsch-Config. This IE is set by the configuration parameter zp_csi_rs_resource and p_zp_csi_resource_set as shown here.
This shows how the ZP-CSI-RS "muting" configuration you wrote in the cell config becomes real RRC signaling under pdsch-Config. The IE to check is zp-CSI-RS-ResourceToAddModList. This list contains the actual ZP-CSI-RS resources that the UE must treat as reserved (zero-power) REs, so that data is not scheduled there and the UE can safely use those REs for measurements such as CSI-IM.
On the left, the configuration defines one zp_csi_rs_resource with csi_rs_id: 0 and specifies its RE pattern and placement. The frequency mapping is defined by frequency_domain_allocation and bitmap, the number of ports and multiplexing are captured by n_ports and cdm_type, and the time placement is controlled mainly by first_symb. The resource also spans the carrier from rb_start to the end using l_crb: -1, and it repeats periodically using period: 80 with offset: 1. These are the practical knobs you adjust when you need to avoid collisions with SSB or to align with your TDD DL symbols.
On the right, you can see the corresponding RRC decode where the gNB created zp-CSI-RS-ResourceId 0 and filled the resourceMapping fields with the same intent: a specific frequency-domain allocation pattern, a chosen OFDM symbol in time, and a defined RB range. The periodic behavior appears as periodicityAndOffset slots80: 1, which is the RRC expression of your period and offset.
Right below that, zp-CSI-RS-ResourceSetToAddModList is also present. This is produced by your p_zp_csi_rs_resource_set configuration and groups the ZP-CSI-RS resources into a set, typically so other CSI configuration blocks can reference the set rather than referencing a single resource ID. In this example the set contains only resource 0, so it is the single muting pattern used by the test, and it becomes the ZP-CSI-RS resource set that supports the interference-measurement configuration built in the CSI measurement section.

Next, check how each of the nzp CSI RS is configured in RRC. These configurations are set in csi-MeasConfig. The individual nzp CSI RS Resource are configured in nzp-CSI-RS-ResourceToAddModList. This is the first nzp-CSI-RS-Resource which will be used for CSI Report.
At this point you move from the PDSCH-side ZP/NZP definitions to the real CSI measurement configuration that is signaled to the UE. The place to check is csi-MeasConfig, because that is where the UE is told exactly which NZP-CSI-RS resources exist for measurement and what their detailed mapping is. Inside csi-MeasConfig, the individual resources appear under nzp-CSI-RS-ResourceToAddModList.
In the highlighted block you are looking at the first NZP-CSI-RS resource that will be used for CSI reporting. In the config file this corresponds to csi_rs_id: 0, and in the RRC decode you see it as nzp-CSI-RS-ResourceId 0. Even though you wrote it in a compact form, the gNB expands it into the full RRC resourceMapping fields: it selects a frequency-domain allocation pattern (shown as the "other/row" style bitmap in the decode), sets the number of ports (nrofPorts reflects your n_ports selection), and places the CSI-RS in time with firstOFDMSymbolInTimeDomain (here it is symbol 4). It also defines the RB span through startingRB and nrofRBs, so the UE knows which part of the carrier contains the CSI-RS.
The periodic behavior is shown explicitly as periodicityAndOffset slots80: 1, which is the RRC form of period: 80 and offset: 1. Power-related parameters are also carried over (powerControlOffset, and the SS/PBCH-related offset if present), and you can see the qcl-infoPeriodicCSI-RS field, which links this CSI-RS resource to the QCL/TCI assumptions used for measurement and reporting.
So this is the confirmation that "CSI-RS resource 0" is not just defined locally in the configuration file, but is fully translated into the standard RRC IE under csi-MeasConfig, and that it is the specific NZP-CSI-RS instance the UE will use as the channel measurement reference for periodic CSI reporting.

After the first NZP-CSI-RS resource (ID 0) for CSI reporting, the next entries in csi-MeasConfig → nzp-CSI-RS-ResourceToAddModList are the additional CSI-RS resources that are intended for TRS use. In this example, you see two of them first: csi_rs_id: 1 and csi_rs_id: 2, and in the RRC decode they appear as nzp-CSI-RS-ResourceId 1 and nzp-CSI-RS-ResourceId 2.
These TRS-oriented resources are deliberately kept simple and stable. They always use n_ports: 1 (so nrofPorts p1 in RRC), independent of the cell’s DL antenna configuration, because TRS is about providing a clean tracking reference rather than multi-port CSI estimation. The mapping also uses a straightforward single-row frequency pattern (frequencyDomainAllocation row1 with the small bitmap), and cdm-Type stays at the non-CDM style, which avoids extra port multiplexing complexity.
The two resources are mainly distinguished by where they land in time. One is placed at firstOFDMSymbolInTimeDomain 4 (matching first_symb: 4) and the other at firstOFDMSymbolInTimeDomain 8 (matching first_symb: 8). Both share the same periodic schedule (periodicityAndOffset slots40: 11), so they repeat every 40 slots with the same offset, but they provide two tracking opportunities within the slot by using two different OFDM symbols. This is a common pattern when you want more frequent/robust tracking without changing the overall period.
So the key takeaway from these two entries is: once CSI-RS 0 is established for reporting, CSI-RS 1 and 2 are added as 1-port, high-reliability CSI-RS occasions placed at different symbols, which are later grouped into the TRS-marked resource set (trs_info: true) and used for tracking rather than as the primary CSI-report measurement reference.

After TRS resources 1 and 2, the RRC continues with the remaining two TRS-oriented NZP-CSI-RS entries: csi_rs_id: 3 and csi_rs_id: 4. In csi-MeasConfig → nzp-CSI-RS-ResourceToAddModList, they appear as nzp-CSI-RS-ResourceId 3 and nzp-CSI-RS-ResourceId 4, and they have the same "TRS style" structure as the previous pair.
Both resources keep n_ports: 1 (so the RRC shows nrofPorts p1) and use the same simple frequency mapping (frequencyDomainAllocation row1 with the small bitmap) with cdm-Type in the non-CDM form. This keeps the signal easy to track and avoids multi-port multiplexing complexity, which is consistent with TRS usage.
What changes compared to resources 1 and 2 is the timing offset. Resources 3 and 4 repeat with periodicityAndOffset slots40: 12 instead of slots40: 11. Within that same periodic schedule, they again split the transmission across two OFDM symbols: resource 3 is placed at firstOFDMSymbolInTimeDomain 4 (matching first_symb: 4), and resource 4 is placed at firstOFDMSymbolInTimeDomain 8 (matching first_symb: 8). So the four TRS resources together form a 2×2 pattern: two symbols (4 and 8) times two offsets (11 and 12), which gives the UE more tracking occasions without changing the core mapping.
This is why later, when you look at the resource set configuration, resources 1-4 are grouped into a single TRS-marked NZP-CSI-RS resource set (trs_info: true), while resource 0 remains isolated in its own set for CSI reporting.

After all individual NZP-CSI-RS resources are listed in nzp-CSI-RS-ResourceToAddModList, the next step in csi-MeasConfig is the higher-level grouping done by nzp-CSI-RS-ResourceSetToAddModList. This is where the gNB turns "many physical CSI-RS resources" into "a small number of logical sets" that can be referenced cleanly by CSI measurement and reporting configuration.
In this test, two NZP-CSI-RS resource sets are created. The first set is nzp-CSI-RS-ResourceSetId 0, and it contains only one resource, {0}. This single-resource set is the one used as the CSI reporting anchor, so when the UE is told to measure NZP-CSI-RS for CSI feedback, it is effectively pointed to this set.
The second set is nzp-CSI-RS-ResourceSetId 1, and it contains four resources, {1, 2, 3, 4}. This set is marked with trs-info true, which indicates these resources are grouped specifically for TRS-style tracking behavior. Because the four resources are distributed across different OFDM symbols and offsets, grouping them under one TRS-marked set gives the UE a consistent tracking reference pattern without mixing them with the CSI-report measurement resource.
So the key outcome here is that the RRC configuration exposes two logical "buckets": one small bucket for CSI reporting (just resource 0), and one larger bucket for tracking (resources 1-4). These sets are what later CSI resource configuration and CSI report configuration blocks will reference, rather than referencing individual CSI-RS resources one by one.

This step is to confirm that the UE is also given a clean setup for 'interference measurement', not only channel measurement. In NR, that is done with 'CSI-IM', and you validate it in 'csi-MeasConfig' by checking two IEs: 'csi-IM-ResourceToAddModList' and 'csi-IM-ResourceSetToAddModList'.
In 'csi-IM-ResourceToAddModList', you see the individual CSI-IM resource created from your 'csi_im_resource' configuration. It appears as 'csi-IM-ResourceId 0', and it contains the RE pattern definition that tells the UE exactly where to measure interference. The "element pattern" fields reflect your 'pattern: 1', and the locations map directly to your 'subcarrier_location: 8' and 'symbol_location: 8'. The frequency span is also carried over through 'startingRB' and the number of RBs (your 'rb_start' and 'l_crb' intent), and the periodic behavior shows up as 'periodicityAndOffset slots80: 1', matching 'period: 80' and 'offset: 1'.
In 'csi-IM-ResourceSetToAddModList', you then see how the CSI-IM resources are grouped. In this test there is a single set, 'csi-IM-ResourceSetId 0', and it simply contains CSI-IM resource '{0}'. This is the set that later CSI resource configuration and CSI report configuration will reference when they need "the interference measurement input" for the periodic CSI report.
So the key confirmation here is: 'csi_im_resource' becomes the concrete 'csi-IM-ResourceId' in RRC, and 'csi_im_resource_set' becomes the 'csi-IM-ResourceSetId' grouping, making the interference measurement path complete and usable by the CSI reporting chain.

Once the NZP-CSI-RS resource sets (for CSI report and for TRS) and the CSI-IM resource set (for interference) are in place, the next level is 'CSI Resource Config'. This is the layer that turns "a resource set" into "a measurement input" that CSI reporting can reference. In RRC it appears as 'csi-ResourceConfigToAddModList', and in Amarisoft it is driven by your 'csi_resource_config' blocks.
You can see multiple 'csi-ResourceConfigId' entries created. Each one points to exactly one type of resource-set list and declares 'resourceType periodic', meaning the UE should measure these resources on their configured periodic occasions.
'csi-ResourceConfigId 0' references 'nzp-CSI-RS-ResourceSetList' containing set 0. This is the channel-measurement input for CSI reporting, so it effectively tells the UE: "measure the NZP-CSI-RS set that contains CSI-RS resource 0."
'csi-ResourceConfigId 1' references 'csi-IM-ResourceSetList' containing set 0. This is the interference-measurement input, so it tells the UE: "measure the CSI-IM set that contains CSI-IM resource 0."
If 'USE_TRS' is enabled, 'csi-ResourceConfigId 2' references 'nzp-CSI-RS-ResourceSetList' containing set 1. Since set 1 is the TRS-marked NZP-CSI-RS set (resources 1-4), this resource config provides the periodic measurement input associated with TRS behavior.
So the important takeaway is that 'csi-ResourceConfigToAddModList' is the "binding layer." It does not define new physical resources. It simply selects which 'resource sets' are used for channel measurement, interference measurement, and (optionally) TRS tracking, and in this example every one of those bindings is configured as 'periodic'.

At the top of the CSI configuration hierarchy, 'csi-ReportConfigToAddModList' is where the gNB finally defines the CSI report itself. Everything you checked earlier (NZP-CSI-RS resources, resource sets, CSI-IM resources, CSI resource configs) is just building the measurement inputs. This IE is where those inputs are bound into one periodic reporting rule that tells the UE 'what to report, when to report, and over which uplink resource'.
In this capture, the configuration comes from 'csi_report_config' in the Amarisoft gNB config, and it creates 'reportConfigId 0'. The report explicitly references the channel-measurement resource config ('resourcesForChannelMeasurement 0'), which is the NZP-CSI-RS resource config that points to resource set 0 (so it is ultimately driven by NZP-CSI-RS resource 0). It also references the interference side ('csi-IM-ResourcesForInterference 1'), which points to the CSI-IM resource config (built from CSI-IM set 0). This makes the report based on both signal measurement and interference measurement.
The report type is set to periodic ('reportConfigType periodic'), and the scheduling is expressed with a periodicity/offset in the RRC view (shown as 'reportSlotConfig slots80: 9'), which corresponds to your configured period while allowing the gNB to choose a concrete reporting offset. The UE is also told how to carry the report, via the 'pucch-CSI-ResourceList', which maps the periodic CSI report onto a specific PUCCH resource (you can see the uplink bandwidth part and the PUCCH resource index in that list).
For the contents of the report, 'reportQuantity' is configured as 'CRI-RI-PMI-CQI', meaning the UE will send the channel rank indicator (RI), precoder matrix indicator (PMI), channel quality indicator (CQI), and also CRI when multiple CSI resources/ports are possible. Because PMI is part of the payload, the report includes a 'codebookConfig' section. That part is selected based on your DL antenna configuration (for example 2/4/8 ports) and defines the codebook type/subtype and restrictions that limit which precoders the UE is allowed to report.
So this IE is the final "result" of the entire chain: it picks the measurement resources (NZP-CSI-RS + CSI-IM), declares periodic reporting timing, selects the feedback quantity (CRI/RI/PMI/CQI), applies the codebook rules, and ties the feedback to a specific PUCCH resource so the UE can send it periodically.

Sub Test 1 : RI-PMI-CQI
The purpose of this Sub Test is just to change report quantity to RI-PMI-CQI while all other configurations are set same as in the main test.
I have used gnb-sa-rq-ri-pmi-cqi.cfg which is copied and modified from gnb-sa.cfg

In this test, the CSI reporting behavior stays the same as in the common configuration of Test 1, and the only intentional change is the reported CSI quantity. The csi_report_config entry still points to the same measurement inputs, so resources_for_channel_measurement: 0 continues to select the NZP-CSI-RS resource configuration used for channel measurement, and csi_im_resources_for_interference: 1 continues to include the CSI-IM-based interference measurement input. The report is still configured as periodic (report_config_type: "periodic") with the same reporting cycle (period: 80), so the UE will keep sending CSI feedback at the same periodic rhythm as before.
What changes is report_quantity, which is set to "CRI_RI_PMI_CQI". This means the UE’s periodic CSI feedback is expected to include the CRI (CSI Resource Indicator, used when multiple CSI resources are possible), RI (rank), PMI (precoder selection), and CQI (channel quality). Because PMI is part of the report payload, the configuration keeps a codebook_config section enabled when N_ANTENNA_DL > 1. In this test, the codebook is Type 1 with the typeI_SinglePanel subtype, which matches the common NR codebook structure used for typical DL MIMO feedback.
The parameters n1, n2, and codebook_mode are selected based on the number of DL antenna ports. They define the codebook resolution and allowed precoder structure, and the comment notes that their values track the 3GPP codebook guidance (the mapping depends on the antenna configuration). Finally, cqi_table: 2 and subband_size: "value1" remain as in the base test, which means the CQI interpretation (and any subband-related setting if used) is unchanged.
So overall, the measurement sources, periodicity, and codebook framework stay aligned with the common configuration, and the practical effect of this test variation is that the UE is asked to deliver the periodic CSI payload specifically in the CRI/RI/PMI/CQI format.

This configuration will be reflected in RRC as shown below. Check out reportQuantity of csi-ReportConfigToAddModList IE and confirm that it is set to cri-RI-PMI-CQI as set in the configuration file.
In RRC, the place to confirm the change is csi-MeasConfig → csi-ReportConfigToAddModList. In the highlighted decode, you can see reportConfigId 0, and inside it the key field is reportQuantity. It is shown as cri-RI-PMI-CQI, which matches your configuration setting report_quantity: "CRI_RI_PMI_CQI".
This confirms that the only change you made at the configuration level is reflected at the top of the CSI hierarchy. The report is still periodic and still references the same channel measurement and interference measurement inputs, but the payload the UE is expected to send is now the CRI/RI/PMI/CQI combination.

Perform the test.
Start LTE service (gNB) and run 'cell phy' and 'cell' command, then everything is configured as you intended.

Before powering on UE, run 't' command first. You can run this command anytime, but I would recommend you to run it before powering on UE to collect the trace log from the very beginning of the attach process.

Check PUCCH with CSI Report. First thing to check is that the gNB is getting csi report with the period set in the configuration file. You can verify the CSI report is really happening on PUCCH with the periodicity you configured. In the PHY log view, you can see repeated PUCCH entries where the payload contains csi=.... The time difference between these CSI-carrying PUCCH transmissions is consistent, and in your capture it matches the configured periodic cycle of 80 slots. That confirms two things at once: the UE is actually sending CSI on PUCCH (not just being configured to do so), and the reporting interval follows the period: 80 setting from csi_report_config.
If you want the log to show the decoded CSI values (CRI/RI/PMI/CQI fields) instead of only the raw csi=... bits, you can enable CSI decoding in Amarisoft logging. One way is to set phy.csi = 1 in the configuration, or you can enable the CSI decoding option in the WebGUI property window. Then the gNB prints the interpreted CSI content alongside the PUCCH message, which makes it easier to confirm the actual reported values, not only the timing.

Sub Test 2 : RI-CQI
The purpose of this Sub Test is just to change report quantity to RI-CQI while all other configurations are set same as in the main test.
I have used gnb-sa-rq-ri-cqi.cfg which is copied and modified from gnb-sa.cfg

In this variation, the periodic CSI reporting framework stays the same as the common configuration, but the payload is simplified by changing report_quantity to "CRI_RI_CQI".
resources_for_channel_measurement: 0 still tells the UE to base the report on the same NZP-CSI-RS channel measurement resource configuration, and csi_im_resources_for_interference: 1 still adds the same CSI-IM interference measurement input. The report is still periodic with period: 80, so the UE keeps sending CSI on PUCCH with the same 80-slot rhythm.
The only functional change is that PMI is no longer requested. With CRI_RI_CQI, the UE reports the CSI resource indicator (CRI), rank indicator (RI), and channel quality indicator (CQI), but it does not report a precoder (PMI). As a result, you typically don’t need a PMI codebook configuration for this report type, while cqi_table: 2 and subband_size: "value1" still control how CQI is formed/encoded in the same way as before

this configuration will be reflected in RRC as shown below. Check out reportQuantity of csi-ReportConfigToAddModList IE and confirm that it is set to cri-RI-CQI as set in the configuration file. In the RRC decode, you verify this change at csi-MeasConfig → csi-ReportConfigToAddModList. In the highlighted block for reportConfigId 0, the reportQuantity field is shown as cri-RI-CQI, which matches your configuration value report_quantity: "CRI_RI_CQI".
You can also see that the report is still periodic and still references the same channel-measurement and interference-measurement inputs (resourcesForChannelMeasurement and csi-IM-ResourcesForInterference). The difference is that there is no PMI-related payload requirement anymore, so the report content is reduced to CRI/RI/CQI as intended.

Perform the test.
Start LTE service (gNB) and run 'cell phy' and 'cell' command, then everything is configured as you intended.

Before powering on UE, run 't' command first. You can run this command anytime, but I would recommend you to run it before powering on UE to collect the trace log from the very beginning of the attach process.

Check PUCCH with CSI Report. First thing to check is that the gNB is getting csi report with the period set in the configuration file. To verify CSI reporting on PUCCH, you focus on the PHY log lines where the message type is 'PUCCH' and the payload includes a 'csi=...' field. In this capture, those CSI-carrying PUCCH transmissions repeat with a constant spacing, and the marked gap is '80 slots', which matches the 'period: 80' you set in 'csi_report_config'. That confirms the gNB is actually receiving periodic CSI reports from the UE at the configured interval, not just signaling the configuration in RRC.
If you want to see the CSI content decoded (e.g., CRI/RI/CQI values) instead of only the raw 'csi' bits, enable CSI decoding in the logs. In Amarisoft, you can set 'phy.csi = 1' or enable CSI in the WebGUI property window. Then the log prints the interpreted CSI fields alongside the PUCCH entry, which makes it easier to validate the reported values in addition to the timing.

Sub Test 3 : RI-CQI with non-PMI-PortIndication
The purpose of this Sub Test is just to change report quantity to RI-CQI with non-PMI-PortIndication while all other configurations are set same as in the main test.
I have used gnb-sa-rq-ri-cqi-non-pmi.cfg which is copied and modified from gnb-sa.cfg

In this test case, the periodic CSI reporting framework is still the same as the common configuration, but two things are different: the report no longer includes PMI, and you explicitly control how the UE indicates the antenna port set when PMI is not reported.
'report_quantity' is set to '"CRI_RI_CQI"', so the UE reports only CRI, RI, and CQI. Because PMI is removed, the gNB cannot rely on the normal PMI/codebook feedback to infer which downlink port subset is being assumed for the report, especially when the cell has multiple DL ports. That is why 'non_pmi_port_indication' is added.
'non_pmi_port_indication' defines the allowed port-subset indications the UE can use for this non-PMI report. In your example, it provides a simple progressive list of port groups: '[0]', '[0,1]', '[0,1,2]', and '[0,1,2,3]'. Conceptually, this tells the UE (and the gNB) which CSI-RS antenna port set the reported RI/CQI should be associated with, even though no precoder (PMI) is being fed back. It acts as an explicit "port assumption" signaling hook for non-PMI reporting cases.
Everything else stays aligned with the baseline: 'resources_for_channel_measurement: 0' still points to the NZP-CSI-RS channel measurement resource config, 'csi_im_resources_for_interference: 1' still includes CSI-IM interference measurement, the report is still periodic with 'period: 80', and CQI is still interpreted using 'cqi_table: 2' with the same subband sizing behavior.

Following is the simplified configuration
|
csi_report_config: [ { resources_for_channel_measurement: 0, csi_im_resources_for_interference: 1,
report_config_type: "periodic", period: 80,
// No PMI in this test report_quantity: "CRI_RI_CQI",
// Port-subset indication used when PMI is not reported non_pmi_port_indication: [ [0], [0, 1], [0, 1, 2], [0, 1, 2, 3], ],
cqi_table: 2, subband_size: "value1", } ] |
This configuration will be reflected in RRC as shown below. In RRC, this change shows up again under 'csi-MeasConfig → nzp-CSI-RS-ResourceToAddModList'. Since the goal of this test is to make the 'RI report' meaningful, you want the CSI-RS used for channel measurement to be configured with 'multiple CSI-RS ports', so the UE can evaluate rank > 1 instead of being forced into a single-layer assumption.
In the decoded block for the channel-measurement NZP-CSI-RS (the one used by the CSI report), you can confirm this by checking 'nrofPorts'. In your screenshot, 'nrofPorts' is set to a multi-port value (for example 'p4'), which matches the intent of using multiple DL antenna ports. With 'nrofPorts' greater than 1, the UE receives a CSI-RS that represents a MIMO channel, so the RI feedback becomes a real rank decision rather than a trivial fixed result.
So the practical check here is simple: open the NZP-CSI-RS resource that feeds 'resourcesForChannelMeasurement', and confirm 'nrofPorts' is not 'p1'. If it is 'p2/p4/p8', then the configuration supports meaningful RI reporting.

Check out reportQuantity of csi-ReportConfigToAddModList IE and confirm that it is set to cri-RI-PMI-CQI and non-PMI-PortIndication as set in the configuration file. In the RRC decode, you confirm this under 'csi-MeasConfig → csi-ReportConfigToAddModList' for 'reportConfigId 0'.
First, 'reportQuantity' is shown as ''cri-RI-CQI'', which matches the configuration where PMI is not included in the periodic CSI payload.
Second, the same report block now contains ''non-PMI-PortIndication'', which confirms that the 'non_pmi_port_indication' you set in the config file was translated into the RRC IE. In the highlighted section, the port indication is structured by rank. You can see entries like 'rank1-4', 'rank2-4', 'rank3-4', and 'rank4-4', and under each one the allowed port sets are listed as port indices. This corresponds to your intended progressive port groups (for example '{0}', '{0,1}', '{0,1,2}', '{0,1,2,3}'), just expressed in the RRC format that groups them by rank category.
So this screen confirms both required points: the report payload is 'CRI/RI/CQI' (no PMI), and the report includes an explicit 'non-PMI port indication' set so the UE can signal which CSI-RS port subset its RI/CQI should be associated with.

Perform the test.
Start LTE service (gNB) and run 'cell phy' and 'cell' command, then everything is configured as you intended.

Before powering on UE, run 't' command first. You can run this command anytime, but I would recommend you to run it before powering on UE to collect the trace log from the very beginning of the attach process.

Check PUCCH with CSI Report. First thing to check is that the gNB is getting csi report with the period set in the configuration file. To verify the CSI report is really being delivered on 'PUCCH', filter the log to PHY and look for repeating 'PUCCH' lines that include a 'csi=...' field in the message text. In your capture, those CSI-bearing PUCCH transmissions appear regularly for the UE, which confirms the UE is actually sending CSI feedback and the gNB is receiving it.
The next check is the 'periodicity'. Since 'csi_report_config' is set to 'period: 80', the CSI-carrying PUCCH entries should repeat with an '80-slot cadence'. In the log view, you can confirm this by comparing the slot numbers (or the SFN/slot indicators shown in the table) between two successive CSI-bearing PUCCH entries: the difference should be 80 slots, matching the configured report period.
If you want to see the decoded CSI fields (RI/CQI and the non-PMI port indication choice) instead of only the raw 'csi' bits, enable CSI decoding by setting 'phy.csi = 1' or turning on CSI decoding in the WebGUI property window. Then the log prints the interpreted CSI content together with each periodic PUCCH CSI report, which makes validation much easier than reading the raw bit string.

Sub Test 4 : RSRP
The purpose of this Sub Test is just to change report quantity to RSRP while all other configurations are set same as in the main test.
I have used gnb-sa-rq-rsrp.cfg which is copied and modified from gnb-sa.cfg

In this variation, the CSI reporting timing and measurement inputs stay the same as in the common configuration, and only the reported quantity is changed to 'RSRP'.
The report is still periodic ('report_config_type: "periodic"') with 'period: 80', so the UE keeps sending CSI feedback on the same 80-slot cadence. It still uses the same channel measurement resource ('resources_for_channel_measurement: 0') and the same interference measurement association ('csi_im_resources_for_interference: 1'), so nothing changes in how the UE performs the underlying measurements.
The difference is 'report_quantity: "CRI_RSRP"'. With this setting, the UE reports 'RSRP' for the selected CSI resource, along with 'CRI' when multiple CSI resources are possible. This turns the report into a "power measurement" style report rather than a link adaptation report. There is no RI/PMI/CQI payload here, so codebook-related configuration becomes irrelevant for this report type.
'subband_size: "value1"' is still present, but for an RSRP-type report the essential outcome is that the periodic CSI feedback now represents reference-signal received power (associated with the CSI resource), instead of rank/precoder/quality indicators.

this configuration will be reflected in RRC as shown below.
Check out reportQuantity of csi-ReportConfigToAddModList IE and confirm that it is set to cri-RSRP. In the RRC decode, go to 'csi-MeasConfig → csi-ReportConfigToAddModList' and open the highlighted 'reportConfigId 0' block. The key field there is 'reportQuantity', and in your screenshot it is shown as ''cri-RSRP''.
That matches the configuration change 'report_quantity: "CRI_RSRP"', so it confirms the periodic CSI report is now an RSRP-style report (with CRI included when multiple CSI resources exist).

Perform the test.
Start LTE service (gNB) and run 'cell phy' and 'cell' command, then everything is configured as you intended.

Before powering on UE, run 't' command first. You can run this command anytime, but I would recommend you to run it before powering on UE to collect the trace log from the very beginning of the attach process.

Check PUCCH with CSI Report. First thing to check is that the gNB is getting csi report with the period set in the configuration file. To confirm the 'CRI-RSRP' report is really being sent, you do the same PHY-log check as the other tests, but now you just interpret the CSI payload as an RSRP report.
In the PHY log view, look for 'PUCCH' entries whose message includes 'csi=...' (highlighted in your capture). Those lines mean the UE is transmitting CSI feedback on PUCCH and the gNB is receiving it. Then verify the spacing between two consecutive CSI-bearing PUCCH entries. In your screenshot the interval is marked as '80 slots', which matches 'period: 80' from the 'csi_report_config'. That confirms the CSI report timing is correct for this test.
If you want to see the 'decoded CRI/RSRP value' instead of the raw 'csi' bits, enable CSI decoding ('phy.csi = 1' or the CSI option in the WebGUI property window). Then the log prints the interpreted report content for each periodic CSI PUCCH, so you can validate the actual reported RSRP value in addition to the 80-slot periodicity.

Sub Test 5 : RI-PMI-CQI with ri-restriction
The purpose of this Sub Test is just to change report quantity to RI-PMI-CQI with manually configured ri-restriction bits while all other configurations are set same as in the main test.
I have used gnb-sa-rq-ri-pmi-cqi-ri-restrict.cfg which is copied and modified from gnb-sa.cfg

Configuratio is set as follows. All other configuration not shown here is assumed to be same as the configuration in Common Configuration of Test 1.
In the configuration file, you can select any specific tdd pattern with the parameter NR_TDD_CONFIG. To apply TDD configuration, you first need to configure the duplex mode (NR_TDD) to 1 (TDD). And then I set NR_TDD_CONFIG to 2 which is one of default sample configuration provided by Amarisoft sample configuration. And I set the channel bandwidth (NR_BANDWIDTH) to 20Mhz and 2x2 MIMO (N_ANTENNA_DL = 2)

In this test, the CSI report stays the same "full" feedback type as the first example, so the UE still sends 'CRI/RI/PMI/CQI' periodically based on the same channel-measurement and interference-measurement resource configs. The report is still 'periodic' with 'period: 80', and it still uses the same Type-1 single-panel codebook framework when 'N_ANTENNA_DL > 1', with 'n1/n2' chosen according to the number of DL antenna ports.
The only functional change is 'ri_restriction'. This parameter limits which 'rank values' the UE is allowed to report in the RI field. In your example, 'ri_restriction: "00001011"' is applied, and the intent (as your comment says) is to restrict the RI behavior so certain ranks are not considered or are deprioritized. Practically, this means that even if the measured channel could support a higher rank, the UE will only choose RI from the ranks that are enabled by this bitmask. As a result, you can force the system to behave like a "rank-limited" MIMO setup and observe how PMI/CQI selection and scheduling behave when RI options are constrained.
So the test purpose is not to change the CSI report type, but to keep the same CRI/RI/PMI/CQI reporting pipeline and then control the RI degrees of freedom by applying a specific 'ri_restriction' mask.

In this test, I need to change radio link quality up and down to see if I am getting RI values based on the restriction set in the configuration. So I extended inactivity_timer so that I can have enough time to play with radio link quality changes

this configuration will be reflected in RRC as shown below.
(
In the RRC decode, you verify both points in the same place: 'csi-MeasConfig → csi-ReportConfigToAddModList' for 'reportConfigId 0'.First, the 'reportQuantity' field is shown as ''cri-RI-PMI-CQI'', so the report type matches your configuration where you kept the full CRI/RI/PMI/CQI payload. Second, inside the 'codebookConfig' section (Type 1 / 'typeI-SinglePanel'), the RI restriction you set in the config is reflected in the RRC field ''typeI-SinglePanel-ri-Restriction''. In your screenshot it appears explicitly (highlighted) as 'typeI-SinglePanel-ri-Restriction: '0B'H', confirming that the gNB carried your RI restriction setting into RRC. This is the control point that limits which RI values the UE is allowed to report while still using the Type 1 SinglePanel codebook for PMI reporting.

Perform the test.
Start LTE service (gNB) and run 'cell phy' and 'cell' command, then everything is configured as you intended.

Once you power on the UE and let it attach in a clean RF setup, the periodic CSI reporting becomes stable and you can confirm the RI behavior from the gNB console trace.
In the (enb) t trace output, the downlink summary table includes an ri column. Under good downlink channel conditions, the UE tends to pick the highest allowed rank because it "sees" enough spatial quality to support multiple layers. In your example, the ri value is consistently 4, which means the UE is repeatedly reporting the maximum rank configured/allowed for this test. That is exactly what you expect when the CSI-RS is configured with multiple ports and the RI restriction allows rank 4, and it is a quick sanity check that the RI reporting path is working end-to-end (RRC config → PUCCH CSI → decoded to RI in the trace).

If you intentionally degrade the downlink channel condition after the UE is attached, the UE starts reporting a lower RI because it no longer "trusts" that multiple spatial layers can be supported reliably.(If you are not familiar with usage of tx_gain, refer to this tutorial).
In the '(enb) t' trace view, you can see the 'ri' column drop from the max value you saw in good conditions to smaller values such as '2' or '1'. This is the expected behavior: as SNR/CQI gets worse, the UE backs off the rank to improve robustness.
The important extra point in your result is that the UE 'never reports RI = 3' even when the channel is in the middle range. That matches the purpose of your test: the RI selection is constrained by the 'Type-I SinglePanel RI restriction' bitmask you configured earlier. So, under poor-to-moderate conditions the UE moves between the allowed ranks (for example 4 → 2 → 1), but it skips rank 3 because it is not permitted by the configured restriction. This makes the trace output a practical end-to-end confirmation that the RI restriction is really applied: changing RF conditions changes RI, but only within the subset of ranks you enabled in the codebook restriction.

Sub Test 6 : ssb-RSRP
When you want CSI report for RSRP, you can set a regular CSI RS to be a reference channel for the measurement or you can set SSB to be the reference channel. The Sub Test 4 is the case where the regular CSI RS is used for RSRP reference. This is the case where SSB is used for RSRP reference.
I have used gnb-sa-rsset-1ssb.cfg which is copied and modified from gnb-sa.cfg

Configuratio is set as follows. All other configuration not shown here is assumed to be same as the configuration in Common Configuration of Test 1.
In the configuration file, you can select any specific tdd pattern with the parameter NR_TDD_CONFIG. To apply TDD configuration, you first need to configure the duplex mode (NR_TDD) to 1 (TDD). And then I set NR_TDD_CONFIG to 2 which is one of default sample configuration provided by Amarisoft sample configuration. And I set the channel bandwidth (NR_BANDWIDTH) to 20Mhz and 2x2 MIMO (N_ANTENNA_DL = 2)

Since we want to use SSB as reference signal for RSRP measurement in this test, we need to configure csi_ssb_resource_set. (
To use SSB as the reference signal for an RSRP-style CSI report, you need to make SSB selectable as a CSI measurement resource in the CSI hierarchy. That is why you add 'csi_ssb_resource_set'. This is not creating a new physical SSB signal. It is only creating the '"CSI measurement handle"' that lets the report configuration point to SSB in the same way it can point to NZP-CSI-RS or CSI-IM.
In this setup you do 'not' define any separate "CSI resource" for SSB itself. The SSB transmissions already exist because the cell’s SSB is configured by 'ssb_pos_bitmap'. What you do instead is define a resource set that references SSB indices. In the shown block, 'csi_ssb_resource_set' creates 'csi_ssb_set_id: 0' and includes 'csi_ssb_resources: [0]'. This means "SSB index 0 is the SSB resource I want to use for CSI measurement/reporting." The mapping is therefore straightforward: SSB index 0 in this CSI resource set corresponds to the actual SSB beam/position that is enabled by 'ssb_pos_bitmap'.
Once this SSB resource set exists, you can later reference it from the CSI resource config / CSI report config chain for RSRP reporting. So the key point is: SSB itself is configured by 'ssb_pos_bitmap', and 'csi_ssb_resource_set' is the glue that makes that SSB usable as a CSI measurement reference for RSRP.

Here you are doing the next "binding" step in the CSI hierarchy. 'csi_ssb_resource_set' only defines which SSB index is available as a CSI measurement source. To actually use it in reporting, you must register it into 'csi_resource_config', because the CSI report configuration references 'CSI resource configs', not the raw SSB set directly.
In your 'csi_resource_config' list, you add a new entry with 'csi_rsc_config_id: 3' and set 'csi_ssb_resource_set_list: [0]'. This means "CSI Resource Config 3 uses SSB Resource Set 0 as its measurement input." The 'resource_type: "periodic"' keeps the behavior consistent with the rest of the test, so the UE treats this SSB-based measurement source as part of the periodic CSI measurement framework.
With this in place, the CSI report can later point to 'resources_for_channel_measurement: 3' (or reference this config through the appropriate field) when you want an 'SSB-based RSRP' style report. So the practical meaning is: 'SSB index 0 → SSB resource set 0 → CSI resource config 3', and that config becomes the selectable measurement source at the report level.

At this final step, you connect everything you prepared (NZP-CSI-RS channel measurement, CSI-IM interference measurement, and the SSB measurement option) into the actual 'report definitions' under 'csi_report_config'. The key idea is that you can define 'multiple report configurations' in the array, and each one can point to a different CSI Resource Config ID depending on what you want to measure and report.
In your test, the first 'csi_report_config' entry is left as the default "full CSI" report based on 'NZP-CSI-RS'. It uses 'resources_for_channel_measurement: 0', which selects the NZP-CSI-RS-based CSI resource config (the one bound to NZP-CSI-RS Resource Set 0), and it also keeps 'csi_im_resources_for_interference: 1' so the report is formed with interference measurement included. The report is 'periodic' with 'period: 80', and 'report_quantity: "CRI_RI_PMI_CQI"' tells the UE to send the full CRI/RI/PMI/CQI payload. Because PMI is included, the Type-1 SinglePanel 'codebook_config' remains relevant, and the 'n1/n2' selection is still tied to the number of DL antenna ports. 'cqi_table' and 'subband_size' remain unchanged, so the CQI formatting rules stay consistent with the earlier examples.
The practical meaning is that this first report entry is your "baseline" CSI feedback path: it is driven by NZP-CSI-RS for channel measurement, optionally uses CSI-IM for interference, and produces full link-adaptation feedback (RI/PMI/CQI). The second report entry (which you said you also configured in this test) will then be the SSB-based report, where you would point 'resources_for_channel_measurement' to the CSI Resource Config ID that you created for SSB (for example the one with 'csi_rsc_config_id: 3') so that the report becomes an SSB-referenced measurement (typically for RSRP-style reporting).

This second 'csi_report_config' entry adds a 'separate periodic CSI report' that is based on 'SSB measurements', not NZP-CSI-RS.
The key linkage is 'resources_for_channel_measurement: 3'. In your earlier step, 'csi_rsc_config_id: 3' was created with 'csi_ssb_resource_set_list: [0]', so "3" here means "use the SSB resource set as the measurement source." Because of that, this report does not need any NZP-CSI-RS-specific details such as codebook configuration, and it also typically does not need CSI-IM interference resources (which is why 'csi_im_resources_for_interference' is commented out).
The report is still 'periodic', but you intentionally use a different cycle: 'period: 160'. That means the UE will send this SSB-based report less frequently than the main CSI report. The payload type is set to 'report_quantity: "ssb_Index_RSRP"', so the UE reports the 'SSB index' (which SSB resource/beam it measured) together with the 'RSRP' measured on that SSB. This is the common way to track beam/SSB quality and perform beam selection or monitoring at a higher level.
So, in one test you now have two parallel CSI reports: a full CRI/RI/PMI/CQI report based on NZP-CSI-RS (period 80), and an SSB-index + RSRP report based on the SSB resource config (period 160).

this configuration will be reflected in RRC as shown below.
Since this is all about CSI configuration, go to csi-MeasConfig IE in RRC message. For CSI-related checks, you should start from the 'csi-MeasConfig' IE in the RRC message, because it contains the entire CSI configuration hierarchy in one place. Inside 'csi-MeasConfig', you first confirm the physical measurement resources are present, such as the NZP-CSI-RS entries in 'nzp-CSI-RS-ResourceToAddModList' and the interference measurement entries in 'csi-IM-ResourceToAddModList', including their mapping, port count, and periodicity. Then you confirm these individual resources are grouped into sets through 'nzp-CSI-RS-ResourceSetToAddModList' and 'csi-IM-ResourceSetToAddModList', and if you use SSB-based measurement you also confirm the SSB resource set is present and points to the intended SSB index. After that, you check 'csi-ResourceConfigToAddModList' to verify which resource sets are bound to which CSI resource configuration IDs, because the report does not reference raw resources directly. Finally, you validate the actual report behavior in 'csi-ReportConfigToAddModList', where you confirm the report quantities, periodicity/offset, and the PUCCH mapping for CSI feedback, including the case where you configured two different report configurations such as an NZP-CSI-RS based CRI/RI/PMI/CQI report and an SSB-index-RSRP report.

To confirm that SSB is registered for CSI use, go into the RRC message and open 'csi-MeasConfig', then find 'csi-SSB-ResourceSetToAddModList'. In your screenshot, this list contains 'csi-SSB-ResourceSetId 0', and inside it you see 'csi-SSB-ResourceList' populated with 'csi_ssb_resources: [0]'. This matches the configuration where you created 'csi_ssb_resource_set' with 'csi_ssb_set_id: 0' and included SSB index 0, so it confirms that SSB has been successfully exposed to the CSI framework as a selectable measurement resource set.

Next, you confirm the SSB resource set is actually bound into the CSI "resource config" layer. In the RRC message under 'csi-MeasConfig', go to 'csi-ResourceConfigToAddModList' and look for the entry that references an SSB set list. In your screenshot, you can see ''csi-ResourceConfigId 3'' and inside it 'csi-SSB-ResourceSetList' is present with the SSB set you configured (the list contains set '0'). The 'resourceType' is also shown as 'periodic', which matches your Amarisoft 'csi_resource_config' entry where you created 'csi_rsc_config_id: 3' with 'csi_ssb_resource_set_list: [0]' and set it to periodic. This confirms that the SSB measurement source is not only defined as a set, but is properly registered as a CSI resource configuration that can be referenced by the CSI report configuration.

For the final verification, you go to 'csi-MeasConfig → csi-ReportConfigToAddModList', because this is the top of the CSI hierarchy and it tells you exactly what the UE is instructed to report.
In the first entry, you can see 'reportConfigId 0' and it matches the default NZP-CSI-RS based report. It references 'resourcesForChannelMeasurement 0' and 'csi-IM-ResourcesForInterference 1', the report type is 'periodic', and the timing is defined by 'reportSlotConfig slots80: 9'. Most importantly, 'reportQuantity' is shown as ''cri-RI-PMI-CQI'', which confirms the first report configuration is still the same full CSI feedback configuration as your baseline.

Report configuration for SSB based RSRP is configured as the second item of the report config. In the same csi-MeasConfig → csi-ReportConfigToAddModList, the second entry confirms the SSB-based RSRP report is configured correctly. You can see reportConfigId 1 and it points to resourcesForChannelMeasurement 3, which is the CSI Resource Config ID you created for the SSB resource set. In this block, reportQuantity is shown as ssb-Index-RSRP, so the UE is instructed to report the measured RSRP together with the SSB index. The report is still periodic, and the timing is expressed through reportSlotConfig (here it corresponds to the longer cycle you configured for the SSB report), and it is also tied to a PUCCH CSI resource entry so the UE knows where to send this second periodic report.

Perform the test.
Start LTE service (gNB) and run 'cell phy' and 'cell' command, then everything is configured as you intended.

Before powering on UE, run 't' command first. You can run this command anytime, but I would recommend you to run it before powering on UE to collect the trace log from the very beginning of the attach process.

Confirm that you are getting both CRI based CSI report and ssb based CSI Report as shown below. First thing to check is that the gNB is getting csi report with the period set in the configuration file and then check the details of CSI to confirm you get all the components specified in the configuration file. What you need to note here is that you get the two different CSI report. One for CRI_RI_PMI_CQI and another one is for RSRP based on SSB.

Test 2 : Aperiodic CSI Report
The perpose of this test is to show how to perform Aperiodic CSI report and verify it from the test log. In this test, I configured aperiodic by changing the periodic only in csi_report_config without changing anything csi_resource_config.
I have used gnb-sa-rq-ri-pmi-cqi-aperiodic.cfg which is copied and modified from gnb-sa.cfg

Configuratio is set as follows. All other configuration not shown here is assumed to be same as the configuration in Common Configuration of Test 1. The only difference is that report_config_type in csi_report_config is set to "aperiodic" in this test.
The measurement linkage is unchanged. 'resources_for_channel_measurement: 0' still points to the NZP-CSI-RS based channel-measurement resource config, and 'csi_im_resources_for_interference: 1' still adds the CSI-IM interference measurement input. The report payload is also unchanged: 'report_quantity: "CRI_RI_PMI_CQI"' still requests the full CRI/RI/PMI/CQI feedback, so the Type 1 SinglePanel 'codebook_config' remains relevant when 'N_ANTENNA_DL > 1', and 'n1/n2' selection continues to follow the DL antenna port count. CQI formatting stays the same through 'cqi_table: 2' and 'subband_size: "value1"'.
What changes is when the UE sends the report. With 'aperiodic', the UE does not transmit CSI on a fixed 80-slot schedule. Instead, the report is triggered by the gNB through downlink scheduling (typically via DCI scheduling that requests an aperiodic CSI report). In this mode, the 'period: 80' parameter is not the driver for transmission timing the way it is in periodic reporting; the actual report occasions depend on when the gNB triggers CSI. So the validation pattern changes as well: in RRC you should see 'reportConfigType aperiodic' for the report config, and in the PHY/PUCCH logs you should see CSI reports only when the gNB issues a trigger, rather than at a constant interval.

This configuration will be reflected in RRC as shown below. In the RRC decode, you confirm the change under 'csi-MeasConfig → csi-ReportConfigToAddModList'. In the highlighted 'reportConfigId 0', 'reportConfigType' is shown as aperiodic, so the UE is no longer told to send CSI on a fixed slot cycle. The same entry still references the same measurement inputs ('resourcesForChannelMeasurement' and 'csi-IM-ResourcesForInterference') and still uses 'reportQuantity cri-RI-PMI-CQI', so only the triggering mechanism changed.
The important extra field for aperiodic reporting is 'reportSlotOffsetList'. This list defines the allowed slot offsets between the downlink trigger and the uplink CSI transmission opportunity. In practice, these offsets act like the k2 candidates the gNB can use when it schedules the uplink CSI report on PUSCH, because the UE needs a known timing relationship to prepare and transmit the CSI payload after being triggered. Amarisoft fills these values automatically based on its internal scheduling constraints, so you typically don’t hand-tune them, but you should still verify the list exists and is populated, because that is the key IE that makes aperiodic CSI scheduling work.

Perform the test.
Start LTE service (gNB) and run 'cell phy' and 'cell' command, then everything is configured as you intended.

Before powering on UE, run 't' command first. You can run this command anytime, but I would recommend you to run it before powering on UE to collect the trace log from the very beginning of the attach process.

To verify aperiodic CSI reporting, you need to correlate the downlink trigger in DCI with the uplink PUSCH that actually carries the CSI payload. In the log view, the first thing to find is the DCI entry where the gNB requests CSI. In your screenshot that DCI is shown as DCI 0_1, and in its decoded details you can see 'k2 = 7' and 'csi_request = 1'. This means the uplink grant is scheduled with a k2 timing of 7 slots and the UE is explicitly instructed to include an aperiodic CSI report.
The second thing is to locate the corresponding PUSCH transmission from the same UE that occurs exactly k2 slots later. In your trace, you then see a 'PUSCH' line appearing after that 7-slot gap, and the message includes a 'csi=...' field, indicating that the CSI report bits were received on PUSCH. This one-two confirmation is the core proof for aperiodic CSI: the CSI request is present in the downlink grant (DCI 0_1), and the CSI payload shows up on the uplink PUSCH at the expected k2 offset.

Test 3 : TCI
This test is to show how to configure TCI(Transmission Configuration Indication) and verify it with the test. There two types of TCI can be configured by 3GPP, one is with pdcch and the other one is with PDSCH ( If you want to get the details of TCI in terms of 3GPP, refer to this note)
I have used gnb-sa-tci-1ssb-1sci.cfg which is copied and modified from gnb-sa.cfg

Configuratio is set as follows. This test adds an explicit TCI association for the PDCCH by using 'tci_states_pdcch' inside the 'common_coreset' configuration. Because 'tci_states_pdcch' is a sub-parameter of 'common_coreset', you have to define the 'common_coreset' block itself, and that is why 'rb_start' and 'l_crb' appear here as mandatory fields. They define where CORESET#0 is located in frequency and how wide it is, and you may need to adjust them depending on the channel bandwidth and CORESET sizing you want.
The important part is 'tci_states_pdcch: [0, 1]'. This list is not creating new TCI states. It is selecting which existing TCI states the UE is allowed to assume for decoding the PDCCH in that CORESET. Each number in the list refers to a 'tci-StateId' that is defined in the 'pdsch_tci_states' (the RRC 'tci-StatesToAddModList' under 'pdsch-Config'). So by putting '[0, 1]' here, you are telling the UE that PDCCH for this CORESET may be transmitted using TCI state 0 or TCI state 1, and the UE should apply the corresponding QCL assumptions when it tries to detect and decode PDCCH candidates.
Everything else in the shown snippet is the normal PDCCH framework around the CORESET and search spaces. 'search_space0_index' chooses the SS0 pattern, 'dedicated_coreset' parameters control the UE-specific CORESET behavior (with '-1' meaning "use maximum" or "auto"), and the CSS/USS candidate settings control how many PDCCH candidates exist for each aggregation level. The key takeaway is that this configuration adds a beam/QCL selection mechanism for PDCCH by tying CORESET#0 to specific 'tci-StateId' values through 'tci_states_pdcch'.
All other configuration not shown here is assumed to be same as the configuration in Common Configuration of Test 1.

TCI for PDSCH is configured by the parameter tci_states in pdsch configuration. In this configuration, you define the TCI states that can be applied to PDSCH by setting tci_states inside the pdsch block. Each entry creates one tci_state_id, and inside that state you declare the QCL assumptions the UE should use when it receives PDSCH scheduled with that TCI state. The QCL part is where you tell the UE which downlink reference signal represents the beam/propagation assumption for the data channel.
The first state, tci_state_id: 0, is an SSB-based state. In qcl_type1 you set reference_signal: "ssb" with ssb_index: 0 and qcl_type: "typeD". This means that when the gNB indicates TCI state 0 for PDSCH, the UE uses SSB#0 as the reference for its spatial/QCL assumption for receiving the data.
The second state, tci_state_id: 1, is a CSI-RS-based state. In qcl_type1 you set reference_signal: "csi_rs" with csi_rs_index: 0 and qcl_type: "typeD". So if PDSCH is scheduled with TCI state 1, the UE treats CSI-RS#0 as the reference that defines the beam/QCL relationship for that PDSCH transmission.
The third state, tci_state_id: 2, combines two QCL references. Here qcl_type1 points to SSB#0 (with qcl_type: "typeC" in your example) and qcl_type2 points to CSI-RS#0 (with qcl_type: "typeD"). This creates a state where the UE is given two QCL relations at once, one derived from SSB and one derived from CSI-RS, which is a common way to express "use this SSB for one aspect of QCL and this CSI-RS for another aspect" depending on what the UE and gNB need.
So the core idea of this block is that PDSCH TCI is not configured by "beam index" directly. You define a small set of named TCI states, each state ties PDSCH reception to an SSB or CSI-RS reference (or both), and later the gNB selects among these states when it schedules PDSCH so the UE knows which QCL assumption to apply.

Following is the simplified configuration
|
pdsch: { tci_states: [ // TCI state 0: SSB-only reference (SSB #0) { tci_state_id: 0, qcl_type1: { reference_signal: "ssb", ssb_index: 0, qcl_type: "typeD" }, },
// TCI state 1: CSI-RS-only reference (CSI-RS #0) { tci_state_id: 1, qcl_type1: { reference_signal: "csi_rs", csi_rs_index: 0, qcl_type: "typeD" }, },
// TCI state 2: SSB + CSI-RS references { tci_state_id: 2, qcl_type1: { reference_signal: "ssb", ssb_index: 0, qcl_type: "typeC" }, qcl_type2: { reference_signal: "csi_rs", csi_rs_index: 0, qcl_type: "typeD" }, }, ], } |
csi_report_config is same as in default configuration (i.e, the configuration in Test 1). It points to the same channel measurement resource config with resources_for_channel_measurement: 0, and it still includes the same CSI-IM interference input with csi_im_resources_for_interference: 1. The report payload is still the full set, report_quantity: "CRI_RI_PMI_CQI", so the UE is expected to feed back CRI, RI, PMI, and CQI, and that is why the Type-1 SinglePanel codebook_config remains present when N_ANTENNA_DL > 1, with n1/n2 chosen based on the number of DL antenna ports. CQI formatting is still controlled the same way through cqi_table: 2 and subband_size: "value1".
The only behavioral difference shown here is report_config_type: "aperiodic". That changes when CSI is sent: CSI is no longer transmitted on a fixed cycle, but only when the gNB triggers it through scheduling (DCI). In this mode the period: 80 line is not what drives actual reporting timing like it does in periodic mode; the actual report occasions depend on CSI request triggers and the slot offsets the UE was configured with in RRC.

This configuration will be reflected in RRC as shown below.
In the RRC decode, you verify the PDCCH TCI configuration under 'pdcch-ConfigCommon', because that is where the common CORESET and its TCI mapping are signaled. In the right-hand tree, find 'pdcch-ConfigCommon setup → commonControlResourceSet' and then locate 'tci-StatesPDCCH-ToAddList'.
In your screenshot, 'tci-StatesPDCCH-ToAddList' contains the entries 0 and 1, which matches the configuration 'tci_states_pdcch: [0, 1]' that you set under 'common_coreset'. This confirms that CORESET#0 is associated with TCI state IDs 0 and 1, so the UE is allowed to decode PDCCH assuming either of those two QCL/beam states, exactly as intended.

Then check out tci-StatesToAddModList in pdsch-Config IE and see if they are configured as you set in the configuration file. In the RRC decode, you check this under 'pdsch-Config setup → tci-StatesToAddModList'. In your screenshot, the list contains three entries, and they match the three 'tci_states' you configured in the 'pdsch' block.
You can see 'tci-StateId 0' with 'qcl-Type1' referencing SSB 0 ('referenceSignal ssb:0') with 'qcl-Type typeD', which corresponds to your "SSB-only" state. Then 'tci-StateId 1' shows 'qcl-Type1' referencing CSI-RS 0 ('referenceSignal csi-rs:0') with 'qcl-Type typeD', which corresponds to your "CSI-RS-only" state. Finally, 'tci-StateId 2' contains both references: 'qcl-Type1' points to SSB 0 (typeC in your config) and 'qcl-Type2' points to CSI-RS 0 (typeD), which matches your combined "SSB + CSI-RS" state.
So 'tci-StatesToAddModList' confirms the PDSCH TCI state table in RRC is built exactly from the 'pdsch.tci_states' entries you defined.

Perform the test.
Start LTE service (gNB) and run 'cell phy' and 'cell' command, then everything is configured as you intended.

Before powering on UE, run 't' command first. You can run this command anytime, but I would recommend you to run it before powering on UE to collect the trace log from the very beginning of the attach process.

Check PUCCH with CSI Report. Just checking out the gNB logging you only can confirm that the configuration is not causing any fatal problem on UE side and not possible to confirm that UE is really applying the TCI as configured in RRC. On gNB log, just check if you are getting the csi report with the expected interval. If you are using a commercial UE with the very detailed logging capability, you can confirm on whether the UE is properly applying or not from the UE log.

Test 4 : CSI RS p32 - Periodic
This is an example showing how to configure 32 port CSI RS, but it is not strongly recommended to use this kind of configuration whereas the number of csi-rs port is greater than the number of physical antenna.
I have used gnb-sa-csi-p32.cfg which is copied and modified from gnb-sa.cfg
In the configuration file, you can select any specific tdd pattern with the parameter NR_TDD_CONFIG. To apply TDD configuration, you first need to configure the duplex mode (NR_TDD) to 1 (TDD). And then I set NR_TDD_CONFIG to 2 which is one of default sample configuration provided by Amarisoft sample configuration. And I set the channel bandwidth (NR_BANDWIDTH) to 20Mhz and 2x2 MIMO (N_ANTENNA_DL = 2)
The point here is to set n_ports value to 32 which is much greater than the number of physical antenna. (

This is the log showing that the csi-rs p32 is configured in signaling message.
In the RRC decode, you check this under pdsch-Config setup → tci-StatesToAddModList. In your screenshot, the list contains three entries, and they match the three tci_states you configured in the pdsch block.
You can see tci-StateId 0 with qcl-Type1 referencing SSB 0 (referenceSignal ssb:0) with qcl-Type typeD, which corresponds to your "SSB-only" state. Then tci-StateId 1 shows qcl-Type1 referencing CSI-RS 0 (referenceSignal csi-rs:0) with qcl-Type typeD, which corresponds to your "CSI-RS-only" state. Finally, tci-StateId 2 contains both references: qcl-Type1 points to SSB 0 (typeC in your config) and qcl-Type2 points to CSI-RS 0 (typeD), which matches your combined "SSB + CSI-RS" state.
So tci-StatesToAddModList confirms the PDSCH TCI state table in RRC is built exactly from the pdsch.tci_states entries you defined.

Test 5 : CSI RS and Physical Antenna Mapping - TRS
This is an example showing how to map the logical antenna port of each CSI RS to physical antenna of Amarisoft gNB antenna. In this example, I will configure a TRS which is made up of 4 CSI-RS and map each of the CSI-RS to two physical antenna as shown below.

I have used gnb-sa-trs-rs-ant-map.cfg which is copied and modified from gnb-sa-rq-ri-pmi-cqi.cfg which is based on manual configuration for CSI-RS (not auto configuration). Since we need to configure physical antenna mapping for each separate csi rs configuration, we need to configure everything manually.
For these TRS-style CSI-RS resources you set n_ports: 1, so the CSI-RS is a single stream that must be transmitted from one (or a weighted combination) of the available physical antenna ports. precoding_matrix is the mapping from the CSI-RS logical port(s) to the gNB’s physical antenna ports.
In your first case (csi_rs_id: 1), precoding_matrix: [[1],[0]] is a column vector with weight 1 on the first physical antenna port and 0 on the second. That means CSI-RS is transmitted only from antenna port 0.
In your second case (csi_rs_id: 2), precoding_matrix: [[0],[1]] flips the selection: weight 0 on the first physical antenna port and 1 on the second. That means CSI-RS is transmitted only from antenna port 1.
So these two resources are identical in CSI-RS pattern/timing, but they differ in which RF chain actually radiates the CSI-RS. This is useful when you want TRS/CSI-RS to represent different beams/ports or when you want to validate per-antenna behavior while keeping the CSI-RS definition itself simple.

csi_rs_id: 3 and csi_rs_id: 4 follow the exact same mapping logic as IDs 1 and 2. The only difference is the slot offset (these are the "offset 12" TRS resources), but the precoding_matrix still selects which physical TX antenna port carries the 1-port CSI-RS.
For csi_rs_id: 3, n_ports: 1 and precoding_matrix: [[1],[0]] means the single CSI-RS stream is transmitted only on the first physical antenna port, so it is mapped to antenna 0.
For csi_rs_id: 4, precoding_matrix: [[0],[1]] means the single CSI-RS stream is transmitted only on the second physical antenna port, so it is mapped to antenna 1.
So across the four TRS resources, you effectively get a 2×2 pattern: two time positions (first_symb 4 and 8) and two antenna selections (port 0 vs port 1), controlled explicitly by the precoding_matrix.

Since the mapping between the logical port of csi-rs and physical antenna of gNB is up to the implementation of the equipment vendor, the mapping information is not shown in the protocol log. I am showing the log here just to explain how the configuration is related to the rrc configuration of TRS csi-rs.
Here you see the first pair of TRS csi-Resource. The physical antenna mapping configured by the precoding_matrix cannot be reflected in RRC message since it is lower layer internal mapping in Amarisoft gNB.
In this first TRS pair, the RRC side only tells the UE what NZP-CSI-RS resources exist and where they are in the grid, but it does not expose how Amarisoft maps that 1-port CSI-RS onto the gNB’s physical TX chains.
In csi-MeasConfig → nzp-CSI-RS-ResourceToAddModList, you can see nzp-CSI-RS-ResourceId 1 and nzp-CSI-RS-ResourceId 2 with the expected TRS-style settings: nrofPorts p1, frequencyDomainAllocation row1, the two different firstOFDMSymbolInTimeDomain values (4 and 8), and the same periodicity (slots40: 11). That is all standardized RRC signaling, and it is what the UE needs to locate and measure the CSI-RS.
The precoding_matrix you configured in Amarisoft, such as [[1],[0]] for one resource and [[0],[1]] for the other, is a baseband/RF implementation detail that selects which physical antenna port actually transmits that CSI-RS. This selection happens below RRC in the gNB PHY, so it is not carried in RRC IEs and therefore cannot be "confirmed" by decoding the RRC message. The best you can do at the RRC layer is confirm both CSI-RS resources are present and correctly timed; the antenna mapping itself must be validated using PHY-side tools or RF observation (for example, per-antenna power monitoring, IQ capture per TX chain, or an external receiver/SA showing the CSI-RS energy appearing only on the intended chain/beam).

Here you see the second pair of TRS csi-Resource. The physical antenna mapping configured by the precoding_matrix cannot be reflected in RRC message since it is lower layer internal mapping in Amarisoft gNB.
This second TRS pair is the same story as the first pair, just with the other timing offset.
In csi-MeasConfig → nzp-CSI-RS-ResourceToAddModList, the UE-visible part is that nzp-CSI-RS-ResourceId 3 and nzp-CSI-RS-ResourceId 4 exist, both are 1-port (nrofPorts p1), both use the same TRS-style mapping (frequencyDomainAllocation row1), and they are placed on the two different OFDM symbols (firstOFDMSymbolInTimeDomain 4 and 8). The key difference versus the first pair is the periodicity/offset: these are transmitted with periodicityAndOffset slots40: 12, so they form the "offset 12" half of the TRS pattern.
What you cannot confirm from RRC is the per-resource physical antenna selection you set with precoding_matrix (for example [[1],[0]] selecting antenna 0 and [[0],[1]] selecting antenna 1). That mapping is an Amarisoft PHY/internal implementation detail, so it is not encoded into the standardized RRC IEs. At the RRC layer, the only confirmation you can make is that the two TRS resources are present and correctly timed/mapped; validating which RF chain actually transmits each TRS CSI-RS must be done using PHY-side observation or RF measurement.

RRC / NAS Signaling
RrcSetup (SA)
: This is the RrcSetup message sent by gNB to configure NR SA. (
{
message c1: rrcSetup: {
rrc-TransactionIdentifier 0,
criticalExtensions rrcSetup: {
radioBearerConfig {
...
},
masterCellGroup {
cellGroupId 0,
rlc-BearerToAddModList {
...
},
mac-CellGroupConfig {
...
},
physicalCellGroupConfig {
pdsch-HARQ-ACK-Codebook dynamic
},
spCellConfig {
spCellConfigDedicated {
initialDownlinkBWP {
pdcch-Config setup: {
...
},
pdsch-Config setup: {
dmrs-DownlinkForPDSCH-MappingTypeA setup: {
dmrs-AdditionalPosition pos1
},
tci-StatesToAddModList {
{
tci-StateId 0,
qcl-Type1 {
referenceSignal ssb: 0,
qcl-Type typeD
}
},
{
tci-StateId 1,
qcl-Type1 {
referenceSignal csi-rs: 0,
qcl-Type typeD
}
},
{
tci-StateId 2,
qcl-Type1 {
referenceSignal ssb: 0,
qcl-Type typeC
},
qcl-Type2 {
referenceSignal csi-rs: 0,
qcl-Type typeD
}
}
},
...
zp-CSI-RS-ResourceToAddModList {
{
zp-CSI-RS-ResourceId 0,
resourceMapping {
frequencyDomainAllocation row4: '100'B,
nrofPorts p4,
firstOFDMSymbolInTimeDomain 8,
cdm-Type fd-CDM2,
density one: NULL,
freqBand {
startingRB 0,
nrofRBs 52
}
},
periodicityAndOffset slots80: 1
}
},
p-ZP-CSI-RS-ResourceSet setup: {
zp-CSI-RS-ResourceSetId 0,
zp-CSI-RS-ResourceIdList {
0
}
}
}
},
firstActiveDownlinkBWP-Id 0,
uplinkConfig {
initialUplinkBWP {
pucch-Config setup: {
...
},
pusch-Config setup: {
...
},
srs-Config setup: {
...
}
},
firstActiveUplinkBWP-Id 0,
pusch-ServingCellConfig setup: {
}
},
pdcch-ServingCellConfig setup: {
},
pdsch-ServingCellConfig setup: {
...
},
csi-MeasConfig setup: {
nzp-CSI-RS-ResourceToAddModList {
{
nzp-CSI-RS-ResourceId 0,
resourceMapping {
frequencyDomainAllocation other: '100000'B,
nrofPorts p2,
firstOFDMSymbolInTimeDomain 4,
cdm-Type fd-CDM2,
density one: NULL,
freqBand {
startingRB 0,
nrofRBs 52
}
},
powerControlOffset 0,
powerControlOffsetSS db0,
scramblingID 500,
periodicityAndOffset slots80: 1,
qcl-InfoPeriodicCSI-RS 0
},
{
nzp-CSI-RS-ResourceId 1,
resourceMapping {
frequencyDomainAllocation row1: '1'H,
nrofPorts p1,
firstOFDMSymbolInTimeDomain 4,
cdm-Type noCDM,
density three: NULL,
freqBand {
startingRB 0,
nrofRBs 52
}
},
powerControlOffset 0,
powerControlOffsetSS db0,
scramblingID 500,
periodicityAndOffset slots40: 11,
qcl-InfoPeriodicCSI-RS 0
},
{
nzp-CSI-RS-ResourceId 2,
resourceMapping {
frequencyDomainAllocation row1: '1'H,
nrofPorts p1,
firstOFDMSymbolInTimeDomain 8,
cdm-Type noCDM,
density three: NULL,
freqBand {
startingRB 0,
nrofRBs 52
}
},
powerControlOffset 0,
powerControlOffsetSS db0,
scramblingID 500,
periodicityAndOffset slots40: 11,
qcl-InfoPeriodicCSI-RS 0
},
{
nzp-CSI-RS-ResourceId 3,
resourceMapping {
frequencyDomainAllocation row1: '1'H,
nrofPorts p1,
firstOFDMSymbolInTimeDomain 4,
cdm-Type noCDM,
density three: NULL,
freqBand {
startingRB 0,
nrofRBs 52
}
},
powerControlOffset 0,
powerControlOffsetSS db0,
scramblingID 500,
periodicityAndOffset slots40: 12,
qcl-InfoPeriodicCSI-RS 0
},
{
nzp-CSI-RS-ResourceId 4,
resourceMapping {
frequencyDomainAllocation row1: '1'H,
nrofPorts p1,
firstOFDMSymbolInTimeDomain 8,
cdm-Type noCDM,
density three: NULL,
freqBand {
startingRB 0,
nrofRBs 52
}
},
powerControlOffset 0,
powerControlOffsetSS db0,
scramblingID 500,
periodicityAndOffset slots40: 12,
qcl-InfoPeriodicCSI-RS 0
}
},
nzp-CSI-RS-ResourceSetToAddModList {
{
nzp-CSI-ResourceSetId 0,
nzp-CSI-RS-Resources {
0
}
},
{
nzp-CSI-ResourceSetId 1,
nzp-CSI-RS-Resources {
1,
2,
3,
4
},
trs-Info true
}
},
csi-IM-ResourceToAddModList {
{
csi-IM-ResourceId 0,
csi-IM-ResourceElementPattern pattern1: {
subcarrierLocation-p1 s8,
symbolLocation-p1 8
},
freqBand {
startingRB 0,
nrofRBs 52
},
periodicityAndOffset slots80: 1
}
},
csi-IM-ResourceSetToAddModList {
{
csi-IM-ResourceSetId 0,
csi-IM-Resources {
0
}
}
},
csi-ResourceConfigToAddModList {
{
csi-ResourceConfigId 0,
csi-RS-ResourceSetList nzp-CSI-RS-SSB: {
nzp-CSI-RS-ResourceSetList {
0
}
},
bwp-Id 0,
resourceType periodic
},
{
csi-ResourceConfigId 1,
csi-RS-ResourceSetList csi-IM-ResourceSetList: {
0
},
bwp-Id 0,
resourceType periodic
},
{
csi-ResourceConfigId 2,
csi-RS-ResourceSetList nzp-CSI-RS-SSB: {
nzp-CSI-RS-ResourceSetList {
1
}
},
bwp-Id 0,
resourceType periodic
}
},
csi-ReportConfigToAddModList {
{
reportConfigId 0,
resourcesForChannelMeasurement 0,
csi-IM-ResourcesForInterference 1,
reportConfigType periodic: {
reportSlotConfig slots80: 9,
pucch-CSI-ResourceList {
{
uplinkBandwidthPartId 0,
pucch-Resource 13
}
}
},
reportQuantity cri-RI-PMI-CQI: NULL,
reportFreqConfiguration {
cqi-FormatIndicator widebandCQI,
pmi-FormatIndicator widebandPMI
},
timeRestrictionForChannelMeasurements notConfigured,
timeRestrictionForInterferenceMeasurements notConfigured,
codebookConfig {
codebookType type1: {
subType typeI-SinglePanel: {
nrOfAntennaPorts two: {
twoTX-CodebookSubsetRestriction '111111'B
},
typeI-SinglePanel-ri-Restriction '03'H
},
codebookMode 1
}
},
groupBasedBeamReporting disabled: {
},
cqi-Table table2,
subbandSize value1
}
}
},
tag-Id 0
}
Tips
Resource Collision Problem
: One of the most common issues that you would encounter when you are configuring CSI RS manually (not using resource_auto) would be the error caused by collision among resources various other channels. Unfortunately there is no single shot solution to fix this automatically. It there is such a way, we might have implmented in our software. We do support a certain level of automation as described in this section and it will suit your purpose for most of the test, but the auto_configuration cannot be as flexible as manual configuration. Here I just want to provide some general guidelines for the case where you want to configure CSI RS manually and come across with physical resource collision issue,
Step 1 : Draw a time domain resource allocation map and remove the collision
First step is to draw all the physical channels and signals on time domain symbol map as follows. You should draw not only for CSI-RS that you want to configure but also draw all other resources (like SSB, PDSCH DMRS etc) and make it sure that there is no collision among any of those physical channels and signals.
You may try to tweak following configuration parameters to avoid time-domain collision :
- ssb_pos_bitmap
- dmrs_type_a_pos
- dmrs_add_pos: 1,
- dmrs_type: 1,
- dmrs_max_len: 1
- *_csi_rs_resource ->first_symb
First draw a picture showing all the major physical signal resources except CSI-RS and mark which slots/symbols are allowed for CSI-RS and which are not allowed as shown below. (

Then allocate the various CSI-RS to any of the allowed slots/symbols. There can be many possibilities, but following diagram shows only one of those possibilities and this will configured into the configuration file for this test. (

Step 2 : Change transmission slot
There might be some cases where you cannot avoid all the collision for some reasons such as :
- available resources for each slot is not enough to accommodate all the configuration
- test requirement does not allow the changes of csi-rs symbol location
In this case, you may distribute the configurations among multiple non-overlapping slot. You may tweak following configuration to distribute the csi-rs resources to different slots.
- *_csi_rs_resource -> period
- *_csi_rs_resource -> offset
Step 3 : Change Frequency Domain Resources
If step 1 and step 2 does not solve the problem, you may try tweaking frequency domain resource allocation of CSI-RS resources using following configuration.
- *_csi_rs_resource ->bitmap
Setting n1, n2
When you want to set n1, n2 of codebook_config[], you should associate it with nzp_csi_rs_resource->n_ports parameters, NOT with number of physical antenna(n_antenna_dl).
No codebook configuration in RRC message ?
If you don't see codebook setting in RRC message (RRCSetup or RrcReconfiguration) in the log where you expect to see, check the number of port that is configured for the csi configuration. If the number of ports is only 1, the codebook setting will not be configured in the RRC message.
If the RRC message is for the serving cell, check the number of port setting in the serving cell. If the RRC message is for another cell (e.g, RrcReconfiguration for Handover) check out the number of port setting for the target (destination) cell.
Logging Decoded CSI Report
In default phy log, you would see only the csi bitmap on PUCCH or PUSCH which would be hard to understand the meaning of each bits. If you want to get those bitmap decoded and printed into the log file. You have two options.
Option 1 : Add phy.csi=1 to log option
Add phy.csi=1 to log option in the confgiuration as shown below.
|
log_options: "all.level=debug,all.max_size=1, phy.csi=1", |
Option 2 : Enable CSI in WebGUI Property Window
You can enable CSI in ENB property window in WebGUI (

Then you can get the decoded CSI report as shown below.
