天天看點

OAI NR nr-softmodem初步解析

編譯和仿真指令

基于版本:OAI_develop_210827。對nr-softmodem,也就是 gnb進行解析。

下載下傳後編譯 先用git init指令,然後chmod 777 -R把檔案夾内權限設定一下。

develop的編譯:

sudo ./build_oai -w USRP --eNB --nrUE --gNB -g -G  -V -x -P --ue-trace --ue-timing   --build-lib telnetsrv  --build-lib all
           

NR_UE_SA的編譯:

sudo ./build_oai -w USRP --eNB --nrUE --gNB -g -G -P --build-lib all
           

​      分别用-P和取消-P分别編譯一次。

gdb 調試和仿真:

ue端:
sudo RFSIMULATOR=127.0.0.1 ./nr-uesoftmodem --rfsim --phy-test --rrc_config_path ./ -d
server端: (在ubuntu終端中輸入export RFSIMULATOR=server,并用env指令檢視)
sudo cgdb --args ./nr-softmodem -O ../../../targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.usrpn300.conf --rfsim --phy-test -d   --command set enviroment RFSIMULATOR=server --rfsimulator.options saviq
           

讀取配置

調試指令:

對NR_SSB的一些配置(讀取nr_init_frame_parms()運作後的fp結構體):

{freq_range = nr_FR1, N_RB_DL = 106, N_RB_UL = 106, N_RBG = 0 '\000', N_RBGS = 0 '\000', 
nr_band = 78, dl_CarrierFreq = 3619080000, ul_CarrierFreq = 3619080000, att_tx = 0, att_rx 
= 0, frame_type = TDD, tdd_config = 0 '\000', Nid_cell = 0, subcarrier_spacing = 30000, 
threequarter_fs = 0 '\000', ofdm_symbol_size= 2048, nb_prefix_samples = 144, 
nb_prefix_samples0 = 176, first_carrier_offset = 1412, symbols_per_slot = 14, 
slots_per_subframe = 2, slots_per_frame = 20, samples_per_subframe = 61440, 
samples_per_slot0 = 30720, samples_per_slotN0 = 30688, samples_per_frame = 614400, 
samples_per_subframe_wCP = 57344, samples_per_slot_wCP = 28672, samples_per_frame_wCP = 
573440, numerology_index = 1 '\001', nb_antennas_tx = 1 '\001', nb_antennas_rx = 1 '\001', 
nb_antenna_ports_gNB = 0 '\000', Ncp = NORMAL, symbol_rotation = {{0 <repeats 448 times>}, 
{0 <repeats 448 times>}}, nushift = 0 '\000', srs_nr = {active_srs_Resource_Set = 0 '\000', 
number_srs_Resource_Set = 0 '\000', p_SRS_ResourceSetList = {0x0}}, ss_PBCH_BlockPower = 0, 
p_tdd_UL_DL_Configuration = 0x0, p_tdd_UL_DL_ConfigurationCommon2 = 0x0, 
p_TDD_UL_DL_ConfigDedicated = 0x0, tdd_uplink_nr = {0 <repeats 320 times>}, half_frame_bit 
= 0 '\000', ssb_start_subcarrier = 0, ssb_type = nr_ssb_type_C, Lmax = 8 '\b', L_ssb = 
9223372036854775808, N_ssb = 1 '\001', ssb_index = 0 '\000', pbch_polar_params = {idx = 0, 
nextPtr = 0x0, n_max = 0 '\000', i_il = 0 '\000', i_seg = 0 '\000', n_pc = 0 '\000', 
n_pc_wm = 0 '\000', i_bil = 0 '\000', payloadBits = 0, encoderLength = 0, crcParityBits = 0 
'\000', crcCorrectionBits = 0 '\000', K = 0, N = 0, n = 0 '\000', crcBit = 0, 
interleaving_pattern = 0x0, deinterleaving_pattern = 0x0, rate_matching_pattern = 0x0, 
Q_0_Nminus1 = 0x0, Q_I_N = 0x0, Q_F_N = 0x0, Q_PC_N = 0x0, information_bit_pattern = 0x0, 
channel_interleaver_pattern = 0x0, crc_generator_matrix = 0x0, G_N = 0x0, G_N_tab = 0x0, 
groupsize = 0, rm_tab = 0x0, cprime_tab0 = {{0 <repeats 256 times>} <repeats 32 times>}, 
cprime_tab1 = {{0 <repeats 256 times>} <repeats 32 times>}, B_tab0 = {{0 <repeats 256 
times>} <repeats 32 times>}, B_tab1 = {{0 <repeats 256 times>} <repeats 32 times>}, 
extended_crc_generator_matrix = 0x0, nr_polar_crc = 0x0, nr_polar_aPrime = 0x0, 
nr_polar_APrime = 0x0, nr_polar_D = 0x0, nr_polar_E = 0x0, nr_polar_A = 0x0, nr_polar_CPrime = 0x0, nr_polar_B = 0x0, nr_polar_U = 0x0, tree = {root = 0x0, num_nodes = 
0}}}
           

 資料發送:

​       按slot來發送。一個子幀是2個,是以大多數情況是0.5ms發送一次。

​       tx_rf()中ru->rfdevice.trx_write_func()進行發送。這個函數指針在usrp發送指向trx_usrp_write()。在RFSIMULATOR=server仿真下,指向  rfsimulator_write_internal()進行的資料發送。

​      發送的資料長度為nsamps,位址為txp,   如下進行指派: 

txp[i] = (void *)&ru->common.txdata[i][fp->get_samples_slot_timestamp(slot,fp,0)-sf_extension];
           

​       在rx_func()末尾,如果滿足下面的條件,則啟動tx_func()。

 tx_slot_type == NR_DOWNLINK_SLOT || tx_slot_type == NR_MIXED_SLOT
           

發送函數作用解釋:

- tx_func():  生成bit幀(dci、csi,旋轉等),主要調用phy_procedures_gNB_TX()。在rx_func()末尾可以啟動。  在Tpool0_1  ~ Tpool7_-1共8個線程中來承載運作;

- ru_tx_func() :   射頻前端、OFDM調制,調用ru->fh_south_out()函數指針,指向tx_rf(),以通過射頻usrp或者仿真網口發出去。ru_tx_func()在tx_func()末尾啟動。 ofdm調制調用Tpoll線程的nr_feptx_prec來實作。 在Tpool0_1  ~ Tpool7_-1共8個線程中承載運作;

- nr_feptx_prec() :OFDM調試、波束預編碼。由線程"feptx"承載運作。 由線程Tpool0_1  ~ Tpool7_-1裡面的tx_func(),通過nr_feptx_ofdm_2thread()調用。

讀取發送儲存的檔案

​     運作時添加參數    --rfsimulator.options saviq。預設儲存位置為tmp/rfsimulator.iqs

​     matlab讀取的對應代碼為:

clear;clc;close all;
format LONGG;

fid = fopen('Z:\work\data\rfsimulator.iqs','r');
skip = 0;  % by bytes
Nframe = 100;

for i = 1:Nframe
    header = fread(fid,8,'uint32');
    frame.header.magic = header(1) * 2^32 +  header(2);
    frame.header.size = header(3);
    frame.header.nbAnt = header(4);
    frame.header.timestamp = header(5) * 2^32 + header(6);
    frame.header.option_value = header(7);
    frame.header.option_flag = header(8); 
    
    skip = skip + 32;
    fseek(fid,skip,1);  % by bytes
    size = frame.header.size;
    data = fread(fid,size*2,'int16');
    frame.real=data(1:2:end-1);
    frame.img =data(2:2:end);
    frame.cmx = frame.real + 1j * frame.img;    
    skip = skip + size * 4;  
    fseek(fid,skip,1);  % by bytes
    FrameS(i) = frame;
end
fclose(fid);
           

# 線程池及調用

​       發送和接收的主要函數是ru_thread(),通過thread_FH線程承載。這個線程又調用函數tx_func()和ru_tx_func()。這兩個函數都是通過Tpool0_1  ~ Tpool7_-1線程池承載。tx_func裡面的OFDM調制又通過調用nr_feptx_prec()裡面的nr_feptx_ofdm_2thread()來實作。而nr_feptx_prec是通過線程feptx來承載。

​      ru_thread()裡面也把接收的資料發給scope,用于顯示;

​     函數通過 pushTpool()如   pushTpool (gNB->threadPool, res)調用函數。如讀取 res内容可以看到線程運作的函數 ru_tx_func():

(gdb) p *res
$39 = {next = 0x0, key = 3, reponseFifo = 0x39c2c40, processingFunc = 0x6b0633 <ru_tx_func>, malloced = true, creationTime = 0, startProcessingTime = 0, endProcessingTime = 0, returnTime = 0, msgData = 0x7fffe001e6c0}
           

​       該線程池的詳解見:“線程池Code詳解"   作者 從善若水。

​        pullTpool() : 傳回可用的線程;pushTpool()運作線程。裡面有線程上一個處理函數和下一個處理函數

​        如tx_func()裡面語句:

res = pullTpool(gNB->resp_RU_tx, gNB->threadPool);
           

​      在此處斷點,列印

p *gNB->resp_RU_tx->outF
p *gNB->resp_RU_tx->inF