I'm steering to the wrong place but have a somewhat working steering animation
This commit is contained in:
parent
f50496ed5d
commit
023c20016f
@ -1,6 +1,6 @@
|
|||||||
# %% imports
|
# %% imports
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from utils import AnimatedPlot, dir_assets
|
from utils import AnimatedPlot, db10, db20, dir_assets, wrap_phase
|
||||||
|
|
||||||
|
|
||||||
# %%
|
# %%
|
||||||
@ -17,7 +17,6 @@ class PcolorPlot(AnimatedPlot):
|
|||||||
self.element_x = np.linspace(-x_range / 2, x_range / 2, elements)
|
self.element_x = np.linspace(-x_range / 2, x_range / 2, elements)
|
||||||
self.element_y = np.zeros(elements)
|
self.element_y = np.zeros(elements)
|
||||||
self.angle = np.deg2rad(angle_deg)
|
self.angle = np.deg2rad(angle_deg)
|
||||||
self.element_phase = np.zeros(elements)
|
|
||||||
self.element_phase = (
|
self.element_phase = (
|
||||||
np.dot(np.array([self.element_x, self.element_y]).T, [np.sin(self.angle), np.cos(self.angle)]) * 2 * np.pi
|
np.dot(np.array([self.element_x, self.element_y]).T, [np.sin(self.angle), np.cos(self.angle)]) * 2 * np.pi
|
||||||
)
|
)
|
||||||
@ -104,18 +103,91 @@ class PcolorMagPlot(PcolorPlot):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class Steer(AnimatedPlot):
|
||||||
|
def __init__(self, elements: int, spacing_lambda: float = 0.5, **kwargs):
|
||||||
|
super().__init__(**kwargs)
|
||||||
|
|
||||||
|
self.ax.remove()
|
||||||
|
self.axs = [
|
||||||
|
self.fig.add_subplot(3, 1, 1),
|
||||||
|
self.fig.add_subplot(3, 1, 2),
|
||||||
|
self.fig.add_subplot(3, 1, 3),
|
||||||
|
]
|
||||||
|
|
||||||
|
self.spacing_lambda = spacing_lambda
|
||||||
|
self.elements = elements
|
||||||
|
|
||||||
|
def update(self, t: float):
|
||||||
|
for ax in self.axs:
|
||||||
|
ax.clear()
|
||||||
|
|
||||||
|
# rewind, don't reset
|
||||||
|
if t > 0.5:
|
||||||
|
t = 1 - t
|
||||||
|
t *= 2
|
||||||
|
|
||||||
|
angle = np.deg2rad((t * 2 - 1) * 90) # steering angle
|
||||||
|
|
||||||
|
def get_phase(position):
|
||||||
|
return wrap_phase(np.sin(angle) * position * 2 * np.pi, deg=False)
|
||||||
|
|
||||||
|
ideal_position = self.spacing_lambda * np.linspace(-(self.elements - 1) / 2, (self.elements - 1) / 2, 1001)
|
||||||
|
ideal_phase = get_phase(ideal_position)
|
||||||
|
|
||||||
|
element_position = self.spacing_lambda * np.linspace(
|
||||||
|
-(self.elements - 1) / 2, (self.elements - 1) / 2, self.elements
|
||||||
|
)
|
||||||
|
element_phase = get_phase(element_position)
|
||||||
|
element_taper = np.ones(self.elements)
|
||||||
|
element_excitation = element_taper * np.exp(1j * element_phase)
|
||||||
|
|
||||||
|
theta = np.linspace(-90, 90, 361)
|
||||||
|
fft_points = 128
|
||||||
|
fft_period = 90 / self.spacing_lambda
|
||||||
|
theta_fft = np.linspace(0, fft_period, fft_points, endpoint=False)
|
||||||
|
ff_pattern = np.interp(
|
||||||
|
theta,
|
||||||
|
theta_fft,
|
||||||
|
np.fft.fft(np.concat([element_excitation, np.zeros(fft_points - self.elements)]), norm="backward")
|
||||||
|
/ self.elements,
|
||||||
|
period=fft_period,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.fig.suptitle(f"{np.rad2deg(angle):+5.1f}° Steer")
|
||||||
|
|
||||||
|
rolloff = np.cos(np.deg2rad(theta))
|
||||||
|
self.axs[0].set_ylabel("Farfield Magnitude [dB]")
|
||||||
|
self.axs[0].plot(theta, db20(rolloff), color="gray")
|
||||||
|
self.axs[0].plot(theta, db20(ff_pattern * rolloff))
|
||||||
|
self.axs[0].set_xlim(-90, 90)
|
||||||
|
self.axs[0].set_ylim(-30, 5)
|
||||||
|
self.axs[0].set_xlabel("Theta [°]")
|
||||||
|
self.axs[0].grid(True)
|
||||||
|
self.axs[0].axvline(np.rad2deg(angle))
|
||||||
|
|
||||||
|
self.axs[1].set_ylabel("Excitation Phase")
|
||||||
|
self.axs[1].stem(element_position, np.rad2deg(element_phase))
|
||||||
|
self.axs[1].plot(ideal_position, np.rad2deg(ideal_phase), linestyle="--")
|
||||||
|
self.axs[1].set_ylim(-200, 200)
|
||||||
|
|
||||||
|
self.axs[2].set_ylabel("Excitation Magnitude")
|
||||||
|
self.axs[2].stem(element_position, element_taper)
|
||||||
|
# self.axs[2].set_xlabel("Element")
|
||||||
|
|
||||||
|
|
||||||
# %%
|
# %%
|
||||||
def generate():
|
def generate():
|
||||||
for elements in [
|
# for elements in [
|
||||||
1,
|
# 1,
|
||||||
2,
|
# 2,
|
||||||
4,
|
# 4,
|
||||||
10,
|
# 10,
|
||||||
]:
|
# ]:
|
||||||
PcolorPhasePlot(elements=elements, angle_deg=45).save(dir_assets / "beamforming" / f"phase_xz_{elements}el.gif")
|
# PcolorPhasePlot(elements=elements, angle_deg=45).save(dir_assets / "beamforming" / f"phase_xz_{elements}el.gif")
|
||||||
PcolorMagPlot(elements=elements, angle_deg=45).save(
|
# PcolorMagPlot(elements=elements, angle_deg=45).save(
|
||||||
dir_assets / "beamforming" / f"magnitude_xz_{elements}el.gif"
|
# dir_assets / "beamforming" / f"magnitude_xz_{elements}el.gif"
|
||||||
)
|
# )
|
||||||
|
Steer(elements=16, spacing_lambda=0.5, frames=200).save(dir_assets / "beamforming" / "steering.gif", framerate=15)
|
||||||
|
|
||||||
|
|
||||||
# %%
|
# %%
|
||||||
|
@ -67,3 +67,28 @@ class AnimatedPlot(ABC):
|
|||||||
[0, 1]
|
[0, 1]
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def db20(v):
|
||||||
|
return 20 * np.log10(np.abs(v))
|
||||||
|
|
||||||
|
|
||||||
|
def db10(v):
|
||||||
|
return 10 * np.log10(np.abs(v))
|
||||||
|
|
||||||
|
|
||||||
|
def db2v(db):
|
||||||
|
return 10 ** (db / 20)
|
||||||
|
|
||||||
|
|
||||||
|
def db2w(db):
|
||||||
|
return 10 ** (db / 10)
|
||||||
|
|
||||||
|
|
||||||
|
def wrap_phase(phase, deg: bool):
|
||||||
|
if deg:
|
||||||
|
maxval = 180
|
||||||
|
else:
|
||||||
|
maxval = np.pi
|
||||||
|
|
||||||
|
return (phase + maxval) % (2 * maxval) - maxval
|
||||||
|
Loading…
x
Reference in New Issue
Block a user