Added changes to support 400 MHz LMS6 sondes.

pull/189/head
Mark Jessop 2019-06-15 16:28:21 +09:30
rodzic 31e8bb8a76
commit 8c7f22890f
11 zmienionych plików z 292 dodań i 104 usunięć

Wyświetl plik

@ -444,8 +444,8 @@ def telemetry_filter(telemetry):
# Regex to check DFM06/09/15/17 callsigns.
dfm_callsign_valid = re.match(r'DFM[01][5679]-\d{6}', _serial)
# If Vaisala or DFMs, check the callsigns are valid. If M10 or iMet, just pass it through.
if vaisala_callsign_valid or dfm_callsign_valid or ('M10' in telemetry['type']) or ('MK2LMS' in telemetry['type']) or ('iMet' in telemetry['type']):
# If Vaisala or DFMs, check the callsigns are valid. If M10, iMet or LMS6, just pass it through.
if vaisala_callsign_valid or dfm_callsign_valid or ('M10' in telemetry['type']) or ('MK2LMS' in telemetry['type']) or ('LMS6' in telemetry['type']) or ('iMet' in telemetry['type']):
return True
else:
_id_msg = "Payload ID %s is invalid." % telemetry['id']

Wyświetl plik

@ -17,7 +17,7 @@ except ImportError:
# 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.1.3-beta1"
__version__ = "1.1.3-beta2"
# Global Variables

Wyświetl plik

@ -67,7 +67,7 @@ def telemetry_to_aprs_position(sonde_data, object_name="<id>", aprs_comment="BOM
# Use the last 5 characters of the unique ID we have generated.
_object_name = "IMET" + sonde_data['id'][-5:]
elif 'MK2LMS' in sonde_data['type']:
elif ('MK2LMS' in sonde_data['type']) or ('LMS6' in sonde_data['type']):
# Use the last 5 hex digits of the sonde ID.
_id_suffix = int(sonde_data['id'].split('-')[1])
_id_hex = hex(_id_suffix).upper()

Wyświetl plik

@ -258,7 +258,7 @@ def read_auto_rx_config(filename):
# New demod tweaks - Added 2019-04-23
# Default to all experimental decoders off.
auto_rx_config['experimental_decoders'] = {'RS41': False, 'RS92': False, 'DFM': False, 'M10': False, 'iMet': False, 'LMS6': False, 'MK2LMS': False}
auto_rx_config['experimental_decoders'] = {'RS41': False, 'RS92': False, 'DFM': False, 'M10': False, 'iMet': False, 'LMS6': True, 'MK2LMS': False}
auto_rx_config['rs41_drift_tweak'] = config.getboolean('advanced', 'drift_tweak')
auto_rx_config['decoder_spacing_limit'] = config.getint('advanced', 'decoder_spacing_limit')
auto_rx_config['decoder_stats'] = config.getboolean('advanced', 'enable_stats')
@ -266,6 +266,7 @@ def read_auto_rx_config(filename):
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')
# When LMS6 support is added, that will have to be added in here.
try:

Wyświetl plik

@ -20,7 +20,7 @@ from .gps import get_ephemeris, get_almanac
from .sonde_specific import *
# Global valid sonde types list.
VALID_SONDE_TYPES = ['RS92', 'RS41', 'DFM', 'M10', 'iMet', 'MK2LMS']
VALID_SONDE_TYPES = ['RS92', 'RS41', 'DFM', 'M10', 'iMet', 'MK2LMS', 'LMS6']
# Known 'Drifty' Radiosonde types
# NOTE: Due to observed adjacent channel detections of RS41s, the adjacent channel decoder restriction
@ -68,7 +68,7 @@ class SondeDecoder(object):
'heading' : 0.0
}
VALID_SONDE_TYPES = ['RS92', 'RS41', 'DFM', 'M10', 'iMet', 'MK2LMS']
VALID_SONDE_TYPES = ['RS92', 'RS41', 'DFM', 'M10', 'iMet', 'MK2LMS', 'LMS6']
def __init__(self,
sonde_type="None",
@ -373,6 +373,28 @@ class SondeDecoder(object):
else:
decode_cmd += "./mk2a_lms1680 --json 2>/dev/null"
elif self.sonde_type == "LMS6":
# LMS6 Decoder command.
# rtl_fm -p 0 -g -1 -M fm -F9 -s 15k -f 405500000 | sox -t raw -r 15k -e s -b 16 -c 1 - -r 48000 -b 8 -t wav - lowpass 2600 2>/dev/null | ./rs41ecc --crc --ecc --ptu
# Note: Have removed a 'highpass 20' filter from the sox line, will need to re-evaluate if adding that is useful in the future.
decode_cmd = "%s %s-p %d -d %s %s-M fm -F9 -s 15k -f %d 2>/dev/null | " % (self.sdr_fm, bias_option, int(self.ppm), str(self.device_idx), gain_param, self.sonde_freq)
# If selected by the user, we can add a highpass filter into the sox command. This helps handle up to about 5ppm of receiver drift
# before performance becomes significantly degraded. By default this is off, as it is not required with TCXO RTLSDRs, and actually
# slightly degrades performance.
if self.rs41_drift_tweak:
_highpass = "highpass 20 "
else:
_highpass = ""
decode_cmd += "sox -t raw -r 15k -e s -b 16 -c 1 - -r 48000 -b 8 -t wav - %slowpass 2600 2>/dev/null | " % _highpass
# Add in tee command to save audio to disk if debugging is enabled.
if self.save_decode_audio:
decode_cmd += " tee decode_%s.wav |" % str(self.device_idx)
decode_cmd += "./lms6mod --json 2>/dev/null"
else:
return None
@ -551,6 +573,30 @@ class SondeDecoder(object):
# iMet-4 (IMET1RS) decoder
decode_cmd += "./imet1rs_dft --json 2>/dev/null"
elif self.sonde_type == "LMS6":
# LMS6 (400 MHz variant) Decoder command.
_sdr_rate = 48000 # IQ rate. Lower rate = lower CPU usage, but less frequency tracking ability.
_output_rate = 48000
_baud_rate = 4800
_offset = 0.25 # Place the sonde frequency in the centre of the passband.
_lower = int(0.025 * _sdr_rate) # Limit the frequency estimation window to not include the passband edges.
_upper = int(0.475 * _sdr_rate)
_freq = int(self.sonde_freq - _sdr_rate*_offset)
decode_cmd = "%s %s-p %d -d %s %s-M raw -F9 -s %d -f %d 2>/dev/null |" % (self.sdr_fm, bias_option, int(self.ppm), str(self.device_idx), gain_param, _sdr_rate, _freq)
# Add in tee command to save IQ to disk if debugging is enabled.
if self.save_decode_iq:
decode_cmd += " tee decode_IQ_%s.bin |" % str(self.device_idx)
decode_cmd += "./fsk_demod --cs16 -b %d -u %d %s2 %d %d - - %s |" % (_lower, _upper, _stats_command_1, _sdr_rate, _baud_rate, _stats_command_2)
decode_cmd += " python ./test/bit_to_samples.py %d %d | sox -t raw -r %d -e unsigned-integer -b 8 -c 1 - -r %d -b 8 -t wav - 2>/dev/null|" % (_output_rate, _baud_rate, _output_rate, _output_rate)
# Add in tee command to save audio to disk if debugging is enabled.
if self.save_decode_audio:
decode_cmd += " tee decode_%s.wav |" % str(self.device_idx)
decode_cmd += "./lms6mod --json 2>/dev/null"
else:
return None
@ -726,8 +772,8 @@ class SondeDecoder(object):
_telemetry['station_code'] = self.imet_location
# LMS6-1680 Specific Actions
if self.sonde_type == 'MK2LMS':
# LMS6 Specific Actions
if self.sonde_type == 'MK2LMS' or self.sonde_type == 'LMS6':
# We are only provided with HH:MM:SS, so the timestamp needs to be fixed, just like with the iMet sondes
_telemetry['datetime_dt'] = fix_datetime(_telemetry['datetime'])

Wyświetl plik

@ -322,13 +322,13 @@ def detect_sonde(frequency, rs_path="./", dwell_time=10, sdr_fm='rtl_fm', device
logging.debug("Scanner #%s - Detected a iMet Sonde! (Type %s - Unsupported) (Score: %.2f)" % (str(device_idx), _type, _score))
return _type
elif 'LMS6' in _type:
logging.debug("Scanner #%s - Detected a LMS6 Sonde! (Unsupported) (Score: %.2f)" % (str(device_idx), _score))
logging.debug("Scanner #%s - Detected a LMS6 Sonde! (Score: %.2f)" % (str(device_idx), _score))
return 'LMS6'
elif 'C34' in _type:
logging.debug("Scanner #%s - Detected a Meteolabor C34/C50 Sonde! (Unsupported) (Score: %.2f)" % (str(device_idx), _score))
return 'C34C50'
elif 'MK2LMS' in _type:
logging.debug("Scanner #%s - Detected a 1680 MHz LMS6 Sonde! (Score: %.2f)" % (str(device_idx), _score))
logging.debug("Scanner #%s - Detected a 1680 MHz LMS6 Sonde (MK2A Telemetry)! (Score: %.2f)" % (str(device_idx), _score))
if _score < 0:
return '-MK2LMS'
else:

Wyświetl plik

@ -30,7 +30,7 @@ except ImportError:
# List of binaries we check for on startup
REQUIRED_RS_UTILS = ['dft_detect', 'dfm09mod', 'm10', 'imet1rs_dft', 'rs41mod', 'rs92mod', 'fsk_demod', 'mk2a_lms1680']
REQUIRED_RS_UTILS = ['dft_detect', 'dfm09mod', 'm10', 'imet1rs_dft', 'rs41mod', 'rs92mod', 'fsk_demod', 'mk2a_lms1680', 'lms6mod']
def check_rs_utils():
""" Check the required RS decoder binaries exist

Wyświetl plik

@ -52,9 +52,16 @@ bias = False
# Minimum and maximum search frequencies, in MHz.
# Australia: Use 400.05 - 403 MHz
# Europe: Use 400.05 - 406 MHz
# US: Somewhere around 1680 MHz... (Need more information!)
# US:
# Some areas have transitioned to the 400.05 - 406 MHz band.
# Some areas are using ~1680 MHZ sondes, which use channels of 1676, 1678, 1680 and 1682 MHz (Thanks Tory!)
# In these areas I suggest using the whitelist feature below instead of using the peak-detect search.
# You may also need to apply a small offset to the frequency for decoding reliability (i.e. 1676.025 MHz) as
# the sondes are often off-frequency. For now, check in something like GQRX to get an idea of what offset is required.
min_freq = 400.05
max_freq = 403.0
# Have the decoder timeout after X seconds of no valid data.
rx_timeout = 180
@ -369,8 +376,8 @@ sdr_power_path = rtl_power
# DEMODULATOR / DECODER TWEAKS #
################################
# RS41 Drift Tweak (Regular demod chain only)
# This tweak adds a high-pass filter into the RS41 demod chain. This extends the frequency offset range
# RS41 / LMS6 Drift Tweak (Regular demod chain only)
# This tweak adds a high-pass filter into the RS41 and LMS6 demod chains. This extends the frequency offset range
# the demod chain can handle, with some performance penalty. This is only required when using RTLSDRs
# with worse than 2-3 PPM drift, and doesn't need to be enabled for TCXO SDRs.
drift_tweak = False
@ -386,6 +393,8 @@ rs41_experimental = False
rs92_experimental = False
dfm_experimental = False
m10_experimental = False
# 400 MHz LMS6 sondes decode best with the fsk_demod decode chain, so we use this by default.
lms6-400_experimental = True
# Note: As iMet sondes use AFSK, using fsk_demod does not give any advantage, so there is no experimental decoder for them.
# Dump FSK Demod statistics to stats_<device_ID>.txt while the modem is running.
@ -398,7 +407,7 @@ enable_stats = False
# Optimize 1680 MHz Scanning for RS92-NGP Sondes
# This flag sets the use of a narrower FM receiver bandwidth when scanning for 1680 MHz RS92-NGP sondes,
# which should improve detection considerably.
# Set this to True if you are know that only RS92-NGPs are flying in your area.
# Set this to True if you are sure that only RS92-NGPs are flying in your area.
ngp_tweak = False

Wyświetl plik

@ -127,7 +127,6 @@ processing_type = {
},
# # RS92 Decoding
'rs92_fsk_demod': {
# Not currently working - need to resolve segfault in dfk_demod when using 96 kHz Fs ans 2400 Rb
# Shift up to ~24 khz, and then pass into fsk_demod.
'demod' : "| csdr shift_addition_cc 0.25 2>/dev/null | csdr convert_f_s16 | ../fsk_demod --cs16 -b 1 -u 45000 --stats=100 2 96000 4800 - - 2>stats.txt | python ./bit_to_samples.py 48000 4800 | sox -t raw -r 48k -e unsigned-integer -b 8 -c 1 - -r 48000 -b 8 -t wav - 2>/dev/null|",
@ -138,7 +137,6 @@ processing_type = {
'files' : "./generated/rs92*"
},
'm10_fsk_demod': {
# Not currently working due to weird baud rate (9614). Doesnt work even with fractional resampling (slow down signal to make it appear to be 9600 baud).
# Shift up to ~24 khz, and then pass into fsk_demod.
'demod' : "| csdr shift_addition_cc 0.25 2>/dev/null | csdr convert_f_s16 | ../tsrc - - 1.0016666 -c | ../fsk_demod --cs16 -b 1 -u 45000 --stats=100 2 96160 9616 - - 2>stats.txt | python ./bit_to_samples.py 57696 9616 | sox -t raw -r 57696 -e unsigned-integer -b 8 -c 1 - -r 57696 -b 8 -t wav - 2>/dev/null| ",
'decode': "../m10 -b -b2 2>/dev/null",
@ -157,7 +155,35 @@ processing_type = {
"post_process" : " | grep frame | wc -l", # ECC
#"post_process" : "| grep -o '\[OK\]' | wc -l", # No ECC
'files' : "./generated/dfm*.bin"
}
},
# LMS6-400 Decoding
'lms6-400_fsk_demod': {
# Shift up to ~24 khz, and then pass into fsk_demod.
'demod' : "| csdr shift_addition_cc 0.25 2>/dev/null | csdr convert_f_s16 | ../fsk_demod --cs16 -b 1 -u 45000 --stats=100 2 96000 4800 - - 2>stats.txt | python ./bit_to_samples.py 48000 4800 | sox -t raw -r 48k -e unsigned-integer -b 8 -c 1 - -r 48000 -b 8 -t wav - 2>/dev/null|",
# Decode using rs41ecc
'decode': "../lms6mod --vit -v 2>/dev/null",
# Count the number of telemetry lines.
"post_process" : "| wc -l",
'files' : "./generated/lms6-400*"
},
'lms6-1680_fsk_demod': {
# This is a weird one.
# The baud rate is ~9616 Baud, but the deviation is *huge* (~170 kHz occupied bandwidth).
# The recording bandwidth needs to be correspondingly huge, with ~480 kHz sample rate required to capture the signal.
# We need to resample up to a multiple of 9616 Hz to be able to get fsk_demod to decode.
# fsk_demod does not decode these types reliably at the moment.
'demod' : "| csdr shift_addition_cc 0.25 2>/dev/null | csdr convert_f_s16 | ./tsrc - - 1.00166666 | ../fsk_demod --cs16 -b 5000 -u 230000 --stats=100 2 480800 9616 - - 2>stats.txt | python ./bit_to_samples.py 57696 9616 | sox -t raw -r 57696 -e unsigned-integer -b 8 -c 1 - -r 57696 -b 8 -t wav - 2>/dev/null|",
# Decode using rs41ecc
'decode': "../mk2a_lms1680 -i --json 2>/dev/null",
# Count the number of telemetry lines.
"post_process" : " | grep frame | wc -l",
# No low-SNR samples for this sonde available yet.
'files' : "./generated/lms6-1680*"
},
}
@ -361,6 +387,67 @@ processing_type['rs41_rtlfm'] = {
# }
# LMS6 - 400 MHz version
_fm_rate = 22000
# Calculate the necessary conversions
_rtlfm_oversampling = 8.0 # Viproz's hacked rtl_fm oversamples by 8x.
_shift = -2.0*_fm_rate/_sample_fs # rtl_fm tunes 'up' by rate*2, so we need to shift the signal down by this amount.
_resample = (_fm_rate*_rtlfm_oversampling)/_sample_fs
if _resample != 1.0:
# We will need to resample.
_resample_command = "csdr convert_f_s16 | ./tsrc - - %.4f | csdr convert_s16_f |" % _resample
_shift = (-2.0*_fm_rate)/(_sample_fs*_resample)
else:
_resample_command = ""
_demod_command = "| %s csdr shift_addition_cc %.5f 2>/dev/null | csdr convert_f_u8 |" % (_resample_command, _shift)
_demod_command += " ./rtl_fm_stdin -M fm -f 401000000 -F9 -s %d 2>/dev/null|" % (int(_fm_rate))
_demod_command += " sox -t raw -r %d -e s -b 16 -c 1 - -r 48000 -b 8 -t wav - highpass 20 2>/dev/null |" % int(_fm_rate)
processing_type['lms6-400_rtlfm'] = {
'demod': _demod_command,
# Decode using rs92ecc
'decode': "../lms6mod 2>/dev/null",
#'decode': "../rs92ecc -vx -v --crc --ecc -r --vel 2>/dev/null", # For measuring No-ECC performance
# Count the number of telemetry lines.
"post_process" : " | wc -l",
#"post_process" : " | grep \"errors: 0\" | wc -l",
'files' : "./generated/lms6-400*.bin"
}
# # LMS6 - 1680
_fm_rate = 200000
_sample_fs = 480000
# Calculate the necessary conversions
_rtlfm_oversampling = 8.0 # Viproz's hacked rtl_fm oversamples by 8x.
_shift = -2.0*_fm_rate/_sample_fs # rtl_fm tunes 'up' by rate*2, so we need to shift the signal down by this amount.
_resample = (_fm_rate*_rtlfm_oversampling)/_sample_fs
if _resample != 1.0:
# We will need to resample.
_resample_command = "csdr convert_f_s16 | ./tsrc - - %.4f | csdr convert_s16_f |" % _resample
_shift = (-2.0*_fm_rate)/(_sample_fs*_resample)
else:
_resample_command = ""
_demod_command = "| %s csdr shift_addition_cc %.5f 2>/dev/null | csdr convert_f_u8 |" % (_resample_command, _shift)
_demod_command += " ./rtl_fm_stdin -M fm -f 401000000 -F9 -s %d 2>/dev/null|" % (int(_fm_rate))
_demod_command += " sox -t raw -r %d -e s -b 16 -c 1 - -r 48000 -b 8 -t wav - highpass 20 2>/dev/null |" % int(_fm_rate)
processing_type['lms6-1680_rtlfm'] = {
'demod': _demod_command,
'decode': "../mk2a_lms1680 --json -i 2>/dev/null",
# Count the number of telemetry lines.
"post_process" : "| grep frame | wc -l",
'files' : "./generated/lms6-1680*.bin"
}
# # RS_Detect
# _fm_rate = 22000
# #_fm_rate = 15000
@ -389,33 +476,34 @@ processing_type['rs41_rtlfm'] = {
# 'files' : "./generated/*.bin"
# }
# # DFT_Detect
# _fm_rate = 22000
# #_fm_rate = 15000
# # Calculate the necessary conversions
# _rtlfm_oversampling = 8.0 # Viproz's hacked rtl_fm oversamples by 8x.
# _shift = -2.0*_fm_rate/_sample_fs # rtl_fm tunes 'up' by rate*2, so we need to shift the signal down by this amount.
# DFT_Detect
_fm_rate = 22000
#_fm_rate = 15000
_sample_fs = 96000
# Calculate the necessary conversions
_rtlfm_oversampling = 8.0 # Viproz's hacked rtl_fm oversamples by 8x.
_shift = -2.0*_fm_rate/_sample_fs # rtl_fm tunes 'up' by rate*2, so we need to shift the signal down by this amount.
# _resample = (_fm_rate*_rtlfm_oversampling)/_sample_fs
_resample = (_fm_rate*_rtlfm_oversampling)/_sample_fs
# if _resample != 1.0:
# # We will need to resample.
# _resample_command = "csdr convert_f_s16 | ./tsrc - - %.4f | csdr convert_s16_f |" % _resample
# _shift = (-2.0*_fm_rate)/(_sample_fs*_resample)
# else:
# _resample_command = ""
if _resample != 1.0:
# We will need to resample.
_resample_command = "csdr convert_f_s16 | ./tsrc - - %.4f | csdr convert_s16_f |" % _resample
_shift = (-2.0*_fm_rate)/(_sample_fs*_resample)
else:
_resample_command = ""
# _demod_command = "| %s csdr shift_addition_cc %.5f 2>/dev/null | csdr convert_f_u8 |" % (_resample_command, _shift)
# _demod_command += " ./rtl_fm_stdin -M fm -f 401000000 -F9 -s %d 2>/dev/null|" % (int(_fm_rate))
# _demod_command += " sox -t raw -r %d -e s -b 16 -c 1 - -r 48000 -b 8 -t wav - highpass 20 2>/dev/null |" % int(_fm_rate)
_demod_command = "| %s csdr shift_addition_cc %.5f 2>/dev/null | csdr convert_f_u8 |" % (_resample_command, _shift)
_demod_command += " ./rtl_fm_stdin -M fm -f 401000000 -F9 -s %d 2>/dev/null|" % (int(_fm_rate))
_demod_command += " sox -t raw -r %d -e s -b 16 -c 1 - -r 48000 -b 8 -t wav - highpass 20 2>/dev/null |" % int(_fm_rate)
# processing_type['dft_detect_rtlfm'] = {
# 'demod': _demod_command,
# 'decode': "../dft_detect 2>/dev/null",
# # Grep out the line containing the detected sonde type.
# "post_process" : " | grep \:",
# 'files' : "./generated/*.bin"
# }
processing_type['dft_detect_rtlfm'] = {
'demod': _demod_command,
'decode': "../dft_detect 2>/dev/null",
# Grep out the line containing the detected sonde type.
"post_process" : " | grep \:",
'files' : "./generated/*.bin"
}

Wyświetl plik

@ -5,13 +5,13 @@
# Copyright (C) 2019 Mark Jessop <vk5qi@rfhead.net>
# Released under GNU GPL v3 or later
#
# Compares the auto_rx calcuated temperature & humidity values with
# truth data produced by a Vaisala ground station.
# Compares the auto_rx calcuated temperature & humidity values with
# truth data produced by a Vaisala ground station.
#
# The 'truth' data must be in vaisalas 'metdata' tab-delimited text format.
# The 'truth' data must be in vaisalas 'metdata' tab-delimited text format.
#
# Run with:
# python3 compare_vaisala.py originalmetdata_20190521_0418_R0230900.txt 20190521-042102_R0230900_RS41_402200_sonde.log
# Run with:
# python3 compare_vaisala.py originalmetdata_20190521_0418_R0230900.txt 20190521-042102_R0230900_RS41_402200_sonde.log
#
# TODO:
# [ ] Calculate temp/rh error vs altitude
@ -37,42 +37,42 @@ from metpy.plots import SkewT
from metpy.units import units
def read_vaisala_metdata(filename):
""" Read in a Vaisala 'metdata' tab-delimtied text file, as produced by the MW32 ground station """
""" Read in a Vaisala 'metdata' tab-delimtied text file, as produced by the MW32 ground station """
_f = open(filename, 'r')
_f = open(filename, 'r')
# Skip past the header.
for i in range(22):
_f.readline()
# Skip past the header.
for i in range(22):
_f.readline()
output = []
# Read in lines of data.
# n Elapsed time HeightMSL Pc Pm Temp RH VirT Lat Lon HeightE Speed Dir
for line in _f:
try:
_fields = line.split('\t')
_count = int(_fields[0])
_flight_time = int(_fields[1])
_height_msl = int(_fields[2])
_pressure_calc = float(_fields[3])
_pressure_meas = float(_fields[4])
_temp = float(_fields[5])
_relhum = int(_fields[6])
_virt = float(_fields[7])
_lat = float(_fields[8])
_lon = float(_fields[9])
_alt = float(_fields[10])
_vel_h = float(_fields[11])
_heading = float(_fields[12])
output = []
# Read in lines of data.
# n Elapsed time HeightMSL Pc Pm Temp RH VirT Lat Lon HeightE Speed Dir
for line in _f:
try:
_fields = line.split('\t')
_count = int(_fields[0])
_flight_time = int(_fields[1])
_height_msl = int(_fields[2])
_pressure_calc = float(_fields[3])
_pressure_meas = float(_fields[4])
_temp = float(_fields[5])
_relhum = int(_fields[6])
_virt = float(_fields[7])
_lat = float(_fields[8])
_lon = float(_fields[9])
_alt = float(_fields[10])
_vel_h = float(_fields[11])
_heading = float(_fields[12])
output.append([_count, _flight_time, _height_msl, _pressure_calc, _pressure_meas, _temp, _relhum, _virt, _lat, _lon, _alt, _vel_h, _heading])
output.append([_count, _flight_time, _height_msl, _pressure_calc, _pressure_meas, _temp, _relhum, _virt, _lat, _lon, _alt, _vel_h, _heading])
except:
pass
except:
pass
return np.array(output)
return np.array(output)
# Earthmaths code by Daniel Richman (thanks!)
@ -250,43 +250,87 @@ def read_log_file(filename, decimation=10, min_altitude=100):
return (np.array(_output), _burst, _startalt, times[-1])
def comparison_plots(vaisala_data, autorx_data):
_vaisala_alt = vaisala_data[:,2]
_vaisala_temp = vaisala_data[:,5]
_vaisala_rh = vaisala_data[:,6]
def comparison_plots(vaisala_data, autorx_data, serial):
_vaisala_alt = vaisala_data[:,2]
_vaisala_temp = vaisala_data[:,5]
_vaisala_rh = vaisala_data[:,6]
_autorx_alt = autorx_data[:,0]
_autorx_temp = autorx_data[:,3]
_autorx_rh = autorx_data[:,5]
_autorx_alt = autorx_data[:,0]
_autorx_temp = autorx_data[:,3]
_autorx_rh = autorx_data[:,5]
# Interpolation
_interp_min_alt = max(np.min(_vaisala_alt), np.min(_autorx_alt))
_interp_max_alt = min(np.max(_vaisala_alt), np.max(_autorx_alt))
# Define the altitude range we interpolate over.
_interp_x = np.linspace(_interp_min_alt, _interp_max_alt, 2000)
# Produce interpolated temperature and humidity data.
_vaisala_interp_temp = np.interp(_interp_x, _vaisala_alt, _vaisala_temp)
_vaisala_interp_rh = np.interp(_interp_x, _vaisala_alt, _vaisala_rh)
_autorx_interp_temp = np.interp(_interp_x, _autorx_alt, _autorx_temp)
_autorx_interp_rh = np.interp(_interp_x, _autorx_alt, _autorx_rh)
# Calculate the error in auto_rx's calculations.
_autorx_temp_error = _autorx_interp_temp - _vaisala_interp_temp
_autorx_rh_error = _autorx_interp_rh - _vaisala_interp_rh
plt.figure()
plt.plot(_vaisala_alt, _vaisala_temp, label="Vaisala")
plt.plot(_autorx_alt, _autorx_temp, label="auto_rx")
plt.xlabel("Altitude (m)")
plt.ylabel("Temperature (degC)")
plt.title("Temperature")
plt.legend()
plt.figure()
plt.plot(_vaisala_alt, _vaisala_temp, label="Vaisala")
plt.plot(_autorx_alt, _autorx_temp, label="auto_rx")
plt.xlabel("Altitude (m)")
plt.ylabel("Temperature (degC)")
plt.title("Temperature - %s" % serial)
plt.legend()
plt.grid()
plt.figure()
plt.plot(_vaisala_alt, _vaisala_rh, label="Vaisala")
plt.plot(_autorx_alt, _autorx_rh, label="auto_rx")
plt.xlabel("Altitude (m)")
plt.ylabel("Relative Humidity (%)")
plt.title("Relative Humidity")
plt.legend()
plt.show()
plt.figure()
plt.plot(_vaisala_alt, _vaisala_rh, label="Vaisala")
plt.plot(_autorx_alt, _autorx_rh, label="auto_rx")
plt.xlabel("Altitude (m)")
plt.ylabel("Relative Humidity (%)")
plt.title("Relative Humidity - %s" % serial)
plt.legend()
plt.grid()
plt.show()
plt.figure()
plt.plot(_interp_x, _autorx_temp_error)
plt.xlabel("Altitude (m)")
plt.ylabel("Error (degC)")
plt.title("auto_rx RS41 Temperature Calculation Error - %s" % serial)
plt.grid()
plt.figure()
plt.plot(_interp_x, _autorx_rh_error)
plt.xlabel("Altitude (m)")
plt.ylabel("Error (% RH)")
plt.title("auto_rx RS41 Humidity Calculation Error - %s" % serial)
plt.grid()
plt.figure()
plt.plot(_vaisala_interp_temp, _autorx_rh_error)
plt.xlabel("Temperature (degC)")
plt.ylabel("Error (% RH)")
plt.title("auto_rx RS41 Humidity Calculation Error - %s" % serial)
plt.grid()
plt.show()
if __name__ == "__main__":
_vaisala_filename = sys.argv[1]
_autorx_filename = sys.argv[2]
_vaisala_filename = sys.argv[1]
_autorx_filename = sys.argv[2]
vaisala_data = read_vaisala_metdata(_vaisala_filename)
_serial = _autorx_filename.split('_')[1]
(autorx_data, burst, startalt, lasttime) = read_log_file(_autorx_filename, decimation=1)
vaisala_data = read_vaisala_metdata(_vaisala_filename)
comparison_plots(vaisala_data, autorx_data)
(autorx_data, burst, startalt, lasttime) = read_log_file(_autorx_filename, decimation=1)
comparison_plots(vaisala_data, autorx_data, _serial)

Wyświetl plik

@ -628,7 +628,7 @@ static void print_frame(gpx_t *gpx, int crc_err, int len) {
// Print JSON output required by auto_rx.
if (crc_err==0) { // CRC-OK
// UTC oder GPS?
printf("{ \"frame\": %d, \"id\": \"%d\", \"time\": \"%02d:%02d:%06.3fZ\", \"lat\": %.5f, \"lon\": %.5f, \"alt\": %.5f, \"vel_h\": %.5f, \"heading\": %.5f, \"vel_v\": %.5f }\n",
printf("{ \"frame\": %d, \"id\": \"LMS6-%d\", \"datetime\": \"%02d:%02d:%06.3fZ\", \"lat\": %.5f, \"lon\": %.5f, \"alt\": %.5f, \"vel_h\": %.5f, \"heading\": %.5f, \"vel_v\": %.5f }\n",
gpx->frnr, gpx->sn, gpx->std, gpx->min, gpx->sek, gpx->lat, gpx->lon, gpx->alt, gpx->vH, gpx->vD, gpx->vV );
printf("\n");
}