Abstract
TI has developed the IWR1843 mmWave radar sensor for industrial and automotive applications, including level sensing. A guide with notes on how to design and implement level sensing systems using the IWR1843 is available, covering topics such as signal processing, antenna design, and calibration techniques. This guide helps users understand and optimize the IWR1843’s level sensing capabilities.
Referance
high_accuracy_user_guide.html resource explorer 配置文件解析 # 原理
这个实验配置了一个发射天线和一个接收天线,并利用Zoom FFT技术进行操作,这种技术包含两个步骤。第一步是进行一维粗略FFT以搜索峰值。第二步是进行第二个放大FFT,它以更高的分辨率分析峰值频谱的一部分
对比14xx
和 16xx/68xx
由于16xx/68xx设备包括片上DSP,而14xx设备没有,因此需要注意一些差异。由于片上FFT加速器的硬件限制,14xx版本的最大FFT大小为16K。因此,14xx版本将具有更低的处理延迟以及更低的功耗。16xx/68xx版本使用片上DSP,因此分辨率更高,FFT大小也更大.
配置命令解析
命令 RangeLimitCfg 使用以下参数结构 ,其中:
RangeLimitCfg <numRangeBinZoomIn> <dis/enable> <min range limited> <max range limited>
<numRangeBinZoomIn >(仅限 16xx/68xx):是在粗峰两侧放大的箱数。注意:这是一个优化值,不建议进行更改。
<dis/enable>:0 表示禁用,1 表示已启用
<min range limited>:以米为单位
<max range limited>:以米为单位
E: RangeLimitCfg 2 1 1.0 3.0
1. MSS通过UART发送数据代码解析
这里整体的发送逻辑是dss
通过mailBox
发送一个Semaphore
给mss
, 然后mss
查看Semaphore
的类型, 如果是MMWDEMO_DSS2MSS_DETOBJ_READY
就去共享内存中将dss
处理好的数据拷贝出来, 拷贝到mss
的全局变量中, 然后mss
就对mss
这边的这个全局变量做操作.
1.2 MailBox发送数据的操作流程
src: mss_main.c
/*z:这个是mailbox的函数, dsp和mss进行通信的工具 */
static void MmwDemo_mboxReadTask(UArg arg0, UArg arg1)
{
;
MmwDemo_message messageint32_t retVal = 0;
uint32_t timeStart;
/* wait for new message and process all the messages received from the peer */
while(1)
{
/* 一直等待mailbox发送发过来数据, 如果没有数据就一直挂起. */
(gMmwMssMCB.mboxSemHandle, BIOS_WAIT_FOREVER);
Semaphore_pend
/* Read the message from the peer mailbox: We are not trying to protect the read
* from the peer mailbox because this is only being invoked from a single thread */
/* 这段代码是从一个消息邮箱 (Mailbox) 中读取消息,并将消息内容保存到一个名为 message
* 的变量中。在这段代码中,使用了 Mailbox_read() 函数来从名为 gMmwMssMCB 的全局变量所
* 表示的邮箱中读取消息。该函数的第一个参数是待读取的邮箱,第二个参数是存储消息的缓冲区
* 的指针,第三个参数是要读取的消息的长度。该函数将返回一个表示操作结果的值。在这段代码中,
* 变量 retVal 将被用于存储该函数的返回值。
* 需要注意的是,在这段代码中,并没有进行任何多线程保护措施,因为该代码被假定只会从一个
* 单一的线程中被调用。如果有多个线程可能会同时访问同一个邮箱,那么就需要在访问邮箱的过程
* 中采取适当的同步措施来确保线程安全性 */
= Mailbox_read(gMmwMssMCB.peerMailbox, (uint8_t*)&message, sizeof(MmwDemo_message));
retVal if (retVal < 0)
{
/* Error: Unable to read the message. Setup the error code and return values */
("Error: Mailbox read failed [Error code %d]\n", retVal);
System_printf }
else if (retVal == 0)
{
/* We are done: There are no messages available from the peer execution domain. */
continue;
}
else
{
/* Flush out the contents of the mailbox to indicate that we are done with the message. This will
* allow us to receive another message in the mailbox while we process the received message. */
/* 刷新邮箱准备后续接收 */
(gMmwMssMCB.peerMailbox);
Mailbox_readFlush
/* Process the received message: */
/* 查看消息类型 */
switch (message.type)
{
/* 如果类型是 "MMWDEMO_DSS2MSS_DETOBJ_READY" */
case MMWDEMO_DSS2MSS_DETOBJ_READY:
/* Got detetced objectes , shipped out through UART */
/* 把接收到的数据中的大小信息提取出来,提取到下面这个变量中 */
.mssDataPathObj.inputInfoBuffSize = message.body.detObj.detObjOutsize;
gMmwMssMCB
/* 到共享内存中地址将检测的dsp处理好的数据拷贝到"gMmwMssMCB.mssDataPathObj.inputInfo"中*/
((void *)&(gMmwMssMCB.mssDataPathObj.inputInfo),
memcpy(uint8_t*)SOC_translateAddress(message.body.detObj.detObjOutAddress, SOC_TranslateAddr_Dir_FROM_OTHER_CPU,NULL),
.body.detObj.detObjOutsize);
message
/* 记录时间戳 */
= Cycleprofiler_getTimeStamp();
timeStart /* 当前时间花费在将处理结果从 DSP 中的共享内存复制到主机内存中的时间, 这里有点疑问, 为什么直接设置1和2 */
.mssDataPathObj.cycleLog.copyResultsTimeCurrInusec = 1.f;
gMmwMssMCB/* uart发送数据 */
();
MmwDemo_transmitProcessedOutput.mssDataPathObj.cycleLog.copyResultsTimeCurrInusec = 2.f;
gMmwMssMCB/* 计算发送时间 */
.mssDataPathObj.cycleLog.sendingToUARTTimeCurrInusec = ((float)(Cycleprofiler_getTimeStamp() - timeStart)/(float)R4F_CLOCK_MHZ);
gMmwMssMCB
/* Send a message to MSS to log the output data */
/* 清空message中的数据为后续重新接收做准备 */
((void *)&message, 0, sizeof(MmwDemo_message));
memset
/* 将消息设置为"MMWDEMO_MSS2DSS_DETOBJ_SHIPPED"为别的操作做准备 */
.type = MMWDEMO_MSS2DSS_DETOBJ_SHIPPED;
message
if (MmwDemo_mboxWrite(&message) != 0)
{
("Error: Mailbox send message id=%d failed \n", message.type);
System_printf }
break;
default:
{
/* Message not support */
("Error: unsupport Mailbox message id=%d\n", message.type);
System_printf break;
}
}
}
}
}
1.2 UART发送数据
这里就是接收到数据后,将数据赋值给mss的变量然后调整通信格式(按照TLV
的格式发送). TLV格式ti的文档中有说明. TLV format guide
/** @brief Transmits detection data over UART
*
* The following data is transmitted:
* 1. Header (size = 32bytes), including "Magic word", (size = 8 bytes)
* and icluding the number of TLV items
* TLV Items:
* 2. If detectedObjects flag is set, pbjOut structure containing range,
* doppler, and X,Y,Z location for detected objects,
* size = sizeof(objOut_t) * number of detected objects
* 3. If logMagRange flag is set, rangeProfile,
* size = number of range bins * sizeof(uint16_t)
* 4. If noiseProfile flag is set, noiseProfile,
* size = number of range bins * sizeof(uint16_t)
* 7. If rangeAzimuthHeatMap flag is set, the zero Doppler column of the
* range cubed matrix, size = number of Rx Azimuth virtual antennas *
* number of chirps per frame * sizeof(uint32_t)
* 8. If rangeDopplerHeatMap flag is set, the log magnitude range-Doppler matrix,
* size = number of range bins * number of Doppler bins * sizeof(uint16_t)
* 9. If statsInfo flag is set, the stats information
* @param[in] uartHandle UART driver handle
* @param[in] obj Pointer data path object MmwDemo_DataPathObj
*/
void MmwDemo_transmitProcessedOutput()
{
/* 创建header变量存储数据头(FrameHeader) */
;
MmwDemo_output_message_header header/* TLV的索引 */
uint32_t tlvIdx = 0;
uint32_t numPaddingBytes;
/* 数据包的长度信息 */
uint32_t packetLen;
/* 数据对齐填充的padding */
uint8_t padding[MMWDEMO_OUTPUT_MSG_SEGMENT_LEN];
/* 用来存放从mailBox接收到的数据头得信息 */
*ptrDetOutputHdr;
MmwDemo_detOutputHdr /* 用来存放从mailBox接收到的数据值部分 */
* outputData;
radarProcessOutput_t /* 设置T(ype)L(ength) */
[MMWDEMO_OUTPUT_MSG_MAX];
MmwDemo_output_message_tl tl/* 用来存放fft数据的长度 */
uint32_t fft1D_length;
/* 存数据对象从结构体中提取出来 */
*obj = &gMmwMssMCB.mssDataPathObj;
MmwDemo_MSS_DataPathObj /* 该变量决定什么变量发送给gui */
= gMmwMssMCB.cfg.guiMonSel;
MmwDemo_GuiMonSel guiMonSel /* 拿到mss的uart句柄 */
= gMmwMssMCB.loggingUartHandle;
UART_Handle uartHandle
/* 将数据放fft处理的header(chirp处理时间, 目标数据, frame处理时间, chirp处理时的负载,frame处理时的负载 ) */
= (MmwDemo_detOutputHdr *)&obj->inputInfo.header;
ptrDetOutputHdr /* 存放处理fft后存储的相位变化量, 最大的range,fft输出等信息 */
= (radarProcessOutput_t *)&obj->inputInfo.pointCloudBuf;
outputData /* 提取出1Dfft的长度信息 */
= outputData->fft1DSize;
fft1D_length
/* Clear message header */
/* 清空数据头, 重新构造数据头, 每一帧的数据都重新构造, 防止出现脏数据 */
((void *)&header, 0, sizeof(MmwDemo_output_message_header));
memset/* Header: */
.platform = 0xA1642;
header.magicWord[0] = 0x0102;
header.magicWord[1] = 0x0304;
header.magicWord[2] = 0x0506;
header.magicWord[3] = 0x0708;
header.numDetectedObj = 1;
header.version = MMWAVE_SDK_VERSION_BUILD | //DEBUG_VERSION
header(MMWAVE_SDK_VERSION_BUGFIX << 8) |
(MMWAVE_SDK_VERSION_MINOR << 16) |
(MMWAVE_SDK_VERSION_MAJOR << 24);
= sizeof(MmwDemo_output_message_header);
packetLen //detectedObjects
{
[tlvIdx].type = MMWDEMO_OUTPUT_MSG_DETECTED_POINTS;
tl[tlvIdx].length = sizeof(MmwDemo_detectedObj) * 1 +
tlsizeof(MmwDemo_output_message_dataObjDescr);
+= sizeof(MmwDemo_output_message_tl) + tl[tlvIdx].length;
packetLen ++;
tlvIdx}
//Range FFT input
if(guiMonSel.logRangeInput)
{
[tlvIdx].type = MMWDEMO_OUTPUT_MSG_RANGE_PROFILE;
tl[tlvIdx].length = 2 * sizeof(float) * fft1D_length;
tl+= sizeof(MmwDemo_output_message_tl) + tl[tlvIdx].length;
packetLen ++;
tlvIdx}
//statsInfo
{
[tlvIdx].type = MMWDEMO_OUTPUT_MSG_STATS;
tl[tlvIdx].length = sizeof(MmwDemo_output_message_stats);
tl+= sizeof(MmwDemo_output_message_tl) + tl[tlvIdx].length;
packetLen ++;
tlvIdx}
.numTLVs = tlvIdx;
header/* Round up packet length to multiple of MMWDEMO_OUTPUT_MSG_SEGMENT_LEN */
.totalPacketLen = MMWDEMO_OUTPUT_MSG_SEGMENT_LEN *
header((packetLen + (MMWDEMO_OUTPUT_MSG_SEGMENT_LEN-1))/MMWDEMO_OUTPUT_MSG_SEGMENT_LEN);
.timeCpuCycles = Pmu_getCount(0);
header.frameNumber = 0;
header
(uartHandle,
UART_writePolling (uint8_t*)&header,
sizeof(MmwDemo_output_message_header));
= 0;
tlvIdx /* Send detected Objects */
{
;
MmwDemo_output_message_dataObjDescr descr; //work around the current format
MmwDemo_detectedObj dummyDetectionOutint32_t tempRange;
((void *)&dummyDetectionOut, 0, sizeof(MmwDemo_detectedObj));
memset
= (int32_t)(outputData->rangeEst * 1048576.f);
tempRange
.dopplerIdx = 0;
dummyDetectionOut.peakVal = 0;
dummyDetectionOut.rangeIdx = (uint16_t) tempRange & 0xFFFF;
dummyDetectionOut.x = tempRange >> 16;
dummyDetectionOut.y = 0;
dummyDetectionOut.z = 0;
dummyDetectionOut
(uartHandle,
UART_writePolling (uint8_t*)&tl[tlvIdx],
sizeof(MmwDemo_output_message_tl));
/* Send objects descriptor */
.numDetetedObj = 1;
descr.xyzQFormat = 20;
descr(uartHandle, (uint8_t*)&descr, sizeof(MmwDemo_output_message_dataObjDescr));
UART_writePolling
/*Send array of objects */
(uartHandle, (uint8_t*)&dummyDetectionOut, sizeof(MmwDemo_detectedObj) * 1);
UART_writePolling ++;
tlvIdx}
/* Send Range FFT input */
if(guiMonSel.logRangeInput)
{
(uartHandle,
UART_writePolling (uint8_t*)&tl[tlvIdx],
sizeof(MmwDemo_output_message_tl));
(uartHandle, (uint8_t*)outputData->fft1Dinput, 2 * fft1D_length * sizeof(float));
UART_writePolling ++;
tlvIdx}
/* Send stats information */
{
;
MmwDemo_output_message_stats stats.interChirpProcessingMargin = (uint32_t) ptrDetOutputHdr->chirpProcessingMarginInUsec;
stats.interFrameProcessingMargin = (uint32_t) ptrDetOutputHdr->frameProcessingMarginInUsec;
stats.interFrameProcessingTime = 0;
stats.transmitOutputTime = (uint32_t) obj->cycleLog.sendingToUARTTimeCurrInusec;
stats.activeFrameCPULoad = (uint32_t) ptrDetOutputHdr->chirpProcessingLoading;
stats.interFrameCPULoad = (uint32_t) ptrDetOutputHdr->frameProcessingLoading;
stats
(uartHandle,
UART_writePolling (uint8_t*)&tl[tlvIdx],
sizeof(MmwDemo_output_message_tl));
(uartHandle,
UART_writePolling (uint8_t*)&stats,
[tlvIdx].length);
tl++;
tlvIdx}
/* Send padding bytes */
= MMWDEMO_OUTPUT_MSG_SEGMENT_LEN - (packetLen & (MMWDEMO_OUTPUT_MSG_SEGMENT_LEN-1));
numPaddingBytes if (numPaddingBytes<MMWDEMO_OUTPUT_MSG_SEGMENT_LEN)
{
(uartHandle,
UART_writePolling (uint8_t*)padding,
);
numPaddingBytes}
}
2. 液位数据处理部分
雷达前端接收数据, 然后将数据在dsp上处理
存储在L2内存中所有的控制结构体, 所有的操作都是基于该结构体进行展开的
typedef struct _RADARDEMO_highAccuRangeProc_handle_
{
float * twiddle; /**< 1DFFT使用的扭曲因子。*/
float * wnCoarse; /**< 粗级别的频率扭曲因子。*/
float * wnFine; /**< 细级别的频率扭曲因子。*/
float * inputSig; /**< 用于累加帧内所有chirp信号 的缓冲区。( 累加一帧内所有chirp的信号,最后进行一个加窗操作,结果存放在这个变量中 )*/
float * demodSig; /**< 指向相位解调信号的指针。*/
float * scratchPad; /**< 模块的缓存内存。*/
float * fft1DOutSig; /**< 指向1D FFT输出信号的指针。*/
float maxBeatFreq; /**< 最大拍频。*/
float chirpBandwidth; /**< chirp带宽。*/
float chirpRampTime; /**< chirp斜坡时间。*/
float fc; /**< chirp起始频率。*/
float chirpSlope; /**< chirp斜率。*/
float adcStartTimeConst; /**< ADC启动时间常量。*/
float adcSampleRate; /**< ADC采样率。*/
int32_t coarseRangeInd; /**< 粗略频率估计的索引。*/
uint32_t fft1DSize; /**< 1D FFT大小。*/
uint32_t log2fft1DSize; /**< 1D FFT大小的log2值。*/
uint32_t nSamplesPerChirp; /**< 每个chirp中的采样数。*/
uint32_t numChirpsPerFrame; /**< 每帧中的chirp数。*/
float * win1D; /**< 指向1D窗函数的指针。*/
int16_t win1DLength; /**< 1D窗函数的一半长度。*/
uint8_t numRangeBinZoomIn; /**< 用于频率估计缩小范围的bin数。*/
uint8_t enablePhaseEst; /**< 启用相位校正进行估计。*/
uint8_t enableLinearFit; /**< 在相位估计中启用线性拟合。*/
uint8_t enableFilter; /**< 在相位估计中启用滤波。*/
uint16_t skipLeft; /**< 从左侧跳过的样本数。*/
uint16_t skipRight; /**< 从右侧跳过的样本数。*/
float skipMin; /* 从0到最小范围(m)要跳过的样本数 */
float skipMax; /* 从最大范围(m)到远处要跳过的样本数 */
} RADARDEMO_highAccuRangeProc_handle;
雷达配置配置结构体, 雷达所有的相关配置都在这个结构体中, 主要的处理操作是将该配置结构体传递到上面的控制结构体中. 然后进行相关操作. 这大大降低了代码的耦合性.
typedef struct _RADARDEMO_highAccuRangeProc_config_
{
uint32_t fft1DSize; /**< 1D FFT size, 一维FFT的大小*/
uint32_t nSamplesPerChirp; /**< number of samples per chirp, 每个chirp中的采样点数*/
uint32_t numChirpsPerFrame; /**< number of chirp per frame, 每帧中的chirp数量*/
float maxBeatFreq; /**< maximum beat frequency, 最大拍频*/
float chirpBandwidth; /**< chirp bandwidth, chirp带宽*/
float chirpRampTime; /**< chirp ramp duration, chirp的斜变时间*/
float fc; /**< chirp start frequency, chirp的起始频率*/
float chirpSlope; /**< chirp slope, chirp的斜率*/
float adcStartTimeConst; /**< ADC start constant, ADC启动常数*/
float adcSampleRate; /**< ADC sampling rate, ADC采样率*/
float *win1D; /**< pointer to 1D windowing function, 指向一维窗函数的指针*/
int16_t win1DLength; /**< half length of the 1D windowing function, 一维窗函数的一半长度*/
uint8_t numRangeBinZoomIn; /**< number of bins to zoom in for frequenc estimation,进行频率估计的缩放的范围*/
uint8_t enablePhaseEst; /**< enable estimation using phase correction, 使用相位校正进行估计的开关*/
uint8_t enableLinearFit; /**< enable linear fit in phase estimation, 在相位估计中开启线性拟合*/
uint8_t enableFilter; /**< enable filtering in phase estimation, 在相位估计中开启滤波*/
uint16_t skipLeft; /**< number of samples to skip from the left, 从左侧跳过的样本数*/
uint16_t skipRight; /**< number of samples to skip from the right, 从右侧跳过的样本数*/
float *fft1DIn; /**< pointer to 1D FFT input, 指向一维FFT输入的指针*/
uint8_t enableRangeLimit; /**< enable RangeLimit, 开启范围限制*/
float skipMin; /**< number of samples to skip from 0 to min range(m), 从0到最小范围跳过的样本数(米)*/
float skipMax; /**< number of samples to skip from the max range(m) to faraway,从最大范围(米)到远处跳过的样本数*/
} RADARDEMO_highAccuRangeProc_config;
2.1 创建和初始化 液位高度Demo
调制斜率为handle->chirpSlope、1D FFT尺寸为handle->fft1DSize时的距离分辨率。距离分辨率是雷达测距系统中的一个参数,表示能够分辨出两个物体之间的最小距离。
距离分辨率公式
其中,\(\Delta r\)为距离分辨率,\(c\)为光速,\(B\)为调制带宽,\(N\)为FFT点数。在代码中,将光速\(c\)和调制带宽\(B\)用常数3.0e8
和handle->adcSampleRate
表示,FFT点数\(N\)用handle->fft1DSize表示。将这些参数代入距离分辨率公式计算即可.
src: RADARDEMO_highAccuRangeProc.c
void * RADARDEMO_highAccuRangeProc_create(
* moduleConfig,
IN RADARDEMO_highAccuRangeProc_config * errorCode)
OUT RADARDEMO_highAccuRangeProc_errorCode
{
int32_t i, itemp;
double real, imag;
double PI = 3.14159265358979323846;
double denom;
uint8_t enableRangeLimit;
float skipMin;
float skipMax;
float rangeResolution;
* handle;
RADARDEMO_highAccuRangeProc_handle
*errorCode = RADARDEMO_HIGHACCURANGEPROC_NO_ERROR;
= (RADARDEMO_highAccuRangeProc_handle *) radarOsal_memAlloc((uint8_t) RADARMEMOSAL_HEAPTYPE_LL2, 0, sizeof(RADARDEMO_highAccuRangeProc_handle), 1);
handle if (handle == NULL)
{
*errorCode = RADARDEMO_HIGHACCURANGEPROC_FAIL_ALLOCATE_HANDLE;
return (handle);
}
->nSamplesPerChirp = moduleConfig->nSamplesPerChirp;//512
handle->fft1DSize = moduleConfig->fft1DSize;//512
handle->numChirpsPerFrame = moduleConfig->numChirpsPerFrame;//200
handle->win1DLength = moduleConfig->win1DLength;//16
handle->maxBeatFreq = moduleConfig->maxBeatFreq;//5000k
handle->chirpBandwidth = moduleConfig->chirpBandwidth;//3450805504Hz
handle->chirpRampTime = moduleConfig->chirpRampTime;//102.4us
handle->fc = moduleConfig->fc;//77GHz
handle->chirpSlope = moduleConfig->chirpSlope;//33.699MHz/us
handle->adcStartTimeConst = moduleConfig->adcStartTimeConst;//0
handle->adcSampleRate = moduleConfig->adcSampleRate;//500K
handle->numRangeBinZoomIn = moduleConfig->numRangeBinZoomIn;//2
handle->enablePhaseEst = moduleConfig->enablePhaseEst;//0
handle->enableLinearFit = moduleConfig->enableLinearFit;//0
handle->enableFilter = moduleConfig->enableFilter;//0
handle->skipLeft = moduleConfig->skipLeft;//0
handle->skipRight = moduleConfig->skipRight;//0
handle= moduleConfig->enableRangeLimit;//0
enableRangeLimit = moduleConfig->skipMin;//0.26
skipMin = moduleConfig->skipMax;//6.00
skipMax = handle->fft1DSize;
itemp = 0;
i
/* 计算距离分辨率 */
= (3.0*1e8) * (float)handle->adcSampleRate/(2 * (float)handle->chirpSlope * (float)handle->fft1DSize);//0.043468
rangeResolution
// printf("DSS:win1DLength=%d\n",handle->fft1DSize);
// printf("DSS:digOutSampleRate=%f\n",handle->adcSampleRate);
// printf("DSS:freqSlopeConst=%f\n",handle->chirpSlope);
// printf("DSS:rangeResolution=%f\n",rangeResolution);
uint16_t RangeBinfft1DSize,RangeBinMin,RangeBinMax;
/* 如果设置距离限制值 */
if(enableRangeLimit)
{
/* fft大小:512, 这里根据限制的距离范围进一步限制处理数据, 提高数据处理的效率 */
= handle->fft1DSize;
RangeBinfft1DSize /* 对计算出的rangebin进行四舍五入 */
= (uint16_t)(skipMin/rangeResolution + 0.5);
RangeBinMin = (uint16_t)(skipMax/rangeResolution + 0.5);
RangeBinMax
/* 如果rangebin下溢就设置为0 */
if(RangeBinMin > RangeBinfft1DSize)
= 0;
RangeBinMin /* 如果rangebin上溢就设置为rangebin最大值 */
if(RangeBinMax > RangeBinfft1DSize)
= RangeBinfft1DSize;
RangeBinMax
/* 限制的rangeBin左右区间 */
->skipLeft = RangeBinMin;//6
handle->skipRight = RangeBinfft1DSize - RangeBinMax;//374
handle
("DSS:enableRangeLimit=%d,skipMin=%.2f,skipMax=%.2f,rangeResolution=%.4f,skipLeft=%d,skipRight=%d\n",enableRangeLimit,skipMin,skipMax,rangeResolution,handle->skipLeft,handle->skipRight);
printf}
else
{
("DSS:enableRangeLimit=%d\n",enableRangeLimit);
printf
}
/* 同价itemp在二进制格式下有多少个1, 然后存储在i变量中 */
while(1)
{
if(itemp == 1) break;
= itemp >> 1;
itemp ++;
i}
/* fft级联次数log2(64)=6 */
->log2fft1DSize = i;
handle
/* 在L2内存中申请一块`窗`句柄空间 */
->win1D = (float *) radarOsal_memAlloc((uint8_t) RADARMEMOSAL_HEAPTYPE_LL2, 0, moduleConfig->win1DLength * sizeof(float), 8);
handle/* 返回错误码 */
if (handle->win1D == NULL)
{
*errorCode = RADARDEMO_HIGHACCURANGEPROC_FAIL_ALLOCATE_LOCALINSTMEM;
return (handle);
}
/* 拿到dss_data_path中的窗参数 */
for (i = 0; i < (int32_t)moduleConfig->win1DLength; i++ )
{
->win1D[i] = moduleConfig->win1D[i];
handle}
/* 首先在内存中为handle->twiddle(旋转因子, 为fft做准备)分配一块空间,大小为2 * handle->fft1DSize *sizeof(float) */
->twiddle = (float *)radarOsal_memAlloc((uint8_t) RADARMEMOSAL_HEAPTYPE_LL2, 0, 2 * handle->fft1DSize * sizeof(float), 8);
handle/* 判断并返回错误码 */
/* 调用tw_gen_float函数生成1D FFT所需的旋转因子,存储在handle->twiddle中,旋转因子可以用于快速傅里叶变换(FFT)算法,它能够快速地将时域采样转换为频域信号 */
(handle->twiddle, handle->fft1DSize);
tw_gen_float
/* 为即将做fft的输入信号(数据)申请空间 */
->inputSig = (float *)radarOsal_memAlloc((uint8_t) RADARMEMOSAL_HEAPTYPE_LL2, 0, 2 * handle->fft1DSize * sizeof(float), 8);
handle/* 判断并返回错误码 */
/* 在L2中申请内存, 用作傅里叶变换运算过程中的中间计算结果 */
->scratchPad = (float *)radarOsal_memAlloc((uint8_t) RADARMEMOSAL_HEAPTYPE_LL2, 1, 2 * 2 * handle->fft1DSize * sizeof(float), 8);
handle/* 判断并返回错误码 */
/* `FFT1D输出结果` 和 `相位解调`的结果都存放在缓冲scratchPad变量中 */
->fft1DOutSig = handle->scratchPad;
handle/* 相位解调:将调制信号从复数域映射到实数域,并通过这种映射 `去除相位信息`。在解调之后,得到的信号 `只包含振幅信息` */
->demodSig = handle->scratchPad;
handle
/* 将所有的fft原始数据放到 `fft1DIn` 这个指针变量中带回去 */
->fft1DIn = handle->inputSig;
moduleConfig
/* 分配一块内存,用于存储 `粗` 调的旋转因子(wnCoarse) */
->wnCoarse = (float *)radarOsal_memAlloc((uint8_t) RADARMEMOSAL_HEAPTYPE_LL2, 0, 2 * handle->fft1DSize * sizeof(float), 8);
handle
/* 生成一组用于傅里叶变换的`粗`调旋转因子, 存储在 `wnCoarse` 中 */
= 1.0/((double)handle->fft1DSize);
denom for (i = 0; i < (int32_t)handle->fft1DSize; i++)
{
= cos(-2 * PI * i *denom);
real = sin(-2 * PI * i *denom);
imag ->wnCoarse[2*i] = imag;
handle->wnCoarse[2*i+ 1 ] = real;
handle}
/* 分配一块内存,用于存储 `细` 调的旋转因子(wnCoarse) */
->wnFine = (float *)radarOsal_memAlloc((uint8_t) RADARMEMOSAL_HEAPTYPE_LL2, 0, 2 * handle->fft1DSize * sizeof(float), 8);
handle
/* 用于生成一组用于傅里叶变换的`细`调旋转因子, 存储在 `wnFine` 中 */
= 1.0/ ((double)(handle->fft1DSize * handle->fft1DSize)); // 将旋转因子限制在单位圆上
denom for (i = 0; i < (int32_t)handle->fft1DSize; i++)
{
= cos(-2 * PI * i *denom);
real = sin(-2 * PI * i *denom);
imag ->wnFine[2*i] = imag;
handle->wnFine[2*i+ 1 ] = real;
handle}
return((void *)handle);
}
2.2 释放所创建时申请的内存空间
/* 释放所有申请额空间 */
void RADARDEMO_highAccuRangeProc_delete(
void * handle)
IN {
*rangeProcInst;
RADARDEMO_highAccuRangeProc_handle
= (RADARDEMO_highAccuRangeProc_handle *) handle;
rangeProcInst
(rangeProcInst->inputSig, rangeProcInst->fft1DSize * 2 * sizeof(float));
radarOsal_memFree(rangeProcInst->twiddle, rangeProcInst->fft1DSize * 2 * sizeof(float));
radarOsal_memFree(rangeProcInst->wnFine, rangeProcInst->fft1DSize * 2 * sizeof(float));
radarOsal_memFree(rangeProcInst->wnCoarse, rangeProcInst->fft1DSize * 2 * sizeof(float));
radarOsal_memFree(rangeProcInst->win1D, rangeProcInst->win1DLength * 2 * sizeof(float));
radarOsal_memFree(rangeProcInst->demodSig, rangeProcInst->nSamplesPerChirp * 2 * sizeof(float));
radarOsal_memFree
(handle, sizeof(RADARDEMO_highAccuRangeProc_handle));
radarOsal_memFree}
2.3 运行
“est” 是 “estimate” 的缩写,表示估计值。在这个函数中, “estRange” 表示范围估计值, “deltaPhaseEst” 表示相位差估计值, “estLinearSNR” 表示线性信噪比估计值。
对输入信号进行高精度的距离处理。
通过 handle
参数转换得到 rangeProcInst
。检查 inputSignal
和 win1D
是否为空,若为空则返回错误码。
接下来通过 rangeProcInput
参数获取 chirpNum
,如果 chirpNum >= 0
,则调用 RADARDEMO_highAccuRangeProc_accumulateInput
函数进行多普勒累积,并转换到浮点数。
否则调用 RADARDEMO_highAccuRangeProc_rangeEst
函数进行距离估计,并将结果存储在 rangeProcOutput
参数中。
最后返回错误码
(
RADARDEMO_highAccuRangeProc_errorCode RADARDEMO_highAccuRangeProc_runvoid * handle,
IN * rangeProcInput,
IN RADARDEMO_highAccuRangeProc_input * rangeProcOutput)
OUT RADARDEMO_highAccuRangeProc_output
{
/* chirp数 */
int32_t chirpNum;
/* 该函数的操作句柄 */
*rangeProcInst;
RADARDEMO_highAccuRangeProc_handle /* 存放原始ADC数据 */
* inputSignal;
cplx16_t /* 设置错误码: 没有错误 */
= RADARDEMO_HIGHACCURANGEPROC_NO_ERROR;
RADARDEMO_highAccuRangeProc_errorCode errorCode
/* 拿到传递过来的原始ADC数据放到inputSignal中 */
= rangeProcInput->inputSignal;
inputSignal /* 拿到传递过来的句柄(操作对象) */
= (RADARDEMO_highAccuRangeProc_handle *) handle;
rangeProcInst
/* 判断是否接收到, 没有接收到数据就将状态码设置为xxx */
if (inputSignal == NULL)
= RADARDEMO_HIGHACCURANGEPROC_INOUTPTR_NOTCORRECT;
errorCode
if (rangeProcInst->win1D == NULL)
= RADARDEMO_HIGHACCURANGEPROC_INOUTPTR_NOTCORRECT;
errorCode
/* 如果存在错误,直接返回状态码, 结束该函数 */
if (errorCode > RADARDEMO_HIGHACCURANGEPROC_NO_ERROR)
return(errorCode);
/* 没有错误的处理 */
/* 拿到chirp数 */
= (int32_t) rangeProcInput->chirpNumber;
chirpNum /* 如果chirp数大于=0, 进行chirp信号累加和加窗操作(先累加, 最后加窗), interframe中会将chirpNum设置为`-1000`,这代表一帧的数据结束 */
if (chirpNum >= 0)
{ /*accumulating all the chirps and convert to float*/
/* 进行chirp信号累加和加窗操作(先累加, 最后加窗) */
(
RADARDEMO_highAccuRangeProc_accumulateInput->nSamplesPerChirp,
rangeProcInst->fft1DSize,
rangeProcInst->numChirpsPerFrame,
rangeProcInst->win1D,
rangeProcInst->win1DLength,
rangeProcInst->inputSignal,
rangeProcInput,
chirpNum->inputSig);
rangeProcInst
}
/* 所有的chirp接收完了, 进行距离估计 */
else
{
/* range measurements*/
(
RADARDEMO_highAccuRangeProc_rangeEst,
rangeProcInst&(rangeProcOutput->rangeEst),
&(rangeProcOutput->deltaPhaseEst),
&(rangeProcOutput->linearSNREst));
}
/* 返回状态码 */
return(errorCode);
}
2.3.1 累加一帧内所有chirp的信号并加窗
if
是格式转换, else
是chirp累加和加窗. 通过加窗和累加输入数据,实现了去除直流分量的效果。
void RADARDEMO_highAccuRangeProc_accumulateInput(
uint32_t nSamplesPerChirp, // 单个chirp中采样点数目
IN uint32_t fftSize1D, // 一维FFT点数
IN uint32_t nChirpPerFrame, // 每个帧的chirp数目
IN float * RESTRICT fftWin1D, // 一维FFT窗口函数
IN int16_t fftWin1DSize, // 一维FFT窗口函数大小
IN * RESTRICT inputPtr, // 采集数据指针
IN cplx16_t int32_t chirpInd, // 当前chirp index
IN float * outputPtr) // 输出数据指针
OUT {
if(procStep != 0)
{
return;
}
int32_t i, itemp;
int64_t input;
/* 判断所有的chirp索引是不是0, 如果是0 */
if (chirpInd == 0)
{
// nSamplesPerchir是配置文件中的 `numAdcSamples` 这个值是采样的点数(假设这个值是256: 因为一个复数采样点包含两个实数采样点, 所以要除以二, 右移1位就是除以2,那就每个点进行递增 )
/* 右移一位相当于将其除以2,这是因为每个复数采样点包含两个实数采样点,而这段代码的目的是将复数形式的采样点转换为实数形式的采样点,所以需要将采样点数除以2 ,因此循环条件中使用了右移运算符 >>,这也是一种常见的快速除以2的方法*/
/* 将输入数据从Q15格式转换为IEEE-754格式的浮点数,并按照一定的规则存储到输出数组中 */
for( i = 0; i < ((int32_t)nSamplesPerChirp>> 1); i++)
{
/* 拿到inputPtr中的数据地址, 然后将该地址存储在input中, input的大小为64bit,一个复数结构(float(32)+float(32)) */
= _amem8(&inputPtr[2 * i]);
input /* `_ftof2`是一个DSP库函数,用于将两个32位浮点数打包成一个64位浮点数,
float64_t _ftof2(float32_t a, float32_t b);
其中,a和b分别是要打包的两个32位浮点数。函数的返回值是一个64位浮点数,由a和b的位构成
(float)_ext(_loll(input), 16, 16)提取了input的低32位中的高16位,并将结果强制转换成32位浮点数.
(float)_ext(_loll(input), 0, 16)提取了input的低32位中的低16位,并将结果强制转换成32位浮点数
--------------------------------------------------------------------------------
将16是因为adc采样的数据是16位采样, 所以这里的操作是将adc的采样数据转换为32位float类型,然后按照采样点进行拼凑, 一个采样点由2个数组成(实部虚部,各占一个flot, 所以是2个float, 这里实际上就是将ADC采样的Q格式数据转换为complex格式(real+image))
*/
/* 这里实际上就是一个complex格式的采样点 */
/* _loll: 用于提取一个64位整数中低32位 */
/* _ext(x, 0, 16)表示提取x中的 高 16位作为输出 */
/* _ext(x, 16, 16)表示提取x中的 低 16位作为输出 */
/* _ext(x, msb, lsb)表示将32位整数x中的第msb到第lsb位(包括msb和lsb)提取出来组成一个新的32位整数. */
(&outputPtr[4*i]) = _ftof2((float)_ext(_loll(input), 16, 16), (float)_ext(_loll(input), 0, 16)); // 实部 将复数的实部转换为浮点数的高16位,将虚部转换为浮点数的低16位,然后存储在outputPtr数组中,
_amem8_f2(&outputPtr[4*i + 2]) = _ftof2((float)_ext(_hill(input), 16, 16), (float)_ext(_hill(input), 0, 16)); // 虚部
_amem8_f2}
/* 如果采样点是奇数, 那么Q格式中只有 */
if((int32_t)nSamplesPerChirp & 1)
{
/* 在这种情况下,最后一个采样点只有一个float存储,而不是两个 */
= _amem4(&inputPtr[nSamplesPerChirp - 1]);
itemp (&outputPtr[2*(nSamplesPerChirp - 1)]) = _ftof2((float)_ext(itemp, 16, 16), (float)_ext(itemp, 0, 16));
_amem8_f2}
}
/* 如果不是第一个chirp的话, (主要目的是为了去除直流分量) */
else
{
/* 将每个输入数据的实部和虚部累加到输出数组的对应位置上 */
for( i = 0; i < ((int32_t)nSamplesPerChirp>> 1); i++)
{
= _amem8(&inputPtr[2 * i]);
input (&outputPtr[4*i]) = _daddsp(_amem8_f2(&outputPtr[4*i]), _ftof2((float)_ext(_loll(input), 16, 16), (float)_ext(_loll(input), 0, 16)));
_amem8_f2(&outputPtr[4*i + 2]) = _daddsp(_amem8_f2(&outputPtr[4*i + 2]), _ftof2((float)_ext(_hill(input), 16, 16), (float)_ext(_hill(input), 0, 16)));
_amem8_f2}
// 如果样本数为奇数,则处理最后一个样本, 内存对齐, 奇数只保留一个float
if((int32_t)nSamplesPerChirp & 1)
{
= _amem4(&inputPtr[nSamplesPerChirp - 1]);
itemp (&outputPtr[2*(nSamplesPerChirp - 1)]) = _daddsp(_amem8_f2(&outputPtr[2*(nSamplesPerChirp - 1)]), _ftof2((float)_ext(itemp, 16, 16), (float)_ext(itemp, 0, 16)));
_amem8_f2}
// 如果是每帧的最后一个 chirp,则需要进行窗函数操作
if (chirpInd == ((int32_t)nChirpPerFrame - 1))
{
;
__float2_t f2win1D// 如果是每帧的最后一个 chirp,则需要进行窗函数操作
/* 将加窗后的数据分别乘以窗函数并存回 outputPtr 数组中 */
for( i = 0; i < fftWin1DSize; i++)
{
= _ftof2(fftWin1D[i], fftWin1D[i]);
f2win1D (&outputPtr[2*i]) = _dmpysp(_amem8_f2(&outputPtr[2*i]), f2win1D);
_amem8_f2(&outputPtr[2*(nSamplesPerChirp - i - 1)]) = _dmpysp(_amem8_f2(&outputPtr[2*(nSamplesPerChirp - i - 1)]), f2win1D);
_amem8_f2}
// 如果一个 chirp 中的样本点数 nSamplesPerChirp 小于 FFT 点数 fftSize1D,则将 outputPtr 数组中多余的部分填充为 0
if (((int32_t)fftSize1D - (int32_t)nSamplesPerChirp) > 0)
{
// 对多余部分进行填零操作
for( i = 0; i < ((int32_t)fftSize1D - (int32_t)nSamplesPerChirp); i++);
{
(&outputPtr[2*nSamplesPerChirp + 2*i]) = _ftof2(0.f, 0.f);
_amem8_f2}
}
}
}
}
2.3.2 测距
void RADARDEMO_highAccuRangeProc_rangeEst(
*highAccuRangeHandle, // 输入参数:高精度测距处理的句柄
IN RADARDEMO_highAccuRangeProc_handle float * estRange, // 输出参数:估计的距离
OUT float * deltaPhaseEst, // 输出参数:估计的相位偏移量
OUT float * estLinearSNR) // 输出参数:估计的线性信噪比
OUT {
int32_t i, j, k, rad1D, coarseRangeInd;
unsigned char * brev = NULL;
float totalPower, max, ftemp, sigPower, * RESTRICT powerPtr;
, * RESTRICT inputPtr, * RESTRICT inputPtr1;
__float2_t f2input
int32_t zoomStartInd, zoomEndInd, itemp, tempIndFine1, tempIndFine2, tempIndCoarse, indMask, shift;
int32_t fineRangeInd, tempFineSearchIdx, tempCoarseSearchIdx;
*RESTRICT wncPtr, wncoarse, *RESTRICT wnfPtr, wnfine1, sigAcc, f2temp;
__float2_t double freqFineEst, fdelta, interpIndx;
float currP, prevP, maxPrevP, maxNextP;
= 30 - _norm(highAccuRangeHandle->fft1DSize);
j if ((j & 1) == 0)
= 4;
rad1D else
= 2;
rad1D
/* copy to scratch is needed because FFT function will corrupt the input. We need to preserve if for zoom-in FFT */
/* 这段注释的意思是,将输入的数据先复制到缓冲区(scratch)中,因为进行 FFT 运算时会破坏原始输入数据。此处需要保留原始输入数据以便进行后续的 "zoom-in FFT" 运算 */
/* inputPtr指向高精度测距模块的输入数据,而inputPtr1指向临时缓冲区的起始位置,每次循环将inputPtr指向的输入数据复制到inputPtr1所指向的位置,
同时重新排列为实部和虚部交替存储的形式。最终,输入数据的实部和虚部交替存储的形式将存储在高精度测距模块的输入数据中。
这个过程的原因是因为FFT算法对于实数输入和复数输入的计算方式不同,需要将实数输入转化为复数输入进行计算。
==> (将高精度测距模块的输入数据复制到一个临时的缓冲区,并将输入数据重新排列为实部和虚部交替存储的形式,以便后续进行一维FFT操作)*/
= (__float2_t *) highAccuRangeHandle->inputSig;
inputPtr = (__float2_t *) &highAccuRangeHandle->scratchPad[2 * highAccuRangeHandle->fft1DSize];
inputPtr1 for (i = 0; i < (int32_t)highAccuRangeHandle->fft1DSize; i++ )
{
= _amem8_f2(inputPtr);
f2input (inputPtr1++) = f2input;
_amem8_f2(inputPtr) = _ftof2(_lof2(f2input), _hif2(f2input));
_amem8_f2++;
inputPtr}
/* 重新 `inputPtr1` 指向首地址 */
= (__float2_t *) &highAccuRangeHandle->scratchPad[2 * highAccuRangeHandle->fft1DSize];
inputPtr1 /* 第一次 fft 运算,
函数 DSPF_sp_fftSPxSP() 将 inputPtr1 指针指向的一维数组进行FFT变换,
并将结果存储在 `highAccuRangeHandle->fft1DOutSig` 指针指向的一维数组中。
*/
(
DSPF_sp_fftSPxSP ->fft1DSize,
highAccuRangeHandle(float*) inputPtr1,
(float *)highAccuRangeHandle->twiddle,
->fft1DOutSig,
highAccuRangeHandle,
brev,
rad1D0,
->fft1DSize);
highAccuRangeHandle
/* 排除的距离 */
for( i = 0; i < (int32_t)highAccuRangeHandle->skipLeft; i++ )
{
(&highAccuRangeHandle->fft1DOutSig[2*i]) = _ftof2(0.f, 0.f);
_amem8_f2}
for( i = (int32_t)highAccuRangeHandle->fft1DSize- (int32_t)highAccuRangeHandle->skipRight; i < (int32_t)highAccuRangeHandle->fft1DSize; i++ )
{
(&highAccuRangeHandle->fft1DOutSig[2*i]) = _ftof2(0.f, 0.f);
_amem8_f2}
/* 存储最大距离和能量和 */
= 0.f;
max = 0.f;
totalPower = 0;
coarseRangeInd = (__float2_t *)highAccuRangeHandle->fft1DOutSig;
inputPtr = (float *)highAccuRangeHandle->scratchPad;
powerPtr /* 对FFT输出进行 功率计算 和 峰值检测
- 循环遍历FFT输出,对每个复数幅度计算其平方得到该频率点的功率。
- 将每个频率点的功率累加到totalPower变量中。
- 判断当前频率点的功率是否为历史最大值,如果是,则更新max和coarseRangeInd变量,
其中coarseRangeInd表示粗估的目标距离在FFT输出中的索引。
*/
for( i = 0; i < (int32_t)highAccuRangeHandle->fft1DSize; i++ )
{
= _amem8_f2(inputPtr++);
f2input = _dmpysp(f2input, f2input);
f2input = _hif2(f2input) + _lof2(f2input);
ftemp [i] = ftemp;
powerPtr+= ftemp;
totalPower if( max < ftemp )
{
= ftemp;
max = i;
coarseRangeInd }
}
= coarseRangeInd;
i = powerPtr[i-2] + powerPtr[i-1] + powerPtr[i] + powerPtr[i+1] + powerPtr[i+2];
sigPower
*estLinearSNR = divsp((float)((int32_t)highAccuRangeHandle->fft1DSize - (int32_t)highAccuRangeHandle->skipLeft - (int32_t)highAccuRangeHandle->skipRight- 5) * sigPower, (totalPower - sigPower));
/* zoom in FFT: assuming always size of fft1DSize x fft1DSize */
= coarseRangeInd - highAccuRangeHandle->numRangeBinZoomIn;
zoomStartInd = coarseRangeInd + highAccuRangeHandle->numRangeBinZoomIn;
zoomEndInd = highAccuRangeHandle->fft1DSize - 1;
indMask = 30 - _norm(highAccuRangeHandle->fft1DSize);
shift = (__float2_t *)highAccuRangeHandle->inputSig;
inputPtr = (__float2_t *)highAccuRangeHandle->wnCoarse;
wncPtr = (__float2_t *)highAccuRangeHandle->wnFine;
wnfPtr = 0.f;
max = 0;
itemp = 0.f;
currP = 0.f;
prevP = 0.f;
maxNextP = 0.f;
maxPrevP for( i = zoomStartInd; i < zoomEndInd; i++)
{
for( j = 0; j < (int32_t)highAccuRangeHandle->fft1DSize; j ++)
{
= j;
tempFineSearchIdx = _ftof2(0.f, 0.f);
sigAcc = 0;
tempCoarseSearchIdx #ifdef _TMS320C6X
#pragma UNROLL(2);
#endif
for( k = 0; k < (int32_t)highAccuRangeHandle->nSamplesPerChirp; k ++)
{
= tempFineSearchIdx & indMask;
tempIndFine1 = tempFineSearchIdx >> shift;
tempIndFine2 += j;
tempFineSearchIdx = (tempCoarseSearchIdx + tempIndFine2) & indMask;
tempIndCoarse += i;
tempCoarseSearchIdx
= _amem8_f2(&inputPtr[k]);
f2input = _amem8_f2(&wncPtr[tempIndCoarse]);
wncoarse = _amem8_f2(&wnfPtr[tempIndFine1]);
wnfine1
= _complex_mpysp(f2input, wnfine1);
f2temp = _complex_mpysp(f2temp, wncoarse);
f2temp = _daddsp(sigAcc, f2temp);
sigAcc #endif
}
= currP;
prevP = _dmpysp(sigAcc,sigAcc);
f2temp = _hif2(f2temp) + _lof2(f2temp);
ftemp = ftemp;
currP if( max < ftemp)
{
= ftemp;
max = itemp;
fineRangeInd = prevP;
maxPrevP }
if(itemp == fineRangeInd + 1)
= currP;
maxNextP ++;
itemp}
}
= 0.5 * divdp((double)maxPrevP - (double)maxNextP, (double)maxPrevP + (double)maxNextP -2.0 * (double) max);
interpIndx
= divdp((double)highAccuRangeHandle->maxBeatFreq, (double)highAccuRangeHandle->fft1DSize * (double)highAccuRangeHandle->fft1DSize);
fdelta = fdelta * ((double)(zoomStartInd * highAccuRangeHandle->fft1DSize + fineRangeInd) + interpIndx);
freqFineEst
*estRange = (float)divdp(freqFineEst * 3.0e8 * (double)highAccuRangeHandle->chirpRampTime, (2.0 * (double)highAccuRangeHandle->chirpBandwidth));
if (highAccuRangeHandle->enablePhaseEst)
{
float phaseCoarseEst1, phaseCoarseEst2, phaseInitial;
double PI = 3.14159265358979323846f;
double real, imag, denom, initReal, initImag, dtemp1, dtemp2, dtemp;
float phaseEst, totalPhase = 0.f, phaseCorrection, rangePhaseCorrection;
, corrSig;
__float2_t demodSig
= (__float2_t *)highAccuRangeHandle->inputSig;
inputPtr = 2 * (float)PI * highAccuRangeHandle->fc * (divsp(2 * (*estRange), (float)3e8) + highAccuRangeHandle->adcStartTimeConst);
phaseCoarseEst1 = (float)PI * highAccuRangeHandle->chirpSlope * (divsp(2 * (*estRange), (float)3e8) + highAccuRangeHandle->adcStartTimeConst) * (divsp(2 * (*estRange), (float)3e8) + highAccuRangeHandle->adcStartTimeConst);
phaseCoarseEst2 = phaseCoarseEst1 - phaseCoarseEst2;
phaseInitial
= divdp(1.0, (double)highAccuRangeHandle->fft1DSize);
denom
= cosdp_i((double)phaseInitial);
dtemp1 = sindp_i(-(double)phaseInitial);
dtemp2 = cosdp_i(2.0 * PI * highAccuRangeHandle->chirpRampTime * (double) freqFineEst * denom) ;
initReal = sindp_i(-2.0 * PI * highAccuRangeHandle->chirpRampTime * (double) freqFineEst * denom);
initImag #endif
//sample @ t = 0;
= _ftof2((float)dtemp1, (float)dtemp2);
corrSig = _complex_mpysp(_amem8_f2(inputPtr++), corrSig);
demodSig ((cplxf_t *)&demodSig, &phaseEst);
RADARDEMO_atan+= phaseEst;
totalPhase
if ((highAccuRangeHandle->enableFilter == 0) && (highAccuRangeHandle->enableLinearFit == 0))
{
//sample @ t = 1;
= dtemp1 * initReal - dtemp2 * initImag;
dtemp = dtemp1 * initImag + dtemp2 * initReal;
imag = dtemp;
real = _ftof2((float)real, (float)imag);
corrSig = _complex_mpysp(_amem8_f2(inputPtr++), corrSig);
demodSig ((cplxf_t *)&demodSig, &phaseEst);
RADARDEMO_atan+= phaseEst;
totalPhase
for( j = 2; j < (int32_t)highAccuRangeHandle->fft1DSize; j ++)
{
= real * initReal - imag * initImag;
dtemp = real * initImag + imag * initReal;
imag = dtemp;
real = _ftof2((float)real, (float)imag);
corrSig = _complex_mpysp(_amem8_f2(inputPtr++), corrSig);
demodSig ((cplxf_t *)&demodSig, &phaseEst);
RADARDEMO_atan+= phaseEst;
totalPhase }
= totalPhase * (float)denom;
phaseCorrection = divsp((phaseCorrection*(float)3e8), (4.f * (float) PI * highAccuRangeHandle->fc));
rangePhaseCorrection*estRange += rangePhaseCorrection;
}
else
{
//Not implemented yet
}
}
return;
}
3. demo的dataPath配置
应用层数据解析部分的配置, 包括: 内存分配, 缓冲区分配, 项目配置传递到硬件层.
static int32_t MmwDemo_dssDataPathConfig(void)
{
/* 接收执行结果 */
int32_t retVal;
uint8_t numRxChannels = 0;
//MMWave_CtrlCfg *ptrCtrlCfg;
/* demo的操作对象(句柄) */
*dataPathObj;
MmwDemo_DSS_DataPathObj //uint32_t numTxAntAzim = 0;
/* Get data path object and control configuration */
//ptrCtrlCfg = &gMmwDssMCB.cfg.ctrlCfg;
/* 将dss的对象控制块中的dataPath对象拿到(拿到雷达部分的对象) */
= &gMmwDssMCB.dataPathObj;
dataPathObj
/*****************************************************************************
* Data path :: Algorithm Configuration
*****************************************************************************/
/* 配置缓冲区,其中包括堆内存分配, demo的配置传递到RSS */
(SOC_XWR18XX_DSS_ADCBUF_BASE_ADDRESS, &gMmwDssMCB.cfg, dataPathObj);
MmwDemo_dataPathConfigBuffers
= MmwDemo_dssDataPathConfigAdcBuf(&numRxChannels);
retVal if (retVal < 0)
{
return -1;
}
(dataPathObj);
MmwDemo_dataPathConfigEdma
return 0;
}
3.1 配置dataPATH和各种缓冲区
代码中首先定义了一个heapconfig
数组,这个数组定义了各种堆内存的类型、地址、大小等信息。接着通过调用radarOsal_memInit
函数来初始化各种内存堆。之后通过调用MmwDemo_initConfigStruct
函数初始化了信号处理链的配置信息。然后调用了RADARDEMO_highAccuRangeProc_create
函数创建了高精度测距模块句柄,并检查返回码是否为错误码。接着用radarOsal_memAlloc
函数分配了rangeProcInput
和rangeProcOutput
所需的内存,最后用radarOsal_memAlloc
函数分配了一个outputToARM_t
类型的结构体。这些内存都是在前面定义的heapconfig
数组中的内存堆中分配的。
void MmwDemo_dataPathConfigBuffers(uint32_t adcBufAddress, MmwDemo_Cfg *demoCfg, MmwDemo_DSS_DataPathObj *dataPathObj)
{
//MmwDemo_DSS_DataPathObj *dataPathObj;
[SOC_XWR16XX_DSS_MAXNUMHEAPS];
radarOsal_heapConfig heapconfig;
RADARDEMO_highAccuRangeProc_errorCode rangeProcErrorCode
/* Get data path object and control configuration */
//dataPathObj = &gMmwDssMCB.dataPathObj;
int32_t tempNumSamples;
//设置ADC数据缓冲区的地址为给定的地址
->ADCdataBuf = (cmplx16ImRe_t *)adcBufAddress;
dataPathObj
//堆初始化 将heapconfig数组的元素初始化为0
(heapconfig, 0, sizeof(heapconfig));
memset
//将heapconfig数组中的第一个元素的heapType成员设置为RADARMEMOSAL_HEAPTYPE_DDR_CACHED
[RADARMEMOSAL_HEAPTYPE_DDR_CACHED].heapType = RADARMEMOSAL_HEAPTYPE_DDR_CACHED;
heapconfig//将heapconfig数组中的第一个元素的heapAddr成员设置为&gMmwL3[0]
[RADARMEMOSAL_HEAPTYPE_DDR_CACHED].heapAddr = (int8_t *)&gMmwL3[0];
heapconfig//将heapconfig数组中的第一个元素的heapSize成员设置为SOC_XWR16XX_DSS_L3RAM_BUFF_SIZE
[RADARMEMOSAL_HEAPTYPE_DDR_CACHED].heapSize = SOC_XWR16XX_DSS_L3RAM_BUFF_SIZE;
heapconfig//将heapconfig数组中的第一个元素的scratchAddr成员设置为NULL
[RADARMEMOSAL_HEAPTYPE_DDR_CACHED].scratchAddr = NULL; //不是DDR临时存储器,TM演示不使用
heapconfig//将heapconfig数组中的第一个元素的scratchSize成员设置为0
[RADARMEMOSAL_HEAPTYPE_DDR_CACHED].scratchSize = 0; //不是DDR临时存储器,TM演示不使用
heapconfig
//将heapconfig数组中的第二个元素的heapType成员设置为RADARMEMOSAL_HEAPTYPE_LL2
[RADARMEMOSAL_HEAPTYPE_LL2].heapType = RADARMEMOSAL_HEAPTYPE_LL2;
heapconfig//将heapconfig数组中的第二个元素的heapAddr成员设置为&gMmwL2[0]
[RADARMEMOSAL_HEAPTYPE_LL2].heapAddr = (int8_t *)&gMmwL2[0];
heapconfig//将heapconfig数组中的第二个元素的heapSize成员设置为SOC_XWR16XX_DSS_L2_BUFF_SIZE
[RADARMEMOSAL_HEAPTYPE_LL2].heapSize = SOC_XWR16XX_DSS_L2_BUFF_SIZE;
heapconfig// 将L2暂存首地址设置为&gMmwL2Scratch[0]
[RADARMEMOSAL_HEAPTYPE_LL2].scratchAddr = (int8_t *)&gMmwL2Scratch[0];
heapconfig// 将L2暂存设置为24KB(L2共计:256KB)
[RADARMEMOSAL_HEAPTYPE_LL2].scratchSize = SOC_XWR16XX_DSS_L2_SCRATCH_SIZE;
heapconfig
/* 配置L1内存 */
[RADARMEMOSAL_HEAPTYPE_LL1].heapType = RADARMEMOSAL_HEAPTYPE_LL1;
heapconfig/* 内存堆地址设置NULL */
[RADARMEMOSAL_HEAPTYPE_LL1].heapAddr = NULL; /* not used as L1 heap in TM demo */
heapconfig/* 设置大小为 0 */
[RADARMEMOSAL_HEAPTYPE_LL1].heapSize = 0; /* not used as L1 heap in TM demo */
heapconfig/* 设置暂存地址为gMmwL1[0] */
[RADARMEMOSAL_HEAPTYPE_LL1].scratchAddr = (int8_t *) &gMmwL1[0];
heapconfig/* L1暂存大小为 16KB (L1一共32KB(L1Program)+32KB(L1Data)) */
[RADARMEMOSAL_HEAPTYPE_LL1].scratchSize = MMW_L1_SCRATCH_SIZE;
heapconfig
/* 配置 HSRAM 高速RAM, 8KB */
[RADARMEMOSAL_HEAPTYPE_HSRAM].heapType = RADARMEMOSAL_HEAPTYPE_HSRAM;
heapconfig[RADARMEMOSAL_HEAPTYPE_HSRAM].heapAddr = (int8_t *) &gMmwHSRAM[0];
heapconfig[RADARMEMOSAL_HEAPTYPE_HSRAM].heapSize = SOC_XWR16XX_DSS_HSRAM_BUFF_SIZE;
heapconfig[RADARMEMOSAL_HEAPTYPE_HSRAM].scratchAddr = NULL; /* not HSRAM scratch for TM demo */
heapconfig[RADARMEMOSAL_HEAPTYPE_HSRAM].scratchSize = 0; /* not HSRAM scratch for TM demo */
heapconfig
/* 按照上述配置进行申请堆内存, 如果失败打印信息 */
if(radarOsal_memInit(&heapconfig[0], SOC_XWR16XX_DSS_MAXNUMHEAPS) == RADARMEMOSAL_FAIL)
{
("Error: radarOsal_memInit fail\n");
System_printf}
/*initializing configuration structure for signal processing chain */
/* 这个函数的作用是将demo中的配置传递给雷达(这么做将软件进行解耦, 应用和硬件隔离, 更好的抽象) */
(demoCfg, &dataPathObj->radarProcConfig); MmwDemo_initConfigStruct
uint32_t uitemp;
float frequencySlopeMHzMicoSec, adcSamplePeriodMicoSec, bandWidth, chirpInterval;
uint16_t frameChirpStartIdx;
uint16_t frameChirpEndIdx;
int16_t frameTotalChirps;
int32_t errCode, itemp;
uint32_t profileLoopIdx, chirpLoopIdx;
bool foundValidProfile = false;
/* 配置传递:传递给RSS(radar sub system) */
* ptrCtrlCfg = &(demoCfg->ctrlCfg);
MMWave_CtrlCfg* ptrOpenCfg = &(demoCfg->openCfg);
MMWave_OpenCfg
uint16_t channelTxEn = ptrOpenCfg->chCfg.txChannelEn;
/* 这段代码中,首先读取了变量demoCfg中的openCfg结构体的chCfg成员变量的txChannelEn字段,
该字段表示雷达系统启用的发射通道,是一个4位的二进制数,每一位表示一个发射天线是否启用,
1表示启用,0表示未启用 */
->numTxAntenna = (uint16_t)_bitc4(demoCfg->openCfg.chCfg.txChannelEn);//3
radarProcConfig->numPhyRxAntenna = (uint16_t)_bitc4(demoCfg->openCfg.chCfg.rxChannelEn);//1
radarProcConfig
/* 判断天线数量, 物理接收天线只能打开1根, 对于该应用来说(液位测量) */
if(radarProcConfig->numPhyRxAntenna > 1)
{
("channelCfg Error: Does not support multiple Rx Antennas !!!");
System_printf(0);
DebugP_assert}
/* 获取到雷达配置中的开始chipr索引和结束索引 */
= ptrCtrlCfg->u.frameCfg.frameCfg.chirpStartIdx;//0
frameChirpStartIdx = ptrCtrlCfg->u.frameCfg.frameCfg.chirpEndIdx;//0
frameChirpEndIdx
/* 计算一帧中chirp数 (结束-开始+1)*/
= frameChirpEndIdx - frameChirpStartIdx + 1;//1
frameTotalChirps
/* since validChirpTxEnBits is static array of 32 */
/* 若果一帧内的chirp数大于32则会触发断言, 程序终止 */
(frameTotalChirps<=32);
DebugP_assert
/* foundValidProfile 是一个布尔类型的变量,用于指示在 for 循环中是否找到了有效的配置文件。
在循环中,如果找到了有效的配置文件,则会将 foundValidProfile 设置为 true,从而退出循环 */
for (
=0;
profileLoopIdx/* 最大支持4中配置, 如果找到有效配置就停止, 提升效率 */
((profileLoopIdx<MMWAVE_MAX_PROFILE)&&(foundValidProfile==false));
++
profileLoopIdx)
{
uint32_t mmWaveNumChirps = 0;
uint16_t validChirpTxEnBits[32]={0};
;
MMWave_ProfileHandle profileHandle
/* 获取给定索引(profileLoopIdx)的配置文件(profile)的句柄(handle),并将其保存在`profileHandle`指针所指向的变量中。
同时,该函数还返回错误码`errCode`,如果执行异常就中断程序 */
if (MMWave_getProfileHandle(gMmwDssMCB.ctrlHandle, profileLoopIdx, &profileHandle, &errCode) < 0)
{
/* Error: Unable to get the profile handle; this should never fail */
(0);
DebugP_assert }
/* 如果获取到的句柄为空就重新进入下一次`profiIdx`进行获取句柄 */
if (profileHandle == NULL)
continue; /* skip this profile */
/* get numChirps for this profile; skip error checking */
/* 通过当前有效句柄获取chirp数 */
(profileHandle,&mmWaveNumChirps,&errCode);
MMWave_getNumChirps/* loop for chirps and find if it has valid chirps for the frame
looping around for all chirps in a profile, in case
there are duplicate chirps
*/
/* 拿到所有的获取到chirp数之后, 按照chirp数进行遍历获取所有chirp的句柄和chirp配置 */
for (chirpLoopIdx=1;chirpLoopIdx<=mmWaveNumChirps;chirpLoopIdx++)
{
;
MMWave_ChirpHandle chirpHandle/* get handle and read ChirpCfg */
/* 通过 `MMWave_getChirpHandle` 获取到chirp的句柄 */
if (MMWave_getChirpHandle(profileHandle,chirpLoopIdx,&chirpHandle,&errCode)==0)
{
;
rlChirpCfg_t chirpCfg/* 通过chirp句柄后获取`chirp`的配置 */
if (MMWave_getChirpCfg(chirpHandle,&chirpCfg,&errCode)==0)
{
/* txEnable是一个二进制值,用于指示哪些天线在当前chirp的时间内应该被使用, 最多可以同时开启2根发射天线 */
/*
b0: 是否启用 TX0 发射天线,0 表示禁用,1 表示启用。
b1: 是否启用 TX1 发射天线,0 表示禁用,1 表示启用。
b2: 是否启用 TX2 发射天线,0 表示禁用,1 表示启用。
*/
uint16_t chirpTxEn = chirpCfg.txEnable;
/* do chirps fall in range and has valid antenna enabled */
/* 这段代码是在循环遍历一个profile中的所有chirps,判断是否有valid的chirp能够覆盖到frame中的chirp范围,
并且判断这个chirp对应的天线是否是valid的。如果找到了这样的valid chirp,
就将对应的bit位设置到validChirpTxEnBits数组中,表示这个chirp对应的TX是valid的 */
if ((chirpCfg.chirpStartIdx >= frameChirpStartIdx) &&
(chirpCfg.chirpEndIdx <= frameChirpEndIdx) &&
((chirpTxEn & channelTxEn) > 0))
{
uint16_t idx = 0;
for (idx=(chirpCfg.chirpStartIdx-frameChirpStartIdx);idx<=(chirpCfg.chirpEndIdx-frameChirpStartIdx);idx++)
{
[idx] = chirpTxEn;
validChirpTxEnBits= true;
foundValidProfile }
}
}
}
}
/* now loop through unique chirps and check if we found all of the ones
needed for the frame and then determine the azimuth antenna
configuration
*/
if (foundValidProfile)
{
for (chirpLoopIdx=0;chirpLoopIdx<frameTotalChirps;chirpLoopIdx++)
{
uint16_t chirpTxEn = validChirpTxEnBits[chirpLoopIdx];
= (uint32_t)_bitc4(chirpTxEn);
uitemp // if (uitemp > 1)
// {
// System_printf("channelCfg Error: Current code only support SIMO and TDM MIMO !!!");
// DebugP_assert(0);
// }
}
}
/* found valid chirps for the frame; mark this profile valid */
if (foundValidProfile==true)
{
;
rlProfileCfg_t profileCfg
//dataPathObj->validProfileIdx = profileLoopIdx;
/* Get the profile configuration: */
/* 获取扫描模式配置句柄, 如果没有获取到就进行断言, 程序终止 */
if (MMWave_getProfileCfg (profileHandle,&profileCfg, &errCode) < 0)
{
("Error: Unable to get the profile configuration [Error code %d]\n", errCode);
System_printf (0);
DebugP_assert }
/* 如果配置有效, 将参数进行传递, 从demo的配置传递给雷达部分. */
->numAdcSamplePerChirp = profileCfg.numAdcSamples;
radarProcConfig->highAccuConfig.nSamplesPerChirp = profileCfg.numAdcSamples;
radarProcConfig
= (float)profileCfg.freqSlopeConst * 3600.f* 900.f/((float)(1<<26));
frequencySlopeMHzMicoSec ->highAccuConfig.chirpSlope = frequencySlopeMHzMicoSec * 1e12;
radarProcConfig= 1000.0f / (float) profileCfg.digOutSampleRate;
adcSamplePeriodMicoSec *= (float)radarProcConfig->numAdcSamplePerChirp;
adcSamplePeriodMicoSec ->highAccuConfig.chirpRampTime = adcSamplePeriodMicoSec * 1e-6;
radarProcConfig= frequencySlopeMHzMicoSec * adcSamplePeriodMicoSec * 1.0e6;
bandWidth ->highAccuConfig.chirpBandwidth = bandWidth;
radarProcConfig->highAccuConfig.adcSampleRate = 1000.0f * profileCfg.digOutSampleRate;
radarProcConfig->highAccuConfig.maxBeatFreq = 1000.0f * profileCfg.digOutSampleRate;
radarProcConfig->highAccuConfig.fc = ((float)profileCfg.startFreqConst * 3.6f/((float)(1<<26))) * 1.0e9 +
radarProcConfig->highAccuConfig.chirpSlope * (float)profileCfg.adcStartTimeConst * 1.0e-8;
radarProcConfig= profileCfg.numAdcSamples;
itemp if ((1 << (30 - _norm(itemp))) == itemp)
->highAccuConfig.fft1DSize = itemp;
radarProcConfigelse
->highAccuConfig.fft1DSize = 1 << (31 - _norm(itemp));
radarProcConfig
//centerFrequency = ((float)profileCfg.startFreqConst * 3.6f/((float)(1<<26))) * 1.0e9 + bandWidth * 0.5;
= (float)((profileCfg.rampEndTime) + (float)(profileCfg.idleTimeConst)) *1.0e-8;
chirpInterval ->chirpInterval = chirpInterval;
radarProcConfig
->numChirpPerFrame = demoCfg->ctrlCfg.u.frameCfg.frameCfg.numLoops;
radarProcConfig->highAccuConfig.numChirpsPerFrame = radarProcConfig->numChirpPerFrame;
radarProcConfig->framePeriod = (demoCfg->ctrlCfg.u.frameCfg.frameCfg.framePeriodicity) * 5e-6;
radarProcConfig}
}//fist for
/* Range window parameters. */
/* 距离窗配置 */
->highAccuConfig.win1DLength = 16;
radarProcConfig->win1D[0] = 0.0800f;
radarProcConfig->win1D[1] = 0.0894f;
radarProcConfig->win1D[2] = 0.1173f;
radarProcConfig->win1D[3] = 0.1624f;
radarProcConfig->win1D[4] = 0.2231f;
radarProcConfig->win1D[5] = 0.2967f;
radarProcConfig->win1D[6] = 0.3802f;
radarProcConfig->win1D[7] = 0.4703f;
radarProcConfig->win1D[8] = 0.5633f;
radarProcConfig->win1D[9] = 0.6553f;
radarProcConfig->win1D[10] = 0.7426f;
radarProcConfig->win1D[11] = 0.8216f;
radarProcConfig->win1D[12] = 0.8890f;
radarProcConfig->win1D[13] = 0.9422f;
radarProcConfig->win1D[14] = 0.9789f;
radarProcConfig->win1D[15] = 0.9976f;
radarProcConfig
/* 将项目的窗也设置为相同的窗 */
->highAccuConfig.win1D = radarProcConfig->win1D; radarProcConfig
附录
1. 配置文件解析
IWR6843vitalsign配置解析
-2022-11-15 dd21
sensorStop
- 传感器停止
flushCfg
- 刷新配置
dfeDataOutputMode 1
- 数据输出模式
|-1 基于帧的chirp模式
|-2 连续chirp模式
|-3 高级帧模式
channelCfg 15 3 0
- 通道设置
|-15 => (0x1111)b 接收天线掩码, 表示打开 4个接收天线
|-3 => (0x11)b 发射天线掩码, 表示打开 2个发射天线
|-0 soc级联(目前不可用[V3.5.4]), 设置为0
adcCfg 2 1
- ADC配置
|-<具体信息查看mmwaveLink 文档>
|-2 adc采样位数(只支持16bits)
|-0 12bits
|-1 14bits
|-2 16bits
|-1 adc输出格式
|-0 real(实数)
|-1 complex 1x (image band filtered output)
|-2 complex 2x (image band visible)
adcbufCfg -1 0 0 1 0
- Adc_buffer配置
|--1子帧索引
|-传统模式 设置为-1
|-高级帧模式 根据需求配置, 若依旧设置为-1, 则表示子帧采取相同的配置
|- 0 ADCBUF adcBuffer输出模式
|-0 复数模式
|-1 实数模式
|- 1 采样交换选择(只支持1)
|-0-I in LSB, Q in MSB
|-1-Q in LSB, I in MSB
|- 1 ADCbuffer通道交错(只支持1)
|-0 交错
|-1 不交错
|- 1 chrip 阈值, 用于 ADCBUF 缓冲区触发 ping /pong 缓冲区开关的 Chirp 阈值配置
|-[0-8] 16xx, 将dsp用于1D-fft处理,如果使用lvds使用的话, 1也是可以的
|-[1] 68xx,64xx,18xx, 有HWA(fft硬件加速)
profileCfg 0 60 7 6 60 0 0 65 1 100 2000 0 0 40
profileCfg 0 77 7 7 114.4 0 0 33.71 1 256 2500 0 0 48
- 雷达前段和数据处理配置
|-0 标识符, 区别第几个配置
|-60 起始频率(GHz,允许浮点数)
|-7 idle time 空闲时间(us)
|-6 adc有效起始时间(us)
|-60 斜坡结束时间(us)
|-0 发射天线功率返回码(只有0测试过)
|-0 发射天线移相器(只有0测试过)
|-65 每个chirp的变化率,MHz/us
|-1 发射天线开始时间(us)
|-100 adc采样数
|-2000 adc采样率
|-0 高通滤波器1
|-0: 175 KHz
|-1: 235 KHz
|-2: 350 KHz
|-3: 700 KHz
|-0 高通滤波器2
|-0: 350 KHz
|-1: 700 KHz
|-2: 1.4 MHz
|-3: 2.8 MHz
|-40 接收增益 以 dB 为单位的 RX 增益和 RF 增益目标的或值
chirpCfg 0 0 0 0 0 0 0 1
chirpCfg 1 1 0 0 0 0 0 2
- 对雷达前段和数据处理的chirp配置
|- 0 chirp开始索引
|- 0 chirp结束索引
|- 0 配置文件标识符
|- 0 起始频率变化(Hz) [只支持0]
|- 0 频率斜率变化(kHz/us) [只支持0]
|- 0 空闲时间(us) [只支持0]
|- 0 ADC 启动时间变化(us) [只支持0]
|- 1 (0x01)b => tx 天线掩码, 打开天线1
frameCfg 0 1 1 0 50 1 0
- fram配置
|-0 chrip 开始索引(0-511)
|-1 chrip 结束索引(开始索引-511)
|-1 循环次数(1-255), 如果用dsp进行计算多普勒chirp, 循环次数必须是4的倍数, 否则需要调整窗的大小
|-0 frame的数量(0-65535),0表示无穷
|-50 frame的周期50ms
|-1 触发选择
|-1:软件触发(只支持软件触发)
|-2:硬件触发
|-0 frame触发延时(ms)
lowPower 0 0
- 低功耗模式
|- 0 don’t_care
|-ADC Mode
|-0 : 常规模式
|-1 : 低功耗adc模式 (不支持 xwr6xxx)
guiMonitor -1 0 0 0 0 0 1
- 图形界面监视器(所有配置0表示关闭, 1表示开启)
|- -1 所有frame配置相同(-1)
|- 0 检测到的物体
|- 0 log magnitude range
|- 0 noise profile
|- 0 各种热图
|- 0 距离多普勒热图
|- 1 CPU 负载、余量、设备温度读数等
calibDcRangeSig -1 0 0 0 0
- 补偿参数
|- -1 所有frame配置相同(-1)
|- Enable DC removal using first few chirps
|-
|-
|-
|-
vitalSignsCfg 0.3 0.9 256 512 4 0.1 0.05 100000 300000
motionDetection 1 20 2.0 0
sensorStart
1. 多普勒累积
多普勒累积(Doppler accumulation)是一种信号处理技术,用于增强雷达系统对运动目标的探测和跟踪能力。在雷达系统中,目标的运动会导致回波信号的频率发生偏移,这种频率偏移称为多普勒频移。通过多普勒累积,可以将多个时刻收到的回波信号进行累加,以增加对目标多普勒频移的测量精度和信噪比。
具体来说,多普勒累积的过程包括以下步骤:
将多个时刻的回波信号进行FFT变换,得到频域信息。
对于每个目标,将它在多个时刻的频域信息进行累加,得到一个累加后的频谱。
对于每个目标,从累加后的频谱中提取出多普勒频移信息。
通过多普勒累积,可以提高雷达系统对运动目标的探测和跟踪能力,特别是在低信噪比环境下。