Add IQ file recording and IQ file viewer to ImScope

This commit introduces the following changes to ImScope:
 - Added the ability to record IQ data using the same mechanism as ImScope.
 - Added a new executable target `imscope_iq_file_viewer` for viewing IQ files.
 - Introduced a command line argument `--imscope-record` that enables data recording mode.
 - Refactored a lot of the scope code

Usage:
 - To record IQ data, run a modem with `--imscope-record` flag.
   The recording happens whenever a modem calls dumpScopeData, which currently is
   done only in gNB on PUSCH DTX and PUSCH CRC NOK.
   There is a limit of ~1GB of files written by the thread in a signle run to avoid
   accidentally exhausting disk space.
   If a directory `imscope-dump` is available the data will be recorded there in .imscope
   files. Otherwise files are written to the directory the modem was run. This is done so that
   the directory can be mapped in a docker container.

 - To view recorded IQ files, use the new executable `imscope_iq_file_viewer`. This can be done by running:
      ```
      ./imscope_iq_file_viewer <path_to_iq_file>
      ```
   Replace `<path_to_iq_file>` with the path to the IQ file you want to view.
This commit is contained in:
Bartosz Podrygajlo
2025-01-28 16:54:54 +01:00
parent 4b9e70b2ba
commit ab75a7ccfb
14 changed files with 729 additions and 242 deletions
+6 -1
View File
@@ -701,7 +701,7 @@ int main( int argc, char **argv ) {
wait_RUs();
// once all RUs are ready initialize the rest of the gNBs ((dependence on final RU parameters after configuration)
if (IS_SOFTMODEM_DOSCOPE || IS_SOFTMODEM_IMSCOPE_ENABLED) {
if (IS_SOFTMODEM_DOSCOPE || IS_SOFTMODEM_IMSCOPE_ENABLED || IS_SOFTMODEM_IMSCOPE_RECORD_ENABLED) {
sleep(1);
scopeParms_t p;
p.argc = &argc;
@@ -714,6 +714,11 @@ int main( int argc, char **argv ) {
if (IS_SOFTMODEM_IMSCOPE_ENABLED) {
load_softscope("im", &p);
}
AssertFatal(!(IS_SOFTMODEM_IMSCOPE_ENABLED && IS_SOFTMODEM_IMSCOPE_RECORD_ENABLED),
"Data recoding and ImScope cannot be enabled at the same time\n");
if (IS_SOFTMODEM_IMSCOPE_RECORD_ENABLED) {
load_module_shlib("imscope_record", NULL, 0, &p);
}
}
if (NFAPI_MODE != NFAPI_MODE_PNF && NFAPI_MODE != NFAPI_MODE_VNF && NFAPI_MODE != NFAPI_MODE_AERIAL) {
+5
View File
@@ -532,6 +532,11 @@ int main(int argc, char **argv)
if (IS_SOFTMODEM_IMSCOPE_ENABLED) {
load_softscope("im", PHY_vars_UE_g[0][0]);
}
AssertFatal(!(IS_SOFTMODEM_IMSCOPE_ENABLED && IS_SOFTMODEM_IMSCOPE_RECORD_ENABLED),
"Data recoding and ImScope cannot be enabled at the same time\n");
if (IS_SOFTMODEM_IMSCOPE_RECORD_ENABLED) {
load_module_shlib("imscope_record", NULL, 0, PHY_vars_UE_g[0][0]);
}
for (int inst = 0; inst < NB_UE_INST; inst++) {
LOG_I(PHY,"Intializing UE Threads for instance %d ...\n", inst);
+5
View File
@@ -77,6 +77,7 @@ void get_common_options(configmodule_interface_t *cfg)
uint32_t noS1 = 0, nonbiot = 0;
uint32_t rfsim = 0, do_forms = 0;
uint32_t enable_imscope = 0;
uint32_t enable_imscope_record = 0;
int nfapi_index = 0;
char *logmem_filename = NULL;
@@ -141,6 +142,10 @@ void get_common_options(configmodule_interface_t *cfg)
IS_SOFTMODEM_IMSCOPE_ENABLED = true;
}
if (enable_imscope_record) {
IS_SOFTMODEM_IMSCOPE_RECORD_ENABLED = true;
}
if (start_websrv) {
load_module_shlib("websrv", NULL, 0, NULL);
}
+5
View File
@@ -80,6 +80,7 @@ extern "C"
#define CONFIG_HLP_CHESTFREQ "Set channel estimation type in frequency domain. 0-Linear interpolation (default). 1-PRB based averaging of channel estimates in frequency. \n"
#define CONFIG_HLP_CHESTTIME "Set channel estimation type in time domain. 0-Symbols take estimates of the last preceding DMRS symbol (default). 1-Symbol based averaging of channel estimates in time. \n"
#define CONFIG_HLP_IMSCOPE "Enable phy scope based on imgui and implot"
#define CONFIG_HLP_IMSCOPE_RECORD "Enable recording scope data to filesystem"
#define CONFIG_HLP_NONSTOP "Go back to frame sync mode after 100 consecutive PBCH failures\n"
//#define CONFIG_HLP_NUMUES "Set the number of UEs for the emulation"
@@ -186,6 +187,7 @@ extern int usrp_tx_thread;
{"A" , CONFIG_HLP_TADV, 0, .iptr=&softmodem_params.command_line_sample_advance,.defintval=0, TYPE_INT, 0}, \
{"E" , CONFIG_HLP_TQFS, PARAMFLAG_BOOL, .iptr=&softmodem_params.threequarter_fs, .defintval=0, TYPE_INT, 0}, \
{"imscope" , CONFIG_HLP_IMSCOPE, PARAMFLAG_BOOL, .uptr=&enable_imscope, .defintval=0, TYPE_UINT, 0}, \
{"imscope-record" , CONFIG_HLP_IMSCOPE_RECORD,PARAMFLAG_BOOL, .uptr=&enable_imscope_record, .defintval=0, TYPE_UINT, 0}, \
}
// clang-format on
@@ -231,6 +233,7 @@ extern int usrp_tx_thread;
{ .s5 = { NULL } }, \
{ .s5 = { NULL } }, \
{ .s5 = { NULL } }, \
{ .s5 = { NULL } }, \
}
// clang-format on
@@ -285,6 +288,7 @@ extern int usrp_tx_thread;
#define IS_SOFTMODEM_5GUE (get_softmodem_optmask()->bit.SOFTMODEM_5GUE_BIT)
#define IS_SOFTMODEM_NOSTATS (get_softmodem_optmask()->bit.SOFTMODEM_NOSTATS_BIT)
#define IS_SOFTMODEM_IMSCOPE_ENABLED (get_softmodem_optmask()->bit.SOFTMODEM_IMSCOPE_BIT)
#define IS_SOFTMODEM_IMSCOPE_RECORD_ENABLED (get_softmodem_optmask()->bit.SOFTMODEM_IMSCOPE_RECORD_BIT)
typedef struct optmask_s {
union {
struct {
@@ -304,6 +308,7 @@ typedef struct optmask_s {
uint64_t SOFTMODEM_5GUE_BIT: 1;
uint64_t SOFTMODEM_NOSTATS_BIT: 1;
uint64_t SOFTMODEM_IMSCOPE_BIT: 1;
uint64_t SOFTMODEM_IMSCOPE_RECORD_BIT : 1;
} bit;
uint64_t v; // allow to export entire bit set, force to 64 bit processor atomic size
};