Announcements

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
JimHeo
Level 1
Level 1
First solution authored 10 sign-ins 5 sign-ins

Hello, I am working on implementing radar images from the raw data using BGT60TR13C.
So far, I have completed reading raw-data from RadarFusionGUI program and producing range-doppler map of the radar.

However, when I applied range-angle map algorithm by following range-angle-map.py of SDK, the map shows quite different images. Specifically, the beam pattern of the target is not obvious as Python figure. Can anyone answer what the problem of my code is?

Here are configuration of my MATLAB code, radar system (Header information), and range-angle map image I got.

 

 

clc; close; clear;

tic;
%% read rawdata & generate radar cube
filename = './data(386)';
[Frame, Header, Frame_count] = read_parse_rawdata(filename);

% configuration parameters
c = 3e8;
Fc = 60e9;
Bsweep =(Header.Upper_RF_Frequency_kHz - Header.Lower_RF_Frequency_kHz)*1e3;
lam = c/Fc;
dAnt = 2.5e-3;      % array distance between virtual antennas
numAnt = 3;         % number of RX antennas
Amax = 40/180*pi;   % maximum Angle of Arrival of array antennas
numBeam = 27;       % number of beams of beamforming function

Vmax = lam / (4 * Header.Pulse_Repetition_Time_sec)
Vres = lam / (2 * Header.Pulse_Repetition_Time_sec * Header.Chirps_per_Frame)
Rres = c / (2 * Bsweep)
Rmax = Rres * Header.Samples_per_Chirp / 2 % divide by 2 because it is I-channel only (symmetry doulbe side band affter FFT)
S = Bsweep / Header.Chirp_Time_sec;
IFmax = Rmax * (4*S) / c; 


% De-normalization ADC signals if needed
% for i = 1:Header.numFrame
%     Frame(i).Chirp = Frame(i).Chirp*4096;   % de-normalized by mutiplying 4096 (12bits) as a factor)
% end

for i = 1:Header.numFrame
    history(i).Chirp = zeros(Header.Samples_per_Chirp,Header.Chirps_per_Frame,Header.Num_Rx_Antennas);
end

% remove mean and static clutter removal
alpha = 0.8;            % static clutter removal coefficient
is_clutter_removal = 1; % set to 1 if you want to remove static clutter

for i = 1:Header.numFrame
    if is_clutter_removal 
        for chIdx = 1:Header.Num_Rx_Antennas
            % remove average from signal (mean removal)
            Frame(i).Chirp(:,:,chIdx) = Frame(i).Chirp(:,:,chIdx) - mean(mean( Frame(i).Chirp(:,:,chIdx) ));
            % MTI processing to remove static clutters (static clutter removal)
            if i == 1
                Frame(i).Chirpfilter(:,:,chIdx) = Frame(i).Chirp(:,:,chIdx)*(1-alpha);
                history(i).Chirp(:,:,chIdx) = Frame(i).Chirp(:,:,chIdx);
            else
                Frame(i).Chirpfilter(:,:,chIdx) = Frame(i).Chirp(:,:,chIdx) - history(i-1).Chirp(:,:,chIdx);
                history(i).Chirp(:,:,chIdx) = alpha*Frame(i).Chirp(:,:,chIdx) + (1-alpha)*history(i-1).Chirp(:,:,chIdx);
            end
        end
    else 
        Frame(i).Chirpfilter = Frame(i).Chirp;
    end
end

%% processing radar cube

% window
rangeWinType = 1;
switch rangeWinType
    case 1 % hann
        for i = 1:numAnt    
            rangedopplerwin(:,:,i) =  (hann(Header.Samples_per_Chirp)*hann(Header.Chirps_per_Frame)');
        end
end
%
numFFT = 512;
% 2D FFT (range-doppler)
for i =1:Header.numFrame
    FFT(i).RD = fft2(Frame(i).Chirpfilter.*rangedopplerwin,numFFT,numFFT) / (numFFT*numFFT);

    % ignore redundant info in negative spectrum
    % compensate energy by doubling magnitude
    FFT(i).RD = 2*FFT(i).RD(1:numFFT/2,:,:);
    FFT(i).RD = fftshift(FFT(i).RD ,2);
    % maximum point search
    [maximum(i),idx(i).maxRD] = maxN(FFT(i).RD);
end

% plot range-doppler map
Range = linspace(0,Rmax,numFFT/2);
Vdoppler = linspace(-Vmax,Vmax,numFFT);
angle = linspace(-40,40,numBeam);
% normalization
for i = 1:Header.numFrame
    FFT(i).RD = FFT(i).RD / max(maximum);
    DBF(i).azi = dbf(FFT(i).RD(:,:,[1,3]),2,numBeam,Amax,dAnt,lam);
    DBF_avg(i).azi = squeeze(mean(DBF(i).azi,2));  % take average across chirps
    max_DBF(i) = max(DBF_avg(i).azi(:));
    
end

scale = 150;

for i = 1:Header.numFrame
    DBF_avg(i).azi = DBF_avg(i).azi / max(max_DBF(:));
end
figure(1)
for i = 1:Header.numFrame    
    imagesc(angle,Range,10*log10( abs(DBF_avg(i).azi) ));
    colormap(jet); c= colorbar; 
    clim([-20,0]);
    set(gca, 'YDir','normal');
    xlabel('Angle (deg)'); ylabel('Distance (m)'); title('Range-angle map');
    drawnow;
%     pause;
    pause(Header.Frame_period_sec);
end

 

 

 

%% Digital Beamforming (DBF) function
% This function applies Array factor weight to range-doppler map so that
% provides angle information of the target
% x: input matrix. It should be complexed-valued
% numAnt: nuymber of virtual RX antenna
% numBeam: number of beam
% Amax: maximum angle of arrival in radian
% dAnt: array distance between virtual antennas
% lam: lambda of the carrier frequency
function beamforming = dbf(x,numAnt, numBeam, Amax, dAnt, lam)
    angle_vector = linspace(-Amax,Amax,numBeam);
    
    % calculate weight factor for different beamforming angle
    weight = zeros(numAnt,numBeam);
    % M = number of samples, N = number of chirps, P = number of antennas
    [M,N,P] = size(x);   
    % preallocation
    beamforming = zeros(M,N,numBeam);

    for i = 1:numBeam
        angle = angle_vector(i);
        for j = 1:numAnt
            weight(j,i) = exp(1i*2*pi*(j-1)*(dAnt/lam)*sin(angle));
        end
        acc = zeros(M,N);
        for j = 1:numAnt
            acc = acc + x(:,:,j) * weight(numAnt+1-j,i);
        end
        beamforming(:,:,i) = acc;
    end
    
end

 


2.png

1.png     JimHeo_0-1674813775552.png

 

0 Likes
1 Solution
Siddharth_H
Moderator
Moderator
Moderator
100 solutions authored 50 likes received First question asked

Hey @JimHeo ,

We figured out that the window you are using ( Hann) might be causing the unusual clutters, so you should be using Blackman-Harris window instead, the python files use this too.

Siddharth_0-1675250435223.png

I tried out with my data set and the plot looked meaningful. 

Siddharth_1-1675250671324.png

Hope this answers your problem.

Thankyou, Siddharth

 

View solution in original post

0 Likes
9 Replies
Siddharth_H
Moderator
Moderator
Moderator
100 solutions authored 50 likes received First question asked

Hi @JimHeo, To understand more about your program can you also share the read_parse_rawdata.m file also. Thankyou

0 Likes

Sure. Here is the read_parse_rawdata.m (MATLAB function). I have used raw-data-read example code.

function [Frame, Header, Frame_count] = read_parse_rawdata(filename)

fIDRaw = fopen([filename '.raw.bin'], 'r', 'b'); % open file handle, big-endian style

if( isequal(fIDRaw, -1) )
    error("file not found, or format not supported!\n"); 
end

Header.file_type_id = fread(fIDRaw, 4, 'char');
if( ~isequal(char(Header.file_type_id'),'IFRB') )
   error("File type not supported!");    
end

Header.file_format_version = fread(fIDRaw, 1, 'float');
if( Header.file_format_version ~= 1 )
   error("File type version not supported!");    
end

% sXML = xml2struct([sFile '.xml']); % parese xml file to struct

% if(~isstruct(sXML.Device.TjpuEndpoint))
%     error("Device not supported, missing TJPU Endpoint in xml!");
% end

Header.Header_Size = fread(fIDRaw, 1, 'int32');
Header.Num_Tx_Antennas = fread(fIDRaw, 1, 'int32');
Header.Num_Rx_Antennas = fread(fIDRaw, 1, 'int32');
Header.Mask_Tx_Antennas = fread(fIDRaw, 1, 'int32');
Header.Mask_Rx_Antennas = fread(fIDRaw, 1, 'int32');
Header.Are_Rx_Antennas_Interleaved = fread(fIDRaw, 1, 'int32'); % If this is 0, the radar data of multiple RX antennas is stored in consecutive data blocks, where each block holds data of one antenna. If this is non-zero, the radar data of multiple RX antennas is stored in one data block, where for each point in time the samples from all RX antennas are stored consecutively before the data of the next point in time follows.
Header.Modulation_Type_Enum = fread(fIDRaw, 1, 'int32');
Header.Chirp_Shape_Enum = fread(fIDRaw, 1, 'int32');

Header.Lower_RF_Frequency_kHz = fread(fIDRaw, 1, 'float');
Header.Upper_RF_Frequency_kHz = fread(fIDRaw, 1, 'float');
Header.Sampling_Frequency_kHz = fread(fIDRaw, 1, 'float');
Header.ADC_Resolution_Bits = fread(fIDRaw, 1, 'int32'); % The ADC resolution of the data in sample_data.
Header.Are_ADC_Samples_Normalized = fread(fIDRaw, 1, 'int32');
Header.Data_Format_Enum = fread(fIDRaw, 1, 'int32'); % This indicates if the data is pDataBuffer is real or complex, and if complex data is interleaved. 0: real, 1: complex, 2: complex interleaved
Header.Chirps_per_Frame = fread(fIDRaw, 1, 'int32'); % The number of chirps in this frame.
Header.Samples_per_Chirp = fread(fIDRaw, 1, 'int32'); % The number of samples acquired in each chirp for each enabled RX antenna.
Header.Samples_per_Frame = fread(fIDRaw, 1, 'int32'); % The number of samples acquired in each frame for each enabled RX antenna.
Header.Chirp_Time_sec = fread(fIDRaw, 1, 'float');
Header.Pulse_Repetition_Time_sec = fread(fIDRaw, 1, 'float');
Header.Frame_period_sec = fread(fIDRaw, 1, 'float');

%## Data_Format_Enum_Def = {DATA_REAL = 0, DATA_COMPLEX = 1, DATA_COMPLEX_INTERLEAVED = 2}
%## Chirp_Shape_Enum_Def = {UP_CHIRP = 0, DOWN_CHIRP = 1, UP_DOWN_CHIRP = 2, DOWN_UP_CHIRP = 3}
%## Modulation_Type_Enum_Def = {DOPPLER = 0, FMCW = 1}

% this is for test!!
% Header.Num_Rx_Antennas = 2;

Header.SignalPart = 1;     % set 1 for real-valued, 2 for complex-valued

NumChirpData = Header.Samples_per_Chirp * Header.Num_Rx_Antennas * Header.SignalPart; % Number of sample values per chirp

Header.NumData = Header.Chirps_per_Frame * NumChirpData; % Number of sample values per frame




%% read in each frame
n = 1;

fread(fIDRaw, 1, 'uint8'); % peek into the next frame data block if there is any data available
while(~feof(fIDRaw))
    fseek(fIDRaw, -1, 'cof');
    
    Frame(n).Frame_Number = fread(fIDRaw, 1, 'int32'); % The running number of the data frame. The frame counter is, reset every time ep_radar_base_set_automatic_frame_trigger is called. If automatic frame trigger is not active, the frame counter may not work, and this could be 0.
    Frame(n).RawData = fread(fIDRaw, Header.NumData, '*single'); %#ok<*SAGROW> The buffer containing the radar data
    Frame(n).Header.Num_Rx_Antennas = Header.Num_Rx_Antennas;
    if( length(Frame(n).RawData) == Header.NumData)
        % dispatch data
        Chirp = zeros(Header.Samples_per_Chirp, Header.Chirps_per_Frame, Header.Num_Rx_Antennas);
        % SamplesPerChirp = Header.Samples_per_Chirp;

        sn = 0:Header.Samples_per_Chirp-1; % zero based sample number

        if Header.Are_Rx_Antennas_Interleaved % interleaved antenna data
            switch Header.Data_Format_Enum
                case 0 % EP_RADAR_BASE_RX_DATA_REAL: The frame data contains only I or Q signal
                    % data_value = pFrameStart[SAMPLE_NUMBER * num_rx_antennas + ANTENNA_NUMBER];
                    for nc = 0:Header.Chirps_per_Frame-1
                        for na = 0:Header.Num_Rx_Antennas-1
                            IData = Frame(n).RawData(1+ sn*Frame(n).Header.Num_Rx_Antennas + na + NumChirpData*nc); % real
                            % QData = []; % imag
                            Chirp(:,nc+1,na+1) = IData;
                        end
                    end

                case 1 % EP_RADAR_BASE_RX_DATA_COMPLEX: The frame data contains I and Q signals in separate data blocks
                    % data_value_real = frame_start[SAMPLE_NUMBER * num_rx_antennas + ANTENNA_NUMBER];
                    % data_value_imag = frame_start[(num_samples_per_chirp + SAMPLE_NUMBER) * num_rx_antennas + ANTENNA_NUMBER];
                    for nc = 0:Header.Chirps_per_Frame-1
                        for na = 0:Header.Num_Rx_Antennas-1
                            IData = Frame(n).RawData(1+ sn *Header.Num_Rx_Antennas + na + NumChirpData*nc); % real
                            QData = Frame(n).RawData(1+ (Header.Samples_per_Chirp + sn)*Header.Num_Rx_Antennas + na + NumChirpData*nc); % imag
                            Chirp(:,nc+1,na+1) = IData + 1i*QData;
                        end
                    end

                case 2 % EP_RADAR_BASE_RX_DATA_COMPLEX_INTERLEAVED: The frame data contains I and Q signals in one interleaved data block
                    % data_value_real = frame_start[2 * SAMPLE_NUMBER * num_rx_antennas + ANTENNA_NUMBER];
                    % data_value_imag = frame_start[2 * SAMPLE_NUMBER * num_rx_antennas + ANTENNA_NUMBER + 1];
                    for nc = 0:Header.Chirps_per_Frame-1
                        for na = 0:Header.Num_Rx_Antennas-1
                            IData = Frame(n).RawData(1+ 2*sn*Header.Num_Rx_Antennas + na     + NumChirpData*nc); % real
                            QData = Frame(n).RawData(1+ 2*sn*Header.Num_Rx_Antennas + na + 1 + NumChirpData*nc); % imag
                            Chirp(:,nc+1,na+1) = IData + 1i*QData;
                        end
                    end
            end

        else % non interleaved antenna data
            switch Header.Data_Format_Enum
                case 0 % EP_RADAR_BASE_RX_DATA_REAL: The frame data contains only I or Q signal
                    % data_value = frame_start[ANTENNA_NUMBER * num_samples_per_chirp + SAMPLE_NUMBER];
                    for nc = 0:Header.Chirps_per_Frame-1
                        for na = 0:Header.Num_Rx_Antennas-1
                            IData = Frame(n).RawData(1+ na*Header.Samples_per_Chirp + sn + NumChirpData*nc); % real
                            % QData = []; % imag
                            Chirp(:,nc+1,na+1) = IData;
                        end
                    end

                case 1 % EP_RADAR_BASE_RX_DATA_COMPLEX: The frame data contains I and Q signals in separate data blocks
                    % data_value_real = frame_start[(2 * ANTENNA_NUMBER    ) * num_samples_per_chirp + SAMPLE_NUMBER];
                    % data_value_imag = frame_start[(2 * ANTENNA_NUMBER + 1) * num_samples_per_chirp + SAMPLE_NUMBER];
                    for nc = 0:Header.Chirps_per_Frame-1
                        for na = 0:Header.Num_Rx_Antennas-1
                            IData = Frame(n).RawData(1+  2*na   *Header.Samples_per_Chirp + sn + NumChirpData*nc); % real
                            QData = Frame(n).RawData(1+ (2*na+1)*Header.Samples_per_Chirp + sn + NumChirpData*nc); % imag
                            Chirp(:,nc+1,na+1) = IData + 1i*QData;
                        end
                    end

                case 2 % EP_RADAR_BASE_RX_DATA_COMPLEX_INTERLEAVED: The frame data contains I and Q signals in one interleaved data block
                    % data_value_real = frame_start[2 * ANTENNA_NUMBER * num_samples_per_chirp + 2*SAMPLE_NUMBER];
                    % data_value_imag = frame_start[2 * ANTENNA_NUMBER * num_samples_per_chirp + 2*SAMPLE_NUMBER + 1];
                    for nc = 0:Header.Chirps_per_Frame-1
                        for na = 0:Header.Num_Rx_Antennas-1
                            IData = Frame(n).RawData(1+ 2*na*Header.Samples_per_Chirp + 2*sn     + NumChirpData*nc); % real
                            QData = Frame(n).RawData(1+ 2*na*Header.Samples_per_Chirp + 2*sn + 1 + NumChirpData*nc); % imag
                            Chirp(:,nc+1,na+1) = IData + 1i*QData;
                        end
                    end
            end
        end

        Frame(n).Chirp = Chirp;
    else
        n = n - 1;
    end
    fread(fIDRaw, 1, 'uint8'); % peek into the next frame data block if there is any data available
    n = n+1;
end
Frame_count = n - 1;
Header.numFrame = length(Frame);

%% close file
fclose(fIDRaw);

 

0 Likes
Siddharth_H
Moderator
Moderator
Moderator
100 solutions authored 50 likes received First question asked

Hi @JimHeo , we were trying to debug your code, but looks like there are some missing files. Can you please share the zipped file of your whole project folder including the data file? Also, please mention the Matlab version you are using.

Thankyou, Siddharth

0 Likes
lock attach
Attachments are accessible only for community members.

Hi, Siddharth

I am sending you complete files of my codes and I attached range-angle image from python source code and experiment I conducted (hand is offset about 30 degree). Please give me some advice.

Thank you so much, Jimheo.

0 Likes
Siddharth_H
Moderator
Moderator
Moderator
100 solutions authored 50 likes received First question asked

Hi @JimHeo ,

About your hand/palm angle offset. Your palm might be at 30 degrees average, but the radar might be detecting the inner edge (thumb) of your palm which might be at ~15 degrees, as the radar doesn't exactly measure the mean position of an object. You can try out with a human target to reconfirm if angle measurement is correct.

Thankyou, Siddharth

0 Likes

Hi @Siddharth_H 

Yes, right. As you mentioned, my thumb is about 15 degree same as the range_angle image in my zip* file.

PREVIEW
FYI,  I slightly vibrated my hands to avoid my hands being removed from static clutter algorithm during the experiment. 
Thank you, JimHeo
0 Likes
Siddharth_H
Moderator
Moderator
Moderator
100 solutions authored 50 likes received First question asked

Hey @JimHeo ,

We figured out that the window you are using ( Hann) might be causing the unusual clutters, so you should be using Blackman-Harris window instead, the python files use this too.

Siddharth_0-1675250435223.png

I tried out with my data set and the plot looked meaningful. 

Siddharth_1-1675250671324.png

Hope this answers your problem.

Thankyou, Siddharth

 

0 Likes
lock attach
Attachments are accessible only for community members.

Hi @Siddharth 

Thank you so much your fast response. With your help, the range-angle figure looks much more clear than before.
However, the range-angle map still shows my hand (scatter) is located at 0 deg.
I think that It's because there is no phase difference in RX channel 1 and RX channel 3. 
The python files give me a correct range-angle map of my hand (it is located about 10~20 deg ).

Could you give me some reason for this problem? Just in case, I attached a raw-data of the experiment.

Range_angle_image.jpg

Thanks, JimHeo

0 Likes
Siddharth_H
Moderator
Moderator
Moderator
100 solutions authored 50 likes received First question asked

Hi @JimHeo , Your data processing might be wrong which is why this problem persists, please follow the python code implementation exactly including fft_spectrum.py, doppler.py and DBF.py files. This will surely solve your problem. 

Thankyou, Siddharth

0 Likes