使用radarsimpy仿真TDM_MIMO_FCMW雷达

radarsimpy 是一个用于雷达仿真的 Python 库项目。功能齐全,文档完善,很好用。

本文将使用 radarsimpy 对TDM MIMO FCMW 雷达进行仿真,并实践 Range-Doppler 和 Angle-FFT。

创建雷达系统#

创建一个 2T4R 的雷达系统。

  • 中心频率 fc 为 60.5e
  • 单 chirp 时长 Tc 为 16e-6
  • 整个 chirp 周期时长为 40e-6
  • 频率调制范围在 [61e9, 60e9]
  • 一帧数量为 512
  • 采样率 fs 为 20e6

关于雷达系统的位置和脉冲信息,可以看后文的图示。

import numpy as np
from radarsimpy import Radar, Transmitter, Receiver
from scipy.constants import speed_of_light

wavelength = speed_of_light / 60.5e9

N_tx = 2
N_rx = 4

tx = []
tx.append(
    dict(
        location=(0, -N_rx / 2 * wavelength, 0),
        delay=0,
    )
)
tx.append(
    dict(
        location=(0, 0, 0),
        delay=20e-6,
    )
)

rx = [dict(location=(0, wavelength / 2 * idx, 0)) for idx in range(N_rx)]


tx = Transmitter(f=[61e9, 60e9], t=16e-6, tx_power=15, prp=40e-6, pulses=512, channels=tx)
rx = Receiver(fs=20e6, noise_figure=8, rf_gain=20, load_resistor=500, baseband_gain=30, channels=rx)

radar = Radar(transmitter=tx, receiver=rx)

显示阵列的位置信息。

import plotly.graph_objs as go
from IPython.display import Image

fig = go.Figure()
fig.add_trace(
    go.Scatter(
        x=radar.radar_prop["transmitter"].txchannel_prop["locations"][:, 1] / wavelength,
        y=radar.radar_prop["transmitter"].txchannel_prop["locations"][:, 2] / wavelength,
        mode='markers',
        name='Transmitter',
        opacity=0.7,
        marker=dict(size=10),
    )
)

fig.add_trace(
    go.Scatter(
        x=radar.radar_prop["receiver"].rxchannel_prop["locations"][:, 1] / wavelength,
        y=radar.radar_prop["receiver"].rxchannel_prop["locations"][:, 2] / wavelength,
        mode='markers',
        opacity=1,
        name='Receiver',
    )
)

fig.update_layout(
    title='Array configuration',
    height=400,
    width=700,
    xaxis=dict(title='y (λ)'),
    yaxis=dict(title='z (λ)', scaleanchor="x", scaleratio=1),
)

fig.show()

雷达阵列

创建目标,获得回波数据#

创建一个目标,位于 30m 处、10° 的位置,其相对雷达的速度为 25m/s。

true_theta = [10]
speed = [25]
ranges = [30]
targets = []

for theta, v, r in zip(true_theta, speed, ranges):
    target = dict(
        location=(r * np.cos(np.radians(theta)), r * np.sin(np.radians(theta)), 0),
        speed=(v * np.cos(np.radians(theta)), v * np.sin(np.radians(theta)), 0),
        rcs=10,
        phase=0,
    )
    targets.append(target)

计算回波数据。

from radarsimpy.simulator import simc

data = simc(radar, targets, noise=False)
timestamp = data['timestamp']
baseband = data['baseband']

现在让我们看下两个 Tx 天线发射的信号:

# reshaped_timestamp 维度:Tx,Rx,脉冲,采样点
reshaped_timestamp = timestamp.reshape((N_tx, N_rx, 512, -1))

fig = go.Figure()

bandwidth = radar.radar_prop["transmitter"].waveform_prop["bandwidth"]
center_freq = 60.5e9
start_freq = center_freq - bandwidth / 2
stop_freq = center_freq + bandwidth / 2

samples_per_pulse = radar.sample_prop["samples_per_pulse"]

for Tx in range(2):
    x_data = reshaped_timestamp[Tx, 0, 0, :] * 1e6  # x 轴。单位为微秒
    y_data = np.linspace(start_freq, stop_freq, samples_per_pulse, endpoint=False) / 1e9
    trace_name = f'Tx {Tx}, Chirp 0'
    fig.add_trace(go.Scatter(x=x_data, y=y_data, name=trace_name))

fig.update_layout(
    title='Transmitter chirps',
    height=400,
    width=700,
    yaxis=dict(tickformat='.2f', title='Frequency (GHz)'),
    xaxis=dict(tickformat='.2f', title='Time (µs)'),
)

fig.show()

Tx 发射信号

进行 Range-Doppler#

首先定义函数:

def range_fft(X, n=None, window=None):
    if window is not None:
        shape = [1] * X.ndim
        shape[-1] = X.shape[-1]
        X = X * window.reshape(shape)
    output = np.fft.fft(X, n, axis=-1)
    return output


def doppler_fft(X, n=None, window=None):
    if window is not None:
        shape = [1] * X.ndim
        shape[-2] = X.shape[-2]
        X = X * window.reshape(shape)
    output = np.fft.fftshift(np.fft.fft(X, n, axis=-2), axes=-2)
    return output

然后进行 Range-Doppler 处理:

from scipy import signal

range_window = signal.windows.chebwin(radar.sample_prop["samples_per_pulse"], at=80)
dop_window = signal.windows.chebwin(radar.radar_prop["transmitter"].waveform_prop["pulses"], at=60)

ranged = range_fft(baseband.conj(), window=range_window)
range_doppler = doppler_fft(ranged, window=dop_window)

绘制处理结果:

from scipy.constants import speed_of_light

max_range = (  # 计算最大探测距离
    speed_of_light  # 光速
    * radar.radar_prop["receiver"].bb_prop["fs"]  # 采样率
    * radar.radar_prop["transmitter"].waveform_prop["pulse_length"]  # 脉冲时长 Tc
    / radar.radar_prop["transmitter"].waveform_prop["bandwidth"]
    / 2
)
range_axis = np.linspace(0, max_range, radar.sample_prop["samples_per_pulse"], endpoint=False)

doppler_axis = np.linspace(
        -1 / radar.radar_prop["transmitter"].waveform_prop["prp"][0] / 2,
        1 / radar.radar_prop["transmitter"].waveform_prop["prp"][0] / 2,
        radar.radar_prop["transmitter"].waveform_prop["pulses"],
        endpoint=False,
    )* speed_of_light / 60.5e9 / 2


fig = go.Figure()
fig.add_trace(
    go.Heatmap(
        z=20 * np.log10(np.mean(np.abs(range_doppler), axis=0)).T,
        x=doppler_axis,
        y=range_axis,
        colorscale='Viridis',
        zmin=-40,
        zmax=0,
    )
)
fig.update_layout(title='Range-Doppler map', xaxis=dict(title='Doppler (m/s)'), yaxis=dict(title='Range (m)'))

fig.show()

Range-Doppler 结果

Angle-FFT#

在进行 Angle-FFT 之前,先进行多普勒补偿。

# 获取 dop_bin 长度
dop_bin = np.arange(range_doppler.shape[-2])
# 计算相位差
delta_phi = np.exp(-1j * np.pi * (dop_bin - len(dop_bin) / 2) / len(dop_bin))
# 进行补偿
range_doppler[8:, :, :] *= delta_phi[None, :, None]

然后进行 Angle-FFT 处理:

def angle_fft(X, n=None, window=None):
    if window is not None:
        shape = [1] * X.ndim
        shape[0] = X.shape[0]
        X = X * window.reshape(shape)
    output = np.fft.fftshift(np.fft.fft(X, n, axis=0), axes=0)
    return output

angled = angle_fft(range_doppler, n=128)

绘制一个 Speed-Azimuth 图看效果。下图主要看 y 轴对不对,x 轴我标歪了。

azimuth = np.linspace(-1, 1, 128)
azimuth = np.arcsin(azimuth) / np.pi * 180

fig = go.Figure()
z = 20 * np.log10(np.abs(angled[:, :, 0]) + 0.001)
fig.add_trace(go.Heatmap(x=doppler_axis, y=azimuth, z=z, colorscale='Rainbow'))

fig.update_layout(
    title='Speed-Azimuth Map',
    height=400,
    width=700,
    scene=dict(
        xaxis=dict(title='Doppler (m/s)'),
        yaxis=dict(title='Azimuth (deg)'),
        zaxis=dict(title='Amplitude (dB)'),
        aspectmode='data',
    ),
    margin=dict(l=0, r=0, b=0, t=40),
)

fig.show()

Angle-FFT 结果

参考来源#

作者:chirp

出处:https://www.cnblogs.com/chirp/p/17993178

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

posted @   倒地  阅读(483)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
more_horiz
keyboard_arrow_up dark_mode palette
选择主题
menu
点击右上角即可分享
微信分享提示