Optimizing chirp parameters for accuracy
The problem
Range range, resolution and accuracy is a function of the chirp definition.
While defining optimal chirp bandwidth, slope, sampling frequency and maximum ADC buffer size is a fairly simple problem to solve for a single target.
Optimizing chirp definition to minimise measurement error over multiple targets can be a more daunting task.
The solution
This workbook shows a simple non-optimised solution for this multi-target error minimisation.
A likely improvement would be to leverage scipy.optimize.minimize
[ ]:
# Install a pip package in the current Jupyter kernel
import sys
!{sys.executable} -m pip install mmWrt
[1]:
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 arange, 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
from tqdm import tqdm
[2]:
%%time
c = 3e8
# Define targets, by default non set values are 0
# so below is a target at x0=1.5 and y0=0, z0=0 with no speed vector
target1 = Target(1.5)
target2 = Target(2)
# initialize the error to the error when no targets are identified
min_error = target1.distance() + target2.distance() # we start at 2.5
# initialize chirp config with text values
config = {"bw": "?", "fs": "?", "error": "?"}
# this scan will take minutes
bws = [0.1e9, 0.2e9, 0.3e9, 0.5e9, 1e9, 2e9, 3e9, 4e9]
slopes = range(1, 100)
fss = arange(100, 25e6, 100)
# this scan takes seconds to verify that min_error is 0 with those settings
bws = [2.9e9, 3e9, 3.1e9]
slopes = [5, 6, 7]
fs = range(50, 200)
debug_ON = False
with tqdm(total=len(bws) * len(slopes) * len(fss)) as pbar:
for bw in bws:
for slope_m in slopes:
slope = slope_m * 1e8
for fs in fss:
pbar.update(1)
try:
radar = Radar(transmitter=Transmitter(bw=bw, slope=slope),
receiver=Receiver(fs=fs,
max_adc_buffer_size=512,
debug=debug_ON),
debug=debug_ON)
bb = rt_points(radar, [target1, target2], debug=debug_ON)
# data_matrix = bb['adc_cube'][0][0][0]
Distances, range_profile = rsp.range_fft(bb)
ca_cfar = rsp.cfar_ca_1d(range_profile)
range_profile = range_profile
ca_cfar = ca_cfar
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 grouped_peaks]
error = rsp.error([target1, target2], found_targets)
# print("error", error)
if error < min_error:
min_error = error
config = {"bw": bw, "fs": fs,
"slope": slope,
"error": error}
except Exception:
pass
# print(str(ex))
# raise
# yields 0 error for bw=3e9, fs=100, slope=6e8
print(f"optimal config: {config}, yields error: {min_error}")
100%|████████████████████████████████████████████████████████████████████| 2249991/2249991 [00:05<00:00, 424840.61it/s]
optimal config: {'bw': 3000000000.0, 'fs': 100.0, 'slope': 600000000.0, 'error': 0.0}, yields error: 0.0
CPU times: total: 2.81 s
Wall time: 5.31 s