Merge pull request #596 from projecthorus/testing

v1.5.8 release - M20 PTU Support, iMet-4 fixes
pull/601/head v1.5.8
Mark Jessop 2021-12-17 16:17:35 +10:30 zatwierdzone przez GitHub
commit a1c9d46218
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
10 zmienionych plików z 560 dodań i 191 usunięć

Wyświetl plik

@ -20,12 +20,12 @@ Vaisala | RS92-SGP/NGP | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_
Vaisala | RS41-SG/SGP/SGM | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: (for -SGP)
Graw | DFM06/09/17 | :heavy_check_mark: | :heavy_check_mark: | :x: | :x:
Meteomodem | M10 | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | Not Sent
Meteomodem | M20 | :heavy_check_mark: | :x: | :x: | Not Sent
Meteomodem | M20 | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: (For some models)
Intermet Systems | iMet-4 | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | Not Sent
Intermet Systems | iMet-54 | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | Not Sent
Lockheed Martin | LMS6-400/1680 | :heavy_check_mark: | :x: | :x: | :x:
Meisei | iMS-100 | :heavy_check_mark: | :x: | :x: | :x:
Meteo-Radiy | MRZ (400 MHz) | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :x:
Meteo-Radiy | MRZ-H1 (400 MHz) | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :x:
Support for other radiosondes may be added as required - please send us sondes to test with! If you have any information about telemetry formats, we'd love to hear from you (see our contact details below).

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.5.7"
__version__ = "1.5.8"
# Global Variables

Wyświetl plik

@ -203,7 +203,12 @@ class SondeDecoder(object):
# which don't necessarily have a consistent packet count to time increment ratio.
# This is a tradeoff between being able to handle multiple iMet sondes on a single frequency, and
# not flooding the various databases with sonde IDs in the case of a bad sonde.
self.imet_id = None
# iMet ID store v2
# Now instead of just latching onto an ID, we allow up to 4 new IDs to be created per decoder.
# This should hopefully handle a few iMets on the same frequency in a graceful manner.
self.imet_max_ids = 4
self.imet_id = []
# This will become our decoder thread.
self.decoder = None
@ -876,7 +881,7 @@ class SondeDecoder(object):
)
# M20 decoder
decode_cmd = f"./mXXmod --json --ptu -vvv --softin -i {self.raw_file_option} 2>/dev/null"
decode_cmd = f"./m20mod --json --ptu -vvv --softin -i {self.raw_file_option} 2>/dev/null"
# M20 sondes transmit in short, irregular pulses - average over the last 2 frames, and use a peak hold
demod_stats = FSKDemodStats(averaging_time=2.0, peak_hold=True)
@ -1315,16 +1320,30 @@ class SondeDecoder(object):
# Fix up the time.
_telemetry["datetime_dt"] = fix_datetime(_telemetry["datetime"])
# Generate a unique ID based on the power-on time and frequency, as iMet sondes don't send one.
# Latch this ID and re-use it for the entire decode run.
if self.imet_id == None:
self.imet_id = imet_unique_id(_telemetry)
# 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)
# If we have seen this ID before, keep using it.
if _new_imet_id in self.imet_id:
_telemetry["id"] = _new_imet_id
else:
# We have seen less than 4 different IDs while this decoder has been runing.
# Accept that this may be a new iMet sonde, and add the ID to the iMet ID list.
if len(self.imet_id) < self.imet_max_ids:
self.imet_id.append(_new_imet_id)
_telemetry["id"] = _new_imet_id
else:
# We have seen see many IDs this decode run, suspect this is likely an old iMet-1
# Which doesn't have a useful frame counter.
self.log_error("Exceeded maximum number of iMet sonde IDs for a decoder (4) - discarding this frame.")
return False
# Re-generate the datetime string.
_telemetry["datetime"] = _telemetry["datetime_dt"].strftime(
"%Y-%m-%dT%H:%M:%SZ"
)
_telemetry["id"] = self.imet_id
# iMet-5x Specific Actions
if self.sonde_type == "IMET5":

Wyświetl plik

@ -46,6 +46,7 @@ REQUIRED_RS_UTILS = [
"meisei100mod",
"imet54mod",
"mp3h1mod",
"m20mod",
]
@ -70,8 +71,8 @@ def get_autorx_version(version_url=AUTORX_MAIN_VERSION_URL):
try:
_r = requests.get(version_url, timeout=5)
except Exception as e:
logging.exception(
f"Version - Error determining version from URL {version_url}", e
logging.error(
f"Version - Error determining version from URL {version_url}: {str(e)}"
)
return None
@ -83,8 +84,8 @@ def get_autorx_version(version_url=AUTORX_MAIN_VERSION_URL):
return _main_version
except Exception as e:
logging.exception(
f"Version - Error extracting version from url {version_url}.", e
logging.error(
f"Version - Error extracting version from url {version_url}: {str(e)}."
)
return None

Wyświetl plik

@ -14,6 +14,7 @@ echo "Building for radiosonde_auto_rx version: $AUTO_RX_VERSION"
VERS_FLAG="-DVER_JSN_STR=$AUTO_RX_VERSION"
# Build rs_detect.
echo "Building dft_detect"
cd ../scan/
@ -38,7 +39,7 @@ gcc meisei100mod.c demod_mod.o bch_ecc_mod.o -lm -O3 -o meisei100mod -w $VERS_FL
echo "Building M10 demod."
gcc m10mod.c demod_mod.o -lm -O3 -o m10mod -w $VERS_FLAG
echo "Building M20 demod."
gcc mXXmod.c demod_mod.o -lm -O3 -o mXXmod -w $VERS_FLAG
gcc m20mod.c demod_mod.o -lm -O3 -o m20mod -w $VERS_FLAG
echo "Building iMet-54 demod."
gcc imet54mod.c demod_mod.o -lm -O3 -o imet54mod -w $VERS_FLAG
echo "Building MRZ demod."
@ -74,7 +75,7 @@ cp ../mk2a/mk2mod .
cp ../demod/mod/rs41mod .
cp ../demod/mod/dfm09mod .
cp ../demod/mod/m10mod .
cp ../demod/mod/mXXmod .
cp ../demod/mod/m20mod .
cp ../demod/mod/rs92mod .
cp ../demod/mod/lms6Xmod .
cp ../demod/mod/meisei100mod .

Wyświetl plik

@ -24,7 +24,10 @@ rm lms6mod
rm lms6Xmod
rm meisei100mod
rm m10mod
rm m20mod
rm mXXmod
rm mp3h1mod
rm imet54mod
# LMS6-1680 Decoder
echo "Cleaning LMS6-1680 Demodulator."
@ -56,8 +59,11 @@ rm rs92mod
rm dfm09mod
rm m10mod
rm mXXmod
rm m20mod
rm lms6Xmod
rm meisei100mod
rm mp3h1mod
rm imet54mod
echo "Done!"

Wyświetl plik

@ -8,7 +8,7 @@ AUTO_RX_VERSION := $(shell PYTHONPATH=../../auto_rx python -m autorx.version)
CFLAGS = -O3 -Wall -Wno-unused-variable -DVER_JSN_STR=\"$(AUTO_RX_VERSION)\"
LDLIBS = -lm
PROGRAMS := rs41mod dfm09mod rs92mod lms6mod lms6Xmod meisei100mod m10mod mXXmod imet54mod
PROGRAMS := rs41mod dfm09mod rs92mod lms6mod lms6Xmod meisei100mod m10mod m20mod imet54mod
all: $(PROGRAMS)
@ -26,9 +26,11 @@ meisei100mod: meisei100mod.o demod_mod.o bch_ecc_mod.o
m10mod: m10mod.o demod_mod.o
mXXmod: mXXmod.o demod_mod.o
m20mod: m20mod.o demod_mod.o
imet54mod: imet54mod.o demod_mod.o
mp3h1mod: mp3h1mod.o demod_mod.o
clean:
$(RM) $(PROGRAMS) $(PROGRAMS:=.o) demod_mod.o bch_ecc_mod.o

Wyświetl plik

@ -145,7 +145,7 @@ static int dft_window(dft_t *dft, int w) {
/* ------------------------------------------------------------------------------------ */
static int getCorrDFT(dsp_t *dsp) {
static int getCorrDFT(dsp_t *dsp, float thres) {
int i;
int mp = -1;
float mx = 0.0;
@ -155,9 +155,8 @@ static int getCorrDFT(dsp_t *dsp) {
ui32_t mpos = 0;
ui32_t pos = dsp->sample_out;
double dc = 0.0;
int mp_ofs = 0;
float *sbuf = dsp->bufs;
float *dcbuf = dsp->fm_buffer;
dsp->mv = 0.0;
dsp->dc = 0.0;
@ -166,38 +165,32 @@ static int getCorrDFT(dsp_t *dsp) {
if (dsp->sample_out < dsp->L) return -2;
if (dsp->opt_iq > 1 && dsp->opt_dc) {
mp_ofs = (dsp->sps-1)/2;
sbuf = dsp->fm_buffer;
}
else {
sbuf = dsp->bufs;
}
for (i = 0; i < dsp->K + dsp->L; i++) (dsp->DFT).xn[i] = sbuf[(pos+dsp->M -(dsp->K + dsp->L-1) + i) % dsp->M];
while (i < dsp->DFT.N) (dsp->DFT).xn[i++] = 0.0;
for (i = 0; i < dsp->K + dsp->L; i++) dsp->DFT.xn[i] = sbuf[(pos+dsp->M -(dsp->K + dsp->L-1) + i) % dsp->M];
while (i < dsp->DFT.N) dsp->DFT.xn[i++] = 0.0;
rdft(&dsp->DFT, dsp->DFT.xn, dsp->DFT.X);
if (dsp->opt_dc) {
/*
//X[0] = 0; // nicht ueber gesamte Laenge ... M10
//
// L < K ? // only last 2L samples (avoid M10 carrier offset)
dc = 0.0;
for (i = dsp->K - dsp->L; i < dsp->K + dsp->L; i++) dc += (dsp->DFT).xn[i];
double dc = 0.0;
for (i = dsp->K - dsp->L; i < dsp->K + dsp->L; i++) dc += dsp->DFT.xn[i];
dc /= 2.0*(float)dsp->L;
dsp->DFT.X[0] -= dsp->DFT.N * dc ;//* 0.95;
Nidft(&dsp->DFT, dsp->DFT.X, (dsp->DFT).cx);
for (i = 0; i < dsp->DFT.N; i++) (dsp->DFT).xn[i] = creal((dsp->DFT).cx[i])/(float)dsp->DFT.N;
*/
dsp->DFT.X[0] = 0;
Nidft(&dsp->DFT, dsp->DFT.X, dsp->DFT.cx);
for (i = 0; i < dsp->DFT.N; i++) dsp->DFT.xn[i] = creal(dsp->DFT.cx[i])/(float)dsp->DFT.N;
}
for (i = 0; i < dsp->DFT.N; i++) dsp->DFT.Z[i] = dsp->DFT.X[i]*dsp->DFT.Fm[i];
Nidft(&dsp->DFT, dsp->DFT.Z, dsp->DFT.cx);
if (fabs(dc) < 0.5) dsp->dc = dc;
// relativ Peak - Normierung erst zum Schluss;
// dann jedoch nicht zwingend corr-Max wenn FM-Amplitude bzw. norm(x) nicht konstant
@ -220,21 +213,88 @@ static int getCorrDFT(dsp_t *dsp) {
//xnorm = sqrt(dsp->qs[(mpos + 2*dsp->M) % dsp->M]); // Nvar = L
xnorm = 0.0;
for (i = 0; i < dsp->L; i++) xnorm += (dsp->DFT).xn[mp-i]*(dsp->DFT).xn[mp-i];
for (i = 0; i < dsp->L; i++) xnorm += dsp->DFT.xn[mp-i]*dsp->DFT.xn[mp-i];
xnorm = sqrt(xnorm);
mx /= xnorm*(dsp->DFT).N;
if (dsp->opt_iq > 1 && dsp->opt_dc) mpos += mp_ofs;
mx /= xnorm*dsp->DFT.N;
dsp->mv = mx;
dsp->mv_pos = mpos;
if (pos == dsp->sample_out) dsp->buffered = dsp->sample_out - mpos;
if (pos == dsp->sample_out) dsp->buffered = dsp->sample_out - dsp->mv_pos;
// FM: s = gain * carg(w)/M_PI = gain * dphi / PI // gain=0.8
// FM audio gain? dc relative to FM-envelope?!
//
dsp->mv2 = 0.0f;
dsp->mv2_pos = 0;
if (dsp->opt_dc) {
if (dsp->opt_iq >= 2 && fabs(mx) < thres) { /*&& !dsp->locked*/
mx = 0.0f;
mpos = 0;
for (i = 0; i < dsp->K + dsp->L; i++) dsp->DFT.xn[i] = dcbuf[(pos+dsp->M -(dsp->K + dsp->L-1) + i) % dsp->M];
while (i < dsp->DFT.N) dsp->DFT.xn[i++] = 0.0;
rdft(&dsp->DFT, dsp->DFT.xn, dsp->DFT.X);
dsp->DFT.X[0] = 0;
Nidft(&dsp->DFT, dsp->DFT.X, dsp->DFT.cx);
for (i = 0; i < dsp->DFT.N; i++) dsp->DFT.xn[i] = creal(dsp->DFT.cx[i])/(float)dsp->DFT.N;
for (i = 0; i < dsp->DFT.N; i++) dsp->DFT.Z[i] = dsp->DFT.X[i]*dsp->DFT.Fm[i];
Nidft(&dsp->DFT, dsp->DFT.Z, dsp->DFT.cx);
mx2 = 0.0; // t = L-1
for (i = dsp->L-1; i < dsp->K + dsp->L; i++) { // i=t .. i=t+K < t+1+K
re_cx = creal(dsp->DFT.cx[i]); // imag(cx)=0
if (re_cx*re_cx > mx2) {
mx = re_cx;
mx2 = mx*mx;
mp = i;
}
}
if (mp == dsp->L-1 || mp == dsp->K + dsp->L-1) return -4; // Randwert
// mp == t mp == K+t
mpos = pos - (dsp->K + dsp->L-1) + mp; // t = L-1
xnorm = 0.0;
for (i = 0; i < dsp->L; i++) xnorm += dsp->DFT.xn[mp-i]*dsp->DFT.xn[mp-i];
xnorm = sqrt(xnorm);
mx /= xnorm*dsp->DFT.N;
dsp->mv2 = mx;
dsp->mv2_pos = mpos - (dsp->lpFMtaps - (dsp->sps-1))/2;
if (dsp->mv2 > thres || dsp->mv2 < -thres) {
dsp->mv = dsp->mv2;
dsp->mv_pos = dsp->mv2_pos;
if (pos == dsp->sample_out) dsp->buffered = dsp->sample_out - dsp->mv2_pos;
}
}
}
if (dsp->opt_dc)
{
double dc = 0.0;
int mp_ofs = 0;
if (dsp->opt_iq >= 2 && dsp->mv2_pos == 0) {
mp_ofs = (dsp->lpFMtaps - (dsp->sps-1))/2;
}
dc = 0.0; // rs41 without preamble?
// unbalanced header?
for (i = 0; i < dsp->L; i++) dc += dcbuf[(mp_ofs + mpos - i + dsp->M) % dsp->M];
dc /= (float)dsp->L;
dsp->dc = dc;
}
// FM: s = gain * carg(w)/M_PI = gain * dphi / PI // gain=0.8
// FM audio gain? dc relative to FM-envelope?!
//
dsp->dDf = dsp->sr * dsp->dc / (2.0*FM_GAIN); // remaining freq offset
return mp;
@ -597,6 +657,7 @@ static float re_lowpass(float buffer[], ui32_t sample, ui32_t taps, float *ws) {
int f32buf_sample(dsp_t *dsp, int inv) {
float s = 0.0;
float s_fm = s;
float xneu, xalt;
float complex z, w, z0;
@ -604,25 +665,41 @@ int f32buf_sample(dsp_t *dsp, int inv) {
double t = dsp->sample_in / (double)dsp->sr;
if (dsp->opt_iq) {
if (dsp->opt_iq)
{
if (dsp->opt_iq == 5) {
ui32_t s_reset = dsp->dectaps*dsp->lut_len;
int j;
if ( f32read_cblock(dsp) < dsp->decM ) return EOF;
for (j = 0; j < dsp->decM; j++) {
dsp->decXbuffer[dsp->sample_dec % dsp->dectaps] = dsp->decMbuf[j] * dsp->ex[dsp->sample_dec % dsp->lut_len];
if (dsp->opt_nolut) {
double _s_base = (double)(dsp->sample_in*dsp->decM+j); // dsp->sample_dec
double f0 = dsp->xlt_fq*_s_base - dsp->Df*_s_base/(double)dsp->sr_base;
z = dsp->decMbuf[j] * cexp(f0*2*M_PI*I);
}
else {
z = dsp->decMbuf[j] * dsp->ex[dsp->sample_dec % dsp->lut_len];
}
dsp->decXbuffer[dsp->sample_dec % dsp->dectaps] = z;
dsp->sample_dec += 1;
if (dsp->sample_dec == s_reset) dsp->sample_dec = 0;
}
z = lowpass(dsp->decXbuffer, dsp->sample_dec, dsp->dectaps, ws_dec);
if (dsp->decM > 1)
{
z = lowpass(dsp->decXbuffer, dsp->sample_dec, dsp->dectaps, ws_dec);
}
}
else if ( f32read_csample(dsp, &z) == EOF ) return EOF;
z *= cexp(-t*2*M_PI*dsp->Df*I);
if (dsp->opt_dc && !dsp->opt_nolut)
{
z *= cexp(-t*2*M_PI*dsp->Df*I);
}
// IF-lowpass
if (dsp->opt_lp) {
if (dsp->opt_lp & LP_IQ) {
dsp->lpIQ_buf[dsp->sample_in % dsp->lpIQtaps] = z;
z = lowpass(dsp->lpIQ_buf, dsp->sample_in, dsp->lpIQtaps, dsp->ws_lpIQ);
}
@ -630,82 +707,88 @@ int f32buf_sample(dsp_t *dsp, int inv) {
z0 = dsp->rot_iqbuf[(dsp->sample_in-1 + dsp->N_IQBUF) % dsp->N_IQBUF];
w = z * conj(z0);
s = gain * carg(w)/M_PI;
s_fm = gain * carg(w)/M_PI;
dsp->rot_iqbuf[dsp->sample_in % dsp->N_IQBUF] = z;
// FM-lowpass
if (dsp->opt_lp) {
dsp->lpFM_buf[dsp->sample_in % dsp->lpFMtaps] = s;
s = re_lowpass(dsp->lpFM_buf, dsp->sample_in, dsp->lpFMtaps, dsp->ws_lpFM);
}
dsp->fm_buffer[(dsp->sample_in - dsp->lpFMtaps/2 + dsp->M) % dsp->M] = s;
if (dsp->opt_iq >= 2)
{
double xbit = 0.0;
//float complex xi = cexp(+I*M_PI*dsp->h/dsp->sps);
double f1 = -dsp->h*dsp->sr/(2*dsp->sps);
double f2 = -f1;
if (dsp->opt_iq >= 2) {
double xbit = 0.0;
//float complex xi = cexp(+I*M_PI*dsp->h/dsp->sps);
double f1 = -dsp->h*dsp->sr/(2.0*dsp->sps);
double f2 = -f1;
float complex X0 = 0;
float complex X = 0;
float complex X0 = 0;
float complex X = 0;
int n = dsp->sps;
double tn = (dsp->sample_in-n) / (double)dsp->sr;
//t = dsp->sample_in / (double)dsp->sr;
//z = dsp->rot_iqbuf[dsp->sample_in % dsp->N_IQBUF];
z0 = dsp->rot_iqbuf[(dsp->sample_in-n + dsp->N_IQBUF) % dsp->N_IQBUF];
int n = dsp->sps;
double tn = (dsp->sample_in-n) / (double)dsp->sr;
//t = dsp->sample_in / (double)dsp->sr;
//z = dsp->rot_iqbuf[dsp->sample_in % dsp->N_IQBUF];
z0 = dsp->rot_iqbuf[(dsp->sample_in-n + dsp->N_IQBUF) % dsp->N_IQBUF];
// f1
X0 = z0 * cexp(-tn*2*M_PI*f1*I); // alt
X = z * cexp(-t *2*M_PI*f1*I); // neu
dsp->F1sum += X - X0;
// f1
X0 = z0 * cexp(-tn*2*M_PI*f1*I); // alt
X = z * cexp(-t *2*M_PI*f1*I); // neu
dsp->F1sum += X - X0;
// f2
X0 = z0 * cexp(-tn*2*M_PI*f2*I); // alt
X = z * cexp(-t *2*M_PI*f2*I); // neu
dsp->F2sum += X - X0;
// f2
X0 = z0 * cexp(-tn*2*M_PI*f2*I); // alt
X = z * cexp(-t *2*M_PI*f2*I); // neu
dsp->F2sum += X - X0;
xbit = cabs(dsp->F2sum) - cabs(dsp->F1sum);
xbit = cabs(dsp->F2sum) - cabs(dsp->F1sum);
s = xbit / dsp->sps;
}
else if (0 && dsp->opt_iq >= 4)
{
double xbit = 0.0;
//float complex xi = cexp(+I*M_PI*dsp->h/dsp->sps);
double f1 = -dsp->h*dsp->sr/(2*dsp->sps);
double f2 = -f1;
float complex X1 = 0;
float complex X2 = 0;
int n = dsp->sps;
while (n > 0) {
n--;
t = -n / (double)dsp->sr;
z = dsp->rot_iqbuf[(dsp->sample_in - n + dsp->N_IQBUF) % dsp->N_IQBUF]; // +1
X1 += z*cexp(-t*2*M_PI*f1*I);
X2 += z*cexp(-t*2*M_PI*f2*I);
s = xbit / dsp->sps;
}
else if (0 && dsp->opt_iq == 4) {
double xbit = 0.0;
//float complex xi = cexp(+I*M_PI*dsp->h/dsp->sps);
double f1 = -dsp->h*dsp->sr/(2*dsp->sps);
double f2 = -f1;
xbit = cabs(X2) - cabs(X1);
float complex X1 = 0;
float complex X2 = 0;
s = xbit / dsp->sps;
int n = dsp->sps;
while (n > 0) {
n--;
t = -n / (double)dsp->sr;
z = dsp->rot_iqbuf[(dsp->sample_in - n + dsp->N_IQBUF) % dsp->N_IQBUF]; // +1
X1 += z*cexp(-t*2*M_PI*f1*I);
X2 += z*cexp(-t*2*M_PI*f2*I);
}
xbit = cabs(X2) - cabs(X1);
s = xbit / dsp->sps;
}
}
else {
s = s_fm;
}
}
else {
if (f32read_sample(dsp, &s) == EOF) return EOF;
s_fm = s;
}
// FM-lowpass
if (dsp->opt_lp & LP_FM) {
dsp->lpFM_buf[dsp->sample_in % dsp->lpFMtaps] = s_fm;
s_fm = re_lowpass(dsp->lpFM_buf, dsp->sample_in, dsp->lpFMtaps, dsp->ws_lpFM);
if (dsp->opt_iq < 2) s = s_fm;
}
dsp->fm_buffer[dsp->sample_in % dsp->M] = s_fm;
if (inv) s = -s;
dsp->bufs[dsp->sample_in % dsp->M] = s;
xneu = dsp->bufs[(dsp->sample_in ) % dsp->M];
xalt = dsp->bufs[(dsp->sample_in+dsp->M - dsp->Nvar) % dsp->M];
dsp->xsum += xneu - xalt; // + xneu - xalt
@ -728,20 +811,23 @@ static int read_bufbit(dsp_t *dsp, int symlen, char *bits, ui32_t mvp, int pos)
ui32_t rcount = ceil(rbitgrenze);//+0.99; // dfm?
double sum = 0.0;
double dc = 0.0;
if (dsp->opt_dc && dsp->opt_iq < 2) dc = dsp->dc;
// bei symlen=2 (Manchester) kein dc noetig: -dc+dc=0 ;
// allerdings M10-header mit symlen=1
rbitgrenze += dsp->sps;
do {
sum += dsp->bufs[(rcount + mvp + dsp->M) % dsp->M] - dsp->dc;
sum += dsp->bufs[(rcount + mvp + dsp->M) % dsp->M] - dc;
rcount++;
} while (rcount < rbitgrenze); // n < dsp->sps
if (symlen == 2) {
rbitgrenze += dsp->sps;
do {
sum -= dsp->bufs[(rcount + mvp + dsp->M) % dsp->M] - dsp->dc;
sum -= dsp->bufs[(rcount + mvp + dsp->M) % dsp->M] - dc;
rcount++;
} while (rcount < rbitgrenze); // n < dsp->sps
}
@ -767,7 +853,7 @@ static int headcmp(dsp_t *dsp, int opt_dc) {
int len = dsp->hdrlen/dsp->symhd;
int inv = dsp->mv < 0;
if (opt_dc == 0 || dsp->opt_iq > 1) dsp->dc = 0; // reset? e.g. 2nd pass
//if (opt_dc == 0 || dsp->opt_iq > 1) dsp->dc = 0;
if (dsp->symhd != 1) step = 2;
if (inv) sign=1;
@ -1067,6 +1153,7 @@ int init_buffers(dsp_t *dsp) {
float *m = NULL;
// decimate
if (dsp->opt_iq == 5)
{
int IF_sr = IF_SAMPLE_RATE; // designated IF sample rate
@ -1107,40 +1194,42 @@ int init_buffers(dsp_t *dsp) {
}
if (dsp->opt_iq == 5)
{
// look up table, exp-rotation
int W = 2*8; // 16 Hz window
int d = 1; // 1..W , groesster Teiler d <= W von sr_base
int freq = (int)( dsp->xlt_fq * (double)dsp->sr_base + 0.5);
int freq0 = freq; // init
double f0 = freq0 / (double)dsp->sr_base; // init
if (!dsp->opt_nolut)
{
// look up table, exp-rotation
int W = 2*8; // 16 Hz window
int d = 1; // 1..W , groesster Teiler d <= W von sr_base
int freq = (int)( dsp->xlt_fq * (double)dsp->sr_base + 0.5);
int freq0 = freq; // init
double f0 = freq0 / (double)dsp->sr_base; // init
for (d = W; d > 0; d--) { // groesster Teiler d <= W von sr
if (dsp->sr_base % d == 0) break;
}
if (d == 0) d = 1; // d >= 1 ?
for (k = 0; k < W/2; k++) {
if ((freq+k) % d == 0) {
freq0 = freq + k;
break;
for (d = W; d > 0; d--) { // groesster Teiler d <= W von sr
if (dsp->sr_base % d == 0) break;
}
if ((freq-k) % d == 0) {
freq0 = freq - k;
break;
if (d == 0) d = 1; // d >= 1 ?
for (k = 0; k < W/2; k++) {
if ((freq+k) % d == 0) {
freq0 = freq + k;
break;
}
if ((freq-k) % d == 0) {
freq0 = freq - k;
break;
}
}
dsp->lut_len = dsp->sr_base / d;
f0 = freq0 / (double)dsp->sr_base;
dsp->ex = calloc(dsp->lut_len+1, sizeof(float complex));
if (dsp->ex == NULL) return -1;
for (n = 0; n < dsp->lut_len; n++) {
t = f0*(double)n;
dsp->ex[n] = cexp(t*2*M_PI*I);
}
}
dsp->lut_len = dsp->sr_base / d;
f0 = freq0 / (double)dsp->sr_base;
dsp->ex = calloc(dsp->lut_len+1, sizeof(float complex));
if (dsp->ex == NULL) return -1;
for (n = 0; n < dsp->lut_len; n++) {
t = f0*(double)n;
dsp->ex[n] = cexp(t*2*M_PI*I);
}
dsp->decXbuffer = calloc( dsp->dectaps+1, sizeof(float complex));
if (dsp->decXbuffer == NULL) return -1;
@ -1148,13 +1237,13 @@ int init_buffers(dsp_t *dsp) {
if (dsp->decMbuf == NULL) return -1;
}
if (dsp->opt_iq && dsp->opt_lp)
// IF lowpass
if (dsp->opt_iq && (dsp->opt_lp & LP_IQ))
{
float f_lp; // lowpass_bw
int taps; // lowpass taps: 4*sr/transition_bw
// IF lowpass
f_lp = 24e3; // default
f_lp = 24e3/(float)dsp->sr/2.0; // default
if (dsp->lpIQ_bw) f_lp = dsp->lpIQ_bw/(float)dsp->sr/2.0;
taps = 4*dsp->sr/IF_TRANSITION_BW; if (taps%2==0) taps++;
taps = lowpass_init(1.5*f_lp, taps, &dsp->ws_lpIQ0); if (taps < 0) return -1;
@ -1175,10 +1264,15 @@ int init_buffers(dsp_t *dsp) {
}
// locked:
//taps = lowpass_update(dsp->lpIQ_fbw, dsp->lpIQtaps, dsp->ws_lpIQ); if (taps < 0) return -1;
}
// FM lowpass
if (dsp->opt_lp & LP_FM)
{
float f_lp; // lowpass_bw
int taps; // lowpass taps: 4*sr/transition_bw
// FM lowpass
f_lp = 10e3; // default
f_lp = 10e3/(float)dsp->sr; // default
if (dsp->lpFM_bw > 0) f_lp = dsp->lpFM_bw/(float)dsp->sr;
taps = 4*dsp->sr/FM_TRANSITION_BW; if (taps%2==0) taps++;
taps = lowpass_init(f_lp, taps, &dsp->ws_lpFM); if (taps < 0) return -1;
@ -1188,6 +1282,7 @@ int init_buffers(dsp_t *dsp) {
if (dsp->lpFM_buf == NULL) return -1;
}
memset(&IQdc, 0, sizeof(IQdc));
IQdc.maxlim = dsp->sr;
IQdc.maxcnt = IQdc.maxlim/32; // 32,16,8,4,2,1
@ -1333,18 +1428,23 @@ int free_buffers(dsp_t *dsp) {
{
if (dsp->decXbuffer) { free(dsp->decXbuffer); dsp->decXbuffer = NULL; }
if (dsp->decMbuf) { free(dsp->decMbuf); dsp->decMbuf = NULL; }
if (dsp->ex) { free(dsp->ex); dsp->ex = NULL; }
if (!dsp->opt_nolut) {
if (dsp->ex) { free(dsp->ex); dsp->ex = NULL; }
}
if (ws_dec) { free(ws_dec); ws_dec = NULL; }
}
// IF lowpass
if (dsp->opt_iq && dsp->opt_lp)
if (dsp->opt_iq && (dsp->opt_lp & LP_IQ))
{
if (dsp->ws_lpIQ0) { free(dsp->ws_lpIQ0); dsp->ws_lpIQ0 = NULL; }
if (dsp->ws_lpIQ1) { free(dsp->ws_lpIQ1); dsp->ws_lpIQ1 = NULL; }
if (dsp->lpIQ_buf) { free(dsp->lpIQ_buf); dsp->lpIQ_buf = NULL; }
}
// FM lowpass
if (dsp->opt_lp & LP_FM)
{
if (dsp->ws_lpFM) { free(dsp->ws_lpFM); dsp->ws_lpFM = NULL; }
if (dsp->lpFM_buf) { free(dsp->lpFM_buf); dsp->lpFM_buf = NULL; }
}
@ -1369,7 +1469,7 @@ int find_header(dsp_t *dsp, float thres, int hdmax, int bitofs, int opt_dc) {
k += 1;
if (k >= dsp->K-4) {
mvpos0 = dsp->mv_pos;
mp = getCorrDFT(dsp); // correlation score -> dsp->mv
mp = getCorrDFT(dsp, thres); // correlation score -> dsp->mv
//if (option_auto == 0 && dsp->mv < 0) mv = 0;
k = 0;
}
@ -1378,17 +1478,40 @@ int find_header(dsp_t *dsp, float thres, int hdmax, int bitofs, int opt_dc) {
continue;
}
if (dsp->mv > thres || dsp->mv < -thres) {
if (dsp->opt_dc) { // Problem: FM-gain
if (dsp->opt_iq < 2) dsp->Df += dsp->dDf*0.4;
else {
double ofs = fabs(dsp->dDf); // (iq-decode controls FM-gain)
if (ofs > 200.0)
if (dsp->mv > thres || dsp->mv < -thres)
{
if (dsp->opt_dc)
{
if (dsp->opt_iq) {
if (fabs(dsp->dDf) > 100.0)
{
dsp->Df += dsp->dDf * 2/3.0;
double diffDf = dsp->dDf*0.6; //0.4
if (1 && dsp->opt_iq >= 2) {
// update rot_iqbuf, F1sum, F2sum
double f1 = -dsp->h*dsp->sr/(2*dsp->sps);
double f2 = -f1;
float complex X1 = 0;
float complex X2 = 0;
float complex _z = 0;
int _n = dsp->sps;
while ( _n > 0 )
{
// update rot_iqbuf
double _tn = (dsp->sample_in - _n) / (double)dsp->sr;
dsp->rot_iqbuf[(dsp->sample_in - _n + dsp->N_IQBUF) % dsp->N_IQBUF] *= cexp(-_tn*2*M_PI*diffDf*I);
//
//update/reset F1sum, F2sum
_z = dsp->rot_iqbuf[(dsp->sample_in - _n + dsp->N_IQBUF) % dsp->N_IQBUF];
X1 += _z*cexp(-_tn*2*M_PI*f1*I);
X2 += _z*cexp(-_tn*2*M_PI*f2*I);
_n--;
}
dsp->F1sum = X1;
dsp->F2sum = X2;
}
dsp->Df += diffDf;
}
if (ofs > 1000.0) { //dsp->opt_lp
if (fabs(dsp->dDf) > 1e3) {
if (dsp->locked) {
dsp->locked = 0;
dsp->ws_lpIQ = dsp->ws_lpIQ0;

Wyświetl plik

@ -7,13 +7,20 @@
#define M_PI (3.1415926535897932384626433832795)
#endif
#define LP_IQ 1
#define LP_FM 2
#define LP_IQFM 4
#ifndef INTTYPES
#define INTTYPES
typedef unsigned char ui8_t;
typedef unsigned short ui16_t;
typedef unsigned int ui32_t;
typedef char i8_t;
typedef short i16_t;
typedef int i32_t;
#endif
typedef struct {
@ -58,6 +65,9 @@ typedef struct {
float mv;
ui32_t mv_pos;
//
float mv2;
ui32_t mv2_pos;
//
int N_norm;
int Nvar;
float xsum;
@ -91,6 +101,7 @@ typedef struct {
double dc;
double Df;
double dDf;
//
ui32_t sample_posframe;
ui32_t sample_posnoise;
@ -100,6 +111,7 @@ typedef struct {
double SNRdB;
// decimate
int opt_nolut; // default: LUT
int opt_IFmin;
int decM;
ui32_t sr_base;
@ -126,7 +138,7 @@ typedef struct {
int lpFMtaps; // ui32_t
float *ws_lpFM;
float *lpFM_buf;
float *fm_buffer;
float *fm_buffer;
} dsp_t;

Wyświetl plik

@ -92,6 +92,9 @@ static char rawheader[] = "10011001100110010100110010011001";
#define t_M20 0x20
typedef struct {
ui32_t gps_cnt;
ui8_t cnt;
ui8_t _diffcnt;
int week; int tow_ms; int gpssec;
int jahr; int monat; int tag;
int wday;
@ -99,9 +102,10 @@ typedef struct {
double lat; double lon; double alt;
double vH; double vD; double vV;
double vx; double vy; double vD2;
float T; float RH; float TH; float P;
ui8_t numSV;
ui8_t utc_ofs;
char SN[12];
char SN[12+4];
ui8_t SNraw[3];
ui8_t frame_bytes[FRAME_LEN+AUX_LEN+4];
char frame_bits[BITFRAME_LEN+BITAUX_LEN+8];
@ -181,9 +185,9 @@ frame[0x0] = framelen // (0x43,) 0x45
frame[0x1] = 0x20 (type M20)
frame[0x02..0x18]: most important data at beginning (incl. counter + M10check)
frame[0x02..0x03]: ADC
frame[0x04..0x05]: ADC
frame[0x06..0x07]: ADC temperature
frame[0x02..0x03]: ADC RH (incl.555)
frame[0x04..0x05]: ADC Temperatur , frame[0x46]: scale/range ?
frame[0x06..0x07]: ADC RH-Temperature range: 0:0..4095 , 1:4096..8191 , 2:8192..12287
frame[0x08..0x0A]: GPS altitude
frame[0x0B..0x0E]: GPS hor.Vel. (velE,velN)
frame[0x0F..0x11]: GPS TOW
@ -242,6 +246,7 @@ frame[0x44..0x45]: frame check
#define col_TXT "\x1b[38;5;244m"
#define col_FRTXT "\x1b[38;5;244m"
#define col_CSok "\x1b[38;5;2m"
#define col_CSoo "\x1b[38;5;220m"
#define col_CSno "\x1b[38;5;1m"
#define col_CNST "\x1b[38;5;58m" // 3 byte
@ -281,11 +286,12 @@ static int get_GPSweek(gpx_t *gpx) {
static char weekday[7][4] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
static int get_GPStime(gpx_t *gpx) {
int i;
int i, ret = 0;
unsigned byte;
ui8_t gpstime_bytes[4];
int gpstime, day;
int ms;
double sec_gps0 = 0.0;
for (i = 0; i < 3; i++) {
byte = gpx->frame_bytes[pos_GPSTOW + i];
@ -312,6 +318,15 @@ static int get_GPStime(gpx_t *gpx) {
gpx->min = (gpstime%3600)/60;
gpx->sek = gpstime%60 + ms/1000.0;
ret = get_GPSweek(gpx);
if (ret) return ret;
sec_gps0 = (double)gpx->week*SECONDS_IN_WEEK + gpx->tow_ms/1e3;
gpx->gps_cnt = (ui32_t)(sec_gps0+0.5);
gpx->cnt = gpx->frame_bytes[pos_CNT];
gpx->_diffcnt = (ui8_t)(gpx->gps_cnt - gpx->cnt);
return 0;
}
@ -435,18 +450,29 @@ static int get_SN(gpx_t *gpx) {
ui8_t ym = b0 & 0x7F; // #{0x0,..,0x77}=120=10*12
ui8_t y = ym / 12;
ui8_t m = (ym % 12)+1; // there is b0=0x69<0x80 from 2018-09-19 ...
ui32_t sn_val = 0;
for (i = 0; i < 11; i++) gpx->SN[i] = ' '; gpx->SN[11] = '\0';
for (i = 0; i < 11; i++) gpx->SN[i] = ' '; gpx->SN[11] = '\0';
for (i = 12; i < 15; i++) gpx->SN[i] = '\0'; gpx->SN[15] = '\0';
for (i = 0; i < 3; i++) {
gpx->SNraw[i] = gpx->frame_bytes[pos_SN + i];
}
sn_val = (gpx->SNraw[0]<<16) | (gpx->SNraw[1]<<8) | gpx->SNraw[2];
sprintf(gpx->SN, "%u%02u", y, m); // more samples needed
sprintf(gpx->SN+3, " %u ", (s2&0x3)+2); // (b0>>7)+1? (s2&0x3)+2?
sprintf(gpx->SN+3, "-%u-", (s2&0x3)+2); // (b0>>7)+1? (s2&0x3)+2?
sprintf(gpx->SN+6, "%u", (s2>>(2+13))&0x1); // ?(s2>>(2+13))&0x1 ?? (s2&0x3)?
sprintf(gpx->SN+7, "%04u", (s2>>2)&0x1FFF);
if (sn_val == 0)
{ // get_GPStime(gpx);
// replace SN: 001-2-00000 -> 000-0-00000-[_diffcnt]
sprintf(gpx->SN, "%s", "000-0-00000");
sprintf(gpx->SN+11, "-%03u", gpx->_diffcnt & 0xFF);
}
return 0;
}
@ -527,13 +553,83 @@ static int blk_checkM10(int len, ui8_t *msg) {
/* -------------------------------------------------------------------------- */
static float get_Tntc0(gpx_t *gpx) {
// SMD ntc
static float get_Temp(gpx_t *gpx) {
// NTC-Thermistor Shibaura PB5-41E ?
// T00 = 273.15 + 0.0 , R00 = 15e3
// T25 = 273.15 + 25.0 , R25 = 5.369e3
// B00 = 3450.0 Kelvin // 0C..100C, poor fit low temps
// [ T/C , R/1e3 ] ( [P__-43]/2.0 ):
// [ -50.0 , 204.0 ]
// [ -45.0 , 150.7 ]
// [ -40.0 , 112.6 ]
// [ -35.0 , 84.90 ]
// [ -30.0 , 64.65 ]
// [ -25.0 , 49.66 ]
// [ -20.0 , 38.48 ]
// [ -15.0 , 30.06 ]
// [ -10.0 , 23.67 ]
// [ -5.0 , 18.78 ]
// [ 0.0 , 15.00 ]
// [ 5.0 , 12.06 ]
// [ 10.0 , 9.765 ]
// [ 15.0 , 7.955 ]
// [ 20.0 , 6.515 ]
// [ 25.0 , 5.370 ]
// [ 30.0 , 4.448 ]
// [ 35.0 , 3.704 ]
// [ 40.0 , 3.100 ]
// -> Steinhart-Hart coefficients (polyfit):
float p0 = 1.07303516e-03,
p1 = 2.41296733e-04,
p2 = 2.26744154e-06,
p3 = 6.52855181e-08;
// T/K = 1/( p0 + p1*ln(R) + p2*ln(R)^2 + p3*ln(R)^3 )
// range/scale 0, 1, 2: // M10-pcb
float Rs[3] = { 12.1e3 , 36.5e3 , 475.0e3 }; // bias/series
float Rp[3] = { 1e20 , 330.0e3 , 2000.0e3 }; // parallel, Rp[0]=inf
ui8_t scT = 0; // {0,1,2}, range/scale voltage divider
ui16_t ADC_RT; // ADC12
//ui16_t Tcal[2];
float x, R;
float T = 0; // T/Kelvin
ADC_RT = (gpx->frame_bytes[0x5] << 8) | gpx->frame_bytes[0x4];
//ui8_t sc = gpx->frame_bytes[0x32] & 3; // (frame[0x32]<<8)|frame[0x31]
// frame[0x31..0x32], frame[0x32]: 0x9=0b1001:0, 0xA=0b1010:1, 0x8=0b1000:2
// ? Temp-Calibration depending on range ?
//
// range: 0:0..4095 , 1:4096..8191 , 2:8192..12287
/*
if (sc == 0x1) { scT = 0; }
else if (sc == 0x2) { scT = 1; ADC_RT -= 4096; }
else if (sc == 0x0) { scT = 2; ADC_RT -= 8192; }
else: // sc == 0x3 // test only range below:
*/
// range, i.e. (ADC_RT>>12)&3
if (ADC_RT > 8191) { scT = 2; ADC_RT -= 8192; }
else if (ADC_RT > 4095) { scT = 1; ADC_RT -= 4096; }
else { scT = 0; } // also if (ADC_RT>>12)&3 == 3
// ADC12 , 4096 = 1<<12, max: 4095
x = (4095.0-ADC_RT)/ADC_RT; // (Vcc-Vout)/Vout = Vcc/Vout - 1
R = Rs[scT] /( x - Rs[scT]/Rp[scT] );
if (R > 0) T = 1/( p0 + p1*log(R) + p2*log(R)*log(R) + p3*log(R)*log(R)*log(R) );
return T - 273.15; // Celsius
}
static float get_Tntc2(gpx_t *gpx) {
// SMD ntc , RH-Temperature
float Rs = 22.1e3; // P5.6=Vcc
float R25 = 2.2e3;// 0.119e3; //2.2e3;
float b = 3650.0; // B/Kelvin
float T25 = 25.0 + 273.15; // T0=25C, R0=R25=5k
// -> Steinhart–Hart coefficients (polyfit):
float R25 = 2.2e3;// 0.119e3; //2.2e3;
float b = 3650.0; // B/Kelvin
float T25 = 25.0 + 273.15; // T0=25C, R0=R25=5k
// -> Steinhart-Hart coefficients (polyfit):
float p0 = 4.42606809e-03,
p1 = -6.58184309e-04,
p2 = 8.95735557e-05,
@ -551,6 +647,67 @@ static float get_Tntc0(gpx_t *gpx) {
return T - 273.15;
}
static float get_RHraw(gpx_t *gpx) {
float _rh = -1.0;
float _RH = -1.0;
ui16_t ADC_rh;
ADC_rh = (gpx->frame_bytes[0x03] << 8) | gpx->frame_bytes[0x02];
_rh = ADC_rh / (float)(1<<15);
_RH = -1.0;
if (_rh < 1.05) _RH = _rh*100.0;
// Transfer function ?
// Calibration ?
// (Hyland and Wexler) Tntc2 (T_RH) <-> Tmain ?
return _RH;
}
static float get_RH(gpx_t *gpx) {
// from DF9DQ,
// https://github.com/einergehtnochrein/ra-firmware
//
float TU = get_Tntc2(gpx);
float RH = -1.0f;
float x;
ui16_t humval = (gpx->frame_bytes[0x03] << 8) | gpx->frame_bytes[0x02];
ui16_t rh_cal = (gpx->frame_bytes[0x30] << 8) | gpx->frame_bytes[0x2F];
float humidityCalibration = 6.4e8f / (rh_cal + 80000.0f);
x = (humval + 80000.0f) * humidityCalibration * (1.0f - 5.8e-4f * (TU-25.0f));
x = 4.16e9f / x;
x = 10.087f*x*x*x - 211.62f*x*x + 1388.2f*x - 2797.0f;
RH = -1.0f;
if (humval < 48000)
{
RH = x;
if (RH < 0.0f ) RH = 0.0f;
if (RH > 100.0f) RH = 100.0f;
}
// (Hyland and Wexler) Tntc2 (T_RH) <-> Tmain ?
return RH;
}
static float get_P(gpx_t *gpx) {
// cf. DF9DQ
//
float hPa = 0.0f;
ui16_t val = (gpx->frame_bytes[0x25] << 8) | gpx->frame_bytes[0x24];
if (val > 0) {
hPa = val/16.0f;
}
return hPa;
}
/* -------------------------------------------------------------------------- */
static int print_pos(gpx_t *gpx, int bcOK, int csOK) {
@ -559,8 +716,7 @@ static int print_pos(gpx_t *gpx, int bcOK, int csOK) {
if (1 || gpx->type == t_M20)
{
err = 0;
err |= get_GPSweek(gpx);
err |= get_GPStime(gpx);
err |= get_GPStime(gpx); // incl. get_GPSweek(gpx)
err |= get_GPSlat(gpx);
err |= get_GPSlon(gpx);
err |= get_GPSalt(gpx);
@ -573,6 +729,12 @@ static int print_pos(gpx_t *gpx, int bcOK, int csOK) {
Gps2Date(gpx->week, gpx->gpssec, &gpx->jahr, &gpx->monat, &gpx->tag);
get_SN(gpx);
if (gpx->option.ptu && csOK) {
gpx->T = get_Temp(gpx); // temperature
gpx->TH = get_Tntc2(gpx); // rel. humidity sensor temperature
gpx->RH = get_RH(gpx); // relative humidity
gpx->P = get_P(gpx); // (optional) pressure
}
if ( !gpx->option.slt )
{
@ -596,15 +758,21 @@ static int print_pos(gpx_t *gpx, int bcOK, int csOK) {
}
if (gpx->option.vbs >= 2) {
fprintf(stdout, " # ");
if (bcOK) fprintf(stdout, " "col_CSok"(ok)"col_TXT);
else fprintf(stdout, " "col_CSno"(no)"col_TXT);
if (bcOK > 0) fprintf(stdout, " "col_CSok"(ok)"col_TXT);
else if (bcOK < 0) fprintf(stdout, " "col_CSoo"(oo)"col_TXT);
else fprintf(stdout, " "col_CSno"(no)"col_TXT);
//
if (csOK) fprintf(stdout, " "col_CSok"[OK]"col_TXT);
else fprintf(stdout, " "col_CSno"[NO]"col_TXT);
}
if (gpx->option.ptu && csOK) {
if (gpx->option.vbs >= 3) {
float t0 = get_Tntc0(gpx);
if (t0 > -270.0) fprintf(stdout, " (T0:%.1fC) ", t0);
fprintf(stdout, " ");
if (gpx->T > -273.0f) fprintf(stdout, " T:%.1fC", gpx->T);
if (gpx->RH > -0.5f) fprintf(stdout, " RH=%.0f%%", gpx->RH);
if (gpx->TH > -273.0f) fprintf(stdout, " TH:%.1fC", gpx->TH);
if (gpx->P > 0.0f) {
if (gpx->P < 100.0f) fprintf(stdout, " P=%.2fhPa ", gpx->P);
else fprintf(stdout, " P=%.1fhPa ", gpx->P);
}
}
fprintf(stdout, ANSI_COLOR_RESET"");
@ -628,13 +796,21 @@ static int print_pos(gpx_t *gpx, int bcOK, int csOK) {
}
if (gpx->option.vbs >= 2) {
fprintf(stdout, " # ");
if (bcOK) fprintf(stdout, " (ok)"); else fprintf(stdout, " (no)");
//if (bcOK) fprintf(stdout, " (ok)"); else fprintf(stdout, " (no)");
if (bcOK > 0) fprintf(stdout, " (ok)");
else if (bcOK < 0) fprintf(stdout, " (oo)");
else fprintf(stdout, " (no)");
//
if (csOK) fprintf(stdout, " [OK]"); else fprintf(stdout, " [NO]");
}
if (gpx->option.ptu && csOK) {
if (gpx->option.vbs >= 3) {
float t0 = get_Tntc0(gpx);
if (t0 > -270.0) fprintf(stdout, " (T0:%.1fC) ", t0);
fprintf(stdout, " ");
if (gpx->T > -273.0f) fprintf(stdout, " T:%.1fC", gpx->T);
if (gpx->RH > -0.5f) fprintf(stdout, " RH=%.0f%%", gpx->RH);
if (gpx->TH > -273.0f) fprintf(stdout, " TH:%.1fC", gpx->TH);
if (gpx->P > 0.0f) {
if (gpx->P < 100.0f) fprintf(stdout, " P=%.2fhPa ", gpx->P);
else fprintf(stdout, " P=%.1fhPa ", gpx->P);
}
}
}
@ -647,17 +823,20 @@ static int print_pos(gpx_t *gpx, int bcOK, int csOK) {
if (csOK) {
char *ver_jsn = NULL;
int j;
char sn_id[4+12] = "M20-";
double sec_gps0 = (double)gpx->week*SECONDS_IN_WEEK + gpx->tow_ms/1e3;
char sn_id[4+12+4] = "M20-";
strncpy(sn_id+4, gpx->SN, 12);
sn_id[15] = '\0';
for (j = 0; sn_id[j]; j++) { if (sn_id[j] == ' ') sn_id[j] = '-'; }
strncpy(sn_id+4, gpx->SN, 12+4);
sn_id[15+4] = '\0';
fprintf(stdout, "{ \"type\": \"%s\"", "M20");
fprintf(stdout, ", \"frame\": %lu, ", (unsigned long)(sec_gps0+0.5));
fprintf(stdout, ", \"frame\": %lu, ", (unsigned long)gpx->gps_cnt); // sec_gps0+0.5
fprintf(stdout, "\"id\": \"%s\", \"datetime\": \"%04d-%02d-%02dT%02d:%02d:%06.3fZ\", \"lat\": %.5f, \"lon\": %.5f, \"alt\": %.5f, \"vel_h\": %.5f, \"heading\": %.5f, \"vel_v\": %.5f",
sn_id, gpx->jahr, gpx->monat, gpx->tag, gpx->std, gpx->min, gpx->sek, gpx->lat, gpx->lon, gpx->alt, gpx->vH, gpx->vD, gpx->vV);
if (gpx->option.ptu) { // temperature
if (gpx->T > -273.0f) fprintf(stdout, ", \"temp\": %.1f", gpx->T );
if (gpx->RH > -0.5f) fprintf(stdout, ", \"humidity\": %.1f", gpx->RH );
if (gpx->P > 0.0f) fprintf(stdout, ", \"pressure\": %.2f", gpx->P );
}
fprintf(stdout, ", \"rawid\": \"M20_%02X%02X%02X\"", gpx->frame_bytes[pos_SN], gpx->frame_bytes[pos_SN+1], gpx->frame_bytes[pos_SN+2]); // gpx->type
fprintf(stdout, ", \"subtype\": \"0x%02X\"", gpx->type);
if (gpx->jsn_freq > 0) {
@ -681,7 +860,7 @@ static int print_frame(gpx_t *gpx, int pos, int b2B) {
int i;
ui8_t byte;
int cs1, cs2;
int bc1, bc2;
int bc1, bc2, bc;
int flen = stdFLEN; // stdFLEN=0x64, auxFLEN=0x76; M20:0x45 ?
if (b2B) {
@ -699,6 +878,9 @@ static int print_frame(gpx_t *gpx, int pos, int b2B) {
bc1 = (gpx->frame_bytes[pos_BlkChk] << 8) | gpx->frame_bytes[pos_BlkChk+1];
bc2 = blk_checkM10(len_BlkChk, gpx->frame_bytes+2); // len(essentialBlock+chk16) = 0x16
if (bc1 == bc2) bc = 1;
else if (bc1 == 0) bc = -1;
else bc = 0;
switch (gpx->frame_bytes[1]) {
case 0x8F: gpx->type = t_M2K2; break;
@ -732,8 +914,9 @@ static int print_frame(gpx_t *gpx, int pos, int b2B) {
}
if (gpx->option.vbs) {
fprintf(stdout, " # "col_Check"%04x"col_FRTXT, cs2);
if (bc1 == bc2) fprintf(stdout, " "col_CSok"(ok)"col_TXT);
else fprintf(stdout, " "col_CSno"(no)"col_TXT);
if (bc > 0) fprintf(stdout, " "col_CSok"(ok)"col_TXT);
else if (bc < 0) fprintf(stdout, " "col_CSoo"(oo)"col_TXT);
else fprintf(stdout, " "col_CSno"(no)"col_TXT);
if (cs1 == cs2) fprintf(stdout, " "col_CSok"[OK]"col_TXT);
else fprintf(stdout, " "col_CSno"[NO]"col_TXT);
}
@ -746,13 +929,15 @@ static int print_frame(gpx_t *gpx, int pos, int b2B) {
}
if (gpx->option.vbs) {
fprintf(stdout, " # %04x", cs2);
if (bc1 == bc2) fprintf(stdout, " (ok)"); else fprintf(stdout, " (no)");
if (bc > 0) fprintf(stdout, " (ok)");
else if (bc < 0) fprintf(stdout, " (oo)");
else fprintf(stdout, " (no)");
if (cs1 == cs2) fprintf(stdout, " [OK]"); else fprintf(stdout, " [NO]");
}
fprintf(stdout, "\n");
}
if (gpx->option.slt /*&& gpx->option.jsn*/) {
print_pos(gpx, bc1 == bc2, cs1 == cs2);
print_pos(gpx, bc, cs1 == cs2);
}
}
/*
@ -766,7 +951,7 @@ static int print_frame(gpx_t *gpx, int pos, int b2B) {
}
}
*/
else print_pos(gpx, bc1 == bc2, cs1 == cs2);
else print_pos(gpx, bc, cs1 == cs2);
return (gpx->frame_bytes[0]<<8)|gpx->frame_bytes[1];
}
@ -782,6 +967,7 @@ int main(int argc, char **argv) {
int option_iqdc = 0;
int option_lp = 0;
int option_dc = 0;
int option_noLUT = 0;
int option_softin = 0;
int option_pcmraw = 0;
int wavloaded = 0;
@ -810,6 +996,8 @@ int main(int argc, char **argv) {
float thres = 0.76;
float _mv = 0.0;
float lpIQ_bw = 24e3;
int symlen = 2;
int bitofs = 0; // 0 .. +2
int shift = 0;
@ -901,8 +1089,18 @@ int main(int argc, char **argv) {
dsp.xlt_fq = -fq; // S(t) -> S(t)*exp(-f*2pi*I*t)
option_iq = 5;
}
else if (strcmp(*argv, "--lp") == 0) { option_lp = 1; } // IQ lowpass
else if (strcmp(*argv, "--lpIQ") == 0) { option_lp |= LP_IQ; } // IQ/IF lowpass
else if (strcmp(*argv, "--lpbw") == 0) { // IQ lowpass BW / kHz
double bw = 0.0;
++argv;
if (*argv) bw = atof(*argv);
else return -1;
if (bw > 4.6 && bw < 48.0) lpIQ_bw = bw*1e3;
option_lp |= LP_IQ;
}
else if (strcmp(*argv, "--lpFM") == 0) { option_lp |= LP_FM; } // FM lowpass
else if (strcmp(*argv, "--dc") == 0) { option_dc = 1; }
else if (strcmp(*argv, "--noLUT") == 0) { option_noLUT = 1; }
else if (strcmp(*argv, "--min") == 0) {
option_min = 1;
}
@ -943,6 +1141,13 @@ int main(int argc, char **argv) {
}
if (!wavloaded) fp = stdin;
if (option_iq == 5 && option_dc) option_lp |= LP_FM;
// LUT faster for decM, however frequency correction after decimation
// LUT recommonded if decM > 2
//
if (option_noLUT && option_iq == 5) dsp.opt_nolut = 1; else dsp.opt_nolut = 0;
if (gpx.option.raw && gpx.option.jsn) gpx.option.slt = 1;
@ -1003,7 +1208,7 @@ int main(int argc, char **argv) {
dsp.opt_iq = option_iq;
dsp.opt_iqdc = option_iqdc;
dsp.opt_lp = option_lp;
dsp.lpIQ_bw = 24e3; // IF lowpass bandwidth
dsp.lpIQ_bw = lpIQ_bw; //24e3; // IF lowpass bandwidth
dsp.lpFM_bw = 10e3; // FM audio lowpass
dsp.opt_dc = option_dc;
dsp.opt_IFmin = option_min;