From d06f6e1e4c6bab5dd847f5e454ab4db182d20fd5 Mon Sep 17 00:00:00 2001 From: Eric Teunis de Boone Date: Sun, 21 May 2023 22:42:29 +0200 Subject: [PATCH] Figure: Radio Interferometry Schematic --- figures/radio_interferometry/.gitignore | 1 + figures/radio_interferometry/Makefile | 42 +++++ .../radio_interferometry/src/rit_scheme.py | 153 ++++++++++++++++++ 3 files changed, 196 insertions(+) create mode 100644 figures/radio_interferometry/.gitignore create mode 100644 figures/radio_interferometry/Makefile create mode 100755 figures/radio_interferometry/src/rit_scheme.py diff --git a/figures/radio_interferometry/.gitignore b/figures/radio_interferometry/.gitignore new file mode 100644 index 0000000..7ea6c68 --- /dev/null +++ b/figures/radio_interferometry/.gitignore @@ -0,0 +1 @@ +rit_schematic_*.* diff --git a/figures/radio_interferometry/Makefile b/figures/radio_interferometry/Makefile new file mode 100644 index 0000000..c8632d6 --- /dev/null +++ b/figures/radio_interferometry/Makefile @@ -0,0 +1,42 @@ +SUBDIRS := $(subst Makefile,,$(wildcard */Makefile)) + +.PHONY: all dist dist-clean $(SUBDIRS) + +all: dist $(SUBDIRS) + +dist: dist.png dist.pdf + # + +.PHONY: dist.png +dist.png: \ + rit_schematic_base.png \ + rit_schematic_true.png \ + rit_schematic_close.png \ + rit_schematic_far.png \ + # + +.PHONY: dist.pdf +dist.pdf: \ + rit_schematic_base.pdf \ + rit_schematic_true.pdf \ + rit_schematic_close.pdf \ + rit_schematic_far.pdf \ + # + +$(SUBDIRS): + @$(MAKE) -C $@ + +dist-clean: + rm -v rit_schematic_* + +rit_schematic_base.%: src/rit_scheme.py + $< 'base' $@ + +rit_schematic_true.%: src/rit_scheme.py + $< 'true' $@ + +rit_schematic_close.%: src/rit_scheme.py + $< 'closeby' $@ + +rit_schematic_far.%: src/rit_scheme.py + $< 'far-away' $@ diff --git a/figures/radio_interferometry/src/rit_scheme.py b/figures/radio_interferometry/src/rit_scheme.py new file mode 100755 index 0000000..629b377 --- /dev/null +++ b/figures/radio_interferometry/src/rit_scheme.py @@ -0,0 +1,153 @@ +#!/usr/bin/env python3 + +__doc__ = \ +""" +Show geometry and time delay between radio antennas +and a source (true, and expected). +""" + +import matplotlib.pyplot as plt +from matplotlib.path import Path +import matplotlib.patches as patches + +import numpy as np + +def antenna_path(loc, size=1, height=(.5)**(.5), width=1, stem_height=None): + stem_height = stem_height if stem_height is not None else height + + vertices = [ + (0, 0), # center, middle + ( width/2*size, height/2*size), #right, top + ( width/2*size, -height/2*size), #right, bottom + (-width/2*size, height/2*size), #left, top + (-width/2*size, -height/2*size), #left, bottom + (0, 0), # back to center + (0, -stem_height), # stem + (0, 0), # back to center + ] + + codes = [ + Path.MOVETO, + Path.LINETO, + Path.LINETO, + Path.LINETO, + Path.LINETO, + Path.LINETO, + Path.LINETO, + Path.CLOSEPOLY, + ] + + # modify vertices + for i, v in enumerate(vertices): + vertices[i] = ( loc[0] + v[0], loc[1] + v[1] ) + + return Path(vertices, codes) + + +def radio_interferometry_figure(emit_loc=(3,8), resolve_loc=None, N_antenna=4, ant_size=0.5, **fig_kwargs): + fig, ax = plt.subplots(**fig_kwargs) + + annot_kwargs = dict( + color='red', + fontsize=15, + ) + + ray_kwargs = dict( + marker=None, + ls='solid', + color='red', + alpha=0.8 + ) + antenna_patch_kwargs = dict( + edgecolor='k', + facecolor='none', + lw=2 + ) + + antenna_patches = [] + dx_antenna = 1.5 + stem_height = ant_size + for i in range(N_antenna): + path = antenna_path( (4+dx_antenna*i, stem_height), size=ant_size, stem_height=stem_height) + patch = patches.PathPatch(path, **antenna_patch_kwargs) + ax.add_patch(patch) + antenna_patches.append(patch) + + if i == N_antenna - 1: + ant_loc = path.vertices[0] + ax.annotate("$\\vec{a_i}$", (ant_loc[0]+0.4, 0.8), va='top', ha='left', **{**annot_kwargs, **dict(color='k')}) + + # ground level + ax.axhline(0, color='k') + + # indicate antenna signal + ant_loc = antenna_patches[int(2/4*N_antenna)].get_path().vertices[0] + ax.annotate("$S_i(t)$", (ant_loc[0], ant_loc[1]-stem_height-0.2), va='top', ha='center', **annot_kwargs) + + + if emit_loc or resolve_loc: + # resolve_loc + if resolve_loc is None: + resolve_loc = emit_loc + + if resolve_loc: + for i, antenna in enumerate(antenna_patches): + ant_loc = antenna.get_path().vertices[0] + + # rays from the antenna to resolve_loc + ax.plot( (ant_loc[0], resolve_loc[0]), (ant_loc[1], resolve_loc[1]), **ray_kwargs) + if i == N_antenna - 1: + ax.annotate("$\Delta_i$", ( (ant_loc[0]+resolve_loc[0])/2, (ant_loc[1]+resolve_loc[1])/2 ), va='bottom', ha='left', **annot_kwargs) + + ax.plot(*resolve_loc, 'ro') + ax.annotate("$S(\\vec{x}, t)$", resolve_loc, ha='left', va='bottom', **annot_kwargs) + + # emit loc + if emit_loc: + ax.plot(*emit_loc, 'ko') + + ax.annotate('$S_0$', emit_loc, ha='right', va='top', **{**annot_kwargs, **dict(color='k')}) + + ax.set_xlim(-1, 10) + ax.set_ylim(-1, 10) + + ax.axis('off') + + fig.tight_layout() + + return fig + + +if __name__ == "__main__": + emit_loc = (2.5, 8) + figsize = (6,6) + + from argparse import ArgumentParser + import os.path as path + + parser = ArgumentParser(description=__doc__) + parser.add_argument('scenario', choices=['base', 'true', 'closeby', 'far-away'], default='true') + parser.add_argument("fname", metavar="path/to/figure[/]", nargs="?", help="Location for generated figure, will append __file__ if a directory. If not supplied, figure is shown.") + + args = parser.parse_args() + + if args.fname is not None and path.isdir(args.fname): + args.fname = path.join(args.fname, path.splitext(path.basename(__file__))[0] + ".pdf") + + ### + emit_loc = None + resolve_loc = None + if args.scenario != 'base': + emit_loc = (2.5, 8) + + if args.scenario == 'closeby': + resolve_loc = (3, 8) + elif args.scenario == 'far-away': + resolve_loc = (8, 8) + + fig = radio_interferometry_figure(emit_loc=emit_loc, resolve_loc=resolve_loc, figsize=figsize) + + if args.fname is not None: + plt.savefig(args.fname) + else: + plt.show()