主题:IQ文件头、IQ文件内容、播放涉及的操作
时间:2021年1月6日
作者:ybb
参考:iqplayer_lib.c
D:\OAI\openairinterface5g-develop-20209018\openairinterface5g-develop\targets\ARCH\iqplayer\iqplayer_lib.c总结
概述:IQ文件头、IQ文件内容、播放涉及的操作
初始化收发设备
device_init
int device_init(openair0_device *device, openair0_config_t *openair0_cfg) {
device->openair0_cfg = openair0_cfg;//应用设定的射频前端参数
device->trx_start_func = trx_iqplayer_start;//启动
device->trx_get_stats_func = NULL;//获取收发函数状态
device->trx_reset_stats_func = NULL;//重设收发函数状态
device->trx_end_func = trx_iqplayer_end;//收发终止函数
device->trx_stop_func = NULL;//收发停止函数
device->trx_set_freq_func = NULL;//收发函数频率设定
device->trx_set_gains_func = NULL;//收发函数增益设置
// Replay subframes from from file从文件回放子帧
// openair0_cfg[0].rx_gain_calib_table = calib_table_b210_38;校准表
// bw_gain_adjust=1;带宽增益调整
device->trx_write_func = trx_iqplayer_write;//收发写函数
device->trx_read_func = trx_iqplayer_read;//收发度函数
iqplayer_loadfile(device, openair0_cfg);
LOG_UI(HW,"iqplayer device initialized, replay %s for %i iterations",openair0_cfg->recplay_conf->u_sf_filename,openair0_cfg->recplay_conf->u_sf_loops);//replay的文件和循环次数
return 0;
}
openair0_device
/*!\brief structure holds the parameters to configure USRP devices用于配置USRP设备的参数*/
typedef struct openair0_device_t openair0_device;
//#define USRP_GAIN_OFFSET (56.0) 定义USRP增益偏置
// 86 calibrated for USRP B210 @ 2.6 GHz to get equivalent RS EPRE in OAI to SMBV100 output
//86用于校准USRP B210 2.6G 得到等效的RS EPRE
typedef enum {
max_gain=0,med_gain,byp_gain
} rx_gain_t;
typedef enum {
duplex_mode_TDD=1,duplex_mode_FDD=0//0代表FDD 1代表TDD
} duplex_mode_t;
openair0_device_t
/*!\brief structure holds the parameters to configure USRP devices 配置USRP设备的参数*/
struct openair0_device_t {
/*!tx write thread*/
openair0_thread_t write_thread;
/*!brief Module ID of this device */
int Mod_id;
/*!brief Component Carrier ID of this device */
int CC_id;
/*!brief Type of this device */
dev_type_t type;
/*!brief Transport protocol type that the device supports (in case I/Q samples need to be transported) 设备支持的传输协议类型,IQ采样需要指定传输类型传输IQ样本*/
transport_type_t transp_type;
/*!brief Type of the device's host (RAU/RRU) */
host_type_t host_type;
/* !brief RF frontend parameters set by application */
openair0_config_t *openair0_cfg;//射频前端参数集
/* !brief ETH params set by application */
eth_params_t *eth_params;
//! record player data, definition in record_player.h//record player的数据和定义
recplay_state_t *recplay_state;
/* !brief Indicates if device already initialized 指示设备是否初始化了*/
int is_init;
/*!brief Can be used by driver to hold internal structure能够由驱动使用的内部结构*/
void *priv;
/* Functions API, which are called by the application FAPI RRU负责物理层low RAU负责物理层high*/
/*! \brief Called to start the transceiver. Return 0 if OK, < 0 if error启动收发机
@param device pointer to the device structure specific to the RF hardware target设备指向设备架构
*/
int (*trx_start_func)(openair0_device *device);
/*! \brief Called to configure the device配置设备
@param device pointer to the device structure specific to the RF hardware target 指向设备结构的射频硬件目标
*/
int (*trx_config_func)(openair0_device* device, openair0_config_t *openair0_cfg);
/*! \brief Called to send a request message between RAU-RRU on control port
@param device pointer to the device structure specific to the RF hardware target
@param msg pointer to the message structure passed between RAU-RRU
@param msg_len length of the message
*/
int (*trx_ctlsend_func)(openair0_device *device, void *msg, ssize_t msg_len);
/*! \brief Called to receive a reply message between RAU-RRU on control port
@param device pointer to the device structure specific to the RF hardware target
@param msg pointer to the message structure passed between RAU-RRU
@param msg_len length of the message
*/
int (*trx_ctlrecv_func)(openair0_device *device, void *msg, ssize_t msg_len);
/*! \brief Called to send samples to the RF target
@param device pointer to the device structure specific to the RF hardware target
@param timestamp The timestamp at whicch the first sample MUST be sent
@param buff Buffer which holds the samples
@param nsamps number of samples to be sent
@param antenna_id index of the antenna if the device has multiple anteannas
@param flags flags must be set to TRUE if timestamp parameter needs to be applied
*/
int (*trx_write_func)(openair0_device *device, openair0_timestamp timestamp, void **buff, int nsamps,int antenna_id, int flags);
/*! \brief Receive samples from hardware.
* Read \ref nsamps samples from each channel to buffers. buff[0] is the array for
* the first channel. *ptimestamp is the time at which the first sample
* was received.
* \param device the hardware to use
* \param[out] ptimestamp the time at which the first sample was received.
* \param[out] buff An array of pointers to buffers for received samples. The buffers must be large enough to hold the number of samples \ref nsamps.
* \param nsamps Number of samples. One sample is 2 byte I + 2 byte Q => 4 byte.
* \param antenna_id Index of antenna for which to receive samples
* \returns the number of sample read
*/
int (*trx_read_func)(openair0_device *device, openair0_timestamp *ptimestamp, void **buff, int nsamps,int antenna_id);
/*! \brief print the device statistics
* \param device the hardware to use
* \returns 0 on success
*/
int (*trx_get_stats_func)(openair0_device *device);
/*! \brief Reset device statistics
* \param device the hardware to use
* \returns 0 in success
*/
int (*trx_reset_stats_func)(openair0_device *device);
/*! \brief Terminate operation of the transceiver -- free all associated resources
* \param device the hardware to use
*/
void (*trx_end_func)(openair0_device *device);
/*! \brief Stop operation of the transceiver
*/
int (*trx_stop_func)(openair0_device *device);
/* Functions API related to UE*/
/*! \brief Set RX feaquencies
* \param device the hardware to use
* \param openair0_cfg RF frontend parameters set by application
* \param exmimo_dump_config dump EXMIMO configuration
* \returns 0 in success
*/
int (*trx_set_freq_func)(openair0_device *device, openair0_config_t *openair0_cfg,int exmimo_dump_config);
/*! \brief Set gains
* \param device the hardware to use
* \param openair0_cfg RF frontend parameters set by application
* \returns 0 in success
*/
int (*trx_set_gains_func)(openair0_device *device, openair0_config_t *openair0_cfg);
/*! \brief RRU Configuration callback
* \param idx RU index
* \param arg pointer to capabilities or configuration
*/
void (*configure_rru)(int idx, void *arg);
/*! \brief RRU Configuration callback
* \param idx RU index
* \param arg pointer to capabilities or configuration
*/
int (*trx_write_init)(openair0_device *device);
/* \brief Get internal parameter
* \param id parameter to get
* \return a pointer to the parameter
*/
void *(*get_internal_parameter)(char *id);
};
openair0_config_t
/*! \brief RF frontend parameters set by application应用设定的射频前端参数 */
typedef struct {
//! Module ID for this configuration用于此配置的模块ID
int Mod_id;
//! device log level设备log级
int log_level;
//! duplexing mode双工模式,0代表FDD,1代表TDD
duplex_mode_t duplex_mode;
//! number of downlink resource blocks下行资源块数量
int num_rb_dl;
//! number of samples per frame每帧的采样数量(与设置的采样速率有关)
unsigned int samples_per_frame;
//! the sample rate for both transmit and receive.发射接收的采样速率
double sample_rate;
//! flag to indicate that the device is doing mmapped DMA transfers设备是否做mmap的标志
int mmapped_dma;
//! offset in samples between TX and RX paths发射和接收路径采样的偏置
int tx_sample_advance;
//! samples per packet on the fronthaul interface在前程链路接口每个包的采样数量
int samples_per_packet;
//! number of RX channels (=RX antennas)接收天线数量
int rx_num_channels;
//! number of TX channels (=TX antennas)发射天线数量
int tx_num_channels;
//! \brief RX base addresses for mmapped_dma接收基地址
int32_t *rxbase[4];
//! \brief TX base addresses for mmapped_dma发射基地址
int32_t *txbase[4];
//! \brief Center frequency in Hz for RX.用于接收的中心频率(设置好中心频率)
//! index: [0..rx_num_channels[
double rx_freq[4];
//! \brief Center frequency in Hz for TX.用于发射的中心频率(设置好中心频率)
//! index: [0..rx_num_channels[ !!! see lte-ue.c:427 FIXME iterates over rx_num_channels
double tx_freq[4];
//! \brief memory
//! \brief Pointer to Calibration table for RX gains指向接收增益校准表的指针
rx_gain_calib_table_t *rx_gain_calib_table;
//! mode for rxgain (ExpressMIMO2)
rx_gain_t rxg_mode[4];
//! \brief Gain for RX in dB.接收增益
//! index: [0..rx_num_channels]
double rx_gain[4];
//! \brief Gain offset (for calibration) in dB用于校准的接收增益偏置
//! index: [0..rx_num_channels]
double rx_gain_offset[4];
//! gain for TX in dB发射增益
double tx_gain[4];
//! RX bandwidth in Hz接收带宽
double rx_bw;
//! TX bandwidth in Hz传输带宽
double tx_bw;
//! clock source时钟源
clock_source_t clock_source;
//! timing_source时间源
clock_source_t time_source;
//! Manual SDR IP address手动指定SDR的IP地址
//#if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR)
char *sdr_addrs;
//! Auto calibration flag自动校准标志
int autocal[4];
//! rf devices work with x bits iqs when oai have its own iq format当OAI有自己的IQ格式时,射频设备和xbit IQ工作
//! the two following parameters are used to convert iqs
int iq_txshift;//IQ传输偏移
int iq_rxrescale;//IQ接收大小再定义
//! Configuration file for LMS7002M
char *configFilename;
//! remote IP/MAC addr for Ethernet interface
char *remote_addr;
//! remote port number for Ethernet interface
unsigned int remote_port;
//! local IP/MAC addr for Ethernet interface (eNB/BBU, UE)
char *my_addr;
//! local port number for Ethernet interface (eNB/BBU, UE)
unsigned int my_port;
//! record player configuration, definition in record_player.h
uint32_t recplay_mode;//recplay模式
recplay_conf_t *recplay_conf;//recplay配置
//! number of samples per tti每个TTI的采样数量(1个TTI对应一个时隙,因为子载波间隔是可变的所以时隙的长度是可变的,但是时钟定义为14个OFDM符号的长度,一个OFDM_symbol_sized对应是FFT size么?)
unsigned int samples_per_tti;
//! the sample rate for receive.接收端采样速率
double rx_sample_rate;
//! the sample rate for transmit.发射端采样率,采样率是对应的帧?还是子帧
double tx_sample_rate;
//! check for threequarter sampling rate检查3/4采样率
int8_t threequarter_fs;
} openair0_config_t;
下面的注释没有懂,需要针对不同USRP设备设置不同的接收增益么?
// Replay subframes from from file从文件回放子帧
// openair0_cfg[0].rx_gain_calib_table = calib_table_b210_38;校准表
// bw_gain_adjust=1;带宽增益调整
replay的文件名和循环次数:
LOG_UI(HW,"iqplayer device initialized, replay %s for %i iterations",openair0_cfg->recplay_conf->u_sf_filename,openair0_cfg->recplay_conf->u_sf_loops);//replay的文件和循环次数
全局变量 静态全局变量 局部变量 静态局部变量 (加了static之后再本文件内都可以使用)
第一步:识别IQ文件头:
指定回放设备类型和带宽
eg:
FRCI_QData100M.bin
usrp_samples.dat
第二步:加载IQ文件
mmap?
用mmap从xxx加载子帧 文件名为u_sf_filename大小为st_size
iqrec_t结构体包含 头部、时间戳、rfu1、rfu2、
unsigned char samples[BELL_LABS_IQ_BYTES_PER_SF]
typedef struct {
int64_t header;//头部
int64_t ts;//时间戳
int64_t rfu1;
int64_t rfu2; // pad for 256 bits alignement required by AVX2
unsigned char samples[BELL_LABS_IQ_BYTES_PER_SF]; // iq's for one subframe贝尔实验室每个子帧的IQ采样,4个字节,2字节对应int16,2字节i与2字节q
} iqrec_t;//iq 记录器类型
#define OAIIQFILE_ID "OIQF"//oai IQ文件ID
typedef struct {
uint64_t devtype;//设备类型 B2XX
uint64_t tx_sample_advance;//发射采样提前
double bw;//带宽 5M
char oaiid[4];//oai ID用4字节存储
} iqfile_header_t;//iq文件头类型
typedef struct {
int64_t header;//头部
int64_t ts;//时间戳
int64_t rfu1;
int64_t rfu2; // pad for 256 bits alignement required by AVX2
unsigned char samples[BELL_LABS_IQ_BYTES_PER_SF]; // iq's for one subframe贝尔实验室每个子帧的IQ采样,4个字节,2字节对应int16,2字节i与2字节q
} iqrec_t;//iq 记录器类型
#define DEF_NB_SF 120000 // default nb of sf or ms to capture (2 minutes at 5MHz)
#define DEF_SF_FILE "/tmp/iqfile" // default subframes file name
#define DEF_SF_DELAY_READ 700 // default read delay 碌s (860=real)
#define DEF_SF_DELAY_WRITE 15 // default write delay 碌s (15=real)
#define DEF_SF_NB_LOOP 5 // default nb loops
加载每ms的采样数量:
parse_iqfile_header(device, (iqfile_header_t *)mptr);
s->ms_sample = (iqrec_t *)((char *)mptr + sizeof(iqfile_header_t));//每ms的采样
s->nb_samples = ((sb.st_size-sizeof(iqfile_header_t)) / sizeof(iqrec_t));//不算IQ文件头部的有效采样
int aligned = (((unsigned long)s->ms_sample & 31) == 0)? 1:0;//是否进行了32位对齐
LOG_I(HW,"Loaded %u subframes.\n",s->nb_samples );//加载采样数量的子帧
需要与mmap地址保持32位对齐,如果映射设备则退出。
第三步:IQ文件定义
跳过头部处理数据
第四步:启动OAI IQ player
第五步:终止OAI IQ player
第六步:replay模式下写入IQ时,写IQ,引入一个时延
第七步:从IQ文件接收样本,读IQ
One sample is 2 byte I + 2 byte Q => 4 byte