Based on the input radar cube this DPU creates the range-azimuth detection matrix (heatmap) along with the doppler and elevation index matrices that are used further in the chain in CFAR detection process.
The top-level block diagram of the DPU is shown in the figure below.
The DOA processing detailed block diagram is shown below.
The HWA processes data in the loop, one range bin per iteration. The input EDMA reads symbols from the radar cube, all chirps and antennas of the current range bin, and copies to the HWA memory. The loaded array, denoted as 𝑋𝐴(𝑐ℎ𝑖𝑟𝑝, 𝑎𝑛𝑡𝑒𝑛𝑛𝑎). The EDMA reads the data from the radar cube in linear fashion (top to bottom along the chirp dimension) the same way in both modes, major and minor. Note that the processing of the circularly shifted data in time from the radar cube, as opposed to linear data (arranged in increased time order), does not change the final values in the detection matrix (due to the magnitude of the FFT being invariant to cyclic shifts – provided there is no zero-padding).
The Chirp indexing in radar cubes for major and minor motion detection modes is shown below
The first HWA parameter in the loop performs the receive channel phase compensation based on the coefficients specified by the CLI configuration command. The output of this step, 𝑋𝐴(𝑐ℎ𝑖𝑟𝑝,𝑎𝑛𝑡𝑒𝑛𝑛𝑎), is also complex16 array. The next set of param sets performs the following functions:
The signal mapping for the IWRL6432 EVM is illustrated below.
The lookup table depends on the antenna geometry, and it is constructed by the function MmwDemo_cfgDopplerParamMapping(), which is called from outside of the DPU. It computes the lookup table based on the CLI configuration command antGeometryCfg that specifies the coordinates of all virtual antennas(Refer to the document - Motion_Presence_Detection_Demo_Tuning_Guide.pdf, in the SDK docs folder, for more details).
Further processing includes 2D angle FFT calculation applied to 2x4 virtual antenna array for each doppler bin. This is achieved with two azimuth FFT param sets and one Elevation FFT param set. The output of this operation is the complex32 3D-array 𝑋E(doppler,azimuthInd,elevationInd) located in M2:M3 memory banks. For both azimuth and elevation FFTs a windowing function win = [1, -1, 1, -1, …] is applied, so that the FFT output indices are circularly shifted by NFFT/2, i.e. the angle FFT indices are arranged from -NFFT / 2 to +(NFFT / 2) - 1.
hwRes = &doaProcDpuCfg.hwRes;
doaStaticCfg = &doaProcDpuCfg.staticCfg;
edmaCfg = &hwRes->edmaCfg;
hwaCfg = &hwRes->hwaCfg;
doaStaticCfg->numTxAntennas = 2;
doaStaticCfg->numRxAntennas = 3;
doaStaticCfg->numVirtualAntennas = 6;
doaStaticCfg->numRangeBins = testConfig->numAdcSamples/2;
doaStaticCfg->numAntRow = 2;
doaStaticCfg->numAntCol = 4;
doaStaticCfg->numDopplerChirps = testConfig->numChirpsPerFrame/doaStaticCfg->numTxAntennas;
doaStaticCfg->numMinorMotionChirpsPerFrame = 0;
doaStaticCfg->numFrmPerMinorMotProc = 0;
doaStaticCfg->numDopplerBins = mathUtils_pow2roundup(doaStaticCfg->numDopplerChirps);
doaStaticCfg->log2NumDopplerBins = mathUtils_ceilLog2(doaStaticCfg->numDopplerBins);
doaStaticCfg->selectCoherentPeakInDopplerDim = 0;
doaStaticCfg->angleDimension = 2;
doaStaticCfg->isDetMatrixLogScale = false;
doaStaticCfg->azimuthFftSize = testConfig->azimuthFftSize;
doaStaticCfg->elevationFftSize = 2;
doaStaticCfg->isStaticClutterRemovalEnabled = 1;
doaStaticCfg->isRxChGainPhaseCompensationEnabled = 0;
doaStaticCfg->doaRangeLoopType = 0;
doaStaticCfg->enableMajorMotion = 1;
retVal = MmwDemo_cfgDopplerParamMapping(&hwaCfg->doaRngGateCfg, 0);
if (retVal < 0)
{
goto exit;
}
if (doaStaticCfg->enableMajorMotion)
{
radarCube.dataSize = doaStaticCfg->numRangeBins * (testConfig->numChirpsPerFrame/doaStaticCfg->numTxAntennas) *
doaStaticCfg->numVirtualAntennas * sizeof(cmplx16ReIm_t);
radarCube.data = (void*)radarCubeData;
if (radarCube.data == NULL)
{
retVal = -1;
goto exit;
}
radarCube.datafmt = DPC_OBJDET_DPIF_RADARCUBE_FORMAT_6;
}
else
{
radarCube.dataSize = 0;
radarCube.data = NULL;
radarCube.datafmt = DPC_OBJDET_DPIF_RADARCUBE_FORMAT_6;
}
if (doaStaticCfg->enableMajorMotion == 0)
{
radarCubeMinMot.dataSize = doaStaticCfg->numRangeBins * (testConfig->numChirpsPerFrame/doaStaticCfg->numTxAntennas) *
doaStaticCfg->numVirtualAntennas * sizeof(cmplx16ReIm_t);
radarCubeMinMot.data = (void*)radarCubeData;
if (radarCubeMinMot.data == NULL)
{
retVal = -2;
goto exit;
}
radarCubeMinMot.datafmt = DPC_OBJDET_DPIF_RADARCUBE_FORMAT_6;
}
else
{
radarCubeMinMot.dataSize = 0;
radarCubeMinMot.data = NULL;
radarCubeMinMot.datafmt = DPC_OBJDET_DPIF_RADARCUBE_FORMAT_6;
}
for (i=0; i<2; i++)
{
if (((i==0) && doaStaticCfg->enableMajorMotion) || ((i==1) && (doaStaticCfg->enableMajorMotion == 0)))
{
if(doaStaticCfg->isDetMatrixLogScale)
{
detMatrix[i].dataSize = doaStaticCfg->numRangeBins * doaStaticCfg->azimuthFftSize * sizeof(uint16_t);
}
else
{
detMatrix[i].dataSize = doaStaticCfg->numRangeBins * doaStaticCfg->azimuthFftSize * sizeof(uint32_t);
}
detMatrix[i].data = detMatrixData;
if (detMatrix[i].data == NULL)
{
retVal = -3;
goto exit;
}
detMatrix[i].datafmt = DPC_DPU_DPIF_DETMATRIX_FORMAT_2;
}
else
{
detMatrix[i].dataSize = 0;
detMatrix[i].data = NULL;
}
}
if ((doaStaticCfg->selectCoherentPeakInDopplerDim == 1) ||
(doaStaticCfg->selectCoherentPeakInDopplerDim == 2))
{
if (doaStaticCfg->angleDimension == 2)
{
dopplerIndexMatrix.dataSize = doaStaticCfg->numRangeBins * doaStaticCfg->azimuthFftSize * doaStaticCfg->elevationFftSize * sizeof(uint8_t);
}
else
{
dopplerIndexMatrix.dataSize = doaStaticCfg->numRangeBins * doaStaticCfg->azimuthFftSize * sizeof(uint8_t);
}
dopplerIndexMatrix.data = dopplerIndexMatrixData;
if (dopplerIndexMatrix.data == NULL)
{
retVal = -4;
goto exit;
}
dopplerIndexMatrix.datafmt = DPC_DPU_DPIF_DETMATRIX_FORMAT_2;
}
else
{
dopplerIndexMatrix.dataSize = 0;
dopplerIndexMatrix.data = NULL;
dopplerIndexMatrix.datafmt = 0;
}
if (doaStaticCfg->angleDimension == 2)
{
elevationIndexMatrix.dataSize = doaStaticCfg->numRangeBins * doaStaticCfg->azimuthFftSize * sizeof(uint8_t);
elevationIndexMatrix.data = elevationIndexMatrixData;
if (elevationIndexMatrix.data == NULL)
{
retVal = -5;
goto exit;
}
elevationIndexMatrix.datafmt = DPC_DPU_DPIF_DETMATRIX_FORMAT_2;
}
else
{
elevationIndexMatrix.dataSize = 0;
elevationIndexMatrix.data = NULL;
elevationIndexMatrix.datafmt = 0;
}
hwRes->radarCube = radarCube;
hwRes->radarCubeMinMot = radarCubeMinMot;
hwRes->detMatrix = detMatrix[0];
hwRes->dopplerIndexMatrix = dopplerIndexMatrix;
hwRes->elevationIndexMatrix = elevationIndexMatrix;
edmaCfg->edmaHandle = gEdmaHandle[0];
edmaCfg->edmaIn.chunk[0].channel = DPC_OBJDET_DPU_DOAPROC_EDMAIN_PING_CH;
edmaCfg->edmaIn.chunk[0].channelShadow = DPC_OBJDET_DPU_DOAPROC_EDMAIN_PING_SHADOW;
edmaCfg->edmaIn.chunk[0].eventQueue = DPC_OBJDET_DPU_DOAPROC_EDMAIN_PING_EVENT_QUE;
edmaCfg->edmaIn.chunk[1].channel = DPC_OBJDET_DPU_DOAPROC_EDMAIN_PONG_CH;
edmaCfg->edmaIn.chunk[1].channelShadow = DPC_OBJDET_DPU_DOAPROC_EDMAIN_PONG_SHADOW;
edmaCfg->edmaIn.chunk[1].eventQueue = DPC_OBJDET_DPU_DOAPROC_EDMAIN_PONG_EVENT_QUE;
edmaCfg->edmaHotSig.channel = DPC_OBJDET_DPU_DOAPROC_EDMA_HOT_SIG_CH;
edmaCfg->edmaHotSig.channelShadow = DPC_OBJDET_DPU_DOAPROC_EDMA_HOT_SIG_SHADOW;
edmaCfg->edmaHotSig.eventQueue = DPC_OBJDET_DPU_DOAPROC_EDMA_HOT_SIG_EVENT_QUE;
edmaCfg->edmaDetMatOut.channel = DPC_OBJDET_DPU_DOAPROC_EDMAOUT_DET_MATRIX_CH;
edmaCfg->edmaDetMatOut.channelShadow = DPC_OBJDET_DPU_DOAPROC_EDMAOUT_DET_MATRIX_SHADOW;
edmaCfg->edmaDetMatOut.eventQueue = DPC_OBJDET_DPU_DOAPROC_EDMAOUT_DET_MATRIX_EVENT_QUE;
edmaCfg->elevIndMatOut.channel = DPC_OBJDET_DPU_DOAPROC_EDMAOUT_ELEVIND_MATRIX_CH;
edmaCfg->elevIndMatOut.channelShadow = DPC_OBJDET_DPU_DOAPROC_EDMAOUT_ELEVIND_MATRIX_SHADOW;
edmaCfg->elevIndMatOut.eventQueue = DPC_OBJDET_DPU_DOAPROC_EDMAOUT_ELEVIND_MATRIX_EVENT_QUE;
edmaCfg->dopIndMatOut.channel = DPC_OBJDET_DPU_DOAPROC_EDMAOUT_DOPIND_MATRIX_CH;
edmaCfg->dopIndMatOut.channelShadow = DPC_OBJDET_DPU_DOAPROC_EDMAOUT_DOPIND_MATRIX_SHADOW;
edmaCfg->dopIndMatOut.eventQueue = DPC_OBJDET_DPU_DOAPROC_EDMAOUT_DOPIND_MATRIX_EVENT_QUE;
edmaCfg->edmaInterLoopOut.channel = DPC_OBJDET_DPU_DOAPROC_INTER_LOOP_EDMAOUT_DET_MATRIX_CH;
edmaCfg->edmaInterLoopOut.channelShadow = DPC_OBJDET_DPU_DOAPROC_INTER_LOOP_EDMAOUT_DET_MATRIX_SHADOW;
edmaCfg->edmaInterLoopOut.eventQueue = DPC_OBJDET_DPU_DOAPROC_INTER_LOOP_EDMAOUT_DET_MATRIX_EVENT_QUE;
edmaCfg->edmaInterLoopIn.channel = DPC_OBJDET_DPU_DOAPROC_INTER_LOOP_EDMAIN_CH;
edmaCfg->edmaInterLoopIn.channelShadow = DPC_OBJDET_DPU_DOAPROC_INTER_LOOP_EDMAIN_SHADOW;
edmaCfg->edmaInterLoopIn.eventQueue = DPC_OBJDET_DPU_DOAPROC_INTER_LOOP_EDMAIN_EVENT_QUE;
edmaCfg->edmaInterLoopHotSig.channel = DPC_OBJDET_DPU_DOAPROC_INTER_LOOP_EDMA_HOT_SIG_CH;
edmaCfg->edmaInterLoopHotSig.channelShadow = DPC_OBJDET_DPU_DOAPROC_INTER_LOOP_EDMA_HOT_SIG_SHADOW;
edmaCfg->edmaInterLoopHotSig.eventQueue = DPC_OBJDET_DPU_DOAPROC_INTER_LOOP_EDMA_HOT_SIG_EVENT_QUE;
edmaCfg->edmaInterLoopChainBack.channel = DPC_OBJDET_DPU_DOAPROC_INTER_LOOP_EDMA_CHAIN_BACK_CH;
edmaCfg->edmaInterLoopChainBack.channelShadow = DPC_OBJDET_DPU_DOAPROC_INTER_LOOP_EDMA_CHAIN_BACK_SHADOW;
edmaCfg->edmaInterLoopChainBack.eventQueue = DPC_OBJDET_DPU_DOAPROC_INTER_LOOP_EDMA_CHAIN_BACK_EVENT_QUE;
edmaCfg->intrObj = &intrObj;
hwaCfg->hwaMemInpAddr = CSL_APP_HWA_DMA0_RAM_BANK3_BASE;
hwaCfg->numParamSets = 0;
hwaCfg->paramSetStartIdx = 0;
winGenLen = (doaStaticCfg->azimuthFftSize > doaStaticCfg->elevationFftSize) ? doaStaticCfg->azimuthFftSize : doaStaticCfg->elevationFftSize;
hwaCfg->windowSize = winGenLen * sizeof(int32_t);
for (i=0; i<winGenLen; i++)
{
windowBuffer[i] = (1 - 2 * (i & 0x1)) * ((1<<17) - 1);
}
hwaCfg->window = (int32_t *)windowBuffer;
hwaCfg->winRamOffset = DPC_OBJDET_HWA_WINDOW_RAM_OFFSET;
{
hwRes->interLoopDataBuffer = (cmplx32ImRe_t *) interLoopDataBufferMem;
if (hwRes->interLoopDataBuffer == NULL)
{
retVal = -5;
goto exit;
}
}
else
{
hwRes->interLoopDataBuffer = NULL;
}
hwRes->interLoopDataBuffer = NULL;