Skip to content

Commit

Permalink
Working towards WXR301D support. Also added Wideband option
Browse files Browse the repository at this point in the history
  • Loading branch information
Mark Jessop authored and Mark Jessop committed Aug 14, 2023
1 parent 79815c8 commit b688084
Show file tree
Hide file tree
Showing 17 changed files with 853 additions and 60 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ auto_rx/imet54mod
auto_rx/mXXmod
auto_rx/mp3h1mod
auto_rx/mts01mod
auto_rx/weathex301d

m10
meisei100mod
Expand Down Expand Up @@ -82,3 +83,4 @@ rs_module/rs41mod
rs_module/rs92mod
scan/reset_usb
scan/rs_detect
weathex/weathex301d
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ SUBDIRS := \
mk2a \
scan \
utils \
weathex \

all: $(SUBDIRS)

Expand Down
4 changes: 3 additions & 1 deletion auto_rx/auto_rx.py
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ def start_scanner():
ppm=autorx.sdr_list[_device_idx]["ppm"],
bias=autorx.sdr_list[_device_idx]["bias"],
save_detection_audio=config["save_detection_audio"],
wideband_sondes=config["wideband_sondes"],
temporary_block_list=temporary_block_list,
temporary_block_time=config["temporary_block_time"],
)
Expand Down Expand Up @@ -272,7 +273,8 @@ def start_decoder(freq, sonde_type, continuous=False):
rs92_ephemeris=rs92_ephemeris,
rs41_drift_tweak=config["rs41_drift_tweak"],
experimental_decoder=config["experimental_decoders"][_exp_sonde_type],
save_raw_hex=config["save_raw_hex"]
save_raw_hex=config["save_raw_hex"],
wideband_sondes=config["wideband_sondes"]
)
autorx.sdr_list[_device_idx]["task"] = autorx.task_list[freq]["task"]

Expand Down
2 changes: 1 addition & 1 deletion auto_rx/autorx/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
# MINOR - New sonde type support, other fairly big changes that may result in telemetry or config file incompatability issus.
# PATCH - Small changes, or minor feature additions.

__version__ = "1.6.3-beta1"
__version__ = "1.6.3-beta2"


# Global Variables
Expand Down
45 changes: 30 additions & 15 deletions auto_rx/autorx/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ def read_auto_rx_config(filename, no_sdr_test=False):
"sondehub_enabled": True,
"sondehub_upload_rate": 30,
# "sondehub_contact_email": "[email protected]" # Commented out to ensure a warning message is shown on startup
"wideband_sondes": False, # Wideband sonde detection / decoding
}

try:
Expand Down Expand Up @@ -455,27 +456,30 @@ def read_auto_rx_config(filename, no_sdr_test=False):
"MEISEI": True,
"MTS01": False, # Until we test it
"MRZ": False, # .... except for the MRZ, until we know it works.
"WXR301": False, # No fsk_demod chain for this yet.
"UDP": False,
}

auto_rx_config["decoder_spacing_limit"] = config.getint(
"advanced", "decoder_spacing_limit"
)
auto_rx_config["experimental_decoders"]["RS41"] = config.getboolean(
"advanced", "rs41_experimental"
)
auto_rx_config["experimental_decoders"]["RS92"] = config.getboolean(
"advanced", "rs92_experimental"
)
auto_rx_config["experimental_decoders"]["M10"] = config.getboolean(
"advanced", "m10_experimental"
)
auto_rx_config["experimental_decoders"]["DFM"] = config.getboolean(
"advanced", "dfm_experimental"
)
auto_rx_config["experimental_decoders"]["LMS6"] = config.getboolean(
"advanced", "lms6-400_experimental"
)
# Use 'experimental' (not really, anymore!) decoders for RS41, RS92, M10, DFM and LMS6-400.
# Don't allow overriding to the FM based decoders.
# auto_rx_config["experimental_decoders"]["RS41"] = config.getboolean(
# "advanced", "rs41_experimental"
# )
# auto_rx_config["experimental_decoders"]["RS92"] = config.getboolean(
# "advanced", "rs92_experimental"
# )
# auto_rx_config["experimental_decoders"]["M10"] = config.getboolean(
# "advanced", "m10_experimental"
# )
# auto_rx_config["experimental_decoders"]["DFM"] = config.getboolean(
# "advanced", "dfm_experimental"
# )
# auto_rx_config["experimental_decoders"]["LMS6"] = config.getboolean(
# "advanced", "lms6-400_experimental"
# )

try:
auto_rx_config["web_control"] = config.getboolean("web", "web_control")
Expand Down Expand Up @@ -760,6 +764,17 @@ def read_auto_rx_config(filename, no_sdr_test=False):
auto_rx_config["email_encrypted_sonde_notifications"] = True


# 1.6.3 - Weathex WXR301d support
try:
auto_rx_config["wideband_sondes"] = config.getboolean(
"advanced", "wideband_sondes"
)
except:
logging.warning(
"Config - Missing wideband_sondes option (new in v1.6.3), using default (False)"
)
auto_rx_config["wideband_sondes"] = False

# If we are being called as part of a unit test, just return the config now.
if no_sdr_test:
return auto_rx_config
Expand Down
52 changes: 50 additions & 2 deletions auto_rx/autorx/decode.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
"MRZ",
"MTS01",
"UDP",
"WXR301"
]

# Known 'Drifty' Radiosonde types
Expand Down Expand Up @@ -119,6 +120,7 @@ class SondeDecoder(object):
"MRZ",
"MTS01",
"UDP",
"WXR301"
]

def __init__(
Expand All @@ -143,7 +145,8 @@ def __init__(
rs92_ephemeris=None,
rs41_drift_tweak=False,
experimental_decoder=False,
save_raw_hex=False
save_raw_hex=False,
wideband_sondes=False
):
""" Initialise and start a Sonde Decoder.
Expand Down Expand Up @@ -182,6 +185,7 @@ def __init__(
rs41_drift_tweak (bool): If True, add a high-pass filter in the decode chain, which can improve decode performance on drifty SDRs.
experimental_decoder (bool): If True, use the experimental fsk_demod-based decode chain.
save_raw_hex (bool): If True, save the raw hex output from the decoder to a file.
wideband_sondes (bool): If True, use a wider bandwidth for iMet sondes. Does not affect settings for any other radiosonde types.
"""
# Thread running flag
self.decoder_running = True
Expand Down Expand Up @@ -212,6 +216,7 @@ def __init__(
self.experimental_decoder = experimental_decoder
self.save_raw_hex = save_raw_hex
self.raw_file = None
self.wideband_sondes = wideband_sondes

# Raw hex filename
if self.save_raw_hex:
Expand Down Expand Up @@ -521,7 +526,11 @@ def generate_decoder_command(self):
elif self.sonde_type == "IMET":
# iMet-4 Sondes

_sample_rate = 48000
# These samples rates probably need to be revisited.
if self.wideband_sondes:
_sample_rate = 96000
else:
_sample_rate = 48000

decode_cmd = get_sdr_iq_cmd(
sdr_type = self.sdr_type,
Expand Down Expand Up @@ -718,6 +727,35 @@ def generate_decoder_command(self):
# Meteosis MTS01 decoder
decode_cmd += f"./mts01mod --json --IQ 0.0 --lpIQ --dc - {_sample_rate} 16 2>/dev/null"


elif self.sonde_type == "WXR301":
# Weathex WxR-301D

_sample_rate = 96000
_if_bw = 64

decode_cmd = get_sdr_iq_cmd(
sdr_type = self.sdr_type,
frequency = self.sonde_freq,
sample_rate = _sample_rate,
sdr_hostname = self.sdr_hostname,
sdr_port = self.sdr_port,
ss_iq_path = self.ss_iq_path,
rtl_device_idx = self.rtl_device_idx,
ppm = self.ppm,
gain = self.gain,
bias = self.bias
)

# Add in tee command to save IQ to disk if debugging is enabled.
if self.save_decode_iq:
decode_cmd += f" tee {self.save_decode_iq_path} |"

# WXR301, via iq_dec as a FM Demod.
decode_cmd += f"./iq_dec --FM --IFbw {_if_bw} --lpFM --wav --iq 0.0 - {_sample_rate} 16 2>/dev/null | ./weathex301d -b --json"



elif self.sonde_type == "UDP":
# UDP Input Mode.
# Used only for testing of new decoders, prior to them being integrated into auto_rx.
Expand Down Expand Up @@ -1607,6 +1645,16 @@ def handle_decoder_line(self, data):
"%Y-%m-%dT%H:%M:%SZ"
)

# Weathex Specific Actions
# Same datetime issues as with iMets, and LMS6
if self.sonde_type == "WXR301":
# Fix up the time.
_telemetry["datetime_dt"] = fix_datetime(_telemetry["datetime"])
# Re-generate the datetime string.
_telemetry["datetime"] = _telemetry["datetime_dt"].strftime(
"%Y-%m-%dT%H:%M:%SZ"
)

# Grab a snapshot of modem statistics, if we are using an experimental decoder.
if self.demod_stats is not None:
if self.demod_stats.snr != -999.0:
Expand Down
41 changes: 30 additions & 11 deletions auto_rx/autorx/scan.py
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,7 @@ def detect_sonde(
bias=False,
save_detection_audio=False,
ngp_tweak=False,
wideband_sondes=False
):
"""Receive some FM and attempt to detect the presence of a radiosonde.
Expand All @@ -248,6 +249,7 @@ def detect_sonde(
bias (bool): If True, enable the bias tee on the SDR.
save_detection_audio (bool): Save the audio used in detection to a file.
ngp_tweak (bool): When scanning in the 1680 MHz sonde band, use a narrower FM filter for better RS92-NGP detection.
wideband_sondes (bool): Use a wider detection filter to allow detection of Weathex and wideband iMet sondes.
Returns:
str/None: Returns None if no sonde found, otherwise returns a sonde type, from the following:
Expand All @@ -262,7 +264,9 @@ def detect_sonde(
"""

# Notes:
# 400 MHz sondes: Use --bw 20 (20 kHz BW)
# 400 MHz sondes
# Normal mode: 48 kHz sample rate, 20 kHz IF BW
# Wideband mode: 96 kHz sample rate, 64 kHz IF BW
# 1680 MHz RS92 Setting: --bw 32
# 1680 MHz LMS6-1680: Use FM demod. as usual.

Expand All @@ -280,16 +284,20 @@ def detect_sonde(

# Adjust the detection bandwidth based on the band the scanning is occuring in.
if frequency < 1000e6:
# 400-406 MHz sondes - use a 20 kHz detection bandwidth.
# 400-406 MHz sondes
_mode = "IQ"
_iq_bw = 48000
_if_bw = 20

# Try and avoid the RTLSDR 403.2 MHz spur.
# Note that this is only goign to work if we are detecting on 403.210 or 403.190 MHz.
if (abs(403200000 - frequency) < 20000) and (sdr_type == "RTLSDR"):
logging.debug("Scanner - Narrowing detection IF BW to avoid RTLSDR spur.")
_if_bw = 15
if wideband_sondes:
_iq_bw = 96000
_if_bw = 64
else:
_iq_bw = 48000
_if_bw = 20

# Try and avoid the RTLSDR 403.2 MHz spur.
# Note that this is only goign to work if we are detecting on 403.210 or 403.190 MHz.
if (abs(403200000 - frequency) < 20000) and (sdr_type == "RTLSDR"):
logging.debug("Scanner - Narrowing detection IF BW to avoid RTLSDR spur.")
_if_bw = 15

else:
# 1680 MHz sondes
Expand Down Expand Up @@ -341,7 +349,7 @@ def detect_sonde(
# )
# Saving of Debug audio, if enabled,
if save_detection_audio:
detect_iq_path = os.path.join(autorx.logging_path, f"detect_IQ_{frequency}_{str(rtl_device_idx)}.raw")
detect_iq_path = os.path.join(autorx.logging_path, f"detect_IQ_{frequency}_{_iq_bw}_{str(rtl_device_idx)}.raw")
rx_test_command += f" tee {detect_iq_path} |"

rx_test_command += os.path.join(
Expand Down Expand Up @@ -594,6 +602,13 @@ def detect_sonde(
else:
_sonde_type = "MTS01"

elif "WXR301" in _type:
logging.debug(
"Scanner (%s) - Detected a Weathex WxR-301D Sonde! (Score: %.2f, Offset: %.1f Hz)"
% (_sdr_name, _score, _offset_est)
)
_sonde_type = "WXR301"

else:
_sonde_type = None

Expand Down Expand Up @@ -648,6 +663,7 @@ def __init__(
temporary_block_list={},
temporary_block_time=60,
ngp_tweak=False,
wideband_sondes=False
):
"""Initialise a Sonde Scanner Object.
Expand Down Expand Up @@ -697,6 +713,7 @@ def __init__(
temporary_block_list (dict): A dictionary where each attribute represents a frequency that should be blocked for a set time.
temporary_block_time (int): How long (minutes) frequencies in the temporary block list should remain blocked for.
ngp_tweak (bool): Narrow the detection filter when searching for 1680 MHz sondes, to enhance detection of RS92-NGPs.
wideband_sondes (bool): Use a wider detection filter to allow detection of Weathex and wideband iMet sondes.
"""

# Thread flag. This is set to True when a scan is running.
Expand Down Expand Up @@ -735,6 +752,7 @@ def __init__(

self.callback = callback
self.save_detection_audio = save_detection_audio
self.wideband_sondes = wideband_sondes

# Temporary block list.
self.temporary_block_list = temporary_block_list.copy()
Expand Down Expand Up @@ -1100,6 +1118,7 @@ def sonde_search(self, first_only=False):
bias=self.bias,
dwell_time=self.detect_dwell_time,
save_detection_audio=self.save_detection_audio,
wideband_sondes=self.wideband_sondes
)

if detected != None:
Expand Down
5 changes: 5 additions & 0 deletions auto_rx/autorx/sondehub.py
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,11 @@ def reformat_data(self, telemetry):
_output["type"] = "MTS01"
_output["serial"] = telemetry["id"].split("-")[1]

elif telemetry["type"] == "WXR301":
_output["manufacturer"] = "Weathex"
_output["type"] = "WxR-301D"
_output["serial"] = telemetry["id"].split("-")[1]

else:
self.log_error("Unknown Radiosonde Type %s" % telemetry["type"])
return None
Expand Down
5 changes: 3 additions & 2 deletions auto_rx/autorx/templates/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -471,8 +471,8 @@
{title:'Freq (MHz)', field:"freq", headerSort:true},
{title:"ID", field:"id", width:125, headerSort:true, formatter:function(cell, formatterParams, onRendered){
_cell_data = cell.getData();
_id = _cell_data.id.replace(/^(DFM|M10|M20|IMET|IMET5|IMET54|MRZ|IMS100|RS11G|MTS01)-/,"");
_sondehub_id = _cell_data.id.replace(/^(DFM|M10|M20|IMET|IMET5|IMET54|MRZ|IMS100|RS11G|MTS01)-/,"");
_id = _cell_data.id.replace(/^(DFM|M10|M20|IMET|IMET5|IMET54|MRZ|IMS100|RS11G|MTS01|WXR)-/,"");
_sondehub_id = _cell_data.id.replace(/^(DFM|M10|M20|IMET|IMET5|IMET54|MRZ|IMS100|RS11G|MTS01|WXR)-/,"");

// Add Sondehub Link
_id += "&nbsp;<a href='http://sondehub.org/" + _sondehub_id + "' title='View on Sondehub' target='_blank'>" + "<img src='{{ url_for('static', filename='img/sondehub.png')}}'/>" + "</a>";
Expand Down Expand Up @@ -1658,6 +1658,7 @@ <h2>Decoder Control</h2>
<option value="MEISEI">iMS-100</option>
<option value="MRZ">MRZ-H1</option>
<option value="MTS01">MTS01</option>
<option value="WXR301">WXR301</option>
</select>
<div style="display:inline;vertical-align:middle;">
<button id="start-decoder" onclick="start_decoder();">Start</button>
Expand Down
Loading

0 comments on commit b688084

Please sign in to comment.