Merge remote-tracking branch 'origin/imscope-csv-export' into integration_2025_w23 (!3417)
imscope updates - Add CSV export button to imscope - Add extra cache for IQ data in imscope record thread so that UE time domain data can be kept until PDSCH is decoded. - Add metadata to UE time domain samples scope - Add UE pdsch pre-compensation IQ and PDSCH channel estimates
This commit is contained in:
+2
-1
@@ -1161,7 +1161,8 @@ void *UE_thread(void *arg)
|
|||||||
const int readBlockSize = get_readBlockSize(slot_nr, fp) - iq_shift_to_apply;
|
const int readBlockSize = get_readBlockSize(slot_nr, fp) - iq_shift_to_apply;
|
||||||
openair0_timestamp rx_timestamp;
|
openair0_timestamp rx_timestamp;
|
||||||
int tmp = UE->rfdevice.trx_read_func(&UE->rfdevice, &rx_timestamp, rxp, readBlockSize, fp->nb_antennas_rx);
|
int tmp = UE->rfdevice.trx_read_func(&UE->rfdevice, &rx_timestamp, rxp, readBlockSize, fp->nb_antennas_rx);
|
||||||
UEscopeCopy(UE, ueTimeDomainSamples, rxp[0], sizeof(c16_t), 1, readBlockSize, 0);
|
metadata meta = {.slot = curMsg.proc.nr_slot_rx, .frame = curMsg.proc.frame_rx};
|
||||||
|
UEscopeCopyWithMetadata(UE, ueTimeDomainSamples, rxp[0] - firstSymSamp * sizeof(c16_t), sizeof(c16_t), 1, readBlockSize, 0, &meta);
|
||||||
AssertFatal(readBlockSize == tmp, "");
|
AssertFatal(readBlockSize == tmp, "");
|
||||||
struct timespec current_time;
|
struct timespec current_time;
|
||||||
if (clock_gettime(CLOCK_REALTIME, ¤t_time)) {
|
if (clock_gettime(CLOCK_REALTIME, ¤t_time)) {
|
||||||
|
|||||||
@@ -323,7 +323,8 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue,
|
|||||||
c16_t ptrs_phase_per_slot[][NR_SYMBOLS_PER_SLOT],
|
c16_t ptrs_phase_per_slot[][NR_SYMBOLS_PER_SLOT],
|
||||||
int32_t ptrs_re_per_slot[][NR_SYMBOLS_PER_SLOT],
|
int32_t ptrs_re_per_slot[][NR_SYMBOLS_PER_SLOT],
|
||||||
int G,
|
int G,
|
||||||
uint32_t nvar)
|
uint32_t nvar,
|
||||||
|
pdsch_scope_req_t *scope_req)
|
||||||
{
|
{
|
||||||
const int nl = dlsch[0].Nl;
|
const int nl = dlsch[0].Nl;
|
||||||
const int matrixSz = ue->frame_parms.nb_antennas_rx * nl;
|
const int matrixSz = ue->frame_parms.nb_antennas_rx * nl;
|
||||||
@@ -463,6 +464,12 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue,
|
|||||||
csi_res_bitmap,
|
csi_res_bitmap,
|
||||||
ue->chest_time);
|
ue->chest_time);
|
||||||
stop_meas_nr_ue_phy(ue, DLSCH_EXTRACT_RBS_STATS);
|
stop_meas_nr_ue_phy(ue, DLSCH_EXTRACT_RBS_STATS);
|
||||||
|
if (scope_req->copy_chanest_to_scope) {
|
||||||
|
size_t size = sizeof(c16_t) * dlsch_config->number_rbs * NR_NB_SC_PER_RB;
|
||||||
|
int copy_index = symbol - dlsch_config->start_symbol;
|
||||||
|
int offset = copy_index * size;
|
||||||
|
UEscopeCopyUnsafe(ue, pdschChanEstimates, dl_ch_estimates_ext[0], size, offset, copy_index);
|
||||||
|
}
|
||||||
if (meas_enabled) {
|
if (meas_enabled) {
|
||||||
LOG_D(PHY,
|
LOG_D(PHY,
|
||||||
"[AbsSFN %u.%d] Slot%d Symbol %d: Pilot/Data extraction %5.2f \n",
|
"[AbsSFN %u.%d] Slot%d Symbol %d: Pilot/Data extraction %5.2f \n",
|
||||||
@@ -481,6 +488,12 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue,
|
|||||||
nb_re_pdsch = (pilots == 1) ? ((config_type == NFAPI_NR_DMRS_TYPE1) ? nb_rb_pdsch * (12 - 6 * dlsch_config->n_dmrs_cdm_groups)
|
nb_re_pdsch = (pilots == 1) ? ((config_type == NFAPI_NR_DMRS_TYPE1) ? nb_rb_pdsch * (12 - 6 * dlsch_config->n_dmrs_cdm_groups)
|
||||||
: nb_rb_pdsch * (12 - 4 * dlsch_config->n_dmrs_cdm_groups))
|
: nb_rb_pdsch * (12 - 4 * dlsch_config->n_dmrs_cdm_groups))
|
||||||
: (nb_rb_pdsch * 12);
|
: (nb_rb_pdsch * 12);
|
||||||
|
if (scope_req->copy_rxdataF_to_scope) {
|
||||||
|
size_t size = sizeof(c16_t) * nb_re_pdsch;
|
||||||
|
int copy_index = symbol - dlsch_config->start_symbol;
|
||||||
|
UEscopeCopyUnsafe(ue, pdschRxdataF, rxdataF_ext[0], size, scope_req->scope_rxdataF_offset, copy_index);
|
||||||
|
scope_req->scope_rxdataF_offset += size;
|
||||||
|
}
|
||||||
//----------------------------------------------------------
|
//----------------------------------------------------------
|
||||||
//--------------------- Channel Scaling --------------------
|
//--------------------- Channel Scaling --------------------
|
||||||
//----------------------------------------------------------
|
//----------------------------------------------------------
|
||||||
|
|||||||
@@ -41,6 +41,13 @@
|
|||||||
#define NR_PUSCH_x 2 // UCI placeholder bit TS 38.212 V15.4.0 subclause 5.3.3.1
|
#define NR_PUSCH_x 2 // UCI placeholder bit TS 38.212 V15.4.0 subclause 5.3.3.1
|
||||||
#define NR_PUSCH_y 3 // UCI placeholder bit
|
#define NR_PUSCH_y 3 // UCI placeholder bit
|
||||||
|
|
||||||
|
// Specifies the data that should be copied to the scope during PDSCH RX
|
||||||
|
typedef struct pdsch_scope_req_s {
|
||||||
|
bool copy_chanest_to_scope;
|
||||||
|
bool copy_rxdataF_to_scope;
|
||||||
|
size_t scope_rxdataF_offset;
|
||||||
|
} pdsch_scope_req_t;
|
||||||
|
|
||||||
// Functions below implement 36-211 and 36-212
|
// Functions below implement 36-211 and 36-212
|
||||||
|
|
||||||
/** @addtogroup _PHY_TRANSPORT_
|
/** @addtogroup _PHY_TRANSPORT_
|
||||||
@@ -314,7 +321,8 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue,
|
|||||||
c16_t ptrs_phase_per_slot[][NR_SYMBOLS_PER_SLOT],
|
c16_t ptrs_phase_per_slot[][NR_SYMBOLS_PER_SLOT],
|
||||||
int32_t ptrs_re_per_slot[][NR_SYMBOLS_PER_SLOT],
|
int32_t ptrs_re_per_slot[][NR_SYMBOLS_PER_SLOT],
|
||||||
int G,
|
int G,
|
||||||
uint32_t nvar);
|
uint32_t nvar,
|
||||||
|
pdsch_scope_req_t *scope_req);
|
||||||
|
|
||||||
int32_t generate_nr_prach(PHY_VARS_NR_UE *ue, uint8_t gNB_id, int frame, uint8_t slot, c16_t **txData);
|
int32_t generate_nr_prach(PHY_VARS_NR_UE *ue, uint8_t gNB_id, int frame, uint8_t slot, c16_t **txData);
|
||||||
|
|
||||||
|
|||||||
@@ -248,6 +248,29 @@ class IQHist {
|
|||||||
if (!ss.str().empty()) {
|
if (!ss.str().empty()) {
|
||||||
ImGui::Text("Data for %s", ss.str().c_str());
|
ImGui::Text("Data for %s", ss.str().c_str());
|
||||||
}
|
}
|
||||||
|
if (ImGui::Button("Save IQ")) {
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << "iq_";
|
||||||
|
if (iq_data->meta.frame != -1) {
|
||||||
|
ss << iq_data->meta.frame << "_";
|
||||||
|
}
|
||||||
|
if (iq_data->meta.slot != -1) {
|
||||||
|
ss << iq_data->meta.slot << "_";
|
||||||
|
}
|
||||||
|
ss << scope_id_to_string(static_cast<enum scopeDataType>(iq_data->scope_id));
|
||||||
|
ss << ".csv";
|
||||||
|
std::ofstream file(ss.str());
|
||||||
|
if (file.is_open()) {
|
||||||
|
file << "real;imag\n";
|
||||||
|
for (int i = 0; i < iq_data->len; i++) {
|
||||||
|
file << iq_data->real[i] << ";" << iq_data->imag[i] << "\n";
|
||||||
|
}
|
||||||
|
file.close();
|
||||||
|
std::cout << "Saved IQ to file: " << ss.str() << std::endl;
|
||||||
|
} else {
|
||||||
|
std::cerr << "Unable to open file";
|
||||||
|
}
|
||||||
|
}
|
||||||
ImGui::EndGroup();
|
ImGui::EndGroup();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -432,6 +455,29 @@ void ShowUeScope(void *data_void_ptr, float t)
|
|||||||
}
|
}
|
||||||
ImGui::End();
|
ImGui::End();
|
||||||
|
|
||||||
|
if (ImGui::Begin("UE PDSCH Chan est")) {
|
||||||
|
static auto iq_data = new IQData();
|
||||||
|
static auto iq_hist = new IQHist("PDSCH Chan est IQ");
|
||||||
|
bool new_data = false;
|
||||||
|
if (iq_hist->ShouldReadData()) {
|
||||||
|
new_data = iq_data->TryCollect(&scope_array[pdschChanEstimates], t, iq_hist->GetEpsilon(), iq_procedure_timer);
|
||||||
|
}
|
||||||
|
iq_hist->Draw(iq_data, t, new_data);
|
||||||
|
}
|
||||||
|
ImGui::End();
|
||||||
|
|
||||||
|
if (ImGui::Begin("UE PDSCH IQ before compensation")) {
|
||||||
|
static auto iq_data = new IQData();
|
||||||
|
static auto iq_hist = new IQHist("PDSCH IQ before compensation");
|
||||||
|
bool new_data = false;
|
||||||
|
if (iq_hist->ShouldReadData()) {
|
||||||
|
new_data = iq_data->TryCollect(&scope_array[pdschRxdataF], t, iq_hist->GetEpsilon(), iq_procedure_timer);
|
||||||
|
}
|
||||||
|
iq_hist->Draw(iq_data, t, new_data);
|
||||||
|
}
|
||||||
|
ImGui::End();
|
||||||
|
|
||||||
|
|
||||||
if (ImGui::Begin("Time domain samples")) {
|
if (ImGui::Begin("Time domain samples")) {
|
||||||
static auto iq_data = new IQData();
|
static auto iq_data = new IQData();
|
||||||
// Issue with imgui deferring draw calls until the end of the frame - cases segfault if scatterplot has too many points
|
// Issue with imgui deferring draw calls until the end of the frame - cases segfault if scatterplot has too many points
|
||||||
|
|||||||
@@ -131,12 +131,9 @@ void unlockScopeData(enum scopeDataType type)
|
|||||||
total_size += scope_data.data.data_copied_per_offset[i];
|
total_size += scope_data.data.data_copied_per_offset[i];
|
||||||
}
|
}
|
||||||
if (total_size != (uint64_t)scope_data.data.scope_graph_data->dataSize) {
|
if (total_size != (uint64_t)scope_data.data.scope_graph_data->dataSize) {
|
||||||
LOG_E(PHY,
|
scope_data.data.scope_graph_data->dataSize = total_size;
|
||||||
"Scope is missing data - not all data that was expected was copied - possibly missed copyDataUnsafeWithOffset call. "
|
scope_data.data.scope_graph_data->lineSz =
|
||||||
"scope = %s, total_size = %lu, dataSize = %d\n",
|
total_size / scope_data.data.scope_graph_data->elementSz / scope_data.data.scope_graph_data->colSz;
|
||||||
scope_id_to_string(type),
|
|
||||||
total_size,
|
|
||||||
scope_data.data.scope_graph_data->dataSize);
|
|
||||||
}
|
}
|
||||||
scope_data.data.scope_id = type;
|
scope_data.data.scope_id = type;
|
||||||
scope_data.is_data_ready = true;
|
scope_data.is_data_ready = true;
|
||||||
@@ -179,8 +176,12 @@ const char *scope_id_to_string(scopeDataType type) {
|
|||||||
return "ueTimeDomainSamplesBeforeSync";
|
return "ueTimeDomainSamplesBeforeSync";
|
||||||
case gNbTimeDomainSamples:
|
case gNbTimeDomainSamples:
|
||||||
return "gNbTimeDomainSamples";
|
return "gNbTimeDomainSamples";
|
||||||
|
case pdschChanEstimates:
|
||||||
|
return "pdschChanEstimates";
|
||||||
|
case pdschRxdataF:
|
||||||
|
return "pdschRxdataF";
|
||||||
default:
|
default:
|
||||||
return "unknown type";
|
return "unknown scope type";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -35,7 +35,7 @@
|
|||||||
constexpr std::size_t hardware_destructive_interference_size = 64;
|
constexpr std::size_t hardware_destructive_interference_size = 64;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define NUM_CACHED_DATA 4
|
#define NUM_CACHED_DATA 8
|
||||||
// Set maximum number of kilobytes written per recording session to 1GB. This is a safeguard against
|
// Set maximum number of kilobytes written per recording session to 1GB. This is a safeguard against
|
||||||
// recoding thread writing too many files and exhausting disk space.
|
// recoding thread writing too many files and exhausting disk space.
|
||||||
#define MAX_KBYTES_WRITTEN_PER_SESSION (1000 * 1000)
|
#define MAX_KBYTES_WRITTEN_PER_SESSION (1000 * 1000)
|
||||||
|
|||||||
@@ -77,6 +77,8 @@ enum scopeDataType {
|
|||||||
ueTimeDomainSamples,
|
ueTimeDomainSamples,
|
||||||
ueTimeDomainSamplesBeforeSync,
|
ueTimeDomainSamplesBeforeSync,
|
||||||
gNbTimeDomainSamples,
|
gNbTimeDomainSamples,
|
||||||
|
pdschChanEstimates,
|
||||||
|
pdschRxdataF,
|
||||||
EXTRA_SCOPE_TYPES
|
EXTRA_SCOPE_TYPES
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -606,6 +606,24 @@ static int nr_ue_pdsch_procedures(PHY_VARS_NR_UE *ue,
|
|||||||
|
|
||||||
int32_t log2_maxh = 0;
|
int32_t log2_maxh = 0;
|
||||||
start_meas_nr_ue_phy(ue, RX_PDSCH_STATS);
|
start_meas_nr_ue_phy(ue, RX_PDSCH_STATS);
|
||||||
|
pdsch_scope_req_t scope_req = { .copy_chanest_to_scope = false,
|
||||||
|
.copy_rxdataF_to_scope = false,
|
||||||
|
.scope_rxdataF_offset = 0 };
|
||||||
|
if (UEScopeHasTryLock(ue)) {
|
||||||
|
metadata mt = {.frame = proc->frame_rx, .slot = proc->nr_slot_rx};
|
||||||
|
scope_req.copy_chanest_to_scope = UETryLockScopeData(ue,
|
||||||
|
pdschChanEstimates,
|
||||||
|
sizeof(c16_t),
|
||||||
|
1,
|
||||||
|
dlschCfg->number_rbs * NR_NB_SC_PER_RB * dlschCfg->number_symbols,
|
||||||
|
&mt);
|
||||||
|
scope_req.copy_rxdataF_to_scope = UETryLockScopeData(ue,
|
||||||
|
pdschRxdataF,
|
||||||
|
sizeof(c16_t),
|
||||||
|
1,
|
||||||
|
dlschCfg->number_rbs * NR_NB_SC_PER_RB * dlschCfg->number_symbols,
|
||||||
|
&mt);
|
||||||
|
}
|
||||||
for (int m = dlschCfg->start_symbol; m < (dlschCfg->number_symbols + dlschCfg->start_symbol); m++) {
|
for (int m = dlschCfg->start_symbol; m < (dlschCfg->number_symbols + dlschCfg->start_symbol); m++) {
|
||||||
bool first_symbol_flag = false;
|
bool first_symbol_flag = false;
|
||||||
if (m == first_symbol_with_data)
|
if (m == first_symbol_with_data)
|
||||||
@@ -632,11 +650,25 @@ static int nr_ue_pdsch_procedures(PHY_VARS_NR_UE *ue,
|
|||||||
ptrs_phase_per_slot,
|
ptrs_phase_per_slot,
|
||||||
ptrs_re_per_slot,
|
ptrs_re_per_slot,
|
||||||
G,
|
G,
|
||||||
nvar)
|
nvar,
|
||||||
< 0)
|
&scope_req)
|
||||||
|
< 0) {
|
||||||
|
if (scope_req.copy_chanest_to_scope) {
|
||||||
|
UEunlockScopeData(ue, pdschChanEstimates);
|
||||||
|
}
|
||||||
|
if (scope_req.copy_rxdataF_to_scope) {
|
||||||
|
UEunlockScopeData(ue, pdschRxdataF);
|
||||||
|
}
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
} // CRNTI active
|
} // CRNTI active
|
||||||
stop_meas_nr_ue_phy(ue, RX_PDSCH_STATS);
|
stop_meas_nr_ue_phy(ue, RX_PDSCH_STATS);
|
||||||
|
if (scope_req.copy_chanest_to_scope) {
|
||||||
|
UEunlockScopeData(ue, pdschChanEstimates);
|
||||||
|
}
|
||||||
|
if (scope_req.copy_rxdataF_to_scope) {
|
||||||
|
UEunlockScopeData(ue, pdschRxdataF);
|
||||||
|
}
|
||||||
free(toFree);
|
free(toFree);
|
||||||
free(toFree2);
|
free(toFree2);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user