Last active
March 10, 2022 01:33
-
-
Save DavidPowell/3cbf000ddde3ca683d665aafc51422c7 to your computer and use it in GitHub Desktop.
Phased array animation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
name: py37 | |
dependencies: | |
- python=3.7 | |
- numpy | |
- matplotlib | |
- ipywidgets | |
- ipympl |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"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