Skip to content

Instantly share code, notes, and snippets.

@DavidPowell
Last active March 10, 2022 01:33
Show Gist options
  • Save DavidPowell/3cbf000ddde3ca683d665aafc51422c7 to your computer and use it in GitHub Desktop.
Save DavidPowell/3cbf000ddde3ca683d665aafc51422c7 to your computer and use it in GitHub Desktop.
Phased array animation
name: py37
dependencies:
- python=3.7
- numpy
- matplotlib
- ipywidgets
- ipympl
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"id": "ce6cee7f-d1fa-4682-85f0-8b321121a098",
"metadata": {},
"source": [
"# Phased array example\n",
"In this example, we are observing an array of 5 antennas radiating at 10GHz from above, and looking at the radiated electric fields in the near-field.\n",
"\n",
"1. Run the notebook by Selecting **Run->Run All Cells** from the menu\n",
"2. **Adjust the sliders for the phase shift phi and spacing d** of the phased array, to observe beam steering and the appearance of grating lobes in the plot\n",
"\n",
"You may observe that for large steering angles, the results diverge a little from the theory. However, such large steering angles are not used in practice."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "e21aaec7-d756-44d5-8457-652c0d63de60",
"metadata": {
"jupyter": {
"source_hidden": true
},
"tags": []
},
"outputs": [],
"source": [
"%matplotlib widget\n",
"import numpy as np\n",
"import matplotlib.pyplot as plt\n",
"from ipywidgets import interact, FloatSlider\n",
"from itertools import count\n",
"from collections import OrderedDict\n",
"\n",
"# fixed parameters\n",
"f = 10e9 # operating frequency\n",
"c = 3e8 # speed of light\n",
"lam = c/f\n",
"k = 2*np.pi*f/c\n",
"N = 5 # number of elements in array\n",
"\n",
"# points in x-y plane to display\n",
"points_x = 200\n",
"points_y = 180\n",
"x_range = np.linspace(0.001, 0.5, points_x)\n",
"y_range = np.linspace(-0.2, 0.2, points_y)\n",
"\n",
"scaling_val = 20/(4*np.pi*np.sqrt(x_range[-1]-x_range[0])) # scaling factor so all of plot can be seen\n",
"\n",
"def calculate_array(N, d, phi):\n",
" \"\"\"Calculate field from a phased array\n",
" N: number of elements\n",
" d: element spacing in meters\n",
" phi: phase between elements in degrees\n",
" \n",
" returns:\n",
" E: electric field in 2D plane\n",
" antenna_y: location of antennas\n",
" lobe_angles: dictionary containing angle of main lobe and any grating lobes in degrees\n",
" \"\"\"\n",
" phi_rad = phi*np.pi/180\n",
" E = np.zeros((points_y, points_x), np.complex64)\n",
" antenna_y = (np.arange(N+1)-0.5*N)*d\n",
" phi_range = np.arange(N+1)*phi_rad\n",
" x, y = np.meshgrid(x_range, y_range)\n",
"\n",
" for y_0, phi_n in zip(antenna_y, phi_range):\n",
" R = np.sqrt(x**2 + (y-y_0)**2)\n",
" E += np.exp(1j*k*R)/(4*np.pi*np.sqrt(R))*np.exp(1j*phi_n)\n",
"\n",
" sin_theta_0 = phi_rad/(k*d)\n",
" lobe_angles = OrderedDict()\n",
" lobe_angles[0] = np.arcsin(sin_theta_0)*180/np.pi\n",
"\n",
" for n in count(1):\n",
" sidelobe_n = False\n",
" negative_lobe = sin_theta_0 - n*lam/d\n",
" if abs(negative_lobe) <= 1.0:\n",
" lobe_angles[-n] = np.arcsin(negative_lobe)*180/np.pi\n",
" sidelobe_n = True\n",
"\n",
" positive_lobe = sin_theta_0 + n*lam/d\n",
" if abs(positive_lobe) <= 1.0:\n",
" lobe_angles[n] = np.arcsin(positive_lobe)*180/np.pi\n",
" sidelobe_n = True\n",
" \n",
" if not sidelobe_n:\n",
" break\n",
" \n",
" return E, antenna_y, lobe_angles\n",
"\n",
"fig = plt.figure(figsize=(8, 6))\n",
"im = plt.imshow(np.zeros((points_y, points_x)), interpolation='nearest', \n",
" origin='lower', \n",
" vmin=-scaling_val, vmax=scaling_val, \n",
" extent = (x_range[0], x_range[-1], y_range[0], y_range[-1]),\n",
" )\n",
"\n",
"antenna_plots, = plt.plot(0, 0, 'rx', markeredgewidth=2)\n",
"plt.xlabel('x (m)')\n",
"plt.ylabel('y (m)')\n",
"ti = plt.title(\"\")\n",
"plt.show()\n",
"\n",
"#@interact(phi=(-180, 180, 5), d=(0.005, 0.05, 0.001))\n",
"@interact(phi = FloatSlider(value=0, min=-180, max=180, step=5, continuous_update=False, readout_format=\".0f\", description=\"phi (deg)\"),\n",
" d = FloatSlider(value=0.02, min=0.005, max=0.05, step=0.001, continuous_update=False, readout_format=\".3f\", description = \"d (m)\"))\n",
"def update_plot(phi=0, d=0.02):\n",
" E, antenna_y, lobe_angles = calculate_array(N, d, phi)\n",
" im.set_data(E.real)\n",
" antenna_plots.set_data(np.zeros_like(antenna_y), antenna_y)\n",
" title_text = fr\"$d/\\lambda={d*f/c:.2f}$\"\n",
" for order, angle in lobe_angles.items():\n",
" title_text += fr\", $\\theta_{{{order}}}={angle:.1f}^\\circ$\"\n",
" ti.set_text(title_text)"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.10"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment