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.

AWR6843: data visualization (No heart Rate while visualizing)

Part Number: AWR6843

Tool/software:

Hii 

I am Mudit Mohan the student of Ramaiah Institute of Technology. We are currently using the AWR6843 radar sensor for monitoring the vital signs(mmwave_industrial_toolbox_4_9_0\labs\vital_signs\68xx_vital_signs\gui\gui_exe) of a driver within a vehicle. Our setup includes the mmWave BOOST board and the AWR6843 radar sensor, positioned at the back of the driver , according to the guidelines provided in the user manual.

We have switched off the motion detection from the params_file. But after switching it off when we visualize it through the matlab code which we converted in python , the heart is not calculated it is showing the Zero Value only breathing rate is there 

below i am attaching the params_file, code, and output 

params_filexwr1642_profile_VitalSigns_20fps_Back.cfg

data taken in the car 

code file we are using to plot file:///C:/Users/MUDIT%20MOHAN/Desktop/VT%20DMS/TI%20Vibrations%20Detector/vitals.py

  • import numpy as np
    import matplotlib.pyplot as plt
    import datetime as dt
    import matplotlib.animation as animation
    import csv
    
    vital_signs_demo_output_stats = {
            'outGlobalCount': [],
            'outPhase': [],
            'outBreathWfm': [],
            'outHeartWfm': [],
            'outHeartRate_FFT': [],
            'outBreathRate_FFT': [],
            'outBreathRate_Peak': [],
            'outHeartRate_Peak': [],
            'outConfidenceMetricHeart': [],
            'outConfidenceMetricBreath': [],
            'outEnergyBreath': [],
            'outEnergyHeart': []
        } 
    
    def calculate_payload_size(params_struct):
        LENGTH_MAGIC_WORD_BYTES = 8
        LENGTH_DEBUG_DATA_OUT_BYTES = 128
        LENGTH_HEADER_BYTES = 40
        LENGTH_TLV_MESSAGE_HEADER_BYTES = 8
        MMWDEMO_OUTPUT_MSG_SEGMENT_LEN = 32
    
        numRangeBinProcessed = params_struct['dataPath']['numRangeBinProcessed']
        TOTAL_PAYLOAD_SIZE_BYTES = LENGTH_HEADER_BYTES
        TOTAL_PAYLOAD_SIZE_BYTES += LENGTH_TLV_MESSAGE_HEADER_BYTES + (4 * numRangeBinProcessed)
        TOTAL_PAYLOAD_SIZE_BYTES += LENGTH_TLV_MESSAGE_HEADER_BYTES + LENGTH_DEBUG_DATA_OUT_BYTES
    
        # Padding
        if TOTAL_PAYLOAD_SIZE_BYTES % MMWDEMO_OUTPUT_MSG_SEGMENT_LEN != 0:
            padding_factor = np.ceil(TOTAL_PAYLOAD_SIZE_BYTES / MMWDEMO_OUTPUT_MSG_SEGMENT_LEN)
            TOTAL_PAYLOAD_SIZE_BYTES = MMWDEMO_OUTPUT_MSG_SEGMENT_LEN * padding_factor
    
        LENGTH_OFFSET_BYTES = LENGTH_HEADER_BYTES - LENGTH_MAGIC_WORD_BYTES + LENGTH_TLV_MESSAGE_HEADER_BYTES
        LENGTH_OFFSET = LENGTH_OFFSET_BYTES + LENGTH_TLV_MESSAGE_HEADER_BYTES
    
        return TOTAL_PAYLOAD_SIZE_BYTES, LENGTH_OFFSET_BYTES, LENGTH_OFFSET
    
    def translate_index(length_offset, index_in):
        return (length_offset + index_in * 4) // 4
    
    def parse_cfg_file(cli_cfg_file_path):
        with open(cli_cfg_file_path, 'r') as cli_cfg_file:
            lines = cli_cfg_file.readlines()
            print(lines)
    
        params = {}
        for line in lines:
            tokens = line.split()
            if len(tokens) > 1:
                if tokens[0] == 'channelCfg':
                    params['channelCfg'] = {
                        'txChannelEn': int(tokens[2]),
                        'rxChannelEn': int(tokens[1])
                    }
                    params['dataPath'] = {
                        'numTxAzimAnt': (params['channelCfg']['txChannelEn'] & 1) +
                                        ((params['channelCfg']['txChannelEn'] >> 2) & 1),
                        'numTxElevAnt': (params['channelCfg']['txChannelEn'] >> 1) & 1,
                        'numRxAnt': bin(params['channelCfg']['rxChannelEn']).count('1')
                    }
                elif tokens[0] == 'profileCfg':
                    params['profileCfg'] = {
                        'startFreq': float(tokens[2]),
                        'idleTime': float(tokens[3]),
                        'rampEndTime': float(tokens[5]),
                        'freqSlopeConst': float(tokens[8]),
                        'numAdcSamples': float(tokens[10]),
                        'digOutSampleRate': float(tokens[11])
                    }
                elif tokens[0] == 'frameCfg':
                    params['frameCfg'] = {
                        'chirpStartIdx': float(tokens[1]),
                        'chirpEndIdx': float(tokens[2]),
                        'numLoops': float(tokens[3]),
                        'framePeriodicity': float(tokens[5])
                    }
                elif tokens[0] == 'guiMonitor':
                    params['guiMonitor'] = {
                        'flag1': float(tokens[1]),
                        'flag2': float(tokens[2]),
                        'rangeAzimuthHeatMap': float(tokens[3]),
                        'rangeDopplerHeatMap': float(tokens[4])
                    }
                elif tokens[0] == 'vitalSignsCfg':
                    params['vitalSignsParams'] = {
                        'rangeStartMeters': float(tokens[1]),
                        'rangeEndMeters': float(tokens[2]),
                        'winLenBreath': float(tokens[3]),
                        'winLenHeart': float(tokens[4])
                    }
    
        params['dataPath']['numChirpsPerFrame'] = (params['frameCfg']['chirpEndIdx'] - params['frameCfg']['chirpStartIdx'] + 1) * params['frameCfg']['numLoops']
        params['dataPath']['numDopplerBins'] = params['dataPath']['numChirpsPerFrame'] // params['dataPath']['numTxAzimAnt']
        params['dataPath']['numRangeBins'] = 2 ** np.ceil(np.log2(params['profileCfg']['numAdcSamples']))
        params['dataPath']['rangeResolutionMeters'] = 3e8 * params['profileCfg']['digOutSampleRate'] * 1e3 / (2 * params['profileCfg']['freqSlopeConst'] * 1e12 * params['profileCfg']['numAdcSamples'])
        params['dataPath']['rangeIdxToMeters'] = 3e8 * params['profileCfg']['digOutSampleRate'] * 1e3 / (2 * params['profileCfg']['freqSlopeConst'] * 1e12 * params['dataPath']['numRangeBins'])
        params['dataPath']['dopplerResolutionMps'] = 3e8 / (2 * params['profileCfg']['startFreq'] * 1e9 * (params['profileCfg']['idleTime'] + params['profileCfg']['rampEndTime']) * 1e-6 *params['dataPath']['numDopplerBins'] * params['dataPath']['numTxAzimAnt'])
        params['dataPath']['chirpDuration_us'] = (1e3 * params['profileCfg']['numAdcSamples']) / params['profileCfg']['digOutSampleRate']
        freq_slope_const_temp = 48 * params['profileCfg']['freqSlopeConst'] * 2 ** 26 * 1e3 / ((3.6 * 1e9) * 900)  # To match the C-code
        params['dataPath']['chirpBandwidth_kHz'] = (freq_slope_const_temp) * (params['dataPath']['chirpDuration_us'])
        num_temp = (params['dataPath']['chirpDuration_us']) * (params['profileCfg']['digOutSampleRate']) * (3e8)
        den_temp = 2 * (params['dataPath']['chirpBandwidth_kHz'])
        params['dataPath']['rangeMaximum'] = num_temp / (den_temp * 1e9)
        params['dataPath']['rangeBinSize_meter'] = params['dataPath']['rangeMaximum'] / params['dataPath']['numRangeBins']
        range_start_index = np.floor(params['vitalSignsParams']['rangeStartMeters'] / params['dataPath']['rangeBinSize_meter'])
        range_end_index = np.floor(params['vitalSignsParams']['rangeEndMeters'] / params['dataPath']['rangeBinSize_meter'])
        params['dataPath']['lambdaCenter_mm'] = (3e8 / params['profileCfg']['startFreq']) / 1e6
        params['dataPath']['rangeStart_Index'] = range_start_index
        params['dataPath']['rangeEnd_Index'] = range_end_index
        params['dataPath']['numRangeBinProcessed'] = range_end_index - range_start_index + 1
    
        return params
    
    def parse_data_evm(data_evm, index_vital_signs_output,length):
        
    
        global vital_signs_demo_output_stats
    
        INDEX_GLOBAL_COUNT = 21
        # INDEX_RANGE_BIN_PHASE = translate_index(length,1)
        # INDEX_RANGE_BIN_VALUE = translate_index(length,2)
        INDEX_PHASE = translate_index(length,5)
        INDEX_BREATHING_WAVEFORM = translate_index(length,6)
        INDEX_HEART_WAVEFORM = translate_index(length,7)
        INDEX_BREATHING_RATE_FFT = translate_index(length,12)
        INDEX_HEART_RATE_EST_FFT = translate_index(length,8)
        INDEX_BREATHING_RATE_PEAK = translate_index(length,14)
        INDEX_HEART_RATE_EST_PEAK = translate_index(length,11)
        INDEX_CONFIDENCE_METRIC_BREATH = translate_index(length,15)
        INDEX_CONFIDENCE_METRIC_HEART = translate_index(length,17)
        INDEX_ENERGYWFM_BREATH = translate_index(length,20)
        INDEX_ENERGYWFM_HEART = translate_index(length,21)
    
        for ii in range(data_evm.shape[1]):
            temp_16 = np.frombuffer(data_evm[INDEX_GLOBAL_COUNT:INDEX_GLOBAL_COUNT + 4, ii].tobytes(), dtype=np.uint32)
            temp_32 = np.frombuffer(data_evm[:, ii].tobytes(), dtype=np.uint32)
            temp_float = np.frombuffer(data_evm[:, ii].tobytes(), dtype=np.float32)
    
            out_global_count = temp_16[0]
            
    
            vital_signs_demo_output_stats['outGlobalCount'].append(out_global_count)
            vital_signs_demo_output_stats['outPhase'].append(temp_float[INDEX_PHASE])
            vital_signs_demo_output_stats['outBreathWfm'].append(temp_float[INDEX_BREATHING_WAVEFORM])
            vital_signs_demo_output_stats['outHeartWfm'].append(temp_float[INDEX_HEART_WAVEFORM])
            vital_signs_demo_output_stats['outHeartRate_FFT'].append(temp_float[INDEX_HEART_RATE_EST_FFT])
            vital_signs_demo_output_stats['outBreathRate_FFT'].append(temp_float[INDEX_BREATHING_RATE_FFT])
            vital_signs_demo_output_stats['outBreathRate_Peak'].append(temp_float[INDEX_BREATHING_RATE_PEAK])
            vital_signs_demo_output_stats['outHeartRate_Peak'].append(temp_float[INDEX_HEART_RATE_EST_PEAK])
            vital_signs_demo_output_stats['outConfidenceMetricHeart'].append(temp_float[INDEX_CONFIDENCE_METRIC_HEART])
            vital_signs_demo_output_stats['outConfidenceMetricBreath'].append(temp_float[INDEX_CONFIDENCE_METRIC_BREATH])
            vital_signs_demo_output_stats['outEnergyBreath'].append(temp_float[INDEX_ENERGYWFM_BREATH])
            vital_signs_demo_output_stats['outEnergyHeart'].append(temp_float[INDEX_ENERGYWFM_HEART])  
           
    
       #print("GLOBAL count" + str(vital_signs_demo_output_stats['outGlobalCount'])+"\n")
       #print("PHASE" + str(vital_signs_demo_output_stats['outPhase'])+"\n")
        print("Breath Waveform" + str(vital_signs_demo_output_stats['outBreathWfm'])+"\n")
        print("Heart waveform" + str(vital_signs_demo_output_stats['outHeartWfm'])+"\n")
       #print("Heart rate FFT" + str(vital_signs_demo_output_stats['outHeartRate_FFT'])+"\n")
       #print("Breath rate FFT" + str(vital_signs_demo_output_stats['outBreathRate_FFT'])+"\n")
       #print("Breath rate peak" + str(vital_signs_demo_output_stats['outBreathRate_Peak'])+"\n")
       #print("Heart rate peak" + str(vital_signs_demo_output_stats['outHeartRate_Peak'])+"\n")
       #print("metric heart" + str(vital_signs_demo_output_stats['outConfidenceMetricHeart'])+"\n")
       #print("metric breath" + str(vital_signs_demo_output_stats['outConfidenceMetricBreath'])+"\n")
       #print("energy breath" + str(vital_signs_demo_output_stats['outEnergyBreath'])+"\n")
       # print("energy heart" + str(vital_signs_demo_output_stats['outEnergyHeart'])+"\n")
    
           
       
        #print(index_vital_signs_output)
        return vital_signs_demo_output_stats
    
    def moving_average(data, window_size):
        cumsum = np.cumsum(data)
        cumsum[window_size:] = cumsum[window_size:] - cumsum[:-window_size]
        smoothed_data = cumsum[window_size - 1:] / window_size
        return smoothed_data
    
    
    def main():
        # Directory name
        dir_name = 'C:\\Users\\MUDIT MOHAN\\Desktop\\mmwave_industrial_toolbox_4_9_0\\labs\\vital_signs\\68xx_vital_signs\\gui\\gui_exe\\'
        dir_config_name = 'C:\\Users\\MUDIT MOHAN\\Desktop\\mmwave_industrial_toolbox_4_9_0\\labs\\vital_signs\\68xx_vital_signs\\gui\\profiles\\'
    
        # Configuration file used to collect the data
        cli_cfg_file_dir = dir_config_name
        cli_cfg_file_name = 'xwr1642_profile_VitalSigns_20fps_Back.cfg'
    
        # Binary Data
        file_name_bin = 'rajan1.bin'
        file_path_bin = dir_name + file_name_bin
    
        with open(file_path_bin, 'rb') as fid_bin:
            data_bin = np.frombuffer(fid_bin.read(), dtype=np.uint8)
    
        cli_cfg_file_path = cli_cfg_file_dir + cli_cfg_file_name
        params_struct = parse_cfg_file(cli_cfg_file_path)
        total_payload_size_bytes, index_vital_signs_output,length = calculate_payload_size(params_struct)
        
    
        num_chirps_file = len(data_bin) // total_payload_size_bytes
    
        data_all = np.reshape(data_bin, (int(total_payload_size_bytes), int(num_chirps_file)), order='F')
        data_evm = data_all
    
        sampling_interval = 1e-3 * params_struct['frameCfg']['framePeriodicity']  # Frame Periodicity
        Fs = 1 / sampling_interval  # Sampling Rate
        time_axis = np.arange(sampling_interval, data_evm.shape[1] * sampling_interval + 1, sampling_interval)
        range_bin_size_meter = params_struct['dataPath']['rangeBinSize_meter']
        range_start_meters = params_struct['vitalSignsParams']['rangeStartMeters']
        range_end_meters = params_struct['vitalSignsParams']['rangeEndMeters']
        range_axis = np.arange(range_start_meters, range_end_meters + range_bin_size_meter, range_bin_size_meter)
    
        INDEX_RANGE_PROFILE_START = index_vital_signs_output
        num_range_bins_sent_uart = params_struct['dataPath']['numRangeBinProcessed']
        range_profile = range_profile = data_evm[int(INDEX_RANGE_PROFILE_START):int((INDEX_RANGE_PROFILE_START + 4 * num_range_bins_sent_uart) - 1), :]
        range_profile = range_profile[::2, :] + np.vstack((range_profile[1::2, :], np.zeros((1, range_profile.shape[1]), dtype=range_profile.dtype))) * 2 ** 8
    
    
        # Convert from the 2's complement form
        range_profile[range_profile > 2 * 15] -= 2 * 16
    
        # Convert to complex format
        range_profile_cplx = range_profile[::2, :] + 1j * range_profile[1::2, :]
    
        # Extract the Phase from a range-bin of interest
        row_index = 4
        ant1_Ph = np.angle(range_profile_cplx[row_index, :])
        ant1_UnWrapPh = np.unwrap(ant1_Ph)
    
        # plt.figure(1)
        # plt.subplot(311)
        # plt.imshow(np.abs(range_profile_cplx), aspect='auto')
        # plt.xlabel('Frame Number')
        # plt.ylabel('Range Bins')
        # plt.title('Magnitude of the Range Profiles')
        # plt.subplot(312)
        # plt.plot(np.abs(range_profile_cplx[:, 10]))
        # plt.grid(True)
        # plt.title('A selected column of the Range Profile')
        # plt.subplot(313)
        # plt.plot(ant1_UnWrapPh)
        # plt.grid(True)
        # plt.title('Unwrapped Phase of a Range Bin')
    
        # plt.show()
    
        # Display the Vital Signs Demo Output
        # Assuming index_vital_signs_output is an integer
        vital_signs_stats = parse_data_evm(data_evm, index_vital_signs_output,length)
        global_count = vital_signs_stats['outGlobalCount']
        phase_data = vital_signs_stats['outPhase']
        breath_wfm = vital_signs_stats['outBreathWfm']
        heart_wfm = vital_signs_stats['outHeartWfm']
        con_heart_wfm=vital_signs_stats['outConfidenceMetricHeart']
    #     LIVE plot code (there's some error figure it out)
    #     plt.ion()  # Turn on interactive mode for real-time updates
    #     fig, ax = plt.subplots()
    #     x_data = vital_signs_demo_output_stats['outHeartWfm']
    
    #     line, = ax.plot(x_data)
    
    # # Example binary file path
       
    #     try:    
    #         while True:
    #            # Read data from the binary file
    #            new_data = vital_signs_demo_output_stats['outHeartWfm']
    #            print("new_data:", new_data)
    #            # Update x and y data
    #            if isinstance(new_data, (list, tuple)) and all(isinstance(item, tuple) and len(item) == 2 for item in new_data):
    #              x_data.extend([item[0] for item in new_data])
    #              #y_data.extend([item[1] for item in new_data])
         
    #              # Update the plot
    #              line.set_xdata(x_data)
    #              #line.set_ydata(y_data)
         
    #              # Adjust the plot limits if needed
    #              ax.relim()
    #              ax.autoscale_view()
         
    #              # Pause to allow time for the plot to update
    #              plt.pause(10)
    
    #     except KeyboardInterrupt:
    #         plt.ioff()
    #         plt.show()
       
       
        plt.figure(2)
        plt.subplot(311)
        plt.plot(phase_data)
        plt.grid(True)
        plt.title('Phase Data')
    
        plt.subplot(312)
        plt.plot(breath_wfm)
        plt.grid(True)
        plt.title('Breath Waveform')
    
        plt.subplot(313)
        plt.plot(heart_wfm)
        plt.grid(True)
        plt.title('Heart Waveform')
        plt.show()
       
        #moving average code
        
        heart_wfm = np.array(vital_signs_stats['outHeartWfm'])
        breath_wfm = np.array(vital_signs_stats['outBreathWfm'])  
    
        # Set the moving average window size
        window_size = 40
        window_sizeb=10
    
        # Apply moving average filter
        smoothed_heart_wfm = moving_average(heart_wfm, window_size)
        smoothed_breath_wfm = moving_average(breath_wfm, window_sizeb)
        # Plot original and smoothed heart waveforms
        smoothed_heart_wfm_diff = np.diff(smoothed_heart_wfm)
        plt.plot(smoothed_heart_wfm)
        plt.plot(smoothed_heart_wfm_diff+80,'*-')
        plt.show()
    
        # smoothed_breath_wfm_diff = np.diff(smoothed_breath_wfm)
        # plt.plot(smoothed_breath_wfm)
        # plt.plot(smoothed_breath_wfm_diff+0.05,'*-')
        # plt.show()
    
        plt.subplot(211)
        plt.plot(heart_wfm, label='Original Heart Waveform')
        plt.plot(smoothed_heart_wfm, label=f'Smoothed (Window Size: {window_size})')
        plt.legend()
        plt.title('Heart Waveform with Moving Average Smoothing')
        # plt.xlabel('Sample Index')
        plt.ylabel('Amplitude')
        plt.grid(True)
    
        plt.subplot(212)
        plt.plot(breath_wfm, label='Original Breath Waveform')
        plt.plot(smoothed_breath_wfm, label=f'Smoothed (Window Size: {window_sizeb})')
        plt.legend()
        plt.title('Breath Waveform with Moving Average Smoothing')
        plt.xlabel('Sample Index')
        plt.ylabel('Amplitude')
        plt.grid(True)
        plt.show()
    
        # plt.plot(con_heart_wfm)
        # plt.show()
    
        # Specify the file name
        csv_file_path = 'C:\\Users\\MUDIT MOHAN\\Desktop\\mmwave_industrial_toolbox_4_9_0\\labs\\vital_signs\\68xx_vital_signs\\gui\\gui_exe\\vitals_demo.csv'
        headings = list(vital_signs_demo_output_stats.keys())
        #data = numpy_data.tolist()
        # Writing data to CSV file
        with open(csv_file_path, 'w', newline='') as csv_file:
         csv_writer = csv.writer(csv_file)
        
         # Write the header row
         csv_writer.writerow(headings)
        
         # Write the data rows
         for row_values in zip(*vital_signs_demo_output_stats.values()):
            csv_writer.writerow(row_values)
        print('******************************************************')
        print(f'Data has been written to {csv_file_path}')
        print('******************************************************')
    
    if __name__ == "__main__":
        main()
  • Hi,

    Did this modification work with the MATLAB code?

    Thanks,

    Clinton

  • Yes, as we had just converted the Matlab visualization code to python, infact when we were not switching off the motion detection at that time it used to show the great visuals for all.

  • Mudit,

    This resource is a deprecated lab that TI no longer maintains or supports. We can only provide the demo code as is with no additional support. 

    Thanks,

    Angie