Last active
October 18, 2023 16:03
-
-
Save 0x9900/1e001e65fd1a2c8fddeaf49093f2a243 to your computer and use it in GitHub Desktop.
Generate Smith chart and VSWR charts from .s1p files
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
#!/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