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 ) # определение функции для прогона модели
    Path = path_to_folder * "/" * name_model * ".engee"
    if name_model in [m.name for m in engee.get_all_models()] # Проверка условия загрузки модели в ядро
        model = engee.open( name_model ) # Открыть модель
        engee.run( model, verbose=true ); # Запустить модель
        engee.close( name_model, force=true ); # Закрыть модель
    else
        model = engee.load( Path, force=true ) # Загрузить модель
        engee.run( model, verbose=true ); # Запустить модель
        engee.close( name_model, force=true ); # Закрыть модель
    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!("Частота, МГц")
    ylabel!("Время, мкс")
    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!("Скорость, м/с")
    ylabel!("Дальность, м")
    title!("Дальностно-доплероский портрет")
    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="оценка расстояния",
        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="истинное расстояние",ls= :dash)
    xlabel!("Время, мс")
    ylabel!("Расстояние, м")
    title!("Зависимость расстояния до объекта ($(name))")

    fig2 = plot(slow_time*1e3,speed_est,
        lab="оценка скорости",
        size=(900,220),
        legend=:outertopright,
        titlefont=font(12,"Computer Modern"),
        guidefont = font(12,"Computer Modern"))
    plot!(fast_time*1e3,true_speed,lab="истинная скорость",ls= :dash)
    xlabel!("Время, мс")
    ylabel!("Скорость, м/c")
    title!("Зависимость относительной скорости объекта ($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") # подключение jl файла для инициализации входных параметров
paramRadarFMCWMT = calcParamFMCWMT() # создание структуры входных параметров
T = paramRadarFMCWMT.T; # шаг дискретизации модели по времени
SimT = 10*paramRadarFMCWMT.NumSweeps*paramRadarFMCWMT.T; # время симуляции модели

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__) # Запустить модель
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) # входной ЛЧМ-сигнал
Range_Estimate, _ = DataFrame2Array(Range) # оценка дальности
Speed_Estimate, slow_time = DataFrame2Array(Speed) # оценки cкорости
RD_Response,_  = DataFrame2Array(RD); # дальностно-доплероский портрет
Truck_vel,_ = DataFrame2Array(Tvel) # скорость грузовика
Truck_pos,_ = DataFrame2Array(Tpos); # положение грузовика
Car_vel,_ = DataFrame2Array(Cvel) # скорость автомобиля
Car_pos,_ = DataFrame2Array(Cpos); # положение автомобиля
Radar_vel,_ = DataFrame2Array(Rvel) # скорость радара
Radar_pos,_ = DataFrame2Array(Rpos); # положение радара

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, # сигнал после обработки (отображается со 2 импульса)
    paramRadarFMCWMT.Fs/paramRadarFMCWMT.NumSweeps, # частота дискретизации
    "Cпектрограмма входного сигнала";
    num_pulses=4, # количество импульсов 
    thesh=-300 # порог, дБ
)
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 [ ]:
# Расчет истинных дальностей и относительный скоростей до автомобиля
true_range_car = calc_range_or_speed_object(Car_pos,Radar_pos)
true_speed_car = calc_range_or_speed_object(Radar_vel,Car_vel)
# Расчет истинных дальностей и относительный скоростей до грузовика
true_range_truck = calc_range_or_speed_object(Truck_pos,Radar_pos)
true_speed_truck = calc_range_or_speed_object(Radar_vel,Truck_vel)
# Расчет оценок дальностей и относительный скоростей до автомобиля
Range_Estimate_Car = Range_Estimate[1,1,:]
Range_Estimate_Truck = Range_Estimate[2,1,:]
# Расчет оценок дальностей и относительный скоростей до грузовика
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 [ ]:
 # графики для сравнения объекта - автомобиль
 plotting_result(Range_Estimate_Car,Speed_Estimate_Car,true_range_car,true_speed_car,"автомобиль",slow_time)
In [ ]:
 # графики для сравнения объекта - грузовки
plotting_result(Range_Estimate_Truck,Speed_Estimate_Truck,true_range_truck,true_speed_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