Строим графики КСВ с помощью Mini60S и Python
19 июня 2019
Один из недостатков антенного анализатора Mini60S заключается в том, что им неудобно смотреть изменение параметров антенны на широком интервале частот (например, от 1 до 30 МГц). Приложение Open60 позволяет строить такие графики, но делает это с большим шагом (около 1 МГц), из-за чего картина получается смазанной. Другой недостаток заключается в том, что иногда приложение подключается к устройству по Bluetooth не с первого раза. Было решено попробовать исправить оба недостатка при помощи небольшого набора скриптов.
Mini60S является клоном открытого антенного анализатора SARK-100, созданного испанским радиолюбителем Melchor Varela, EA4FRB. Оригинально SARK-100 можно было приобрести в виде набора для сборки. К сожалению, с октября 2011 наборы больше не выпускаются, а сам проект был объявлен устаревшим в пользу более продвинутого (и дорогого) анализатора SARK-110. Однако архив сайта SARK-100 до сих пор доступен онлайн вместе с прошивкой, схемой и пользовательским мануалом. Сейчас нас особенно интересует последний.
На странице 35 мы можем узнать, что устройство имеет USB-UART интерфейс, и что его скорость — 57600 бод. В свою очередь «Appendix I: PC Command Interface» на странице 77 содержит список поддерживаемых команд. Давайте проверим. Подключаем Mini60S к компьютеру через USB, нажимаем SET → PC Link. На компьютере говорим:
Попробуем ввести какую-нибудь команду:
Start
1.27,57,0,58
1.28,58,0,59
1.29,59,0,60
1.30,60,0,61
1.32,62,0,63
1.35,63,0,64
1.38,63,16,65
1.43,65,16,67
End
Хм… выглядит чем-то рабочим. Теперь дело за малым — автоматизировать сбор данных и их визуализацию.
За сбор будет отвечать скрипт mini60scan.py:
# vim: set ai et ts=4 sw=4:
import serial
import argparse
parser = argparse.ArgumentParser(
description='Scan antenna parameters using SARK100/Mini60'
)
parser.add_argument(
'-b', '--begin', metavar='N', type=int, required=True,
help='Frequency to start from, Hz')
parser.add_argument(
'-e', '--end', metavar='N', type=int, required=True,
help='The end frequency, Hz')
parser.add_argument(
'-s', '--step', metavar='N', type=int, required=True,
help='Step size, Hz')
parser.add_argument(
'-d', '--device', metavar='D', type=str, required=True,
help='Serial port device name (e.g. /dev/tty.usbserial-00000000)')
parser.add_argument(
'-r', '--baudrate', metavar='N', type=int, default=57600,
help='Baud rate (default 57600)')
args = parser.parse_args()
with serial.Serial(args.device, args.baudrate) as conn:
cmd = "scan {} {} {}".format(args.begin, args.end, args.step)
conn.write((cmd+"\r\n").encode('ascii'))
freq = args.begin
print("Freq,SWR,R,X,Z")
while True:
line = conn.readline().decode('ascii').strip()
if line == '':
continue
elif line == 'Start':
continue
elif line == 'End':
break
swr, r, x, z = line.split(',')
print("{},{},{},{},{}".format(freq,swr,r,x,z))
freq += args.step
Пример использования:
-d /dev/tty.usbserial-00000000 | tee double-vertical.csv
Скан от 1.5 МГц до 30 МГц с шагом 0.25 МГц дает достаточно точную картину и занимает 2 минуты 30 секунд. Если вы желаете просканировать тот же диапазон с шагом 0.1 МГц, это займет у вас 6 минут 10 секунд.
Для рисования графиков входного сопротивления и КСВ антенны воспользуемся библиотекой Matplotlib. Код скрипта mini60plot.py:
# vim: set ai et ts=4 sw=4:
import matplotlib as mpl
# for MacOS, see https://stackoverflow.com/a/21789908/1565238
mpl.use('TkAgg')
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import sys
if len(sys.argv) < 3:
print("Usage: " + sys.argv[0] + " input.csv output.png")
sys.exit(1)
infile = sys.argv[1]
outfile = sys.argv[2]
swr_color = 'green'
z_color = 'red'
freqs = []
values = { 'swr' : [], 'z': [] }
nline = 0
min_freq, max_freq = 9999, 0
max_swr, max_z = 0, 0
with open(infile, newline = '') as f:
for line in f:
nline += 1
if nline == 1: # skip title
continue
f, swr, r, x, z = [ float(x) for x in line.strip().split(",") ]
f = f / 1000000
print("f = {}, swr = {}".format(f, swr))
freqs += [f]
values['swr'] += [ swr ]
values['z'] += [ z ]
max_swr = max(swr, max_swr)
min_freq = min(f, min_freq)
max_freq = max(f, max_freq)
max_z = max(z, max_z)
dpi = 80
fig = plt.figure(dpi = dpi, figsize = (512 / dpi, 384 / dpi) )
mpl.rcParams.update({'font.size': 10})
ax1 = fig.add_subplot(111)
lns1 = ax1.plot(freqs, values['swr'], color=swr_color,
linestyle = 'solid', label = 'SWR')
ax1.set_xlabel("Freq (MHz)")
ax1.set_xlim(min_freq, max_freq)
# ax1.set_ylabel("SWR", color = swr_color)
ax1.yaxis.label.set_color(swr_color)
ax1.tick_params(axis='y', colors=swr_color)
ax1.spines['left'].set_color(swr_color)
ax1.spines['right'].set_color(z_color)
ax1.set_ylim(1, max_swr)
# highlight amateur radio bands
for band in [ [1.8, 2.0], [3.5, 3.8], [7.0, 7.2], [10.1, 10.15],
[14.0, 14.35], [18.068, 18.168], [21.0, 21.45],
[24.89,24.99], [28.0,29.7] ]:
ax1.axvspan(band[0], band[1], color='grey', alpha=0.3)
ax2 = ax1.twinx()
lns2 = ax2.plot(freqs, values['z'], color=z_color,
linestyle = 'solid', label = 'Z (Ω)')
# ax2.set_ylabel("Z", color = z_color)
ax2.yaxis.label.set_color(z_color)
ax2.tick_params(axis='y', colors=z_color)
ax2.spines['left'].set_color(swr_color)
ax2.spines['right'].set_color(z_color)
ax2.set_ylim(0, max_z)
lns = lns1 + lns2
labs = [ x.get_label() for x in lns ]
ax2.legend(lns, labs, framealpha = 1, loc = 'upper right')
fig.savefig(outfile)
Пример использования:
А так выглядит результат:
Можно догадаться, что здесь мы смотрим на вертикал, описанный в недавнем посте Походная антенна-вертикал на диапазоны 15, 20 и 40 метров.
В данном контексте следует сказать пару слов о том, как именно следует производить измерения. В идеале антенный анализатор следует подключать прямо к месту запитки, или напрямую к балуну / запорному дросселю, если он предсмотрен в антенне. Использование даже пары метров коаксиального кабеля вносит заметные искажения.
Тому есть ряд причин. В частности, ни один запорный дроссель не избавляет от синфазного тока на 100%. Следовательно, кабель всегда немножечко, но все-таки излучает. Кроме того, линия никогда не бывает идеальной, а значит в ней всегда есть какие-то потери. В случае с КСВ это особенно критично, потому что сначала сигнал ослабевает по пути в одну сторону, какая-то часть ослабленного сигнала отражается, и идет до КСВ-метра, ослабевая на обратном пути. В итоге КСВ-метр видит стоячую волну, образованную исходным сигналом и ослабленным отражением ослабленного сигнала. Добавьте сюда прочие факторы — волновое сопротивление кабеля, немного отличное от 50 Ом, не совсем точную калибровку устройства, и так далее, и можно легко увидеть КСВ 3-4 вместо КСВ 5-10 при использовании всего лишь нескольких метров RG58.
Fun fact! Двухпроводные линии с высоким волновым сопротивлением (от 300 до 600 Ом) имеют очень небольшие потери на КВ, поэтому написанное относится к ним в меньше степени. Однако при использовании такого фидера возникают другие нюансы — согласование импеданса, необходимость в отсутствии металлических предметов или земли на расстоянии от линии, равном десяти расстояниям между ее проводами, и так далее.
Такие дела. Теперь, когда 1) соединение с устройством действительно надежно, без этих ваших модных беспроводных протоколов, 2) сканирование диапазона можно производить с любым желаемым шагом и 3) мы выяснили, как правильно производить измерения, КСВ-метром прям стало можно пользоваться.
Дополнение: См также обзоры антенного анализатора EU1KY и NanoVNA.
Метки: Python, Беспроводная связь, Любительское радио.
Вы можете прислать свой комментарий мне на почту, или воспользоваться комментариями в Telegram-группе.