xWRL6432 MMWAVE-L-SDK  05.05.00.00
Doaproc

Introduction

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.

Block Diagram

The top-level block diagram of the DPU is shown in the figure below.

DOA DPU top-level diagram

The DOA processing detailed block diagram is shown below.

DOA DPU block diagram

DOA DPU Functioning

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

Chirp indexing in radar cubes

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:

  • Doppler FFT per antenna,
  • Antenna symbol mapping from input arrangement to the two-dimensional row column matrix,
  • Optional clutter removal by dropping zero Doppler bin

The signal mapping for the IWRL6432 EVM is illustrated below.

Chirp indexing in radar cubes

The antenna symbols are transformed from the 2D array 𝑋𝐵(𝑐ℎ𝑖𝑟𝑝,𝑎𝑛𝑡𝑒𝑛𝑛𝑎) into 3D array 𝑋𝐶(𝑑𝑜𝑝𝑝𝑙𝑒𝑟,𝑟𝑜𝑤,𝑐𝑜𝑙) where the 𝑟𝑜𝑤 and 𝑐𝑜𝑙 are row and column index of the 2D virtual antenna array. The output 𝑋𝐶 is complex32 array. Note that the HWA param set denoted as Param C, is performing dummy transfer to positions 4 and 7 with the scale in the HWA preprocessing block set to zero. The number of Doppler param sets and the offset positions are defined in the lookup table doaRngGateCfg defined with structures DPU_DoaProc_HWA_Option_Cfg and DPU_DoaProc_HWA_Doppler_Fft_Cfg shown below.

typedef struct DPU_DoaProc_HWA_Option_Cfg_t
{
uint8_t numDopFftParams; /* Number of Param sets for Doppler FFT */
typedef struct DPU_DoaProc_HWA_Doppler_Fft_Cfg_t
{
uint16_t srcBcnt; /* Number of input columns (PARAM iterations) */
int16_t srcAddrOffset; /* Source column offset */
int16_t srcBidx; /* Source column increment (per PARAM iteration) */
int16_t scale; /* Scale in pre processing block (0 or 1) */
int16_t dstAddrOffset; /* Destination column offset */
int16_t dstBidx; /* Destination column increment (per PARAM iteration) */

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.

Usage Overview

API

  • DPU_DoaProc_init(): This function allocates memory for the DOA DPU instance and initializes it to zero. It also constructs the semaphores used for processing.
  • DPU_DoaProc_process(): This function is called per frame after the range DPU is completed. In auto mode it is called twice, for major motion detection and for minor motion. The input arguments to the function are:

    • pointer to the radar cube and
    • pointer to the output detection matrix

    Note that in the current implementation, there is only one instance of DOA DPU, and all the configuration parameters must be the same in both major and minor motion modes. The function performs the following steps:

    • configures the source address of the input EDMA parameters,
    • configures destination address of the output EDMA parameters,
    • configures the common registers of the HWA, such as start and end param set, and the number of loops,
    • triggers the input EDMA,
    • pends on the semaphores for the end of the processing as the entire chain processing is performed by HWA.

    Then the function exits.

  • DPU_DoaProc_deinit(): It frees the resources used for the DPU.
  • DPU_DoaProc_config(): Based on the configuration parameters, this function configures hardware accelerator FFT engine and the input and output EDMA channels to bring data in and out of HWA memory. The function is normally called one time, before the sensor start command is issued to the RF. In the low power deep sleep mode, the function is called per frame.

Example Usage

Include the below file to access the APIs

DPU Initialization Example

initParams.hwaHandle = gHwaHandle;
/* generate the dpu handler*/
doaProcDpuHandle = DPU_DoaProc_init(&initParams, &errorCode);
if (doaProcDpuHandle == NULL)
{
DebugP_log ("Debug: DoaProc DPU initialization returned error %d\n", errorCode);
return;
}

DPU Configuration Parsing Example

hwRes = &doaProcDpuCfg.hwRes;
doaStaticCfg = &doaProcDpuCfg.staticCfg;
edmaCfg = &hwRes->edmaCfg;
hwaCfg = &hwRes->hwaCfg;
/* overwrite the DPIF_commonParams with the test configuration*/
doaStaticCfg->numTxAntennas = 2; //testConfig->numTxAntennas;
doaStaticCfg->numRxAntennas = 3; //staticCfg->ADCBufData.dataProperty.numRxAntennas;
doaStaticCfg->numVirtualAntennas = 6; //testConfig->numTxAntennas * testConfig->numRxAntennas;
doaStaticCfg->numRangeBins = testConfig->numAdcSamples/2; //testConfig->numRangeBins;
doaStaticCfg->numAntRow = 2;
doaStaticCfg->numAntCol = 4;
doaStaticCfg->numDopplerChirps = testConfig->numChirpsPerFrame/doaStaticCfg->numTxAntennas; //staticCfg->numDopplerChirpsPerProc;
doaStaticCfg->numMinorMotionChirpsPerFrame = 0; //staticCfg->numMinorMotionChirpsPerFrame; // staticCfg->numDopplerChirps / staticCfg->numFramesPerMinorMotProc;
doaStaticCfg->numFrmPerMinorMotProc = 0;
doaStaticCfg->numDopplerBins = mathUtils_pow2roundup(doaStaticCfg->numDopplerChirps); //staticCfg->numDopplerBins;
doaStaticCfg->log2NumDopplerBins = mathUtils_ceilLog2(doaStaticCfg->numDopplerBins);
doaStaticCfg->selectCoherentPeakInDopplerDim = 0; //staticCfg->selectCoherentPeakInDopplerDim;
doaStaticCfg->angleDimension = 2; //staticCfg->angleDimension;
doaStaticCfg->isDetMatrixLogScale = false; //staticCfg->isDetMatrixLogScale;
doaStaticCfg->azimuthFftSize = testConfig->azimuthFftSize; //staticCfg->azimuthFftSize;
doaStaticCfg->elevationFftSize = 2; //staticCfg->elevationFftSize;
doaStaticCfg->isStaticClutterRemovalEnabled = 1; //dynCfg->staticClutterRemovalCfg.enabled;
doaStaticCfg->isRxChGainPhaseCompensationEnabled = 0; //staticCfg->isRxChGainPhaseCompensationEnabled;
doaStaticCfg->doaRangeLoopType = 0;
doaStaticCfg->enableMajorMotion = 1;
retVal = MmwDemo_cfgDopplerParamMapping(&hwaCfg->doaRngGateCfg, 0);
if (retVal < 0)
{
goto exit;
}
/* L3 allocations */
/* L3 - radar cube */
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;
}
/* L3 - radar cube for minor motion detection */
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;
}
/* L3 - Detection Matrix */
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;
}
}
/* L3 - Doppler Index Matrix */
if ((doaStaticCfg->selectCoherentPeakInDopplerDim == 1) ||
(doaStaticCfg->selectCoherentPeakInDopplerDim == 2))
{
if (doaStaticCfg->angleDimension == 2)
{
/* 2D-case - with elevation */
dopplerIndexMatrix.dataSize = doaStaticCfg->numRangeBins * doaStaticCfg->azimuthFftSize * doaStaticCfg->elevationFftSize * sizeof(uint8_t);
}
else
{
/* 1D-case - no elevation */
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
{
/* Non-coherent combining along Doppler dimension, Doppler output = 0 */
dopplerIndexMatrix.dataSize = 0;
dopplerIndexMatrix.data = NULL;
dopplerIndexMatrix.datafmt = 0;
}
if (doaStaticCfg->angleDimension == 2)
{
/* L3 - Elevation Index Matrix */
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 - copy these structures */
hwRes->radarCube = radarCube;
hwRes->radarCubeMinMot = radarCubeMinMot;
hwRes->detMatrix = detMatrix[0];
hwRes->dopplerIndexMatrix = dopplerIndexMatrix;
hwRes->elevationIndexMatrix = elevationIndexMatrix;
/* hwRes - edmaCfg */
edmaCfg->edmaHandle = gEdmaHandle[0];
/* edmaIn - ping - minor motion*/
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;
/* edmaIn - pong - minor motion*/
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;
/* edmaHotSig */
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;
/* edmaOut - Detection Matrix */
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;
/* edmaOut - Elevation Index Matrix */
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;
/* edmaOut - Doppler Index Matrix */
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 */
hwaCfg->hwaMemInpAddr = CSL_APP_HWA_DMA0_RAM_BANK3_BASE;
hwaCfg->numParamSets = 0; //The number depends on the configuration, will be populated by DPU_DoaProc_config()
hwaCfg->paramSetStartIdx = 0;
/* hwaCfg - window */
winGenLen = (doaStaticCfg->azimuthFftSize > doaStaticCfg->elevationFftSize) ? doaStaticCfg->azimuthFftSize : doaStaticCfg->elevationFftSize;
hwaCfg->windowSize = winGenLen * sizeof(int32_t);
/*Alternate 1,-1,...*/
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;
hwaCfg->winSym = HWA_FFT_WINDOW_NONSYMMETRIC;
if (doaStaticCfg->doaRangeLoopType == DPU_DOAPROC_RANGE_LOOP_CPU_CONTROL)
{
//External range loop
hwRes->interLoopDataBuffer = (cmplx32ImRe_t *) interLoopDataBufferMem;
if (hwRes->interLoopDataBuffer == NULL)
{
retVal = -5;
goto exit;
}
}
else
{
hwRes->interLoopDataBuffer = NULL;
}
hwRes->interLoopDataBuffer = NULL;

DPU Configuration Example

retVal = DPU_DoaProc_config (doaProcDpuHandle,
&doaProcDpuCfg);
if(retVal < 0)
{
DebugP_log("DEBUG: DOA DPU config return error:%d \n", retVal);
}

DPU Process Trigger Example

retVal = DPU_DoaProc_process(doaProcDpuHandle, &radarCubeSrc, &hwRes->detMatrix, &outParms);
if(retVal < 0)
{
DebugP_log("DEBUG: DOA DPU process return error:%d \n", retVal);
}

DPU Close Example

retval = DPU_DoaProc_deinit(doaProcDpuHandle);
if(retVal < 0)
{
/* Not Expected */
DebugP_log("DOAProc DPU deinit error %d\n", retVal);
}
HWA_FFT_WINDOW_NONSYMMETRIC
#define HWA_FFT_WINDOW_NONSYMMETRIC
Definition: hwa/v0/hwa.h:253
DPU_DOAPROC_RANGE_LOOP_CPU_CONTROL
#define DPU_DOAPROC_RANGE_LOOP_CPU_CONTROL
Range loop type controlled by CPU.
Definition: doaproc.h:171
DPU_DoaProc_init
DPU_DoaProc_Handle DPU_DoaProc_init(DPU_DoaProc_InitParams *initCfg, int32_t *errCode)
doaproc.h
Implements Data path DoA processing functionality.
DebugP_log
#define DebugP_log(format,...)
Function to log a string to the enabled console.
Definition: DebugP.h:213
DPU_DoaProc_InitParams::hwaHandle
HWA_Handle hwaHandle
Definition: doaproc.h:216
DPU_DoaProc_HWA_Option_Cfg
Definition: doaproc.h:269
DPU_DoaProc_InitParams
dopplerProc DPU initial configuration parameters
Definition: doaproc.h:215
DPU_DoaProc_HWA_Doppler_Fft_Cfg
Configuration parameters for each HWA param set performing the Doppler FFTs and mappng output into ro...
Definition: doaproc.h:232
DPU_DoaProc_deinit
int32_t DPU_DoaProc_deinit(DPU_DoaProc_Handle handle)
DPU_DoaProc_process
int32_t DPU_DoaProc_process(DPU_DoaProc_Handle handle, DPU_DoaProc_RadarCubeSource *radarCubeSrc, DPIF_DetMatrix *detMatrix, DPU_DoaProc_OutParams *outParams)
DPU_DoaProc_config
int32_t DPU_DoaProc_config(DPU_DoaProc_Handle handle, DPU_DoaProc_Config *cfg)
DebugP_assert
#define DebugP_assert(expression)
Function to call for assert check.
Definition: DebugP.h:159