This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

IWR6843ISK-ODS: how to get rangeAzimuthHeatMap(RA map)

Part Number: IWR6843ISK-ODS


Tool/software:

Hello everyone,
I want to use deep learning methods for object detection based on the rangeAzimuthHeatMap in TI's millimeter wave radar, but I don't know how to obtain the rangeAzimuthHeatMap(array in format of (numInputRangeBins * nAzimuthBins). Using "mmWave Demo Visualizer" can only output the Azimuth static heatmap(array in format of(Range FFT size) x (Number of virtual antennas) . Please can you clarify this aspect?

 
Sincerely,
Yang liu 
  • Hi,

    You can use our default outputs if you would like, or you can re program the radar yourself to output different data. For this specific question - you would simply run an FFT on the angle domain to transform the data from the antenna domain to the angle domain.

    Best,

    Nate

  • Thanks for your reply, I have run an FFT on the angle domain to transform the data from the antenna domain to the angle domain. However, I encountered a new problem where the converted rangeAzimuthHeatMap did not show clear target movement trajectories, and there were people walking inside the scene, I have uploaded relevant materials in the attachment, including RA images and videos(which need to be downloaded before opening), as well as data processing scripts. Please can you clarify this aspect?


    # ****************************************************************************
    # * (C) Copyright 2020, Texas Instruments Incorporated. - www.ti.com
    # ****************************************************************************
    # *
    # *  Redistribution and use in source and binary forms, with or without
    # *  modification, are permitted provided that the following conditions are
    # *  met:
    # *
    # *    Redistributions of source code must retain the above copyright notice,
    # *    this list of conditions and the following disclaimer.
    # *
    # *    Redistributions in binary form must reproduce the above copyright
    # *    notice, this list of conditions and the following disclaimer in the
    # *     documentation and/or other materials provided with the distribution.
    # *
    # *    Neither the name of Texas Instruments Incorporated nor the names of its
    # *    contributors may be used to endorse or promote products derived from
    # *    this software without specific prior written permission.
    # *
    # *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    # *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
    # *  PARTICULAR TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    # *  A PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT  OWNER OR
    # *  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
    # *  EXEMPLARY, ORCONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
    # *  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
    # *  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
    # *  LIABILITY, WHETHER IN CONTRACT,  STRICT LIABILITY, OR TORT (INCLUDING
    # *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
    # *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    # *
    
    # import the required Python packages
    import struct
    import math
    import binascii
    import codecs
    
    # definations for parser pass/fail
    TC_PASS   =  0
    TC_FAIL   =  1
    
    def getUint32(data):
        """!
           This function coverts 4 bytes to a 32-bit unsigned integer.
    
            @param data : 1-demension byte array  
            @return     : 32-bit unsigned integer
        """ 
        return (data[0] +
                data[1]*256 +
                data[2]*65536 +
                data[3]*16777216)
    
    def getUint16(data):
        """!
           This function coverts 2 bytes to a 16-bit unsigned integer.
    
            @param data : 1-demension byte array
            @return     : 16-bit unsigned integer
        """ 
        return (data[0] +
                data[1]*256)
    
    def getUint8(data):
        """!
           This function coverts 2 bytes to a 16-bit unsigned integer.
    
            @param data : 1-demension byte array
            @return     : 16-bit unsigned integer
        """ 
        return (data[0])
    
    def getHex(data):
        """!
           This function coverts 4 bytes to a 32-bit unsigned integer in hex.
    
            @param data : 1-demension byte array
            @return     : 32-bit unsigned integer in hex
        """ 
        return (binascii.hexlify(data[::-1]))
    
    def checkMagicPattern(data):
        """!
           This function check if data arrary contains the magic pattern which is the start of one mmw demo output packet.  
    
            @param data : 1-demension byte array
            @return     : 1 if magic pattern is found
                          0 if magic pattern is not found 
        """ 
        found = 0
        if (data[0] == 2 and data[1] == 1 and data[2] == 4 and data[3] == 3 and data[4] == 6 and data[5] == 5 and data[6] == 8 and data[7] == 7):
            found = 1
        return (found)
              
    def parser_helper(data, readNumBytes):
        """!
           This function is called by parser_one_mmw_demo_output_packet() function or application to read the input buffer, find the magic number, header location, the length of frame, the number of detected object and the number of TLV contained in this mmw demo output packet.
    
            @param data                   : 1-demension byte array holds the the data read from mmw demo output. It ignorant of the fact that data is coming from UART directly or file read.  
            @param readNumBytes           : the number of bytes contained in this input byte array  
                
            @return headerStartIndex      : the mmw demo output packet header start location
            @return totalPacketNumBytes   : the mmw demo output packet lenght           
            @return numDetObj             : the number of detected objects contained in this mmw demo output packet          
            @return numTlv                : the number of TLV contained in this mmw demo output packet           
            @return subFrameNumber        : the sbuframe index (0,1,2 or 3) of the frame contained in this mmw demo output packet
        """ 
    
        headerStartIndex = -1
    
        for index in range (readNumBytes):
            if checkMagicPattern(data[index:index+8:1]) == 1:
                headerStartIndex = index
                break
      
        if headerStartIndex == -1: # does not find the magic number i.e output packet header 
            totalPacketNumBytes = -1
            numDetObj           = -1
            numTlv              = -1
            subFrameNumber      = -1
            platform            = -1
            frameNumber         = -1
            timeCpuCycles       = -1
        else: # find the magic number i.e output packet header 
            totalPacketNumBytes = getUint32(data[headerStartIndex+12:headerStartIndex+16:1])
            platform            = getHex(data[headerStartIndex+16:headerStartIndex+20:1])
            frameNumber         = getUint32(data[headerStartIndex+20:headerStartIndex+24:1])
            timeCpuCycles       = getUint32(data[headerStartIndex+24:headerStartIndex+28:1])
            numDetObj           = getUint32(data[headerStartIndex+28:headerStartIndex+32:1])
            numTlv              = getUint32(data[headerStartIndex+32:headerStartIndex+36:1])
            subFrameNumber      = getUint32(data[headerStartIndex+36:headerStartIndex+40:1])
            
        print("headerStartIndex    = %d" % (headerStartIndex))
        print("totalPacketNumBytes = %d" % (totalPacketNumBytes))
        print("platform            = %s" % (platform)) 
        print("frameNumber         = %d" % (frameNumber)) 
        print("timeCpuCycles       = %d" % (timeCpuCycles))   
        print("numDetObj           = %d" % (numDetObj)) 
        print("numTlv              = %d" % (numTlv))
        print("subFrameNumber      = %d" % (subFrameNumber))   
                                  
        return (headerStartIndex, totalPacketNumBytes, numDetObj, numTlv, subFrameNumber)
    
    import numpy as np
    # n_angle = 64
    n_angle = 128
    n_vel = 256
    n_range = 256
    n_chirp = 255
    n_rx = 12
    n_sample = 256
    noma_rcs = 30000
    
    def produce_RA_slice(data, filter_static=False, keep_complex=False):
        hanning_win = np.hamming(n_rx)
        win_data = np.zeros([data.shape[0], data.shape[1]], dtype=np.complex128) #[256,12]
        for i in range(data.shape[0]):
                win_data[i] = np.multiply(data[i], hanning_win)
        
        # fft3d_data_cmplx = np.fft.fft(win_data, n_angle, axis=1) ### add
        fft_data_raw = np.fft.fft(win_data, n_angle, axis=1)
        fft3d_data_cmplx = fft_data_raw # 不移位
        # np.fft.fftshift,将数据沿着指定的轴进行循环移位
        # fft3d_data_cmplx = np.fft.fftshift(fft_data_raw, axes=1)
        # fft3d_data_cmplx = np.fft.fftshift(fft3d_data_cmplx, axes=0) # add liuyang
        if keep_complex is True:
            fft3d_data = fft3d_data_cmplx
        else:
            fft_data_real = np.expand_dims(fft3d_data_cmplx.real, axis=2)
            fft_data_imag = np.expand_dims(fft3d_data_cmplx.imag, axis=2)
            # output format [range, angle, chirps, real/imag]
            fft3d_data = np.float32(np.concatenate((fft_data_real, fft_data_imag), axis=2))
        if filter_static:
            fft3d_data = fft3d_data - np.mean(fft3d_data, axis=1, keepdims=True)
    
        return fft3d_data
    
    
    def parser_one_mmw_demo_output_packet(img_idx, data, readNumBytes):
        """!
           This function is called by application. Firstly it calls parser_helper() function to find the start location of the mmw demo output packet, then extract the contents from the output packet.
           Each invocation of this function handles only one frame at a time and user needs to manage looping around to parse data for multiple frames.
    
            @param data                   : 1-demension byte array holds the the data read from mmw demo output. It ignorant of the fact that data is coming from UART directly or file read.  
            @param readNumBytes           : the number of bytes contained in this input byte array  
                
            @return result                : parser result. 0 pass otherwise fail
            @return headerStartIndex      : the mmw demo output packet header start location
            @return totalPacketNumBytes   : the mmw demo output packet lenght           
            @return numDetObj             : the number of detected objects contained in this mmw demo output packet          
            @return numTlv                : the number of TLV contained in this mmw demo output packet           
            @return subFrameNumber        : the sbuframe index (0,1,2 or 3) of the frame contained in this mmw demo output packet
            @return detectedX_array       : 1-demension array holds each detected target's x of the mmw demo output packet
            @return detectedY_array       : 1-demension array holds each detected target's y of the mmw demo output packet
            @return detectedZ_array       : 1-demension array holds each detected target's z of the mmw demo output packet
            @return detectedV_array       : 1-demension array holds each detected target's v of the mmw demo output packet
            @return detectedRange_array   : 1-demension array holds each detected target's range profile of the mmw demo output packet
            @return detectedAzimuth_array : 1-demension array holds each detected target's azimuth of the mmw demo output packet
            @return detectedElevAngle_array : 1-demension array holds each detected target's elevAngle of the mmw demo output packet
            @return detectedSNR_array     : 1-demension array holds each detected target's snr of the mmw demo output packet
            @return detectedNoise_array   : 1-demension array holds each detected target's noise of the mmw demo output packet
        """
    
        headerNumBytes = 40   
    
        PI = 3.14159265
    
        detectedX_array = []
        detectedY_array = []
        detectedZ_array = []
        detectedV_array = []
        detectedRange_array = []
        detectedAzimuth_array = []
        detectedElevAngle_array = []
        detectedSNR_array = []
        detectedNoise_array = []
    
        result = TC_PASS
    
        # call parser_helper() function to find the output packet header start location and packet size 
        (headerStartIndex, totalPacketNumBytes, numDetObj, numTlv, subFrameNumber) = parser_helper(data, readNumBytes)
                             
        if headerStartIndex == -1:
            result = TC_FAIL
            print("************ Frame Fail, cannot find the magic words *****************")
        else:
            # nextHeaderStartIndex = headerStartIndex + totalPacketNumBytes 
            # # tt = checkMagicPattern(data[nextHeaderStartIndex:nextHeaderStartIndex+8:1])
            if headerStartIndex + totalPacketNumBytes > readNumBytes:
                result = TC_FAIL
                print("********** Frame Fail, readNumBytes may not long enough ***********")
            # elif nextHeaderStartIndex + 8 < readNumBytes and checkMagicPattern(data[nextHeaderStartIndex:nextHeaderStartIndex+8:1]) == 0:
        
            #     result = TC_FAIL
            #     print("********** Frame Fail, incomplete packet **********") 
            # elif numDetObj <= 0:
            #     result = TC_FAIL
            #     print("************ Frame Fail, numDetObj = %d *****************" % (numDetObj))
            # elif subFrameNumber > 3:
            #     result = TC_FAIL
            #     print("************ Frame Fail, subFrameNumber = %d *****************" % (subFrameNumber))
            else: 
                # process the 1st TLV ## 
                tlvStart = headerStartIndex + headerNumBytes
                                                        
                tlvType    = getUint32(data[tlvStart+0:tlvStart+4:1])
                tlvLen     = getUint32(data[tlvStart+4:tlvStart+8:1])       
                offset = 8
                print("The 1st TLV") 
                print("    type %d" % (tlvType))
                print("    len %d bytes" % (tlvLen))
    
                save_data = data[tlvStart + offset: tlvStart + offset+tlvLen]
                import pickle
                pickle.dump(save_data,open('ra_bin_data','wb'))  #后缀.pkl可加可不加
                ### 解析RAmap, 目前还不确定解析是否正确
                import numpy as np
                import matplotlib.pyplot as plt
                radar_npy_win_ra = np.zeros((256, 12), dtype=np.complex128)
                idx=0
                endian = '<' ### 小端存储    
                # hh表示2个int16,有符号短整型   
                format_str = endian +'hh'
                if tlvType == 8 and tlvLen < totalPacketNumBytes:
                    while(idx<256*12):
                        img, real = struct.unpack(format_str,data[tlvStart + offset + 0:tlvStart + offset + 4:1])
                        # img = img/2000
                        # real = real/2000
                        radar_npy_win_ra[int(idx/12),int(idx%12)] = real + 1j*img
                        # radar_npy_win_ra[int(idx/6),int(idx%6)].imag = img
                        # radar_npy_win_ra[int(idx/6),int(idx%6)].real = real
                        offset = offset + 4
                        idx+=1
                radar_npy_win_ra = produce_RA_slice(radar_npy_win_ra) #(256,128,2)
                radar_npy_win_ra = radar_npy_win_ra[0:128]
                # radar_npy_win_ra = np.concatenate((radar_npy_win_ra, radar_npy_win_ra), axis=1)[0:128]
                np.save('ra.npy', radar_npy_win_ra)
                ra_imag = np.sqrt(radar_npy_win_ra[:, :, 0] ** 2 + radar_npy_win_ra[:, :, 1] ** 2)
                plt.imshow(ra_imag, origin='lower')
                img_path = "/work/ai_lab/miner/code/data_process/3d/ra_img/"+str(img_idx)+".jpg"
                plt.savefig(img_path) 
    
    
        return (result, headerStartIndex, totalPacketNumBytes, numDetObj, numTlv, subFrameNumber, detectedX_array, detectedY_array, detectedZ_array, detectedV_array, detectedRange_array, detectedAzimuth_array, detectedElevAngle_array, detectedSNR_array, detectedNoise_array)
    
    
    
    
        
    
    
    
    
    
    
    
    
    
    

  • Hi,

    One of your videos doesn't play, but we don't debug custom code on this forum. I would recommend passing synthetic data through your script to see if the output matches what you expect. Alternatively, you can use the radar point cloud demo as it exists as a ground truth guide.

    Best

    Nate