Skip to content

Instantly share code, notes, and snippets.

@0x9900
Last active October 18, 2023 16:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save 0x9900/1e001e65fd1a2c8fddeaf49093f2a243 to your computer and use it in GitHub Desktop.
Save 0x9900/1e001e65fd1a2c8fddeaf49093f2a243 to your computer and use it in GitHub Desktop.
Generate Smith chart and VSWR charts from .s1p files
#!/usr/bin/env python3
#
# BSD 3-Clause License
# Copyright (c) 2022 Fred W6BSD All rights reserved.
#
# This program reads Touchstone files (.s1p) coming from any good
# antenna analyzer or VNA. The the type of the data is limited to the
# format S,RI.
#
# You can go to https://0x9900.com/hustler-4btv-cleanup-tuning/ to see
# an example of images generated by this program.
#
import argparse
import os
import matplotlib.pyplot as plt
import skrf as rf
from matplotlib.ticker import MultipleLocator
DPI = 100
MAX_VSWR = 5
LINE_COLOR = "yellow"
MY_PARAMS = {
"figure.dpi": DPI,
"figure.figsize": [14, 6],
"axes.labelsize": 10,
"axes.grid" : True,
"legend.fontsize": 8,
"grid.color": "brown",
"grid.linewidth": 1,
"lines.linewidth": 1.5,
}
BANDS = [
(1800, 2000, '160m'),
(3500, 4000, '80m'),
(5258, 5450, '60m'),
(7000, 7300, '40m'),
(10100, 10150, '30m'),
(14000, 14350, '20m'),
(18068, 18168, '17m'),
(21000, 21450, '15m'),
(24890, 24990, '12m'),
(28000, 29700, '10m'),
(50000, 54000, '6m'),
(144000, 148000, '2m'),
]
plt.style.use('dark_background')
plt.rcParams.update(MY_PARAMS)
def open_network(s1p_file):
return rf.Network(s1p_file)
def draw_smithvswr(dut, path, ext='png'):
image = os.path.join(path, f"{dut.name}-smith-vswr.{ext}")
fig, (ax1, ax2) = plt.subplots(1, 2)
fig.suptitle(dut.name + "Smith Chart + VSWR")
fmin = dut.frequency.f.min()
fmax = dut.frequency.f.max()
dut.plot_s_smith(ax=ax1, show_legend=True, color=LINE_COLOR)
dut.plot_s_vswr(ax=ax2, color=LINE_COLOR)
ax2.set_xlim(fmin, fmax)
max_vswr = (1+dut.s_mag.max())/(1-dut.s_mag.max())
if max_vswr < MAX_VSWR:
ax2.set_ylim(1, MAX_VSWR)
ax2.yaxis.set_minor_locator(MultipleLocator(.1))
ax2.yaxis.set_major_locator(MultipleLocator(.5))
else:
ax2.set_ylim(1, max_vswr * 1.12)
ax2.yaxis.set_minor_locator(MultipleLocator(1))
ax2.yaxis.set_major_locator(MultipleLocator(5))
ax2.axhline(y=3, linewidth=1.5, zorder=1, color='orange', linestyle="dotted")
for low, high, _ in BANDS:
ax2.axvspan(low*1000, high*1000, facecolor='lightgray', alpha=0.1)
fig.text(0.01, 0.05, "Smith Chart By W6BSD - https://0x9900.com/", color='gray',
rotation=90, fontsize=8)
plt.tight_layout()
fig.savefig(image, transparent=False, dpi=DPI)
print(image)
def draw_rl(dut, path, ext='png'):
image = os.path.join(path, f"{dut.name}-rl.{ext}")
fmin = dut.frequency.f.min()
fmax = dut.frequency.f.max()
fig, ax = plt.subplots()
fig.suptitle(dut.name + " - Return Loss (dB)")
dut.plot_s_db(color=LINE_COLOR)
for low, high, _ in BANDS:
ax.axvspan(low*1000, high*1000, facecolor='lightgray', alpha=0.1)
ax.axhline(y=-6, linewidth=1.5, zorder=1, color='orange', linestyle="dotted")
ax.set_xlim(fmin, fmax)
ax.set_ylim(top=0)
fig.text(0.01, 0.05, "Smith Chart By W6BSD - https://0x9900.com/", color='gray',
rotation=90, fontsize=8)
plt.savefig(image, transparent=False, dpi=DPI)
print(image)
def draw_vswr(dut, path, ext='png'):
image = os.path.join(path, f"{dut.name}-vswr.{ext}")
fmin = dut.frequency.f.min()
fmax = dut.frequency.f.max()
fig, ax = plt.subplots()
fig.suptitle(dut.name + " - VSWR")
dut.plot_s_vswr(color=LINE_COLOR)
for low, high, _ in BANDS:
ax.axvspan(low*1000, high*1000, facecolor='lightgray', alpha=0.1)
ax.axhline(y=3, linewidth=1.5, zorder=1, color='orange', linestyle="dotted")
max_vswr = (1+dut.s_mag.max())/(1-dut.s_mag.max())
ax.set_ylim(1, 6 if max_vswr < 6 else max_vswr * 1.2)
ax.set_xlim(fmin, fmax)
fig.text(0.01, 0.05, "Smith Chart By W6BSD - https://0x9900.com/", color='gray',
rotation=90, fontsize=8)
plt.savefig(image, transparent=False)
print(image)
def main():
parser = argparse.ArgumentParser(description="Antenna Smith chart and VSWR chart")
parser.add_argument('-V', '--version', action='version', version='%(prog)s 1.0')
parser.add_argument('-f', '--file', required=True, help='s1p filename')
parser.add_argument('-t', '--type', choices=['jpg', 'png', 'svg'], default='png',
help='image type [jpg, png, svg] (default: %(default)s)')
opts = parser.parse_args()
path = os.path.dirname(opts.file)
dut = open_network(opts.file)
draw_smithvswr(dut, path=path, ext=opts.type)
draw_rl(dut, path=path, ext=opts.type)
draw_vswr(dut, path=path, ext=opts.type)
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment