FMCW Intro

You can open this workbook in Google Colab to experiment with mmWrt image0

Below is an intro to mmWrt for simple targets position estimation

For a generic introduction to mmWave sensors: Watch Here

linear chirps and IF frequencies

Signal model According to (Barriok 1973; Stove 1992; Komarov and Smolskiy 2003; Winkler 2007) the transmitted signal of an FMCW radar system can be modeled as where

\[y_T (t) = A_T \cdot cos\left( 2 \pi \cdot ( f_{0min} \cdot t +\int_0^tf_T({\tau}) d\tau)\right)\]

Given for a linear chirp that

\[f_T(\tau) = \frac{B}{T} \cdot \tau = s \cdot \tau\]

We derive the phase, given

\[\int_0^t f_T({\tau}) d\tau = \frac{s}{2} \cdot \tau^2 - K\]

which can be written as:

\[y_T (t) = A_T \cdot cos \left( 2 \pi \cdot ( f_{0min} \cdot t + \frac{s}{2} \cdot t^2 )+\Phi_0 \right)\]

Where:

  • \(f_{0min}\) is the start frequency at the begining of the raising frequency of the chirp.

  • s is the slope at which the frequency is ramped ( \(S = \frac{B}{T}\))

  • B is the total bandwdith of the chirp

  • T is the total time of the chirp

Considering a reflected signal with a time delay \(\delta = 2 · \frac{R0+ v\cdot t}{c}\) and Doppler shift \(f_D = −2 · \frac{f_c \cdot v}{c}\)

Where:

  • c is the speed of light

  • \(f_D\) is the doppler shift

  • R0 is the nominal distance to the target

  • \(\Delta\) is the time of flight (to and from the target)

  • v is the velocity of the target

The receive signal \(y_R(t)\) can be written as :

\[y_R(t) = A_R \cdot cos ( 2\pi \cdot (f_{0min} + \frac{s}{2} \cdot (t-\delta)) \cdot (t-\delta))\]

\(y_{IF}(t)\) is the IF signal (after mixer) which is obtained by multiplication in the time domain, and passed to a low-pass filter (LPF)

This can be done easily when remembering the trigonometric relation:

\[cos(\alpha) \cdot cos(\beta) = \frac{cos(\alpha + \beta) + cos(\alpha - \beta)}{2}\]
\[y_{IF}(t) = y_R(t) \cdot y_T(t)\]

Noticing that the element which sums the elements will be higher frequency and will be filtered by the LPF, it remains that:

\[y_{IF}(t) = \frac{A_t \cdot A_r}{2} \cdot cos(2 \pi \cdot [f_{0min} \cdot \delta + s \cdot \delta \cdot t - \frac{s}{2} \cdot \delta^2])\]

Where:

  • \(f_{0min}\) the starting frequency of the chirp

  • s is the slope of the chirp

  • \(\Delta\) is the total time of flight between antennas and target

  • At, Ar: Amplitude of the RX and TX waves

[1]:
# Install a pip package in the current Jupyter kernel
import sys
from os.path import abspath, basename, join, pardir
import datetime

# hack to handle if running from git cloned folder or stand alone (like Google Colab)
cw = basename(abspath(join(".")))
dp = abspath(join(".",pardir))
if cw=="docs" and basename(dp) == "mmWrt":
    # running from cloned folder
    print("running from git folder, using local path (latest) mmWrt code", dp)
    sys.path.insert(0, dp)
else:
    print("running standalone, need to ensure mmWrt is installed")
    !{sys.executable} -m pip install mmWrt
print(datetime.datetime.now())
running from git folder, using local path (latest) mmWrt code c:\git\mmWrt
2024-05-23 14:22:24.667261
[2]:
from os.path import abspath, join, pardir
import sys
import matplotlib.pyplot as plt
import matplotlib.cm as cm
from matplotlib import colors
from numpy import where, expand_dims

# uncomment below if the notebook is launched from project's root folder
# dp = abspath(join(".",pardir))
# sys.path.insert(0, dp)


from mmWrt.Raytracing import rt_points  # noqa: E402
from mmWrt.Scene import Radar, Transmitter, Receiver, Target  # noqa: E402
from mmWrt import RadarSignalProcessing as rsp  # noqa: E402

[3]:
c = 3e8

debug_ON = False
test = 0
radar = Radar(transmitter=Transmitter(bw=1e9, slope=70e8),
              receiver=Receiver(fs=1e3, max_adc_buffer_size=256,
                                debug=debug_ON), debug=debug_ON)

target1 = Target(2.11)
target2 = Target(4.53, 0, 0, xt=lambda t: 2*t+4.53)
# below is also an equivalent definition of target2
# as at t=0 the position will be x0=2+3=5
# target2 = Target(2, 0, 0, vx=lambda t: 2*t+3)
targets = [target1, target2]

bb = rt_points(radar, targets, debug=debug_ON)
Distances, range_profile = rsp.range_fft(bb)
ca_cfar = rsp.cfar_ca_1d(range_profile)

mag_r = abs(range_profile)
mag_c = abs(ca_cfar)
# little hack to remove small FFT ripples : mag_r> 5
target_filter = ((mag_r > mag_c) & (mag_r > 5))

index_peaks = where(target_filter)[0]
# grouped_peaks = rsp.peak_grouping_1d(index_peaks)

found_targets = [Target(Distances[i]) for i in index_peaks]
error = rsp.error([target1, target2], found_targets)
print("synthetic targets", [t.distance() for t in targets])
print("found targets", [t.distance() for t in found_targets])
print("error is", error)

# 2D representation of the FFT and CFAR
# plot on X,Y axis the FFT and CFAR
plt.plot(Distances, mag_r)
plt.plot(Distances, mag_c)
plt.title("2D plots FFT w/ CFAR")
plt.show()
synthetic targets [2.11, 4.53]
found targets [2.112676056338028, 4.527162977867203]
error is 0.005513078470825494
_images/Intro_nb_4_1.png
[4]:
# 1D representation of the FFT
# useful later on to show the link between 1D FFT and 2D FFTs

# Select the color map named CMRmap_r
cmap = cm.get_cmap(name='CMRmap_r')
# convert the 1D array in 2D array to plot using imshow
mag_r = expand_dims(mag_r, axis=0)
# set aspect ratio to auto to have high enough pixels to see them in the y_axis
# change the norm to have a log color scale
# to better see the peaks in correlation with 2D FFT plot
plt.imshow(mag_r, cmap,
           aspect='auto',
           norm=colors.LogNorm(vmin=min(mag_r[0][:]), vmax=max(mag_r[0][:])))
plt.title("1D FFT")
# plt.savefig(fp_fft_1D)
plt.show()
C:\Users\matth\AppData\Local\Temp\ipykernel_20492\95121931.py:5: MatplotlibDeprecationWarning: The get_cmap function was deprecated in Matplotlib 3.7 and will be removed two minor releases later. Use ``matplotlib.colormaps[name]`` or ``matplotlib.colormaps.get_cmap(obj)`` instead.
  cmap = cm.get_cmap(name='CMRmap_r')
_images/Intro_nb_5_1.png

NON REGRESSION

[6]:
assert index_peaks[0]==14
[ ]: