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.

AWR1843BOOST: Lag when displaying Heat Map.

Part Number: AWR1843BOOST
Other Parts Discussed in Thread: AWR1843

Hi, I am having an issue where the Azmath Heat Map I am displaying from the AWR1843Boost has a lag that gets progressively worse. I am operating the AWR1843 in factory demo mode i received it in. I suspect that the display is due to a backlog of Data from the AWR1843 but could be wrong. I am not sure where to go from here to debug this issue. 

I have tried increasing the frame period in frameCfg to 0.8 which I assumed would account for any delay in the serial communications. It does not seem to have any effect on how fast the lag builds. 

With only the rangeAzimuthHeatMap enabled in guiMonitor the lag builds to about a second almost immediately and within 5 to 10 seconds becomes unmanageable.  When I enable rangeDopplerHeatMap in guiMonitor the delay can take 30 to 60 seconds to become unmanagable even though I am only reading/displaying the rangeAzimuthHeatMap data. 

I have tried to clear the data serial buffer with flush() and flushInput() but the data stops after about 10 seconds of displaying data. 

I have also tried to sensorStop and sensorStart 0. This works for once cycle, but on the second or third time something goes wrong and no data is displayed. 

I am not sure if there is an issue with my code or the config file. 

import serial
import time
import numpy as np

import matplotlib.pyplot as plt
from serial.tools import list_ports

# The Configuration file name
# configFileName = 'AWR1843config copy 2.cfg'
configFileName = 'AWR1843configManual.cfg'
# configFileName = 'AWR1843DemoConfig.cfg'

figure_no = 0

CLIport = {}
Dataport = {}
byteBuffer = np.zeros(2 ** 15, dtype='uint8')
byteBufferLength = 0

TimeOfLastRead = 0

# List the Serial COM ports currently available.
port = list(list_ports.comports())
for p in port:
    print(p.device)


# ------------------------------------------------------------------
# ------------------------------------------------------------------
# ------------------------------------------------------------------
# ------------------------------------------------------------------
# ------------------------------------------------------------------
# ------------------------------------------------------------------

# Function to configure the serial ports and send the data from
# the configuration file to the radar
def serialConfig(configFileName):
    # Open the serial ports for the configuration and the data ports
    # Mac       /dev/tty.usbmodemR20910491	/dev/tty.usbmodemR20910494
    global CLIport
    global Dataport
    CLIport = serial.Serial('/dev/tty.usbmodemR20910491', 115200)
    Dataport = serial.Serial('/dev/tty.usbmodemR20910494', 921600)

    # Read the configuration file and send it to the board
    config = [line.rstrip('\r\n') for line in open(configFileName)]
    for i in config:
        CLIport.write((i + '\n').encode())
        print(i)
        time.sleep(0.01)

    return CLIport, Dataport


# ------------------------------------------------------------------

# Function to parse the data inside the configuration file
def parseConfigFile(configFileName):
    configParameters = {}  # Initialize an empty dictionary to store the configuration parameters

    # Read the configuration file and send it to the board
    config = [line.rstrip('\r\n') for line in open(configFileName)]
    for i in config:

        # Split the line
        splitWords = i.split(" ")

        # Hard code the number of antennas, change if other configuration is used
        numRxAnt = 4
        numTxAnt = 3

        # Get the information about the profile configuration
        if "profileCfg" in splitWords[0]:
            startFreq = int(float(splitWords[2]))
            idleTime = int(splitWords[3])
            rampEndTime = float(splitWords[5])
            freqSlopeConst = float(splitWords[8])
            numAdcSamples = int(splitWords[10])
            numAdcSamplesRoundTo2 = 1

            while numAdcSamples > numAdcSamplesRoundTo2:
                numAdcSamplesRoundTo2 = numAdcSamplesRoundTo2 * 2

            digOutSampleRate = int(splitWords[11])

        # Get the information about the frame configuration
        elif "frameCfg" in splitWords[0]:

            chirpStartIdx = int(splitWords[1])
            chirpEndIdx = int(splitWords[2])
            numLoops = int(splitWords[3])
            numFrames = int(splitWords[4])
            framePeriodicity = float(splitWords[5])

    # Combine the read data to obtain the configuration parameters
    numChirpsPerFrame = (chirpEndIdx - chirpStartIdx + 1) * numLoops
    configParameters["numDopplerBins"] = numChirpsPerFrame / numTxAnt
    configParameters["numRangeBins"] = numAdcSamplesRoundTo2
    configParameters["rangeResolutionMeters"] = (3e8 * digOutSampleRate * 1e3) / (
            2 * freqSlopeConst * 1e12 * numAdcSamples)
    configParameters["rangeIdxToMeters"] = (3e8 * digOutSampleRate * 1e3) / (
            2 * freqSlopeConst * 1e12 * configParameters["numRangeBins"])
    configParameters["dopplerResolutionMps"] = 3e8 / (
            2 * startFreq * 1e9 * (idleTime + rampEndTime) * 1e-6 * configParameters["numDopplerBins"] * numTxAnt)
    configParameters["maxRange"] = (300 * 0.9 * digOutSampleRate) / (2 * freqSlopeConst * 1e3)
    configParameters["maxVelocity"] = 3e8 / (4 * startFreq * 1e9 * (idleTime + rampEndTime) * 1e-6 * numTxAnt)

    return configParameters


# ------------------------------------------------------------------

# Funtion to read and parse the incoming data
def readAndParseData18xx(Dataport, configParameters):
    global byteBuffer, byteBufferLength, TimeOfLastRead

    # Constants
    MMWDEMO_OUTPUT_MSG_AZIMUT_STATIC_HEAT_MAP = 4
    maxBufferSize = 2 ** 15
    magicWord = [2, 1, 4, 3, 6, 5, 8, 7]

    # Initialize variables
    magicOK = 0  # Checks if magic number has been read
    dataOK = 0  # Checks if the data has been read correctly
    CartX = {}
    CartY = {}
    ThetaX = {}
    RangeY = {}
    QQ = {}

    readBuffer = Dataport.read(Dataport.in_waiting)
    byteVec = np.frombuffer(readBuffer, dtype='uint8')
    byteCount = len(byteVec)

    # Check that the buffer is not full, and then add the data to the buffer
    if (byteBufferLength + byteCount) < maxBufferSize:
        byteBuffer[byteBufferLength:byteBufferLength + byteCount] = byteVec[:byteCount]
        byteBufferLength = byteBufferLength + byteCount

    # Check that the buffer has some data
    if byteBufferLength > 16:

        # Check for all possible locations of the magic word
        possibleLocs = np.where(byteBuffer == magicWord[0])[0]

        # Confirm that is the beginning of the magic word and store the index in startIdx
        startIdx = []
        for loc in possibleLocs:
            check = byteBuffer[loc:loc + 8]
            if np.all(check == magicWord):
                startIdx.append(loc)

        # Check that startIdx is not empty
        if startIdx:
            # Remove the data before the first start index
            if startIdx[0] > 0 and startIdx[0] < byteBufferLength:
                byteBuffer[:byteBufferLength - startIdx[0]] = byteBuffer[startIdx[0]:byteBufferLength]
                byteBuffer[byteBufferLength - startIdx[0]:] = np.zeros(len(byteBuffer[byteBufferLength - startIdx[0]:]),
                                                                       dtype='uint8')
                byteBufferLength = byteBufferLength - startIdx[0]

            # Check that there have no errors with the byte buffer length
            if byteBufferLength < 0:
                byteBufferLength = 0

            # word array to convert 4 bytes to a 32 bit number
            word = [1, 2 ** 8, 2 ** 16, 2 ** 24]

            # Read the total packet length
            totalPacketLen = np.matmul(byteBuffer[12:12 + 4], word)

            # Check that all the packet has been read
            if (byteBufferLength >= totalPacketLen) and (byteBufferLength != 0):
                magicOK = 1

    # If magicOK is equal to 1 then process the message
    if magicOK:
        # word array to convert 4 bytes to a 32 bit number
        word = [1, 2 ** 8, 2 ** 16, 2 ** 24]
        '''
        # Initialize the pointer index
        idX = 0
        # Read the header
        # magicNumber = byteBuffer[idX:idX + 8]
        idX += 8
        version = format(np.matmul(byteBuffer[idX:idX + 4], word), 'x')
        idX += 4
        totalPacketLen = np.matmul(byteBuffer[idX:idX + 4], word)
        idX += 4
        platform = format(np.matmul(byteBuffer[idX:idX + 4], word), 'x')
        idX += 4
        frameNumber = np.matmul(byteBuffer[idX:idX + 4], word)
        idX += 4
        timeCpuCycles = np.matmul(byteBuffer[idX:idX + 4], word)
        idX += 4
        numDetectedObj = np.matmul(byteBuffer[idX:idX + 4], word)
        idX += 4
        numTLVs = np.matmul(byteBuffer[idX:idX + 4], word)
        idX += 4
        subFrameNumber = np.matmul(byteBuffer[idX:idX + 4], word)
        idX += 4
        '''

        numTLVs = np.matmul(byteBuffer[32:36], word)
        idX = 40
        # Read the TLV messages
        for tlvIdx in range(numTLVs):

            # word array to convert 4 bytes to a 32 bit number
            word = [1, 2 ** 8, 2 ** 16, 2 ** 24]

            # Check the header of the TLV message
            tlv_type = np.matmul(byteBuffer[idX:idX + 4], word)
            idX += 4
            # tlv_length = np.matmul(byteBuffer[idX:idX + 4], word)
            idX += 4

            if tlv_type == MMWDEMO_OUTPUT_MSG_AZIMUT_STATIC_HEAT_MAP:

                '''
                ################Have also tried this to prevent displaying to often. #######
                ReadTime = time.time() - TimeOfLastRead
                print("Time: " + str(ReadTime))
                if ReadTime <= 0.4:
                    return 0, 0, 0, 0, 0, 0
                ##############################################################
                '''

                '''
                numTxAzimAnt = 3
                numRxAnt = 4
                numBytes = numTxAzimAnt * numRxAnt * configParameters["numRangeBins"] * 4
                '''
                numBytes = 12288
                q = byteBuffer[idX:idX + numBytes]  # single dimension array of the data.

                idX += numBytes
                # qrows = numTxAzimAnt * numRxAnt
                qrows = 12
                # qcols = configParameters["numRangeBins"]
                qcols = 256
                NUM_ANGLE_BINS = 64
                # NUM_ANGLE_BINS = 128   # Seems to be more accurate?

                # Specifying a Stride in a String Slice    Start:End:Skip
                real = q[::4] + q[1::4] * 256
                imaginary = q[2::4] + q[3::4] * 256

                real = real.astype(np.int16)  # Assign type to array
                imaginary = imaginary.astype(np.int16)  # Assign type to array

                q = real + 1j * imaginary  # Sets up imaginary number from data
                q = np.reshape(q, (qrows, qcols), order="F")  # Reshape from 1 dim array to 2 dim array. 12x256

                Q = np.fft.fft(q, NUM_ANGLE_BINS, axis=0)  # One-dimensional discrete Fourier Transform Q 64x256
                QQ = np.fft.fftshift(abs(Q), axes=0)  # Shift the zero-frequency component to center of spectrum.
                QQ = QQ.T  # The transposed array.  QQ array 256x64

                QQ = QQ[:, 1:]
                QQ = np.fliplr(QQ)  # Reverse the order of elements along axis 1 (left/right)  Is a 256x63 array

                theta = np.rad2deg(
                    np.arcsin(np.array(range(-NUM_ANGLE_BINS // 2 + 1, NUM_ANGLE_BINS // 2)) * (2 / NUM_ANGLE_BINS)))

                rangeArray = np.array(range(configParameters["numRangeBins"])) * configParameters["rangeIdxToMeters"]

                CartX = np.outer(rangeArray.T, np.sin(np.deg2rad(theta)))  # Is a 256x63 array
                CartY = np.outer(rangeArray.T, np.cos(np.deg2rad(theta)))  # Is a 256x63 array
                # np.concatenate(posX)
                ThetaX, RangeY = np.meshgrid(theta, rangeArray)

                '''
                np.savetxt('/Users/isaacwilliams/Desktop/Working.nosync/RadarImage/RadDataX-' + str(figure_no) + '.txt',
                           ThetaX, fmt='%.1f', delimiter='\t')

                np.savetxt('/Users/isaacwilliams/Desktop/Working.nosync/RadarImage/RadDataY-' + str(figure_no) + '.txt',
                           RangeY, fmt='%.1f', delimiter='\t')

                np.savetxt('/Users/isaacwilliams/Desktop/Working.nosync/RadarImage/RadDataQ-' + str(figure_no) + '.txt',
                           QQ, fmt='%.1f', delimiter='\t')

                np.save('/Users/isaacwilliams/Desktop/Working.nosync/RadarData/QQ-' + str(figure_no) + '.npy',
                        QQ)
                np.save('/Users/isaacwilliams/Desktop/Working.nosync/RadarData/ThetaX-' + str(figure_no) + '.npy',
                        ThetaX)
                np.save('/Users/isaacwilliams/Desktop/Working.nosync/RadarData/RangeY-' + str(figure_no) + '.npy',
                        RangeY)
                np.save('/Users/isaacwilliams/Desktop/Working.nosync/RadarData/CartX-' + str(figure_no) + '.npy',
                        CartX)
                np.save('/Users/isaacwilliams/Desktop/Working.nosync/RadarData/CartY-' + str(figure_no) + '.npy',
                        CartY)
                '''
                dataOK = 1
                TimeOfLastRead = time.time()


        # Remove already processed data
        if idX > 0 and byteBufferLength > idX:
            byteBuffer = np.zeros(2 ** 15, dtype='uint8')
            """
            shiftSize = totalPacketLen

            byteBuffer[:byteBufferLength - shiftSize] = byteBuffer[shiftSize:byteBufferLength]
            byteBuffer[byteBufferLength - shiftSize:] = np.zeros(len(byteBuffer[byteBufferLength - shiftSize:]),
                                                                 dtype='uint8')
            byteBufferLength = byteBufferLength - shiftSize

            # Check that there are no errors with the buffer length
            if byteBufferLength < 0:
                byteBufferLength = 0
            """


    return dataOK, CartX, CartY, ThetaX, RangeY, QQ


# ------------------------------------------------------------------

# Funtion to update the data and display in the plot
def update():
    global figure_no, frameNo

    # Read and parse the received data
    # return dataOK, frameNumber, CartX, CartY, ThetaX, RangeY, QQ
    dataOk, CartX, CartY, ThetaX, RangeY, QQ = readAndParseData18xx(Dataport, configParameters)

    if dataOk and len(QQ) > 0:
        ## 2D POSITION HEAT MAP
        subplots[0].contourf(CartX, CartY, QQ)
        subplots[0].set_xlim([-1, 1])
        subplots[0].set_ylim([0, 2])

        # ANGLE VS. RANGE HEATMAP
        subplots[1].contourf(ThetaX, RangeY, QQ)
        subplots[1].set_xlim([-60, 60])
        subplots[1].set_ylim([0, 2])
        plt.pause(0.01)

    return dataOk


# -------------------------    MAIN   -----------------------------------------

# Configurate the serial port
CLIport, Dataport = serialConfig(configFileName)

# Get the configuration parameters from the configuration file
configParameters = parseConfigFile(configFileName)

fig = plt.figure(constrained_layout=True, figsize=(10, 5))
subplots = fig.subplots(nrows=1, ncols=2)
subplots[0].grid()
subplots[1].grid()

# Main loop
HeatMapData = {}
frameData = {}
currentIndex = 0

TimeReset = time.time()
ProgRun = True
while ProgRun:
    try:
        # Update the data and check if the data is okay
        # x = time.time_ns()
        # time.sleep(0.5)
        dataOk = update()
        if time.time() - TimeReset >= 10:       #Reset Radar every 10 seconds


            ####### Have tried variations on this to fix lag but does not help######
            CLIport.write(('sensorStop\n').encode())
            time.sleep(0.6)
            # Dataport.flush()
            # Dataport.flushInput()
            # Dataport.flushOutput()
            CLIport.write(('sensorStart 0\n').encode())
            time.sleep(0.6)
            TimeReset = time.time()
            #################################################



    # Stop the program and close everything if Ctrl + c is pressed
    except KeyboardInterrupt:
        x = input('\n\nEnter Command:\n\t-Pause\n\t-Quit\n\n\t')
        if x == 'Quit' or x == 'Q':
            print('User Quit Program')
            CLIport.write(('sensorStop\n').encode())
            CLIport.close()
            Dataport.close()
            time.sleep(1)
            ProgRun = False
        elif x == 'Pause' or x == 'P':
            print('Program Paused')
            CLIport.write(('sensorStop\n').encode())
            x = input('\n\nEnter Command:\n\t-Resume\n\t-Quit\n\n\t')
            paused = True
            while paused == True:
                if x == 'Quit' or x == 'Q':
                    print('User Quit Program')
                    CLIport.write(('sensorStop\n').encode())
                    CLIport.close()
                    Dataport.close()
                    time.sleep(1)
                    ProgRun = False
                elif x == 'Resume' or x == 'R':
                    paused = False
                    # CLIport.write(('sensorStart\n').encode())

                else:
                    print('Unknown command. Program Paused\n\n')
        else:
            print('Unknown command. Program continued')

Configuration file:

sensorStop
flushCfg
dfeDataOutputMode 1
channelCfg 15 7 0
adcCfg 2 1
adcbufCfg -1 0 1 1 1
profileCfg 0 77 5 5.3 18.22 0 0 84.34 1 149 12496 0 0 30
chirpCfg 0 0 0 0 0 0 0 1
chirpCfg 1 1 0 0 0 0 0 4
chirpCfg 2 2 0 0 0 0 0 2
frameCfg 0 2 16 0 500 1 0
lowPower 0 0
guiMonitor -1 0 0 0 1 1 0
cfarCfg -1 0 2 8 4 3 0 15 1
cfarCfg -1 1 0 4 2 3 1 15 1
multiObjBeamForming -1 1 0.5
clutterRemoval -1 0
calibDcRangeSig -1 0 -5 8 256
extendedMaxVelocity -1 0
lvdsStreamCfg -1 0 0 0
compRangeBiasAndRxChanPhase 0.0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
measureRangeBiasAndRxChanPhase 0 1.5 0.2
CQRxSatMonitor 0 3 5 121 0
CQSigImgMonitor 0 127 4
analogMonitor 0 0
aoaFovCfg -1 -90 90 -90 90
cfarFovCfg -1 0 0 8.92
cfarFovCfg -1 1 -1 1.00
sensorStart

This is my displayed data. Only showing 2m of the 20m.

  • Hi,

    Yes, we think this is an issue with your custom GUI.

    We have not seen this feedback with the TI GUI.

    I recommend that you also try to record this data to a file and check the behavior

    With the TI GUI there is a record button and there are python scripts provided to parse recorded data

    C:\ti\mmwave_sdk_03_05_00_04\packages\ti\demo\parser_scripts\mmw_demo_example_script.py

    thank you

    Cesar

  • Hi Cesar,

    Ok good to know it is with my GUI. 

    Are you suggesting that I just use the TI GUI to record my data? Unfortunately for my application that wont work as I need data collected in sink with two other sensors. 

    For recording the data to file to check the behavior, what specifically should I be looking for? 

    Is there a way to pause the data capture on the AWR1843, or scrub any data waiting to be sent to computer or reset the device between captures? I know it is not ideal but if it works then I can at least capture the data I require. 

  • The AWR1843 runs free and sends data to the computer every frame. The only thing that we can do is increase the  frame duration to give the computer more time to read the data. I see that you already have 500ms for frame duration. This is already high.

    I am not sure what you have running on the PC and why it is too slow. I can imagine that if you have several sensors connected to the PC it will be slow

    Unfortunately we don't have sufficient knowledge to support PC issues

    thank you
    Cesar

  • Hi, Based on your previous feedback I have made some adjustments and believe that I have come up with a work around specific for my requirements. For anyone else who might have a similar issue I will go through the work around. 

    I am still unable to display the data without the delay. However wrote another python script that allows me to save the HeatMapArray QQ as a .npy array. For this I have cut out any calculations for the Theta, Range, CartesianX and CartesianY arrays for plotting the Heat Map as, from what I understand they would not change once the configuration file is set. I have Theta, Range, CartesianX and CartesianY saved as .npy array to plot data post capture. 

    In this script, I let the program run and read from the AWR1843 without any delays. I believe this regularly reads from the serial and clears the buffer. I only pass the QQ array to be saved when I need it and then read from my my two cameras once at this point. This seems to work fine. 

    I suspect that in the previous example there is a delay somewhere that is just longer than it takes to get updated data from the radar, but am unsure.