Skip to content

Commit

Permalink
iMet-1/4 XDATA decoding, add initial detection of iMet1 vs iMet4 sondes.
Browse files Browse the repository at this point in the history
  • Loading branch information
Mark Jessop authored and Mark Jessop committed Jan 30, 2022
1 parent 965aedf commit 1372b70
Show file tree
Hide file tree
Showing 6 changed files with 330 additions and 110 deletions.
2 changes: 1 addition & 1 deletion auto_rx/auto_rx.py
Original file line number Diff line number Diff line change
Expand Up @@ -497,7 +497,7 @@ def telemetry_filter(telemetry):
if "sats" in telemetry:
if telemetry["sats"] < 4:
logging.warning(
"Sonde %s can only see %d SVs - discarding position as bad."
"Sonde %s can only see %d GNSS sats - discarding position as bad."
% (telemetry["id"], telemetry["sats"])
)
return False
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 @@ -17,7 +17,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.5.8"
__version__ = "1.5.9-beta1"


# Global Variables
Expand Down
45 changes: 43 additions & 2 deletions auto_rx/autorx/decode.py
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,12 @@ def __init__(
# This should hopefully handle a few iMets on the same frequency in a graceful manner.
self.imet_max_ids = 4
self.imet_id = []
# iMet-1 and iMet-4 sondes behave differently.
# iMet-1 sondes increment the frame counter *twice* each second, imet-4 only once per second.
# We need to detect this to be able to calculate a start time, and hence generate a serial number.
self.imet_type = None
self.imet_prev_time = None
self.imet_prev_frame = None

# This will become our decoder thread.
self.decoder = None
Expand Down Expand Up @@ -1307,7 +1313,7 @@ def handle_decoder_line(self, data):
# We append -Ozone to the sonde type field to indicate this.
# TODO: Decode device ID from aux field to indicate what the aux payload actually is?
if "aux" in _telemetry:
_telemetry["type"] += "-Ozone"
_telemetry["type"] += "-Ozone"

# iMet Specific actions
if self.sonde_type == "IMET":
Expand All @@ -1321,9 +1327,44 @@ def handle_decoder_line(self, data):
# Fix up the time.
_telemetry["datetime_dt"] = fix_datetime(_telemetry["datetime"])


# An attempt at detecting iMet-1 vs iMet-4 sondes based on how the frame count increments
# compared to the time.
# Note that this is going to break horribly if an iMet-1 and an iMet-4 are on the same frequency,
# or if there are multiple iMet-4's in the air when this is performed. I don't have a nice
# solution to that second problem.
# This may also break when running in UDP mode for long periods.
if self.imet_type is None:
if self.imet_prev_frame is None:
self.imet_prev_frame = _telemetry['frame']
self.imet_prev_time = _telemetry["datetime_dt"]
self.log_info("Waiting for additional frames to determine iMet type (1 or 4)")
return False
else:
# Calculate and compare frame vs time deltas.
_time_delta = (_telemetry["datetime_dt"] - self.imet_prev_time).total_seconds()
_frame_delta = _telemetry['frame'] - self.imet_prev_frame

if _time_delta == _frame_delta//2:
# Frame counter increments at twice the rate of the time counter = iMet-1
self.log_info("iMet sonde is most likely an iMet-1")
self.imet_type = "iMet-1"
elif _time_delta == _frame_delta:
# Frame counter increments at the same rate as the time counter = iMet-4
self.log_info("iMet sonde is most likely an iMet-4")
self.imet_type = "iMet-4"
else:
# Some other case (possibly 2 sondes on the same frequency?)
# Assume iMet-4...
self.log_info("iMet sonde is most likely an iMet-4 (less confidence)")
self.imet_type = "iMet-4"
else:
_telemetry['subtype'] = self.imet_type


# Generate a unique ID based on the power-on time and frequency, as iMet sonde telemetry is painful
# and doesn't send any ID.
_new_imet_id = imet_unique_id(_telemetry)
_new_imet_id = imet_unique_id(_telemetry, imet1=(self.imet_type=="iMet-1"))

# If we have seen this ID before, keep using it.
if _new_imet_id in self.imet_id:
Expand Down
12 changes: 10 additions & 2 deletions auto_rx/autorx/sonde_specific.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ def fix_datetime(datetime_str, local_dt_str=None):
#


def imet_unique_id(telemetry, custom="SONDE"):
def imet_unique_id(telemetry, custom="SONDE", imet1=False):
"""
Generate a 'unique' imet radiosonde ID based on the power-on time, frequency, and an optional location code.
This requires the following fields be present in the telemetry dict:
Expand All @@ -62,8 +62,16 @@ def imet_unique_id(telemetry, custom="SONDE"):

_imet_dt = telemetry["datetime_dt"]

if imet1:
# iMet-1 sondes increment their frame counter TWICE every second, so we need to
# compensate for this to be able to determine a power-on time.
_frame = telemetry["frame"]//2
else:
# iMet-4 sondes increment the frame counter once per second.
_frame = telemetry["frame"]

# Determine power on time: Current time - number of frames (one frame per second)
_power_on_time = _imet_dt - datetime.timedelta(seconds=telemetry["frame"])
_power_on_time = _imet_dt - datetime.timedelta(seconds=_frame)

# Round frequency to the nearest 100 kHz (iMet sondes only have 100 kHz frequency steps)
_freq = round(telemetry["freq_float"] * 10.0) / 10.0
Expand Down
5 changes: 4 additions & 1 deletion auto_rx/autorx/sondehub.py
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,10 @@ def reformat_data(self, telemetry):

elif telemetry["type"] == "IMET":
_output["manufacturer"] = "Intermet Systems"
_output["type"] = "iMet-4"
if "subtype" in telemetry:
_output["type"] = telemetry['subtype']
else:
_output["type"] = "iMet-4"
_output["serial"] = telemetry["id"].split("-")[1]

elif telemetry["type"] == "IMET5":
Expand Down
Loading

0 comments on commit 1372b70

Please sign in to comment.