Engee documentation
Notebook

Car radar for estimating the range and speed of multiple targets

The example considers the design of a system model of an automotive radar for determining the range and speed of several objects.

Functions used

In [ ]:
Pkg.add(["LinearAlgebra", "DSP"])
   Resolving package versions...
  No Changes to `~/.project/Project.toml`
  No Changes to `~/.project/Manifest.toml`
In [ ]:
using DSP,FFTW,LinearAlgebra

function run_model( name_model, path_to_folder ) # defining a function for running the model
    Path = path_to_folder * "/" * name_model * ".engee"
    if name_model in [m.name for m in engee.get_all_models()] # Checking the condition for loading a model into the kernel
        model = engee.open( name_model ) # Open the model
        engee.run( model, verbose=true ); # Launch the model
        engee.close( name_model, force=true ); # Close the model
    else
        model = engee.load( Path, force=true ) # Upload a model
        engee.run( model, verbose=true ); # Launch the model
        engee.close( name_model, force=true ); # Close the model
    end
    return
end;

function DataFrame2Array(X)
    out = collect(X)
    out_data = zeros(eltype(out.value[1]),size(out.value[1],1),size(out.value[1],2),length(out.value))
    [out_data[:,:,i] = out.value[i] for i in 1:length(out.value)]

    return out_data, out.time
end

function calc_spectrogram(x::Array,fs::Real,title::String;
    num_pulses::Int64 = 4,
    window_length::Int64 = 64,
    nfft::Int64=512,
    lap::Int64  = 60,
    thesh::Real = -Inf)

    gr()

    spec_out = DSP.spectrogram(x[:,:,1:num_pulses][:],window_length,lap;window=kaiser(window_length,3.95),nfft=nfft,fs=fs)

    power = DSP.pow2db.(spec_out.power)
    power .= map(x -> x < thesh ? thesh : x,power)

    power_new = zeros(size(power))

    power_new[1:round(Int64,size(power,1)/2),:] .= power[round(Int64,size(power,1)/2)+1:end,:]
    power_new[round(Int64,size(power,1)/2)+1:end,:] .= power[1:round(Int64,size(power,1)/2),:]

    fig = heatmap(fftshift(spec_out.freq).*1e-6,spec_out.time .*1e6, permutedims(power_new),color= :jet,
        gridalpha=0.5,margin=5Plots.mm,size=(900,400))
    xlabel!("Frequency, MHz")
    ylabel!("Time, iss")
    title!(title)

    return fig
end

function calc_RD_Response(x,param;tresh=-Inf)
    plotlyjs()
    range_scale = Vector(range(param.RngLims...,length=size(x,1)))
    speed_scale = Vector(range(param.SpeedLims...,length=size(x,2)))

    out_RD = pow2db.(abs.(x[:,:,end]))
    out_RD  .= rot180(map(x -> x < tresh ? tresh : x,out_RD))

    fig = heatmap(speed_scale,range_scale,
        out_RD,colorscale=:parula256,
        top_margin=10Plots.mm,size=(900,400))
    xlabel!("Speed, m/s")
    ylabel!("Range, m")
    title!("Range-Doppler portrait")
    return fig
end

function plotting_result(rng_est,speed_est,true_range,true_speed,name::String,slow_time)
    plotlyjs()
    fig1=plot(slow_time*1e3,rng_est,
        lab="distance estimation",
        margin=5Plots.mm,
        legend=:outertopright,
        titlefont=font(12,"Computer Modern"),
        guidefont = font(12,"Computer Modern"),size=(900,220))
    plot!(fast_time*1e3,true_range,lab="The true distance",ls= :dash)
    xlabel!("Time, ms")
    ylabel!("Distance, m")
    title!("Dependence of the distance to the object ($(name))")

    fig2 = plot(slow_time*1e3,speed_est,
        lab="speed assessment",
        size=(900,220),
        legend=:outertopright,
        titlefont=font(12,"Computer Modern"),
        guidefont = font(12,"Computer Modern"))
    plot!(fast_time*1e3,true_speed,lab="true speed",ls= :dash)
    xlabel!("Time, ms")
    ylabel!("Speed, m/s")
    title!("Dependence of the relative velocity of an object ($name)")

    display(fig1)
    display(fig2)
    return
end

calc_range_or_speed_object(x,y) = [norm(x[:,1,i]).-norm(y[:,1,i]) for i in 1:size(y,3)];
WARNING: using LinearAlgebra.I in module Main conflicts with an existing identifier.

1. Description of the structure of the system model

1.1 General structure of the model

The general block diagram of the system model is given below:

image_3.png

The model in question has a similar structure, as in the example (car radar for detecting a single цели) , but it has several main differences:

  • simulates the movement of 2 vehicles - a car and a truck;
  • implements Doppler frequency processing using the "Range-Doppler Response" block;
  • Single-channel processing;
  • performs detection using a two-dimensional averaging detector using the block - "CA CFAR 2-D"

1.2 Digital Signal Processing Unit

The model uses joint range and Doppler frequency processing in the Signal Processing subsystem. Such processing makes it possible to estimate the frequency shift of the received signal relative to the probing signal during coherent accumulation, and then use the processing result to estimate range and speed.

The subsystem of digital signal processing is presented below:

image_2.png

The digital processing process is divided into the following stages:

  • Stage 1: The received signal is demodulated and 64 pulses are coherently accumulated. The data is then transferred to the Range-Doppler Response block to calculate the range-Doppler portrait of the received signal. The samples carrying the range information are transmitted to the Range Subset subsystem. It extracts a part of the estimated data that corresponds to the predefined range limits (from 1 to 200 m) in the calcParamFMCW file.jl;
  • Stage 2: The detection process is underway. The detector in this example is a CA CFAR 2-D unit that detects the signal;
  • Stage 3: The clustering process is performed in the "DBSCAN Clusterer" block, where detection cells are grouped by range and speed using the data obtained in the CA CFAR 2-D block;
  • Stage 4: estimates of the range and speed of targets are calculated using the Range Estimator blocks and Doppler Estimator.

1.3 Channel and Goal models

image.png

The simulation scenario is the following scenario: a vehicle with radar is moving from a reference point at a speed of 100 km/h (27.8 m/s)

There are ** two target vehicles** in the viewing area, which are a passenger car and a truck, each vehicle has a corresponding distribution channel. The car is moving at a distance of 50 meters from the radar and is moving at a speed of 60 km/h (16.7 m/s). The truck is located at a distance of 150 meters from the radar and is moving at a speed of 130 km/h (36.1 m/s).

The signal propagation channel is a free space.

2. Initialization of input parameters

To initialize the input parameters of the model, we will connect the file "calcParamFMCWMT.jl". If you need to change the parameter values, then open this file and edit the necessary parameters.

In [ ]:
include("$(@__DIR__)/calcParamFMCWMT.jl") # connecting a jl file to initialize input parameters
paramRadarFMCWMT = calcParamFMCWMT() # creating a structure of input parameters
T = paramRadarFMCWMT.T; # the sampling step of the model in time
SimT = 10*paramRadarFMCWMT.NumSweeps*paramRadarFMCWMT.T; # simulation time of the model

3. Launching the model

Let's start calculating the simulation of the model using the run_model function:

In [ ]:
run_model("FMCW_Radar_Range_Estimation_MT",@__DIR__) # Launch the model
Building...
Progress 0%
Progress 0%
Progress 0%
Progress 5%
Progress 10%
Progress 10%
Progress 15%
Progress 20%
Progress 25%
Progress 30%
Progress 36%
Progress 41%
Progress 50%
Progress 58%
Progress 70%
Progress 80%
Progress 100%

4. Extraction of simulation results

We will extract the simulation results from the variables recorded in the workspace into an array for further visualization.:

In [ ]:
FMCW_signal, fast_time = DataFrame2Array(FMCW_sig) # the LCHM input signal
Range_Estimate, _ = DataFrame2Array(Range) # range estimation
Speed_Estimate, slow_time = DataFrame2Array(Speed) # speed estimates
RD_Response,_  = DataFrame2Array(RD); # range-Doppler portrait
Truck_vel,_ = DataFrame2Array(Tvel) # truck speed
Truck_pos,_ = DataFrame2Array(Tpos); # truck position
Car_vel,_ = DataFrame2Array(Cvel) # vehicle speed
Car_pos,_ = DataFrame2Array(Cpos); # vehicle position
Radar_vel,_ = DataFrame2Array(Rvel) # radar speed
Radar_pos,_ = DataFrame2Array(Rpos); # radar position

5. Visualization of simulation results

5.1 Input signal spectrogram

After completing the model run and reading the data into the array, we will visualize the spectrogram of the probing signal using the calc_spectrogram function.:

In [ ]:
calc_spectrogram(
    FMCW_signal, # signal after processing (displayed with 2 pulses)
    paramRadarFMCWMT.Fs/paramRadarFMCWMT.NumSweeps, # sampling rate
    "The spectrogram of the input signal";
    num_pulses=4, # number of pulses
    thesh=-300 # threshold, dB
)
Out[0]:

The spectrogram shown above shows that the frequency deviation is 150 MHz with a period of every 7 microseconds, which corresponds to a resolution of about 1 meter.

5.2 Long-range Doppler portrait

In [ ]:
calc_RD_Response(RD_Response,paramRadarFMCWMT;tresh=-Inf)
Out[0]:

In the drawing, you can mark 2 targets at a distance of 50 and 150 meters. It is difficult to accurately determine the speed of targets due to the low speed resolution

5.3 Analysis of the accuracy of parameter estimation

For a better analysis of the accuracy of the radar, let's compare the true coordinates and speeds with the estimates found.

First, we calculate the true values of the parameters and extract the estimates into the corresponding variables.:

In [ ]:
# Calculation of true ranges and relative speeds to the vehicle
true_range_car = calc_range_or_speed_object(Car_pos,Radar_pos)
true_speed_car = calc_range_or_speed_object(Radar_vel,Car_vel)
# Calculation of true ranges and relative speeds to the truck
true_range_truck = calc_range_or_speed_object(Truck_pos,Radar_pos)
true_speed_truck = calc_range_or_speed_object(Radar_vel,Truck_vel)
# Calculation of range estimates and relative speeds to the vehicle
Range_Estimate_Car = Range_Estimate[1,1,:]
Range_Estimate_Truck = Range_Estimate[2,1,:]
# Calculation of estimated ranges and relative speeds to the truck
Speed_Estimate_Car = Speed_Estimate[1,1,:]
Speed_Estimate_Truck = Speed_Estimate[2,1,:];

Let's display the results on graphs for each object using the plotting_result function.:

In [ ]:
 # graphs for comparing an object - a car
 plotting_result(Range_Estimate_Car,Speed_Estimate_Car,true_range_car,true_speed_car,"car",slow_time)
In [ ]:
 # graphs for comparing a cargo object
plotting_result(Range_Estimate_Truck,Speed_Estimate_Truck,true_range_truck,true_speed_truck,"truck",slow_time)

Analyzing the obtained dependencies, it can be concluded that the values of the radar estimates correspond to the stated accuracy in range (1 meter) and speed (4 m/s)

Conclusion

In the example, the modeling of the basic model of an atomic radar using a continuous LFM signal as a sounding signal was considered. As a result of the model, an estimate of the relative speed and distance from the radar to objects (car and truck) was found with a radar resolution accuracy of 1 meter in range and approximately 4 m/s in speed.

Blocks used in example