Initial meisei IMS-100 support.

pull/206/head
Mark Jessop 2019-09-08 18:16:18 +09:30
rodzic df181346f9
commit d56ab1805c
14 zmienionych plików z 3927 dodań i 137 usunięć

Wyświetl plik

@ -451,8 +451,12 @@ def telemetry_filter(telemetry):
# Regex to check DFM06/09/15/17 callsigns. Also catches the 'unknown' types (xC, xD, etc)
dfm_callsign_valid = re.match(r'DFM[01x][5679CD]-\d{6}', _serial)
# Check Meisei sonde callsigns for validity.
# meisei_ims returns a callsign of IMS100-0 until it receives the serial number, so we filter based on the 0 being present or not.
meisei_callsign_valid = int(_serial.split('-')[1]) != 0
# 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']):
if vaisala_callsign_valid or dfm_callsign_valid or meisei_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.3"
__version__ = "1.1.4-beta1"
# Global Variables

Wyświetl plik

@ -82,6 +82,15 @@ def telemetry_to_aprs_position(sonde_data, object_name="<id>", aprs_comment="BOM
_id_hex = hex(_id_suffix).upper()
_object_name = "LMS6" + _id_hex[-5:]
elif 'MEISEI' in sonde_data['type']:
# Convert the serial number to an int
_meisei_id = int(sonde_data['id'].split('-')[-1])
_id_suffix = hex(_meisei_id).upper().split('0X')[1]
# Clip to 6 hex digits, in case we end up with more for some reason.
if len(_id_suffix) > 6:
_id_suffix = _id_suffix[-6:]
_object_name = "IMS" + _id_suffix
# New Sonde types will be added in here.
else:
# Unknown sonde type, don't know how to handle this yet.

Wyświetl plik

@ -263,7 +263,7 @@ def read_auto_rx_config(filename, no_sdr_test=False):
# 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': True, 'MK2LMS': False}
auto_rx_config['experimental_decoders'] = {'RS41': False, 'RS92': False, 'DFM': False, 'M10': False, 'iMet': False, 'LMS6': True, 'MK2LMS': False, 'MEISEI': 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')

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', 'LMS6']
VALID_SONDE_TYPES = ['RS92', 'RS41', 'DFM', 'M10', 'iMet', 'MK2LMS', 'LMS6', 'MEISEI']
# Known 'Drifty' Radiosonde types
# NOTE: Due to observed adjacent channel detections of RS41s, the adjacent channel decoder restriction
@ -68,7 +68,8 @@ class SondeDecoder(object):
'heading' : 0.0
}
VALID_SONDE_TYPES = ['RS92', 'RS41', 'DFM', 'M10', 'iMet', 'MK2LMS', 'LMS6']
# TODO: Use the global valid sonde type list.
VALID_SONDE_TYPES = ['RS92', 'RS41', 'DFM', 'M10', 'iMet', 'MK2LMS', 'LMS6', 'MEISEI']
def __init__(self,
sonde_type="None",
@ -395,6 +396,20 @@ class SondeDecoder(object):
decode_cmd += "./lms6mod --json 2>/dev/null"
elif self.sonde_type == "MEISEI":
# Meisei IMS-100 Sondes
# Starting out with a 15 kHz bandwidth filter.
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)
decode_cmd += "sox -t raw -r 15k -e s -b 16 -c 1 - -r 48000 -b 8 -t wav - highpass 20 2>/dev/null |"
# 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)
# Meisei IMS-100 decoder
decode_cmd += "./meisei_ims --json 2>/dev/null"
else:
return None
@ -562,6 +577,7 @@ class SondeDecoder(object):
elif self.sonde_type == "iMet":
# iMet-4 Sondes
# These are AFSK and hence cannot be decoded using fsk_demod.
# Note: This block can probably be removed, as we should never be trying to start up an experimental demod for this sonde type.
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)
decode_cmd += "sox -t raw -r 15k -e s -b 16 -c 1 - -r 48000 -b 8 -t wav - highpass 20 2>/dev/null |"

Wyświetl plik

@ -281,17 +281,6 @@ def detect_sonde(frequency, rs_path="./", dwell_time=10, sdr_fm='rtl_fm', device
# dft_detect return codes:
# 2 = DFM
# 3 = RS41
# 4 = RS92
# 5 = M10
# 6 = IMET (AB)
# 7 = IMET (RS)
# 8 = LMS6
# 9 = C34/C50
# 10 = MK2LMS (1680 MHz LMS6, which uses the MK2A telemetry format)
# Split the line into sonde type and correlation score.
_fields = ret_output.split(':')
@ -333,6 +322,13 @@ def detect_sonde(frequency, rs_path="./", dwell_time=10, sdr_fm='rtl_fm', device
return '-MK2LMS'
else:
return 'MK2LMS'
elif 'MEISEI' in _type:
logging.debug("Scanner #%s - Detected a Meisei Sonde! (Score: %.2f)" % (str(device_idx), _score))
# Not currently sure if we expect to see inverted Meisei sondes.
if _score < 0:
return '-MEISEI'
else:
return 'MEISEI'
else:
return None

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', 'lms6mod']
REQUIRED_RS_UTILS = ['dft_detect', 'dfm09mod', 'm10', 'imet1rs_dft', 'rs41mod', 'rs92mod', 'fsk_demod', 'mk2a_lms1680', 'lms6mod', 'meisei_ims']
def check_rs_utils():
""" Check the required RS decoder binaries exist

Wyświetl plik

@ -40,6 +40,10 @@ echo "Building iMet Demodulator."
cd ../imet/
gcc imet1rs_dft.c -lm -o imet1rs_dft
echo "Building Meisei Demodulator."
cd ../meisei/
gcc meisei_ims.c -lm -o meisei_ims
echo "Building fsk-demod utils from codec2"
cd ../utils/
# This produces a static build of fsk_demod
@ -58,6 +62,7 @@ cp ../demod/dfm09ecc .
cp ../m10/m10 .
cp ../utils/fsk_demod .
cp ../imet/imet1rs_dft .
cp ../meisei/meisei_ims .
cp ../mk2a/mk2a_lms1680 .
cp ../demod/mod/rs41mod .

1018
meisei/bch_ecc.c 100644

Plik diff jest za duży Load Diff

Wyświetl plik

@ -0,0 +1,82 @@
Meisei-Radiosonden
RS-06G, RS-11G, iMS-100
PCM-FM, 1200 baud biphase-S
Die 1200 bit pro Sekunde bestehen aus zwei Frames, die wiederum in zwei Subframes unterteilt werden koennen, d.h. 4 mal 300 bit.
Einige Wetterdaten werden zweimal pro Sekunde gesendet, Telemetrie einmal pro Sekunde.
Es gibt zwei 600=300+300 bit Frames pro Sekunde mit einen 23+1 bit Header 0x049DCE gefolgt von einem Frame-Counter.
Die zweiten 300 bit werden wiederum mit dem Header 0xFB6230 eingeleitet, der bis auf das letzte bit das Komplement des anderen Headers ist,
d.h. 0x049DCE xor 0xFB6230 = 0xFFFFFE.
Nach jedem Header folgen 6 Bloecke zu je 46 bit, also 24+6*46=300.
Die 46bit-Bloecke sind BCH-Codewoerter. Es handelt sich um einen (63,51)-Code mit Generatorpolynom
g(x)=x^12+x^10+x^8+x^5+x^4+x^3+1=(x^6+x^4+x^2+x+1)(x^6+x+1).
gekuerzt auf (46,34), die letzten 12 bit sind die BCH-Kontrollbits.
Die 34 Nachrichtenbits sind aufgeteilt in 16+1+16+1, d.h. nach einem 16 bit Block kommt ein Paritaetsbit,
das 1 ist, wenn die Anzahl 1en in den 16 bit davor gerade ist, und sonst 0.
Fuer Datenanordnung und Inhalt gibt es mindestens zwei Version je nach Sondentyp.
GPS z.B. ist bei dem einen Typ jeweils 32bit Integer mit Faktor 1e7 bzw. Hoehe Faktor 1e2;
beim zweiten Typ hat die Hoehe nur 24 bit auch mit 1e2, und Lon und Lat mit Faktor 1e6, wobei die Nachkommastellen Minuten sind,
also wie bei NMEA mit Faktor 1e4.
Variante 1 (RS-11G ?)
049DCE1C667FDD8F537C8100004F20764630A20000000010040436 FB623080801F395FFE08A76540000FE01D0C2C1E75025006DE0A07
049DCE1C67008C73D7168200004F0F764B31A2FFFF000010270B14 FB6230000000000000000000000000000000000000000000001D59
0x00..0x02 HEADER 0x049DCE
0x03..0x04 16 bit 0.5s-counter, count%2=0:
0x1B..0x1D HEADER 0xFB6230
0x20..0x23 32 bit GPS-lat * 1e7 (DD.dddddd)
0x24..0x27 32 bit GPS-lon * 1e7 (DD.dddddd)
0x28..0x2B 32 bit GPS-alt * 1e2 (m)
0x2C..0x2D 16 bit GPS-vH * 1e2 (m/s)
0x2E..0x2F 16 bit GPS-vD * 1e2 (degree) (0..360 unsigned)
0x30..0x31 16 bit GPS-vU * 1e2 (m/s)
0x32..0x35 32 bit date jjJJMMTT
0x00..0x02 HEADER 0x049DCE
0x03..0x04 16 bit 0.5s-counter, count%2=1:
0x17..0x18 16 bit time ms xxyy, 00.000-59.000
0x19..0x1A 16 bit time hh:mm
0x1B..0x1D HEADER 0xFB6230
Variante 2 (iMS-100 ?)
049DCE3E228023DBF53FA700003C74628430C100000000ABE00B3B FB62302390031EECCC00E656E42327562B2436C4C01CDB0F18B09A
049DCE3E23516AF62B3FC700003C7390D131C100000000AB090000 FB62300000000000032423222422202014211B13220000000067C4
0x00..0x02 HEADER 0x049DCE
0x03..0x04 16 bit 0.5s-counter, count%2=0:
0x07..0x0A 32 bit cfg[cnt%64] (float32); cfg[0,16,32,48]=SN
0x11..0x12 30xx, xx=C1(ims100?),A2(rs11?)
0x17..0x18 16 bit time ms yyxx, 00.000-59.000
0x19..0x1A 16 bit time hh:mm
0x1B..0x1D HEADER 0xFB6230
0x1E..0x1F 16 bit ? date (TT,MM,JJ)=(date/1000,(date/10)%100,(date%10)+10)
0x20..0x23 32 bit GPS-lat * 1e4 (NMEA DDMM.mmmm)
0x24..0x27 32 bit GPS-lon * 1e4 (NMEA DDMM.mmmm)
0x28..0x2A 24 bit GPS-alt * 1e2 (m)
0x30..0x31 16 bit GPS-vD * 1e2 (degree)
0x32..0x33 16 bit GPS-vH * 1.944e2 (knots)
0x00..0x02 HEADER 0x049DCE
0x03..0x04 16 bit 0.5s-counter, count%2=1:
0x07..0x0A 32 bit cfg[cnt%64] (float32); freq=400e3+cfg[15]*1e2/kHz
0x11..0x12 31xx, xx=C1(ims100?),A2(rs11?)
0x17..0x18 16 bit 1024-counter yyxx, +0x400=1024; rollover synchron zu ms-counter, nach rollover auch +0x300=768
0x1B..0x1D HEADER 0xFB6230
0x22..0x23 yy00..yy03 (yy00: GPS PRN?)

782
meisei/meisei_ecc.c 100644
Wyświetl plik

@ -0,0 +1,782 @@
/*
* big endian forest
*
* Meisei radiosondes
* author: zilog80
*
*/
/*
PCM-FM, 1200 baud biphase-S
1200 bit pro Sekunde: zwei Frames, die wiederum in zwei Subframes unterteilt werden koennen, d.h. 4 mal 300 bit.
Variante 1 (RS-11G ?)
<option -1>
049DCE1C667FDD8F537C8100004F20764630A20000000010040436 FB623080801F395FFE08A76540000FE01D0C2C1E75025006DE0A07
049DCE1C67008C73D7168200004F0F764B31A2FFFF000010270B14 FB6230000000000000000000000000000000000000000000001D59
0x00..0x02 HEADER 0x049DCE
0x03..0x04 16 bit 0.5s-counter, count%2=0:
0x1B..0x1D HEADER 0xFB6230
0x20..0x23 32 bit GPS-lat * 1e7 (DD.dddddd)
0x24..0x27 32 bit GPS-lon * 1e7 (DD.dddddd)
0x28..0x2B 32 bit GPS-alt * 1e2 (m)
0x2C..0x2D 16 bit GPS-vH * 1e2 (m/s)
0x2E..0x2F 16 bit GPS-vD * 1e2 (degree) (0..360 unsigned)
0x30..0x31 16 bit GPS-vU * 1e2 (m/s)
0x32..0x35 32 bit date jjJJMMTT
0x00..0x02 HEADER 0x049DCE
0x03..0x04 16 bit 0.5s-counter, count%2=1:
0x17..0x18 16 bit time ms xxyy, 00.000-59.000
0x19..0x1A 16 bit time hh:mm
0x1B..0x1D HEADER 0xFB6230
0x049DCE ^ 0xFB6230 = 0xFFFFFE
Variante 2 (iMS-100 ?)
<option -2>
049DCE3E228023DBF53FA700003C74628430C100000000ABE00B3B FB62302390031EECCC00E656E42327562B2436C4C01CDB0F18B09A
049DCE3E23516AF62B3FC700003C7390D131C100000000AB090000 FB62300000000000032423222422202014211B13220000000067C4
0x00..0x02 HEADER 0x049DCE
0x03..0x04 16 bit 0.5s-counter, count%2=0:
0x17..0x18 16 bit time ms yyxx, 00.000-59.000
0x19..0x1A 16 bit time hh:mm
0x1B..0x1D HEADER 0xFB6230
0x1E..0x1F 16 bit ? date (TT,MM,JJ)=(date/1000,(date/10)%100,(date%10)+10)
0x20..0x23 32 bit GPS-lat * 1e4 (NMEA DDMM.mmmm)
0x24..0x27 32 bit GPS-lon * 1e4 (NMEA DDMM.mmmm)
0x28..0x2A 24 bit GPS-alt * 1e2 (m)
0x30..0x31 16 bit GPS-vD * 1e2 (degree)
0x32..0x33 16 bit GPS-vH * 1.944e2 (knots)
0x00..0x02 HEADER 0x049DCE
0x03..0x04 16 bit 0.5s-counter, count%2=1:
0x17..0x18 16 bit 1024-counter yyxx, +0x400=1024; rollover synchron zu ms-counter, nach rollover auch +0x300=768
0x1B..0x1D HEADER 0xFB6230
Die 46bit-Bloecke sind BCH-Codewoerter. Es handelt sich um einen (63,51)-Code mit Generatorpolynom
x^12+x^10+x^8+x^5+x^4+x^3+1;
gekuerzt auf (46,34), die letzten 12 bit sind die BCH-Kontrollbits.
Die 34 Nachrichtenbits sind aufgeteilt in 16+1+16+1, d.h. nach einem 16 bit Block kommt ein Paritaetsbit,
dass 1 ist, wenn die Anzahl 1en in den 16 bit davor gerade ist, und sonst 0.
*/
/*
2 "raw" symbols -> 1 biphase-symbol (bit): 2400 (raw) baud
ecc: option_b, exact symbol rate; if necessary, adjust --br <baud>
e.g.
./meisei_ecc -1 --ecc -v -b --br 2398 audio.wav
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// #include <math.h>
#ifdef CYGWIN
#include <fcntl.h> // cygwin: _setmode()
#include <io.h>
#endif
typedef unsigned char ui8_t;
typedef unsigned short ui16_t;
typedef unsigned int ui32_t;
typedef short i16_t;
typedef struct {
int jahr; int monat; int tag;
int std; int min; int sek;
double lat; double lon; double alt;
} datum_t;
datum_t datum;
int option_verbose = 0, // ausfuehrliche Anzeige
option_raw = 0, // rohe Frames
option_inv = 0, // invertiert Signal
option_res = 0, // genauere Bitmessung
option1 = 0,
option2 = 0,
option_b = 0,
option_ecc = 0, // BCH(63,51)
wavloaded = 0;
float baudrate = -1;
/* -------------------------------------------------------------------------- */
// Fehlerkorrektur (noch?) nicht sehr effektiv... (t zu klein)
#include "bch_ecc.c"
int errors;
ui8_t cw[63+1], // BCH(63,51), t=2
err_pos[4],
err_val[4];
ui8_t block_err[6];
int block, check_err;
/* -------------------------------------------------------------------------- */
#define BAUD_RATE 2400 // raw symbol rate; bit=biphase_symbol, bitrate=1200
int sample_rate = 0, bits_sample = 0, channels = 0;
float samples_per_bit = 0;
int findstr(char *buff, char *str, int pos) {
int i;
for (i = 0; i < 4; i++) {
if (buff[(pos+i)%4] != str[i]) break;
}
return i;
}
int read_wav_header(FILE *fp) {
char txt[4+1] = "\0\0\0\0";
unsigned char dat[4];
int byte, p=0;
if (fread(txt, 1, 4, fp) < 4) return -1;
if (strncmp(txt, "RIFF", 4)) return -1;
if (fread(txt, 1, 4, fp) < 4) return -1;
// pos_WAVE = 8L
if (fread(txt, 1, 4, fp) < 4) return -1;
if (strncmp(txt, "WAVE", 4)) return -1;
// pos_fmt = 12L
for ( ; ; ) {
if ( (byte=fgetc(fp)) == EOF ) return -1;
txt[p % 4] = byte;
p++; if (p==4) p=0;
if (findstr(txt, "fmt ", p) == 4) break;
}
if (fread(dat, 1, 4, fp) < 4) return -1;
if (fread(dat, 1, 2, fp) < 2) return -1;
if (fread(dat, 1, 2, fp) < 2) return -1;
channels = dat[0] + (dat[1] << 8);
if (fread(dat, 1, 4, fp) < 4) return -1;
memcpy(&sample_rate, dat, 4); //sample_rate = dat[0]|(dat[1]<<8)|(dat[2]<<16)|(dat[3]<<24);
if (fread(dat, 1, 4, fp) < 4) return -1;
if (fread(dat, 1, 2, fp) < 2) return -1;
//byte = dat[0] + (dat[1] << 8);
if (fread(dat, 1, 2, fp) < 2) return -1;
bits_sample = dat[0] + (dat[1] << 8);
// pos_dat = 36L + info
for ( ; ; ) {
if ( (byte=fgetc(fp)) == EOF ) return -1;
txt[p % 4] = byte;
p++; if (p==4) p=0;
if (findstr(txt, "data", p) == 4) break;
}
if (fread(dat, 1, 4, fp) < 4) return -1;
fprintf(stderr, "sample_rate: %d\n", sample_rate);
fprintf(stderr, "bits : %d\n", bits_sample);
fprintf(stderr, "channels : %d\n", channels);
if ((bits_sample != 8) && (bits_sample != 16)) return -1;
samples_per_bit = sample_rate/(float)BAUD_RATE;
fprintf(stderr, "samples/bit: %.2f\n", samples_per_bit);
return 0;
}
#define EOF_INT 0x1000000
unsigned long sample_count = 0;
int read_signed_sample(FILE *fp) { // int = i32_t
int byte, i, ret; // EOF -> 0x1000000
for (i = 0; i < channels; i++) {
// i = 0: links bzw. mono
byte = fgetc(fp);
if (byte == EOF) return EOF_INT;
if (i == 0) ret = byte;
if (bits_sample == 16) {
byte = fgetc(fp);
if (byte == EOF) return EOF_INT;
if (i == 0) ret += byte << 8;
}
}
sample_count++;
if (bits_sample == 8) return ret-128; // 8bit: 00..FF, centerpoint 0x80=128
if (bits_sample == 16) return (short)ret;
return ret;
}
int par=1, par_alt=1;
int read_bits_fsk(FILE *fp, int *bit, int *len) {
int n, sample, y0;
float l, x1;
static float x0;
n = 0;
do{
y0 = sample;
sample = read_signed_sample(fp);
if (sample == EOF_INT) return EOF;
//sample_count++; // in read_signed_sample()
par_alt = par;
par = (sample > 0) ? 1 : -1;
n++;
} while (par*par_alt > 0);
if (!option_res) l = (float)n / samples_per_bit;
else { // genauere Bitlaengen-Messung
x1 = sample/(float)(sample-y0); // hilft bei niedriger sample rate
l = (n+x0-x1) / samples_per_bit; // meist mehr frames (nicht immer)
x0 = x1;
}
*len = (int)(l+0.5);
if (!option_inv) *bit = (1+par_alt)/2; // oben 1, unten -1
else *bit = (1-par_alt)/2; // sdr#<rev1381?, invers: unten 1, oben -1
/* Y-offset ? */
return 0;
}
int bitstart = 0;
double bitgrenze = 0;
/*unsigned*/ long scount = 0;
int read_rawbit(FILE *fp, int *bit) {
int sample;
int sum;
sum = 0;
if (bitstart) {
scount = 0; // eigentlich scount = 1
bitgrenze = 0; // oder bitgrenze = -1
bitstart = 0;
}
bitgrenze += samples_per_bit;
do {
sample = read_signed_sample(fp);
if (sample == EOF_INT) return EOF;
//sample_count++; // in read_signed_sample()
//par = (sample >= 0) ? 1 : -1; // 8bit: 0..127,128..255 (-128..-1,0..127)
sum += sample;
scount++;
} while (scount < bitgrenze); // n < samples_per_bit
if (sum >= 0) *bit = 1;
else *bit = 0;
if (option_inv) *bit ^= 1;
return 0;
}
/* ------------------------------------------------------------------------------------ */
#define BITFRAME_LEN 1200
#define RAWBITFRAME_LEN (BITFRAME_LEN*2)
char frame_rawbits[RAWBITFRAME_LEN+10]; // braucht eigentlich nur 1/4
char frame_bits[BITFRAME_LEN+10];
#define HEADLEN 24
#define RAWHEADLEN (2*HEADLEN)
char header0x049DCE[] = // 0x049DCE =
"101010101011010100101011001101001100101011001101"; // 00000100 10011101 11001110
char header0x049DCEbits[] = "000001001001110111001110";
//111110110110001000110000
char header0xFB6230[] = // 0xFB6230 =
"110011001101001101001101010100101010110010101010"; // 11111011 01100010 00110000
char header0xFB6230bits[] = "111110110110001000110000";
// 0x049DCE ^ 0xFB6230 = 0xFFFFFE
char buf[RAWHEADLEN+1] = "xxxxxxxxxx\0";
int bufpos = 0;
/* -------------------------------------------------------------------------- */
void inc_bufpos() {
bufpos = (bufpos+1) % RAWHEADLEN;
}
char cb_inv(char c) {
if (c == '0') return '1';
if (c == '1') return '0';
return c;
}
int compare_subheader() {
int i, j;
i = 0;
j = bufpos;
while (i < RAWHEADLEN) {
if (j < 0) j = RAWHEADLEN-1;
if (buf[j] != header0x049DCE[RAWHEADLEN-1-i]) break;
j--;
i++;
}
if (i == RAWHEADLEN) return 1;
i = 0;
j = bufpos;
while (i < RAWHEADLEN) {
if (j < 0) j = RAWHEADLEN-1;
if (buf[j] != cb_inv(header0x049DCE[RAWHEADLEN-1-i])) break;
j--;
i++;
}
if (i == RAWHEADLEN) return 3;
i = 0;
j = bufpos;
while (i < RAWHEADLEN) {
if (j < 0) j = RAWHEADLEN-1;
if (buf[j] != header0xFB6230[RAWHEADLEN-1-i]) break;
j--;
i++;
}
if (i == RAWHEADLEN) return 2;
i = 0;
j = bufpos;
while (i < RAWHEADLEN) {
if (j < 0) j = RAWHEADLEN-1;
if (buf[j] != cb_inv(header0xFB6230[RAWHEADLEN-1-i])) break;
j--;
i++;
}
if (i == RAWHEADLEN) return 4;
return 0;
}
/* -------------------------------------------------------------------------- */
int biphi_s(char* frame_rawbits, ui8_t *frame_bits) {
int j = 0;
int byt;
j = 0;
while ((byt = frame_rawbits[2*j]) && frame_rawbits[2*j+1]) {
if ((byt < 0x30) || (byt > 0x31)) break;
if ( frame_rawbits[2*j] == frame_rawbits[2*j+1] ) { byt = 1; }
else { byt = 0; }
frame_bits[j] = byt;
j++;
}
frame_bits[j] = 0;
return j;
}
/* -------------------------------------------------------------------------- */
/*
ui32_t bitstr2val(char *bits, int len) {
int j;
ui8_t bit;
ui32_t val;
if ((len < 0) || (len > 32)) return -1;
val = 0;
for (j = 0; j < len; j++) {
bit = bits[j] - 0x30;
val |= (bit << (len-1-j)); // big endian
//val |= (bit << j); // little endian
}
return val;
}
*/
ui32_t bits2val(ui8_t bits[], int len) {
int j;
ui8_t bit;
ui32_t val;
if ((len < 0) || (len > 32)) return -1;
val = 0;
for (j = 0; j < len; j++) {
bit = bits[j];
val |= (bit << (len-1-j)); // big endian
//val |= (bit << j); // little endian
}
return val;
}
/* -------------------------------------------------------------------------- */
int main(int argc, char **argv) {
FILE *fp;
char *fpname;
int i, j;
int bit_count = 0,
header_found = 0,
bit, len;
int counter;
ui32_t val;
ui32_t dat2;
int lat, lat1, lat2,
lon, lon1, lon2,
alt, alt1, alt2;
ui16_t vH, vD;
i16_t vU;
double velH, velD, velU;
int latdeg,londeg;
double latmin, lonmin;
ui32_t t1, t2, ms, min, std, tt, mm, jj;
#ifdef CYGWIN
_setmode(fileno(stdin), _O_BINARY); // _setmode(_fileno(stdin), _O_BINARY);
#endif
setbuf(stdout, NULL);
fpname = argv[0];
++argv;
while ((*argv) && (!wavloaded)) {
if ( (strcmp(*argv, "-h") == 0) || (strcmp(*argv, "--help") == 0) ) {
help_out:
fprintf(stderr, "%s <-n> [options] audio.wav\n", fpname);
fprintf(stderr, " n=1,2\n");
fprintf(stderr, " options:\n");
//fprintf(stderr, " -v, --verbose\n");
fprintf(stderr, " -r, --raw\n");
return 0;
}
else if ( (strcmp(*argv, "-r") == 0) || (strcmp(*argv, "--raw") == 0) ) {
option_raw = 1;
}
else if (strcmp(*argv, "--res") == 0) { option_res = 1; }
else if ( (strcmp(*argv, "-i") == 0) || (strcmp(*argv, "--invert") == 0) ) {
option_inv = 1; // nicht noetig
}
else if ( (strcmp(*argv, "-2") == 0) ) {
option2 = 1;
}
else if ( (strcmp(*argv, "-1") == 0) ) {
option1 = 1;
}
else if (strcmp(*argv, "-b") == 0) { option_b = 1; }
else if (strcmp(*argv, "--ecc") == 0) { option_ecc = 1; }
else if ( (strcmp(*argv, "-v") == 0) ) {
option_verbose = 1;
}
else if ( (strcmp(*argv, "--br") == 0) ) {
++argv;
if (*argv) {
baudrate = atof(*argv);
if (baudrate < 2200 || baudrate > 2400) baudrate = 2400; // default: 2400
}
else return -1;
}
else {
if ((option1 == 1 && option2 == 1) || (!option_raw && option1 == 0 && option2 == 0)) goto help_out;
fp = fopen(*argv, "rb");
if (fp == NULL) {
fprintf(stderr, "%s konnte nicht geoeffnet werden\n", *argv);
return -1;
}
wavloaded = 1;
}
++argv;
}
if (!wavloaded) fp = stdin;
i = read_wav_header(fp);
if (i) {
fclose(fp);
return -1;
}
if (baudrate > 0) {
samples_per_bit = sample_rate/baudrate; // default baudrate: 2400
fprintf(stderr, "sps corr: %.4f\n", samples_per_bit);
}
if (option_ecc) {
rs_init_BCH64();
}
bufpos = 0;
bit_count = 0;
while (!read_bits_fsk(fp, &bit, &len)) {
if (len == 0) { // reset_frame();
/*
if (byte_count > FRAME_LEN-20) {
print_frame(byte_count);
bit_count = 0;
byte_count = FRAMESTART;
header_found = 0;
}
*/
//inc_bufpos();
//buf[bufpos] = 'x';
continue; // ...
}
for (i = 0; i < len; i++) {
inc_bufpos();
buf[bufpos] = 0x30 + bit; // Ascii
if (!header_found) {
header_found = compare_subheader();
if (header_found) {
bit_count = 0;
for (j = 0; j < HEADLEN; j++) {
if (header_found % 2 == 1) frame_bits[j] = header0x049DCEbits[j] - 0x30;
else frame_bits[j] = header0xFB6230bits[j] - 0x30;
}
}
}
else {
frame_rawbits[bit_count] = 0x30 + bit;
bit_count++;
if (option_b) {
while (++i < len) {
frame_rawbits[bit_count] = 0x30 + bit;
bit_count++;
}
bitstart = 1;
while (bit_count < RAWBITFRAME_LEN/4-RAWHEADLEN) {
if (read_rawbit(fp, &bit) == EOF) break;
frame_rawbits[bit_count] = 0x30 + bit;
bit_count++;
}
}
if (bit_count >= RAWBITFRAME_LEN/4-RAWHEADLEN) { // 600-48
frame_rawbits[bit_count] = '\0';
biphi_s(frame_rawbits, frame_bits+HEADLEN);
if (option_ecc) {
for (block = 0; block < 6; block++) {
// prepare block-codeword
for (j = 0; j < 46; j++) cw[45-j] = frame_bits[HEADLEN + block*46+j];
for (j = 46; j < 63; j++) cw[j] = 0;
errors = rs_decode_bch_gf2t2(cw, err_pos, err_val);
// check parity,padding
if (errors >= 0) {
check_err = 0;
for (j = 46; j < 63; j++) { if (cw[j] != 0) check_err = 0x1; }
par = 1;
for (j = 13; j < 13+16; j++) par ^= cw[j];
if (cw[12] != par) check_err |= 0x100;
par = 1;
for (j = 30; j < 30+16; j++) par ^= cw[j];
if (cw[29] != par) check_err |= 0x10;
if (check_err) errors = -3;
}
if (errors >= 0) {
for (j = 0; j < 46; j++) frame_bits[HEADLEN + block*46+j] = cw[45-j];
}
if (errors < 0) block_err[block] = 0xE;
else block_err[block] = errors;
}
}
if (!option2 && !option_raw) {
if (header_found % 2 == 1) {
val = bits2val(frame_bits+HEADLEN, 16);
counter = val & 0xFFFF;
if (counter % 2 == 0) printf("\n");
//printf("[0x%04X = %d] ", counter, counter);
printf("[%d] ", counter);
if (counter % 2 == 1) {
t2 = bits2val(frame_bits+HEADLEN+5*46 , 8); // LSB
t1 = bits2val(frame_bits+HEADLEN+5*46+8, 8);
ms = (t1 << 8) | t2;
std = bits2val(frame_bits+HEADLEN+5*46+17, 8);
min = bits2val(frame_bits+HEADLEN+5*46+25, 8);
printf(" ");
printf("%02d:%02d:%06.3f ", std, min, (double)ms/1000.0);
printf(" ");
//printf("\n");
}
}
if (header_found % 2 == 0) {
val = bits2val(frame_bits+HEADLEN, 16);
//printf("%04x ", val & 0xFFFF);
if ((counter % 2 == 0)) { // (val & 0xFFFF) > 0) {// == 0x8080
//offset=24+16+1;
lat1 = bits2val(frame_bits+HEADLEN+46*0+17, 16);
lat2 = bits2val(frame_bits+HEADLEN+46*1 , 16);
lon1 = bits2val(frame_bits+HEADLEN+46*1+17, 16);
lon2 = bits2val(frame_bits+HEADLEN+46*2 , 16);
alt1 = bits2val(frame_bits+HEADLEN+46*2+17, 16);
alt2 = bits2val(frame_bits+HEADLEN+46*3 , 16);
lat = (lat1 << 16) | lat2;
lon = (lon1 << 16) | lon2;
alt = (alt1 << 16) | alt2;
//printf("%08X %08X %08X : ", lat, lon, alt);
printf(" ");
printf("lat: %.5f lon: %.5f alt: %.2f", (double)lat/1e7, (double)lon/1e7, (double)alt/1e2);
printf(" ");
vH = bits2val(frame_bits+HEADLEN+46*3+17, 16);
vD = bits2val(frame_bits+HEADLEN+46*4 , 16);
vU = bits2val(frame_bits+HEADLEN+46*4+17, 16);
velH = (double)vH/1e2;
velD = (double)vD/1e2;
velU = (double)vU/1e2;
printf(" vH: %.2fm/s D: %.1f vV: %.2fm/s", velH, velD, velU);
printf(" ");
jj = bits2val(frame_bits+HEADLEN+5*46+ 8, 8) + 0x0700;
mm = bits2val(frame_bits+HEADLEN+5*46+17, 8);
tt = bits2val(frame_bits+HEADLEN+5*46+25, 8);
printf(" ");
printf("%4d-%02d-%02d ", jj, mm, tt);
printf(" ");
//printf("\n");
}
}
}
else if (option2 && !option_raw) {
if (header_found % 2 == 1) {
val = bits2val(frame_bits+HEADLEN, 16);
counter = val & 0xFFFF;
if (counter % 2 == 0) printf("\n");
//printf("[0x%04X = %d] ", counter, counter);
printf("[%d] ", counter);
if (counter % 2 == 0) {
t1 = bits2val(frame_bits+HEADLEN+5*46 , 8); // MSB
t2 = bits2val(frame_bits+HEADLEN+5*46+8, 8);
ms = (t1 << 8) | t2;
std = bits2val(frame_bits+HEADLEN+5*46+17, 8);
min = bits2val(frame_bits+HEADLEN+5*46+25, 8);
printf(" ");
printf("%02d:%02d:%06.3f ", std, min, (double)ms/1000.0);
printf(" ");
}
}
if (header_found % 2 == 0) {
val = bits2val(frame_bits+HEADLEN, 16);
//printf("%04x ", val & 0xFFFF);
if ((counter % 2 == 0)) { // (val & 0xFFFF) > 0) {// == 0x2390
//offset=24+16+1;
dat2 = bits2val(frame_bits+HEADLEN, 16);
if (option_verbose) printf("%05u ", dat2);
printf("(%02d-%02d-%02d) ", dat2/1000,(dat2/10)%100, (dat2%10)+10); // 2020: +20 ?
lat1 = bits2val(frame_bits+HEADLEN+46*0+17, 16);
lat2 = bits2val(frame_bits+HEADLEN+46*1 , 16);
lon1 = bits2val(frame_bits+HEADLEN+46*1+17, 16);
lon2 = bits2val(frame_bits+HEADLEN+46*2 , 16);
alt1 = bits2val(frame_bits+HEADLEN+46*2+17, 16);
alt2 = bits2val(frame_bits+HEADLEN+46*3 , 8);
// NMEA?
lat = (lat1 << 16) | lat2;
lon = (lon1 << 16) | lon2;
alt = (alt1 << 8) | alt2;
latdeg = (int)lat / 1e6;
latmin = (double)(lat/1e6-latdeg)*100/60.0;
londeg = (int)lon / 1e6;
lonmin = (double)(lon/1e6-londeg)*100/60.0;
//printf("%08X %08X %08X : ", lat, lon, alt);
printf(" ");
printf("lat: %.5f lon: %.5f alt: %.2f", (double)latdeg+latmin, (double)londeg+lonmin, (double)alt/1e2);
printf(" ");
vD = bits2val(frame_bits+HEADLEN+46*4+17, 16);
vH = bits2val(frame_bits+HEADLEN+46*5 , 16);
velD = (double)vD/1e2; // course, true
velH = (double)vH/1.94384e2; // speed: knots -> m/s
printf(" (vH: %.1fm/s D: %.2f)", velH, velD);
printf(" ");
}
//else { printf("\n"); }
}
}
else { // raw
val = bits2val(frame_bits, HEADLEN);
printf("%06X ", val & 0xFFFFFF);
printf(" ");
for (i = 0; i < 6; i++) {
val = bits2val(frame_bits+HEADLEN+46*i , 16);
printf("%04X ", val & 0xFFFF);
val = bits2val(frame_bits+HEADLEN+46*i+17, 16);
printf("%04X ", val & 0xFFFF);
val = bits2val(frame_bits+HEADLEN+46*i+34, 12);
//printf("%03X ", val & 0xFFF);
//printf(" ");
}
printf("\n");
}
bit_count = 0;
header_found = 0;
if (option_ecc && option_verbose) {
printf("#");
for (block = 0; block < 6; block++) printf("%X", block_err[block]);
printf("# ");
}
}
}
}
}
printf("\n");
fclose(fp);
return 0;
}

886
meisei/meisei_ims.c 100644
Wyświetl plik

@ -0,0 +1,886 @@
/*
* big endian forest
*
* Meisei radiosondes
* author: zilog80
*
*/
/*
PCM-FM, 1200 baud biphase-S
1200 bit pro Sekunde: zwei Frames, die wiederum in zwei Subframes unterteilt werden koennen, d.h. 4 mal 300 bit.
Variante 1 (RS-11G ?)
<option -1>
049DCE1C667FDD8F537C8100004F20764630A20000000010040436 FB623080801F395FFE08A76540000FE01D0C2C1E75025006DE0A07
049DCE1C67008C73D7168200004F0F764B31A2FFFF000010270B14 FB6230000000000000000000000000000000000000000000001D59
0x00..0x02 HEADER 0x049DCE
0x03..0x04 16 bit 0.5s-counter, count%2=0:
0x1B..0x1D HEADER 0xFB6230
0x20..0x23 32 bit GPS-lat * 1e7 (DD.dddddd)
0x24..0x27 32 bit GPS-lon * 1e7 (DD.dddddd)
0x28..0x2B 32 bit GPS-alt * 1e2 (m)
0x2C..0x2D 16 bit GPS-vH * 1e2 (m/s)
0x2E..0x2F 16 bit GPS-vD * 1e2 (degree) (0..360 unsigned)
0x30..0x31 16 bit GPS-vU * 1e2 (m/s)
0x32..0x35 32 bit date jjJJMMTT
0x00..0x02 HEADER 0x049DCE
0x03..0x04 16 bit 0.5s-counter, count%2=1:
0x17..0x18 16 bit time ms xxyy, 00.000-59.000
0x19..0x1A 16 bit time hh:mm
0x1B..0x1D HEADER 0xFB6230
0x049DCE ^ 0xFB6230 = 0xFFFFFE
Variante 2 (iMS-100 ?)
<option -2>
049DCE3E228023DBF53FA700003C74628430C100000000ABE00B3B FB62302390031EECCC00E656E42327562B2436C4C01CDB0F18B09A
049DCE3E23516AF62B3FC700003C7390D131C100000000AB090000 FB62300000000000032423222422202014211B13220000000067C4
0x00..0x02 HEADER 0x049DCE
0x03..0x04 16 bit 0.5s-counter, count%2=0:
0x07..0x0A 32 bit cfg[cnt%64] (float32); cfg[0,16,32,48]=SN
0x11..0x12 30xx, xx=C1(ims100?),A2(rs11?)
0x17..0x18 16 bit time ms yyxx, 00.000-59.000
0x19..0x1A 16 bit time hh:mm
0x1B..0x1D HEADER 0xFB6230
0x1E..0x1F 16 bit ? date (TT,MM,JJ)=(date/1000,(date/10)%100,(date%10)+10)
0x20..0x23 32 bit GPS-lat * 1e4 (NMEA DDMM.mmmm)
0x24..0x27 32 bit GPS-lon * 1e4 (NMEA DDMM.mmmm)
0x28..0x2A 24 bit GPS-alt * 1e2 (m)
0x30..0x31 16 bit GPS-vD * 1e2 (degree)
0x32..0x33 16 bit GPS-vH * 1.944e2 (knots)
0x00..0x02 HEADER 0x049DCE
0x03..0x04 16 bit 0.5s-counter, count%2=1:
0x07..0x0A 32 bit cfg[cnt%64] (float32); freq=400e3+cfg[15]*1e2/kHz
0x11..0x12 31xx, xx=C1(ims100?),A2(rs11?)
0x17..0x18 16 bit 1024-counter yyxx, +0x400=1024; rollover synchron zu ms-counter, nach rollover auch +0x300=768
0x1B..0x1D HEADER 0xFB6230
0x22..0x23 yy00..yy03 (yy00: GPS PRN?)
Die 46bit-Bloecke sind BCH-Codewoerter. Es handelt sich um einen (63,51)-Code mit Generatorpolynom
x^12+x^10+x^8+x^5+x^4+x^3+1;
gekuerzt auf (46,34), die letzten 12 bit sind die BCH-Kontrollbits.
Die 34 Nachrichtenbits sind aufgeteilt in 16+1+16+1, d.h. nach einem 16 bit Block kommt ein Paritaetsbit,
dass 1 ist, wenn die Anzahl 1en in den 16 bit davor gerade ist, und sonst 0.
*/
/*
2 "raw" symbols -> 1 biphase-symbol (bit): 2400 (raw) baud
ecc: option_b, exact symbol rate; if necessary, adjust --br <baud>
e.g. -b --br 2398
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// #include <math.h>
#ifdef CYGWIN
#include <fcntl.h> // cygwin: _setmode()
#include <io.h>
#endif
typedef unsigned char ui8_t;
typedef unsigned short ui16_t;
typedef unsigned int ui32_t;
typedef short i16_t;
typedef struct {
int frnr;
int jahr; int monat; int tag;
int std; int min; float sek;
double lat; double lon; double alt;
double vH; double vD; double vV;
ui32_t ecc;
float cfg[64];
ui32_t _sn;
float sn; // 0 mod 16
float fq; // 15 mod 64
} gpx_t;
gpx_t gpx;
int option_verbose = 0, // ausfuehrliche Anzeige
option_raw = 0, // rohe Frames
option_inv = 0, // invertiert Signal
option_res = 0, // genauere Bitmessung
option1 = 0,
option2 = 0,
option_b = 0,
option_ecc = 0, // BCH(63,51)
option_jsn = 0, // JSON output (auto_rx)
wavloaded = 0;
float baudrate = -1;
/* -------------------------------------------------------------------------- */
// Fehlerkorrektur (noch?) nicht sehr effektiv... (t zu klein)
#include "bch_ecc.c"
int errors;
ui8_t cw[63+1], // BCH(63,51), t=2
err_pos[4],
err_val[4];
ui8_t block_err[6];
int block, check_err;
/* -------------------------------------------------------------------------- */
#define BAUD_RATE 2400 // raw symbol rate; bit=biphase_symbol, bitrate=1200
int sample_rate = 0, bits_sample = 0, channels = 0;
float samples_per_bit = 0;
int findstr(char *buff, char *str, int pos) {
int i;
for (i = 0; i < 4; i++) {
if (buff[(pos+i)%4] != str[i]) break;
}
return i;
}
int read_wav_header(FILE *fp) {
char txt[4+1] = "\0\0\0\0";
unsigned char dat[4];
int byte, p=0;
if (fread(txt, 1, 4, fp) < 4) return -1;
if (strncmp(txt, "RIFF", 4)) return -1;
if (fread(txt, 1, 4, fp) < 4) return -1;
// pos_WAVE = 8L
if (fread(txt, 1, 4, fp) < 4) return -1;
if (strncmp(txt, "WAVE", 4)) return -1;
// pos_fmt = 12L
for ( ; ; ) {
if ( (byte=fgetc(fp)) == EOF ) return -1;
txt[p % 4] = byte;
p++; if (p==4) p=0;
if (findstr(txt, "fmt ", p) == 4) break;
}
if (fread(dat, 1, 4, fp) < 4) return -1;
if (fread(dat, 1, 2, fp) < 2) return -1;
if (fread(dat, 1, 2, fp) < 2) return -1;
channels = dat[0] + (dat[1] << 8);
if (fread(dat, 1, 4, fp) < 4) return -1;
memcpy(&sample_rate, dat, 4); //sample_rate = dat[0]|(dat[1]<<8)|(dat[2]<<16)|(dat[3]<<24);
if (fread(dat, 1, 4, fp) < 4) return -1;
if (fread(dat, 1, 2, fp) < 2) return -1;
//byte = dat[0] + (dat[1] << 8);
if (fread(dat, 1, 2, fp) < 2) return -1;
bits_sample = dat[0] + (dat[1] << 8);
// pos_dat = 36L + info
for ( ; ; ) {
if ( (byte=fgetc(fp)) == EOF ) return -1;
txt[p % 4] = byte;
p++; if (p==4) p=0;
if (findstr(txt, "data", p) == 4) break;
}
if (fread(dat, 1, 4, fp) < 4) return -1;
fprintf(stderr, "sample_rate: %d\n", sample_rate);
fprintf(stderr, "bits : %d\n", bits_sample);
fprintf(stderr, "channels : %d\n", channels);
if ((bits_sample != 8) && (bits_sample != 16)) return -1;
samples_per_bit = sample_rate/(float)BAUD_RATE;
fprintf(stderr, "samples/bit: %.2f\n", samples_per_bit);
return 0;
}
#define EOF_INT 0x1000000
unsigned long sample_count = 0;
int read_signed_sample(FILE *fp) { // int = i32_t
int byte, i, ret; // EOF -> 0x1000000
for (i = 0; i < channels; i++) {
// i = 0: links bzw. mono
byte = fgetc(fp);
if (byte == EOF) return EOF_INT;
if (i == 0) ret = byte;
if (bits_sample == 16) {
byte = fgetc(fp);
if (byte == EOF) return EOF_INT;
if (i == 0) ret += byte << 8;
}
}
sample_count++;
if (bits_sample == 8) return ret-128; // 8bit: 00..FF, centerpoint 0x80=128
if (bits_sample == 16) return (short)ret;
return ret;
}
int par=1, par_alt=1;
int read_bits_fsk(FILE *fp, int *bit, int *len) {
int n, sample, y0;
float l, x1;
static float x0;
n = 0;
do{
y0 = sample;
sample = read_signed_sample(fp);
if (sample == EOF_INT) return EOF;
//sample_count++; // in read_signed_sample()
par_alt = par;
par = (sample > 0) ? 1 : -1;
n++;
} while (par*par_alt > 0);
if (!option_res) l = (float)n / samples_per_bit;
else { // genauere Bitlaengen-Messung
x1 = sample/(float)(sample-y0); // hilft bei niedriger sample rate
l = (n+x0-x1) / samples_per_bit; // meist mehr frames (nicht immer)
x0 = x1;
}
*len = (int)(l+0.5);
if (!option_inv) *bit = (1+par_alt)/2; // oben 1, unten -1
else *bit = (1-par_alt)/2; // sdr#<rev1381?, invers: unten 1, oben -1
/* Y-offset ? */
return 0;
}
int bitstart = 0;
double bitgrenze = 0;
/*unsigned*/ long scount = 0;
int read_rawbit(FILE *fp, int *bit) {
int sample;
int sum;
sum = 0;
if (bitstart) {
scount = 0; // eigentlich scount = 1
bitgrenze = 0; // oder bitgrenze = -1
bitstart = 0;
}
bitgrenze += samples_per_bit;
do {
sample = read_signed_sample(fp);
if (sample == EOF_INT) return EOF;
//sample_count++; // in read_signed_sample()
//par = (sample >= 0) ? 1 : -1; // 8bit: 0..127,128..255 (-128..-1,0..127)
sum += sample;
scount++;
} while (scount < bitgrenze); // n < samples_per_bit
if (sum >= 0) *bit = 1;
else *bit = 0;
if (option_inv) *bit ^= 1;
return 0;
}
/* ------------------------------------------------------------------------------------ */
#define BITFRAME_LEN 1200
#define RAWBITFRAME_LEN (BITFRAME_LEN*2)
char frame_rawbits[RAWBITFRAME_LEN+10]; // braucht eigentlich nur 1/2 (vormals 1/4)
ui8_t frame_bits[BITFRAME_LEN+10];
ui8_t *subframe_bits;
#define HEADLEN 24
#define RAWHEADLEN (2*HEADLEN)
char header0x049DCE[] = // 0x049DCE =
"101010101011010100101011001101001100101011001101"; // 00000100 10011101 11001110
char header0x049DCEbits[] = "000001001001110111001110";
//111110110110001000110000
char header0xFB6230[] = // 0xFB6230 =
"110011001101001101001101010100101010110010101010"; // 11111011 01100010 00110000
char header0xFB6230bits[] = "111110110110001000110000";
// 0x049DCE ^ 0xFB6230 = 0xFFFFFE
char buf[RAWHEADLEN+1] = "xxxxxxxxxx\0";
int bufpos = 0;
/* -------------------------------------------------------------------------- */
void inc_bufpos() {
bufpos = (bufpos+1) % RAWHEADLEN;
}
char cb_inv(char c) {
if (c == '0') return '1';
if (c == '1') return '0';
return c;
}
int compare_subheader() {
int i, j;
i = 0;
j = bufpos;
while (i < RAWHEADLEN) {
if (j < 0) j = RAWHEADLEN-1;
if (buf[j] != header0x049DCE[RAWHEADLEN-1-i]) break;
j--;
i++;
}
if (i == RAWHEADLEN) return 1;
i = 0;
j = bufpos;
while (i < RAWHEADLEN) {
if (j < 0) j = RAWHEADLEN-1;
if (buf[j] != cb_inv(header0x049DCE[RAWHEADLEN-1-i])) break;
j--;
i++;
}
if (i == RAWHEADLEN) return 3;
i = 0;
j = bufpos;
while (i < RAWHEADLEN) {
if (j < 0) j = RAWHEADLEN-1;
if (buf[j] != header0xFB6230[RAWHEADLEN-1-i]) break;
j--;
i++;
}
if (i == RAWHEADLEN) return 2;
i = 0;
j = bufpos;
while (i < RAWHEADLEN) {
if (j < 0) j = RAWHEADLEN-1;
if (buf[j] != cb_inv(header0xFB6230[RAWHEADLEN-1-i])) break;
j--;
i++;
}
if (i == RAWHEADLEN) return 4;
return 0;
}
/* -------------------------------------------------------------------------- */
int biphi_s(char* frame_rawbits, ui8_t *frame_bits) {
int j = 0;
int byt;
j = 0;
while ((byt = frame_rawbits[2*j]) && frame_rawbits[2*j+1]) {
if ((byt < 0x30) || (byt > 0x31)) break;
if ( frame_rawbits[2*j] == frame_rawbits[2*j+1] ) { byt = 1; }
else { byt = 0; }
frame_bits[j] = byt;
j++;
}
frame_bits[j] = 0;
return j;
}
/* -------------------------------------------------------------------------- */
/*
ui32_t bitstr2val(char *bits, int len) {
int j;
ui8_t bit;
ui32_t val;
if ((len < 0) || (len > 32)) return -1;
val = 0;
for (j = 0; j < len; j++) {
bit = bits[j] - 0x30;
val |= (bit << (len-1-j)); // big endian
//val |= (bit << j); // little endian
}
return val;
}
*/
ui32_t bits2val(ui8_t bits[], int len) {
int j;
ui8_t bit;
ui32_t val;
if ((len < 0) || (len > 32)) return -1;
val = 0;
for (j = 0; j < len; j++) {
bit = bits[j];
val |= (bit << (len-1-j)); // big endian
//val |= (bit << j); // little endian
}
return val;
}
/* -------------------------------------------------------------------------- */
int main(int argc, char **argv) {
FILE *fp;
char *fpname;
int i, j;
int bit_count = 0,
header_found = 0,
bit, len;
int subframe = 0;
int err_frm = 0;
int counter;
ui32_t val;
ui32_t dat2;
int lat, lat1, lat2,
lon, lon1, lon2,
alt, alt1, alt2;
ui16_t vH, vD;
i16_t vU;
double velH, velD, velU;
int latdeg,londeg;
double latmin, lonmin;
ui32_t t1, t2, ms, min, std, tt, mm, jj;
float sn = -1;
float fq = -1;
#ifdef CYGWIN
_setmode(fileno(stdin), _O_BINARY); // _setmode(_fileno(stdin), _O_BINARY);
#endif
setbuf(stdout, NULL);
fpname = argv[0];
++argv;
while ((*argv) && (!wavloaded)) {
if ( (strcmp(*argv, "-h") == 0) || (strcmp(*argv, "--help") == 0) ) {
help_out:
fprintf(stderr, "%s <-n> [options] audio.wav\n", fpname);
fprintf(stderr, " n=1,2\n");
fprintf(stderr, " options:\n");
//fprintf(stderr, " -v, --verbose\n");
fprintf(stderr, " -r, --raw\n");
return 0;
}
else if ( (strcmp(*argv, "-r") == 0) ) { option_raw = 1; }
else if (strcmp(*argv, "--res") == 0) { option_res = 1; }
else if ( (strcmp(*argv, "-i") == 0) || (strcmp(*argv, "--invert") == 0) ) {
option_inv = 1; // nicht noetig
}
else if ( (strcmp(*argv, "-2") == 0) ) {
option2 = 1;
}
else if ( (strcmp(*argv, "-1") == 0) ) {
option1 = 1;
}
else if (strcmp(*argv, "-b") == 0) { option_b = 1; }
else if (strcmp(*argv, "--ecc") == 0) { option_ecc = 1; }
else if ( (strcmp(*argv, "-v") == 0) ) { option_verbose = 1; }
else if ( (strcmp(*argv, "--br") == 0) ) {
++argv;
if (*argv) {
baudrate = atof(*argv);
if (baudrate < 2200 || baudrate > 2400) baudrate = 2400; // default: 2400
}
else return -1;
}
else if (strcmp(*argv, "--json") == 0) {
option_jsn = 1;
option_ecc = 1;
}
else {
if (option1 == 1 && option2 == 1) goto help_out;
if (!option_raw && option1 == 0 && option2 == 0) option2 = 1;
fp = fopen(*argv, "rb");
if (fp == NULL) {
fprintf(stderr, "%s konnte nicht geoeffnet werden\n", *argv);
return -1;
}
wavloaded = 1;
}
++argv;
}
if (!wavloaded) fp = stdin;
i = read_wav_header(fp);
if (i) {
fclose(fp);
return -1;
}
if (baudrate > 0) {
samples_per_bit = sample_rate/baudrate; // default baudrate: 2400
fprintf(stderr, "sps corr: %.4f\n", samples_per_bit);
}
if (option_ecc) {
rs_init_BCH64();
}
bufpos = 0;
bit_count = 0;
while (!read_bits_fsk(fp, &bit, &len)) {
if (len == 0) { // reset_frame();
/*
if (byte_count > FRAME_LEN-20) {
print_frame(byte_count);
bit_count = 0;
byte_count = FRAMESTART;
header_found = 0;
}
*/
//inc_bufpos();
//buf[bufpos] = 'x';
continue; // ...
}
for (i = 0; i < len; i++) {
inc_bufpos();
buf[bufpos] = 0x30 + bit; // Ascii
if (!header_found) {
header_found = compare_subheader();
/* //type 1: detect GPS position in FB6230 first
if ( header_found % 2 == 0 && !option2 //header0xFB6230
|| header_found % 2 == 1 && option2 ) { //header0x049DCE
*/
if (header_found % 2 == 1) { //header0x049DCE
bit_count = 0;
for (j = 0; j < HEADLEN; j++) {
if (header_found % 2 == 1) frame_bits[j] = header0x049DCEbits[j] - 0x30;
else frame_bits[j] = header0xFB6230bits[j] - 0x30;
}
}
else header_found = 0;
}
else {
frame_rawbits[bit_count] = 0x30 + bit;
bit_count++;
if (option_b) {
while (++i < len) {
frame_rawbits[bit_count] = 0x30 + bit;
bit_count++;
}
bitstart = 1;
while (bit_count < RAWBITFRAME_LEN/2-RAWHEADLEN) { // 2*600-48
if (read_rawbit(fp, &bit) == EOF) break;
frame_rawbits[bit_count] = 0x30 + bit;
bit_count++;
}
}
if (bit_count >= RAWBITFRAME_LEN/2-RAWHEADLEN) { // 2*600-48
frame_rawbits[bit_count] = '\0';
biphi_s(frame_rawbits, frame_bits+HEADLEN);
err_frm = 0;
for (subframe = 0; subframe < 2; subframe++)
{ // option2:
subframe_bits = frame_bits; // subframe 0: 049DCE
if (subframe > 0) subframe_bits += BITFRAME_LEN/4; // subframe 1: FB6230
if (option_ecc) {
for (block = 0; block < 6; block++) {
// prepare block-codeword
for (j = 0; j < 46; j++) cw[45-j] = subframe_bits[HEADLEN + block*46+j];
for (j = 46; j < 63; j++) cw[j] = 0;
errors = rs_decode_bch_gf2t2(cw, err_pos, err_val);
// check parity,padding
if (errors >= 0) {
check_err = 0;
for (j = 46; j < 63; j++) { if (cw[j] != 0) check_err = 0x1; }
par = 1;
for (j = 13; j < 13+16; j++) par ^= cw[j];
if (cw[12] != par) check_err |= 0x100;
par = 1;
for (j = 30; j < 30+16; j++) par ^= cw[j];
if (cw[29] != par) check_err |= 0x10;
if (check_err) errors = -3;
}
if (errors >= 0) // errors > 0
{
for (j = 0; j < 46; j++) subframe_bits[HEADLEN + block*46+j] = cw[45-j];
}
if (errors < 0) {
if (errors == -3) block_err[block] = 0xF;
else block_err[block] = 0xE;
err_frm += 1;
}
else block_err[block] = errors;
}
}
if (!option2 && !option_raw) {
jmpRS11:
if (header_found % 2 == 1)
{
val = bits2val(subframe_bits+HEADLEN, 16);
counter = val & 0xFFFF;
printf("[%d] ", counter);
// 0x30yy, 0x31yy
val = bits2val(subframe_bits+HEADLEN+46*3+17, 16);
if ( (val & 0xFF) >= 0xC0 && err_frm == 0) {
option2 = 1;
printf("\n");
goto jmpIMS;
}
if (counter % 2 == 1) {
t2 = bits2val(subframe_bits+HEADLEN+5*46 , 8); // LSB
t1 = bits2val(subframe_bits+HEADLEN+5*46+8, 8);
ms = (t1 << 8) | t2;
std = bits2val(subframe_bits+HEADLEN+5*46+17, 8);
min = bits2val(subframe_bits+HEADLEN+5*46+25, 8);
printf(" ");
printf("%02d:%02d:%06.3f ", std, min, (double)ms/1000.0);
printf("\n");
}
}
if (header_found % 2 == 0)
{
if ((counter % 2 == 0)) {
//offset=24+16+1;
lat1 = bits2val(subframe_bits+HEADLEN+46*0+17, 16);
lat2 = bits2val(subframe_bits+HEADLEN+46*1 , 16);
lon1 = bits2val(subframe_bits+HEADLEN+46*1+17, 16);
lon2 = bits2val(subframe_bits+HEADLEN+46*2 , 16);
alt1 = bits2val(subframe_bits+HEADLEN+46*2+17, 16);
alt2 = bits2val(subframe_bits+HEADLEN+46*3 , 16);
lat = (lat1 << 16) | lat2;
lon = (lon1 << 16) | lon2;
alt = (alt1 << 16) | alt2;
//printf("%08X %08X %08X : ", lat, lon, alt);
printf(" ");
printf("lat: %.5f lon: %.5f alt: %.2f", (double)lat/1e7, (double)lon/1e7, (double)alt/1e2);
printf(" ");
vH = bits2val(subframe_bits+HEADLEN+46*3+17, 16);
vD = bits2val(subframe_bits+HEADLEN+46*4 , 16);
vU = bits2val(subframe_bits+HEADLEN+46*4+17, 16);
velH = (double)vH/1e2;
velD = (double)vD/1e2;
velU = (double)vU/1e2;
printf(" vH: %.2fm/s D: %.1f vV: %.2fm/s", velH, velD, velU);
printf(" ");
jj = bits2val(subframe_bits+HEADLEN+5*46+ 8, 8) + 0x0700;
mm = bits2val(subframe_bits+HEADLEN+5*46+17, 8);
tt = bits2val(subframe_bits+HEADLEN+5*46+25, 8);
printf(" %4d-%02d-%02d ", jj, mm, tt);
printf("\n");
}
}
}
else if (option2 && !option_raw) { // iMS-100
jmpIMS:
if (header_found % 2 == 1) { // 049DCE
ui16_t w16[2];
ui32_t w32;
float *fcfg = (float *)&w32;
// 0x30C1, 0x31C1
val = bits2val(subframe_bits+HEADLEN+46*3+17, 16);
if ( (val & 0xFF) < 0xC0 && err_frm == 0) {
option2 = 0;
printf("\n");
goto jmpRS11;
}
val = bits2val(subframe_bits+HEADLEN, 16);
counter = val & 0xFFFF;
if (counter % 2 == 0) printf("[%d] ", counter);
w16[0] = bits2val(subframe_bits+HEADLEN+46*1 , 16);
w16[1] = bits2val(subframe_bits+HEADLEN+46*1+17, 16);
w32 = (w16[1]<<16) | w16[0];
if (err_frm == 0) // oder kleineren subblock pruefen
{
gpx.cfg[counter%64] = *fcfg;
// (main?) SN
if (counter % 0x10 == 0) { sn = *fcfg; gpx.sn = sn; gpx._sn = w32; }
// freq
if (counter % 64 == 15) { fq = 400e3+(*fcfg)*100.0; gpx.fq = fq; }
}
if (counter % 2 == 0) {
gpx.frnr = counter;
t1 = bits2val(subframe_bits+HEADLEN+5*46 , 8); // MSB
t2 = bits2val(subframe_bits+HEADLEN+5*46+8, 8);
ms = (t1 << 8) | t2;
std = bits2val(subframe_bits+HEADLEN+5*46+17, 8);
min = bits2val(subframe_bits+HEADLEN+5*46+25, 8);
gpx.sek = (float)ms/1000.0;
gpx.std = std;
gpx.min = min;
printf(" ");
printf("%02d:%02d:%06.3f ", gpx.std, gpx.min, gpx.sek);
printf(" ");
}
}
if (header_found % 2 == 0) // FB6230
{
if ((counter % 2 == 0)) {
//offset=24+16+1;
dat2 = bits2val(subframe_bits+HEADLEN, 16);
gpx.tag = dat2/1000;
gpx.monat = (dat2/10)%100;
gpx.jahr = 2000 + (dat2%10)+10;
//if (option_verbose) printf("%05u ", dat2);
//printf("(%02d-%02d-%02d) ", gpx.tag, gpx.monat, gpx.jahr%100); // 2020: +20 ?
printf("(%04d-%02d-%02d) ", gpx.jahr, gpx.monat, gpx.tag); // 2020: +20 ?
lat1 = bits2val(subframe_bits+HEADLEN+46*0+17, 16);
lat2 = bits2val(subframe_bits+HEADLEN+46*1 , 16);
lon1 = bits2val(subframe_bits+HEADLEN+46*1+17, 16);
lon2 = bits2val(subframe_bits+HEADLEN+46*2 , 16);
alt1 = bits2val(subframe_bits+HEADLEN+46*2+17, 16);
alt2 = bits2val(subframe_bits+HEADLEN+46*3 , 8);
// NMEA?
lat = (lat1 << 16) | lat2;
lon = (lon1 << 16) | lon2;
alt = (alt1 << 8) | alt2;
latdeg = (int)lat / 1e6;
latmin = (double)(lat/1e6-latdeg)*100/60.0;
londeg = (int)lon / 1e6;
lonmin = (double)(lon/1e6-londeg)*100/60.0;
gpx.lat = (double)latdeg+latmin;
gpx.lon = (double)londeg+lonmin;
gpx.alt = (double)alt/1e2;
printf(" ");
printf("lat: %.5f lon: %.5f alt: %.2f", gpx.lat, gpx.lon, gpx.alt);
printf(" ");
vD = bits2val(subframe_bits+HEADLEN+46*4+17, 16);
vH = bits2val(subframe_bits+HEADLEN+46*5 , 16);
velD = (double)vD/1e2; // course, true
velH = (double)vH/1.94384e2; // knots -> m/s
gpx.vH = velH;
gpx.vD = velD;
printf(" (vH: %.1fm/s D: %.2f)", gpx.vH, gpx.vD);
printf(" ");
}
if (counter % 2 == 0) {
if (option_ecc) {
printf(" ");
if (err_frm) printf("[NO]"); else printf("[OK]");
}
if (option_verbose) {
if (sn > 0) {
printf(" : sn %.0f", sn);
sn = -1;
}
if (fq > 0) {
printf(" : fq %.1f MHz", fq/1e3);
fq = -1;
}
}
printf("\n");
if (option_jsn && err_frm==0) {
printf("{ \"frame\": %d, \"id\": \"IMS100-%.0f\", \"datetime\": \"%04d-%02d-%02dT%02d:%02d:%06.3fZ\", \"lat\": %.5f, \"lon\": %.5f, \"alt\": %.5f, \"vel_h\": %.5f, \"heading\": %.5f }\n",
gpx.frnr, gpx.sn, gpx.jahr, gpx.monat, gpx.tag, gpx.std, gpx.min, gpx.sek, gpx.lat, gpx.lon, gpx.alt, gpx.vH, gpx.vD );
printf("\n");
}
}
}
}
else { // raw
val = bits2val(subframe_bits, HEADLEN);
printf("%06X ", val & 0xFFFFFF);
//printf(" ");
for (i = 0; i < 6; i++) {
val = bits2val(subframe_bits+HEADLEN+46*i , 16);
printf("%04X ", val & 0xFFFF);
val = bits2val(subframe_bits+HEADLEN+46*i+17, 16);
printf("%04X ", val & 0xFFFF);
//val = bits2val(subframe_bits+HEADLEN+46*i+34, 12);
//printf("%03X ", val & 0xFFF);
//printf(" ");
}
if (option_ecc && option_verbose) {
printf("#");
for (block = 0; block < 6; block++) printf("%X", block_err[block]);
printf("# ");
}
if (subframe > 0) printf("\n");
}
bit_count = 0;
header_found += 1;
}
header_found = 0;
}
}
}
}
printf("\n");
fclose(fp);
return 0;
}

644
meisei/meisei_rs.c 100644
Wyświetl plik

@ -0,0 +1,644 @@
/*
* big endian forest
*
* Meisei radiosondes
* author: zilog80
*
*/
/*
PCM-FM, 1200 baud biphase-S
1200 bit pro Sekunde: zwei Frames, die wiederum in zwei Subframes unterteilt werden koennen, d.h. 4 mal 300 bit.
Variante 1 (RS-11G ?)
<option -1>
049DCE1C667FDD8F537C8100004F20764630A20000000010040436 FB623080801F395FFE08A76540000FE01D0C2C1E75025006DE0A07
049DCE1C67008C73D7168200004F0F764B31A2FFFF000010270B14 FB6230000000000000000000000000000000000000000000001D59
0x00..0x02 HEADER 0x049DCE
0x03..0x04 16 bit 0.5s-counter, count%2=0:
0x1B..0x1D HEADER 0xFB6230
0x20..0x23 32 bit GPS-lat * 1e7 (DD.dddddd)
0x24..0x27 32 bit GPS-lon * 1e7 (DD.dddddd)
0x28..0x2B 32 bit GPS-alt * 1e2 (m)
0x32..0x35 32 bit date jjJJMMTT
0x00..0x02 HEADER 0x049DCE
0x03..0x04 16 bit 0.5s-counter, count%2=1:
0x17..0x18 16 bit time ms xxyy, 00.000-59.000
0x19..0x1A 16 bit time hh:mm
0x1B..0x1D HEADER 0xFB6230
0x049DCE ^ 0xFB6230 = 0xFFFFFE
Variante 2 (iMS-100 ?)
<option -2>
049DCE3E228023DBF53FA700003C74628430C100000000ABE00B3B FB62302390031EECCC00E656E42327562B2436C4C01CDB0F18B09A
049DCE3E23516AF62B3FC700003C7390D131C100000000AB090000 FB62300000000000032423222422202014211B13220000000067C4
0x00..0x02 HEADER 0x049DCE
0x03..0x04 16 bit 0.5s-counter, count%2=0:
0x17..0x18 16 bit time ms yyxx, 00.000-59.000
0x19..0x1A 16 bit time hh:mm
0x1B..0x1D HEADER 0xFB6230
0x1E..0x1F 16 bit ? date (TT,MM,JJ)=(date/1000,(date/10)%100,(date%10)+10)
0x20..0x23 32 bit GPS-lat * 1e4 (NMEA DDMM.mmmm)
0x24..0x27 32 bit GPS-lon * 1e4 (NMEA DDMM.mmmm)
0x28..0x2A 24 bit GPS-alt * 1e2 (m)
0x00..0x02 HEADER 0x049DCE
0x03..0x04 16 bit 0.5s-counter, count%2=1:
0x17..0x18 16 bit 1024-counter yyxx, +0x400=1024; rollover synchron zu ms-counter, nach rollover auch +0x300=768
0x1B..0x1D HEADER 0xFB6230
Die 46bit-Bloecke sind BCH-Codewoerter. Es handelt sich um einen (63,51)-Code mit Generatorpolynom
x^12+x^10+x^8+x^5+x^4+x^3+1;
gekuerzt auf (46,34), die letzten 12 bit sind die BCH-Kontrollbits.
Die 34 Nachrichtenbits sind aufgeteilt in 16+1+16+1, d.h. nach einem 16 bit Block kommt ein Paritaetsbit,
dass 1 ist, wenn die Anzahl 1en in den 16 bit davor gerade ist, und sonst 0.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// #include <math.h>
#ifdef CYGWIN
#include <fcntl.h> // cygwin: _setmode()
#include <io.h>
#endif
typedef unsigned char ui8_t;
typedef unsigned short ui16_t;
typedef unsigned int ui32_t;
typedef struct {
int jahr; int monat; int tag;
int std; int min; int sek;
double lat; double lon; double alt;
} datum_t;
datum_t datum;
int option_verbose = 0, // ausfuehrliche Anzeige
option_raw = 0, // rohe Frames
option_inv = 0, // invertiert Signal
option_res = 0, // genauere Bitmessung
option1 = 0,
option2 = 0,
wavloaded = 0;
/* -------------------------------------------------------------------------- */
#define BAUD_RATE 2400
int sample_rate = 0, bits_sample = 0, channels = 0;
float samples_per_bit = 0;
int findstr(char *buff, char *str, int pos) {
int i;
for (i = 0; i < 4; i++) {
if (buff[(pos+i)%4] != str[i]) break;
}
return i;
}
int read_wav_header(FILE *fp) {
char txt[4+1] = "\0\0\0\0";
unsigned char dat[4];
int byte, p=0;
if (fread(txt, 1, 4, fp) < 4) return -1;
if (strncmp(txt, "RIFF", 4)) return -1;
if (fread(txt, 1, 4, fp) < 4) return -1;
// pos_WAVE = 8L
if (fread(txt, 1, 4, fp) < 4) return -1;
if (strncmp(txt, "WAVE", 4)) return -1;
// pos_fmt = 12L
for ( ; ; ) {
if ( (byte=fgetc(fp)) == EOF ) return -1;
txt[p % 4] = byte;
p++; if (p==4) p=0;
if (findstr(txt, "fmt ", p) == 4) break;
}
if (fread(dat, 1, 4, fp) < 4) return -1;
if (fread(dat, 1, 2, fp) < 2) return -1;
if (fread(dat, 1, 2, fp) < 2) return -1;
channels = dat[0] + (dat[1] << 8);
if (fread(dat, 1, 4, fp) < 4) return -1;
memcpy(&sample_rate, dat, 4); //sample_rate = dat[0]|(dat[1]<<8)|(dat[2]<<16)|(dat[3]<<24);
if (fread(dat, 1, 4, fp) < 4) return -1;
if (fread(dat, 1, 2, fp) < 2) return -1;
//byte = dat[0] + (dat[1] << 8);
if (fread(dat, 1, 2, fp) < 2) return -1;
bits_sample = dat[0] + (dat[1] << 8);
// pos_dat = 36L + info
for ( ; ; ) {
if ( (byte=fgetc(fp)) == EOF ) return -1;
txt[p % 4] = byte;
p++; if (p==4) p=0;
if (findstr(txt, "data", p) == 4) break;
}
if (fread(dat, 1, 4, fp) < 4) return -1;
fprintf(stderr, "sample_rate: %d\n", sample_rate);
fprintf(stderr, "bits : %d\n", bits_sample);
fprintf(stderr, "channels : %d\n", channels);
if ((bits_sample != 8) && (bits_sample != 16)) return -1;
samples_per_bit = sample_rate/(float)BAUD_RATE;
fprintf(stderr, "samples/bit: %.2f\n", samples_per_bit);
return 0;
}
#define EOF_INT 0x1000000
int read_signed_sample(FILE *fp) { // int = i32_t
int byte, i, ret; // EOF -> 0x1000000
for (i = 0; i < channels; i++) {
// i = 0: links bzw. mono
byte = fgetc(fp);
if (byte == EOF) return EOF_INT;
if (i == 0) ret = byte;
if (bits_sample == 16) {
byte = fgetc(fp);
if (byte == EOF) return EOF_INT;
if (i == 0) ret += byte << 8;
}
}
if (bits_sample == 8) return ret-128; // 8bit: 00..FF, centerpoint 0x80=128
if (bits_sample == 16) return (short)ret;
return ret;
}
int par=1, par_alt=1;
unsigned long sample_count = 0;
int read_bits_fsk(FILE *fp, int *bit, int *len) {
int n, sample, y0;
float l, x1;
static float x0;
n = 0;
do{
y0 = sample;
sample = read_signed_sample(fp);
if (sample == EOF_INT) return EOF;
sample_count++;
par_alt = par;
par = (sample > 0) ? 1 : -1;
n++;
} while (par*par_alt > 0);
if (!option_res) l = (float)n / samples_per_bit;
else { // genauere Bitlaengen-Messung
x1 = sample/(float)(sample-y0); // hilft bei niedriger sample rate
l = (n+x0-x1) / samples_per_bit; // meist mehr frames (nicht immer)
x0 = x1;
}
*len = (int)(l+0.5);
if (!option_inv) *bit = (1+par_alt)/2; // oben 1, unten -1
else *bit = (1-par_alt)/2; // sdr#<rev1381?, invers: unten 1, oben -1
/* Y-offset ? */
return 0;
}
/* ------------------------------------------------------------------------------------ */
#define BITFRAME_LEN 1200
#define RAWBITFRAME_LEN (BITFRAME_LEN*2)
char frame_rawbits[RAWBITFRAME_LEN+10]; // braucht eigentlich nur 1/4
char frame_bits[BITFRAME_LEN+10];
#define HEADLEN 24
#define RAWHEADLEN (2*HEADLEN)
char header0x049DCE[] = // 0x049DCE =
"101010101011010100101011001101001100101011001101"; // 00000100 10011101 11001110
char header0x049DCEbits[] = "000001001001110111001110";
//111110110110001000110000
char header0xFB6230[] = // 0xFB6230 =
"110011001101001101001101010100101010110010101010"; // 11111011 01100010 00110000
char header0xFB6230bits[] = "111110110110001000110000";
// 0x049DCE ^ 0xFB6230 = 0xFFFFFE
char buf[RAWHEADLEN+1] = "xxxxxxxxxx\0";
int bufpos = 0;
/* -------------------------------------------------------------------------- */
void inc_bufpos() {
bufpos = (bufpos+1) % RAWHEADLEN;
}
char cb_inv(char c) {
if (c == '0') return '1';
if (c == '1') return '0';
return c;
}
int compare_subheader() {
int i, j;
i = 0;
j = bufpos;
while (i < RAWHEADLEN) {
if (j < 0) j = RAWHEADLEN-1;
if (buf[j] != header0x049DCE[RAWHEADLEN-1-i]) break;
j--;
i++;
}
if (i == RAWHEADLEN) return 1;
i = 0;
j = bufpos;
while (i < RAWHEADLEN) {
if (j < 0) j = RAWHEADLEN-1;
if (buf[j] != cb_inv(header0x049DCE[RAWHEADLEN-1-i])) break;
j--;
i++;
}
if (i == RAWHEADLEN) return 3;
i = 0;
j = bufpos;
while (i < RAWHEADLEN) {
if (j < 0) j = RAWHEADLEN-1;
if (buf[j] != header0xFB6230[RAWHEADLEN-1-i]) break;
j--;
i++;
}
if (i == RAWHEADLEN) return 2;
i = 0;
j = bufpos;
while (i < RAWHEADLEN) {
if (j < 0) j = RAWHEADLEN-1;
if (buf[j] != cb_inv(header0xFB6230[RAWHEADLEN-1-i])) break;
j--;
i++;
}
if (i == RAWHEADLEN) return 4;
return 0;
}
/* -------------------------------------------------------------------------- */
int biphi_s0(char* frame_rawbits, char *frame_bits) {
int j = 0;
int byt, bytes[2];
int c = 0;
j = 0;
while (byt = frame_rawbits[j]) {
if ((byt >= 0x30) && (byt <= 0x31)) {
bytes[c] = byt;
c = !c;
if ((j > 0) && (c == 0)) {
if ( bytes[0] == bytes[1] ) { byt = '1'; }
else
if ( bytes[0] != bytes[1] ) { byt = '0'; }
frame_bits[j/2] = byt;
}
j++;
}
}
frame_bits[j/2] = '\0';
return j/2;
}
int biphi_s(char* frame_rawbits, char *frame_bits) {
int j = 0;
int byt;
j = 0;
while ( (byt = frame_rawbits[2*j]) && frame_rawbits[2*j+1] ) {
if ((byt < 0x30) || (byt > 0x31)) break;
if ( frame_rawbits[2*j] == frame_rawbits[2*j+1] ) { byt = '1'; }
else { byt = '0'; }
frame_bits[j] = byt;
j++;
}
frame_bits[j] = '\0';
return j;
}
/* -------------------------------------------------------------------------- */
ui32_t bitstr2val(char *bits, int len) {
int j;
ui8_t bit;
ui32_t val;
if ((len < 0) || (len > 32)) return -1;
val = 0;
for (j = 0; j < len; j++) {
bit = bits[j] - 0x30;
val |= (bit << (len-1-j)); // big endian
//val |= (bit << j); // little endian
}
return val;
}
/* -------------------------------------------------------------------------- */
int main(int argc, char **argv) {
FILE *fp;
char *fpname;
int i, j;
int bit_count = 0,
header_found = 0,
bit, len;
int counter;
ui32_t val;
ui32_t dat2;
int lat, lat1, lat2,
lon, lon1, lon2,
alt, alt1, alt2;
int latdeg,londeg;
double latmin, lonmin;
ui32_t t1, t2, ms, min, std, tt, mm, jj;
#ifdef CYGWIN
_setmode(fileno(stdin), _O_BINARY); // _setmode(_fileno(stdin), _O_BINARY);
#endif
setbuf(stdout, NULL);
fpname = argv[0];
++argv;
while ((*argv) && (!wavloaded)) {
if ( (strcmp(*argv, "-h") == 0) || (strcmp(*argv, "--help") == 0) ) {
help_out:
fprintf(stderr, "%s <-n> [options] audio.wav\n", fpname);
fprintf(stderr, " n=1,2\n");
fprintf(stderr, " options:\n");
//fprintf(stderr, " -v, --verbose\n");
fprintf(stderr, " -r, --raw\n");
return 0;
}
/*
else if ( (strcmp(*argv, "-v") == 0) || (strcmp(*argv, "--verbose") == 0) ) {
option_verbose = 1;
}
*/
else if ( (strcmp(*argv, "-r") == 0) || (strcmp(*argv, "--raw") == 0) ) {
option_raw = 1;
}
else if (strcmp(*argv, "--res") == 0) { option_res = 1; }
else if ( (strcmp(*argv, "-i") == 0) || (strcmp(*argv, "--invert") == 0) ) {
option_inv = 1; // nicht noetig
}
else if ( (strcmp(*argv, "-2") == 0) ) {
option2 = 1;
}
else if ( (strcmp(*argv, "-1") == 0) ) {
option1 = 1;
}
else {
if ((option1 == 1 && option2 == 1) || (!option_raw && option1 == 0 && option2 == 0)) goto help_out;
fp = fopen(*argv, "rb");
if (fp == NULL) {
fprintf(stderr, "%s konnte nicht geoeffnet werden\n", *argv);
return -1;
}
wavloaded = 1;
}
++argv;
}
if (!wavloaded) fp = stdin;
i = read_wav_header(fp);
if (i) {
fclose(fp);
return -1;
}
bufpos = 0;
bit_count = 0;
while (!read_bits_fsk(fp, &bit, &len)) {
if (len == 0) { // reset_frame();
/*
if (byte_count > FRAME_LEN-20) {
print_frame(byte_count);
bit_count = 0;
byte_count = FRAMESTART;
header_found = 0;
}
*/
//inc_bufpos();
//buf[bufpos] = 'x';
continue; // ...
}
for (i = 0; i < len; i++) {
inc_bufpos();
buf[bufpos] = 0x30 + bit; // Ascii
if (!header_found) {
header_found = compare_subheader();
if (header_found) {
bit_count = 0;
for (j = 0; j < HEADLEN; j++) {
if (header_found % 2 == 1) frame_bits[j] = header0x049DCEbits[j];
else frame_bits[j] = header0xFB6230bits[j];
}
}
}
else {
frame_rawbits[bit_count] = 0x30 + bit;
bit_count++;
if (bit_count >= RAWBITFRAME_LEN/4-RAWHEADLEN) { // 600-48
frame_rawbits[bit_count] = '\0';
biphi_s(frame_rawbits, frame_bits+HEADLEN);
if (!option2 && !option_raw) {
if (header_found % 2 == 1) {
val = bitstr2val(frame_bits+HEADLEN, 16);
counter = val & 0xFFFF;
if (counter % 2 == 0) printf("\n");
//printf("[0x%04X = %d] ", counter, counter);
printf("[%d] ", counter);
if (counter % 2 == 1) {
t2 = bitstr2val(frame_bits+HEADLEN+5*46 , 8); // LSB
t1 = bitstr2val(frame_bits+HEADLEN+5*46+8, 8);
ms = (t1 << 8) | t2;
std = bitstr2val(frame_bits+HEADLEN+5*46+17, 8);
min = bitstr2val(frame_bits+HEADLEN+5*46+25, 8);
printf(" ");
printf("%02d:%02d:%06.3f ", std, min, (double)ms/1000.0);
printf(" ");
//printf("\n");
}
}
if (header_found % 2 == 0) {
val = bitstr2val(frame_bits+HEADLEN, 16);
//printf("%04x ", val & 0xFFFF);
if ((counter % 2 == 0)) { // (val & 0xFFFF) > 0) {// == 0x8080
//offset=24+16+1;
lat1 = bitstr2val(frame_bits+HEADLEN+17, 16);
lat2 = bitstr2val(frame_bits+HEADLEN+46, 16);
lon1 = bitstr2val(frame_bits+HEADLEN+46+17, 16);
lon2 = bitstr2val(frame_bits+HEADLEN+46+46, 16);
alt1 = bitstr2val(frame_bits+HEADLEN+46+46+17, 16);
alt2 = bitstr2val(frame_bits+HEADLEN+46+46+46, 16);
lat = (lat1 << 16) | lat2;
lon = (lon1 << 16) | lon2;
alt = (alt1 << 16) | alt2;
//printf("%08X %08X %08X : ", lat, lon, alt);
printf(" ");
printf("%.6f %.6f %.2f", (double)lat/1e7, (double)lon/1e7, (double)alt/1e2);
printf(" ");
jj = bitstr2val(frame_bits+HEADLEN+5*46+ 8, 8) + 0x0700;
mm = bitstr2val(frame_bits+HEADLEN+5*46+17, 8);
tt = bitstr2val(frame_bits+HEADLEN+5*46+25, 8);
printf(" ");
printf("%4d-%02d-%02d ", jj, mm, tt);
printf(" ");
//printf("\n");
}
}
}
else if (option2 && !option_raw) {
if (header_found % 2 == 1) {
val = bitstr2val(frame_bits+HEADLEN, 16);
counter = val & 0xFFFF;
if (counter % 2 == 0) printf("\n");
//printf("[0x%04X = %d] ", counter, counter);
printf("[%d] ", counter);
if (counter % 2 == 0) {
t1 = bitstr2val(frame_bits+HEADLEN+5*46 , 8); // MSB
t2 = bitstr2val(frame_bits+HEADLEN+5*46+8, 8);
ms = (t1 << 8) | t2;
std = bitstr2val(frame_bits+HEADLEN+5*46+17, 8);
min = bitstr2val(frame_bits+HEADLEN+5*46+25, 8);
printf(" ");
printf("%02d:%02d:%06.3f ", std, min, (double)ms/1000.0);
printf(" ");
}
}
if (header_found % 2 == 0) {
val = bitstr2val(frame_bits+HEADLEN, 16);
//printf("%04x ", val & 0xFFFF);
if ((counter % 2 == 0)) { // (val & 0xFFFF) > 0) {// == 0x2390
//offset=24+16+1;
dat2 = bitstr2val(frame_bits+HEADLEN, 16);
printf("%05u (?%02d-%02d-%02d) ", dat2, dat2/1000,(dat2/10)%100, (dat2%10)+10);
lat1 = bitstr2val(frame_bits+HEADLEN+17, 16);
lat2 = bitstr2val(frame_bits+HEADLEN+46, 16);
lon1 = bitstr2val(frame_bits+HEADLEN+46+17, 16);
lon2 = bitstr2val(frame_bits+HEADLEN+46+46, 16);
alt1 = bitstr2val(frame_bits+HEADLEN+46+46+17, 16);
alt2 = bitstr2val(frame_bits+HEADLEN+46+46+46, 8);
lat = (lat1 << 16) | lat2;
lon = (lon1 << 16) | lon2;
alt = (alt1 << 8) | alt2;
latdeg = (int)lat / 1e6;
latmin = (double)(lat/1e6-latdeg)*100/60.0;
londeg = (int)lon / 1e6;
lonmin = (double)(lon/1e6-londeg)*100/60.0;
//printf("%08X %08X %08X : ", lat, lon, alt);
printf(" ");
printf("%.6f %.6f %.2f", (double)latdeg+latmin, (double)londeg+lonmin, (double)alt/1e2);
printf(" ");
}
//else { printf("\n"); }
}
}
else { // raw
val = bitstr2val(frame_bits, HEADLEN);
printf("%06X ", val & 0xFFFFFF);
printf(" ");
for (i = 0; i < 6; i++) {
val = bitstr2val(frame_bits+HEADLEN+46*i , 16);
printf("%04X ", val & 0xFFFF);
val = bitstr2val(frame_bits+HEADLEN+46*i+17, 16);
printf("%04X ", val & 0xFFFF);
val = bitstr2val(frame_bits+HEADLEN+46*i+34, 12);
//printf("%03X ", val & 0xFFF);
//printf(" ");
}
printf("\n");
}
bit_count = 0;
header_found = 0;
}
}
}
}
printf("\n");
fclose(fp);
return 0;
}

Wyświetl plik

@ -15,18 +15,18 @@ typedef int i32_t;
static int option_verbose = 0, // ausfuehrliche Anzeige
option_inv = 0, // invertiert Signal
//option_dc = 0,
option_iq = 0,
option_dc = 0,
option_silent = 0,
option_debug = 0,
option_cont = 0,
wavloaded = 0;
static int wav_channel = 0; // audio channel: left
//int dfm_bps = 2500;
//int dfm_sps = 2500;
static char dfm_header[] = "10011010100110010101101001010101"; // DFM-09
// "01100101011001101010010110101010"; // DFM-06
//int vai_bps = 4800;
//int vai_sps = 4800;
static char rs41_header[] = "00001000011011010101001110001000"
"01000100011010010100100000011111";
static char rs92_header[] = //"10100110011001101001"
@ -35,14 +35,14 @@ static char rs92_header[] = //"10100110011001101001"
"10100110011001101001"
"1010011001100110100110101010100110101001";
//int lms_bps = 4800; // lms6_403MHz
//int lms_sps = 4800; // lms6_403MHz
static char lms6_header[] = "0101011000001000""0001110010010111"
"0001101010100111""0011110100111110";
//int mk2a_bps = 9600; // lms6_1680MHz
//int mk2a_sps = 9600; // lms6_1680MHz
static char mk2a_header[] = "0010100111""0010100111""0001001001""0010010101";
//int m10_bps = 9600;
//int m10_sps = 9600;
static char m10_header[] = "10011001100110010100110010011001";
// frame byte[0..1]: byte[0]=framelen-1, byte[1]=type(8F=M2K2,9F=M10,AF=M10+)
// M2K2 : 64 8F : 0110010010001111
@ -50,19 +50,20 @@ static char m10_header[] = "10011001100110010100110010011001";
// M10-aux: 76 9F : 0111011010011111 (framelen 0x76+1)
// M10+ : 64 AF : 0110010010101111 (w/ gtop-GPS)
//int meisei_sps = 2400; // 0xFB6230 =
static char meisei_header[] = "110011001101001101001101010100101010110010101010"; // 11111011 01100010 00110000
// imet_9600 / 1200 Hz;
static char imet_preamble[] = "11110000111100001111000011110000"
"11110000111100001111000011110000"
"11110000111100001111000011110000"
"11110000111100001111000011110000"; // 1200 Hz preamble
//int imet1ab_bps = 9600; // 1200 bits/sec
//int imet1ab_sps = 9600; // 1200 bits/sec
static char imet1ab_header[] = "11110000111100001111000011110000"
// "11110000""10101100110010101100101010101100"
"11110000""10101100110010101100101010101100";
// 11110000:1 , 001100110:0 // 11/4=2.1818..
static char imet1rs_header[] =
"0000""1111""0000""1111""0000""1111" // preamble
@ -72,14 +73,13 @@ static char imet1rs_header[] =
// 1:1200Hz/0:2200Hz tones, bit-duration 1/1200 sec, phase ...
// bits: 1111111111111111111 10 10000000 10 ..;
// C34/C50: 2400 baud, 1:2900Hz/0:4800Hz
static char c34_preheader[] =
"01010101010101010101010101010101"; // 2900 Hz tone
// dft, dB-max(1000Hz..5000Hz) = 2900Hz ?
typedef struct {
int bps; // header: here bps means baudrate ...
int sps; // header: symbol rate, baud
int hLen;
int L;
char *header;
@ -89,23 +89,27 @@ typedef struct {
int herrs;
float complex *Fm;
char *type;
ui8_t tn; // signed?
int tn;
int lpFM;
int lpIQ;
float dc;
} rsheader_t;
#define Nrs 10
#define idxAB 8
#define idxRS 9
#define Nrs 11
#define idxAB 9
#define idxRS 10
static rsheader_t rs_hdr[Nrs] = {
{ 2500, 0, 0, dfm_header, 1.0, 0.0, 0.62, 2, NULL, "DFM9", 2}, // DFM6: -2 (unsigned)
{ 4800, 0, 0, rs41_header, 0.5, 0.0, 0.53, 2, NULL, "RS41", 3},
{ 4800, 0, 0, rs92_header, 0.5, 0.0, 0.54, 3, NULL, "RS92", 4},
{ 4800, 0, 0, lms6_header, 1.0, 0.0, 0.70, 2, NULL, "LMS6", 8},
{ 9616, 0, 0, mk2a_header, 1.0, 0.0, 0.70, 2, NULL, "MK2LMS", 10}, // Mk2a/LMS6-1680
{ 9616, 0, 0, m10_header, 1.0, 0.0, 0.76, 2, NULL, "M10", 5},
{ 5800, 0, 0, c34_preheader, 1.5, 0.0, 0.80, 2, NULL, "C34C50", 9}, // C34/C50 2900 Hz tone
{ 9600, 0, 0, imet_preamble, 0.5, 0.0, 0.80, 4, NULL, "IMET", 6}, // IMET1AB=7, IMET1RS=8
{ 9600, 0, 0, imet1ab_header, 1.0, 0.0, 0.80, 2, NULL, "IMET1AB", 6}, // (rs_hdr[idxAB])
{ 9600, 0, 0, imet1rs_header, 0.5, 0.0, 0.80, 2, NULL, "IMET1RS", 7} // IMET4 (rs_hdr[idxRS])
{ 2500, 0, 0, dfm_header, 1.0, 0.0, 0.62, 2, NULL, "DFM9", 2 , 0, 0, 0.0}, // DFM6: -2 ?
{ 4800, 0, 0, rs41_header, 0.5, 0.0, 0.53, 2, NULL, "RS41", 3 , 0, 0, 0.0},
{ 4800, 0, 0, rs92_header, 0.5, 0.0, 0.54, 3, NULL, "RS92", 4 , 0, 0, 0.0},
{ 4800, 0, 0, lms6_header, 1.0, 0.0, 0.70, 2, NULL, "LMS6", 8 , 0, 0, 0.0},
{ 9616, 0, 0, mk2a_header, 1.0, 0.0, 0.70, 2, NULL, "MK2LMS", 10 , 1, 2, 0.0}, // Mk2a/LMS6-1680
{ 9616, 0, 0, m10_header, 1.0, 0.0, 0.76, 2, NULL, "M10", 5 , 1, 1, 0.0},
{ 2400, 0, 0, meisei_header, 1.0, 0.0, 0.70, 2, NULL, "MEISEI", 11 , 0, 1, 0.0},
{ 5800, 0, 0, c34_preheader, 1.5, 0.0, 0.80, 2, NULL, "C34C50", 9 , 0, 1, 0.0}, // C34/C50 2900 Hz tone
{ 9600, 0, 0, imet_preamble, 0.5, 0.0, 0.80, 4, NULL, "IMET", 6 , 1, 2, 0.0}, // IMET1AB=7, IMET1RS=8
{ 9600, 0, 0, imet1ab_header, 1.0, 0.0, 0.80, 2, NULL, "IMET1AB", 6 , 1, 2, 0.0}, // (rs_hdr[idxAB])
{ 9600, 0, 0, imet1rs_header, 0.5, 0.0, 0.80, 2, NULL, "IMET1RS", 7 , 0, 2, 0.0} // (rs_hdr[idxRS]) IMET4: lpIQ=1 ...
};
@ -116,8 +120,8 @@ static rsheader_t rs_hdr[Nrs] = {
// - power level / frame < 1s, noise
// - fm: - frame duration <-> noise (variance/standard deviation)
// - pulse-shaping
// m10: 00110011 at 9600 bps
// rs41: 0 1 0 1 at 4800 bps
// m10: 00110011 at 9600 sps
// rs41: 0 1 0 1 at 4800 sps
// - after header, m10-baudrate < rs41-baudrate
// - m10 top-carrier, fm-mean/average
// - m10-header ..110(1)0110011()011.. bit shuffle
@ -134,26 +138,15 @@ static rsheader_t rs_hdr[Nrs] = {
static int sample_rate = 0, bits_sample = 0, channels = 0;
static int wav_ch = 0; // 0: links bzw. mono; 1: rechts
static unsigned int sample_in, sample_out, delay;
static ui32_t sample_in, sample_out, delay;
static int M;
static float *bufs = NULL;
static float *buf_fm[3];
static float *bufs = NULL;
static char *rawbits = NULL;
static int Nvar = 0; // < M
static double xsum = 0;
static float *xs = NULL;
/*
static double xsum=0, qsum=0;
static float *xs = NULL,
*qs = NULL;
*/
static float dc_ofs = 0.0;
static float dc = 0.0;
/* ------------------------------------------------------------------------------------ */
@ -165,6 +158,19 @@ static float complex *X, *Z, *cx;
static float *xn;
static float *db;
// FM: lowpass
static float *ws_lpFM[2];
static int dsp__lpFMtaps[2]; // ui32_t
static float complex *Y;
static float complex *WS[2];
// IF: lowpass
static float *ws_lpIQ[2];
static int dsp__lpIQtaps; // ui32_t
static float complex *lpIQ_buf;
static float complex *iq_buf;
static void dft_raw(float complex *Z) {
int s, l, l2, i, j, k;
float complex w1, w2, T;
@ -220,22 +226,12 @@ static float freq2bin(int f) {
}
static float bin2freq(int k) {
return sample_rate * k / (float)N_DFT;
float fq = k / (float)N_DFT;
if ( fq >= 0.5) fq -= 1.0;
return fq*sample_rate;
}
/* ------------------------------------------------------------------------------------ */
/*
static float get_bufvar(int ofs) {
float mu = xs[(sample_out+M + ofs) % M]/Nvar;
float var = qs[(sample_out+M + ofs) % M]/Nvar - mu*mu;
return var;
}
*/
static float get_bufmu(int ofs) {
float mu = xs[(sample_out+M + ofs) % M]/Nvar;
return mu;
}
static int getCorrDFT(int K, unsigned int pos, float *maxv, unsigned int *maxvpos, rsheader_t *rshd) {
int i;
@ -243,25 +239,47 @@ static int getCorrDFT(int K, unsigned int pos, float *maxv, unsigned int *maxvpo
float mx = 0.0;
float mx2 = 0.0;
float re_cx = 0.0;
double xnorm = 1;
double xnorm = 1.0;
unsigned int mpos = 0;
dc = 0.0;
double dc = 0.0;
rshd->dc = 0.0;
if (K + rshd->L > N_DFT) return -1;
// if (sample_out < rshd->L) return -2; // nur falls K-4 < L
if (pos == 0) pos = sample_out;
bufs = buf_fm[rshd->lpIQ];
for (i = 0; i < K+rshd->L; i++) xn[i] = bufs[(pos+M -(K+rshd->L-1) + i) % M];
while (i < N_DFT) xn[i++] = 0.0;
dft(xn, X);
dc = get_bufmu(pos-sample_out); //oder: dc = creal(X[0])/(K+rshd->L) = avg(xn) // zu lang (M10)
for (i = 0; i < N_DFT; i++) Z[i] = X[i]*rshd->Fm[i];
//dc = get_bufmu(pos-sample_out); //oder: dc = creal(X[0])/(K+rshd->L) = avg(xn) // zu lang (M10)
dc = 0.0;
if (option_dc) {
//X[0] = 0; // all samples in window
// L < K
for (i=K-rshd->L; i<K+rshd->L;i++) dc += xn[i]; // only last 2L samples (avoid M10 carrier offset)
dc /= 2.0*(float)rshd->L;
X[0] -= N_DFT*dc * 0.98;
}
rshd->dc = dc;
if (option_iq) {
// FM-lowpass(xn)
for (i = 0; i < N_DFT; i++) X[i] *= WS[rshd->lpFM][i];
}
if (option_dc || option_iq) { // mx = mx(xn[]), xn(lowpass, dc)
Nidft(X, cx);
for (i = 0; i < N_DFT; i++) xn[i] = creal(cx[i])/(float)N_DFT;
}
for (i = 0; i < N_DFT; i++) Z[i] = X[i] * rshd->Fm[i];
Nidft(Z, cx);
@ -285,13 +303,14 @@ static int getCorrDFT(int K, unsigned int pos, float *maxv, unsigned int *maxvpo
mpos = pos - (K + rshd->L-1) + mp; // t = L-1
//xnorm = sqrt(qs[(mpos + 2*M) % M]);
xnorm = 0.0; //xn[mp-t + i]
for (i = 0; i < rshd->L; i++) xnorm += bufs[(mpos-i + M) % M]*bufs[(mpos-i + M) % M];
xnorm = 0.0;
for (i = 0; i < rshd->L; i++) xnorm += xn[mp-i]*xn[mp-i];
xnorm = sqrt(xnorm);
mx /= xnorm*N_DFT;
if (option_iq) mpos -= dsp__lpFMtaps[rshd->lpFM]/2; // lowpass delay
*maxv = mx;
*maxvpos = mpos;
@ -359,53 +378,214 @@ static int read_wav_header(FILE *fp, int wav_channel) {
if (wav_channel >= 0 && wav_channel < channels) wav_ch = wav_channel;
else wav_ch = 0;
fprintf(stderr, "channel-In : %d\n", wav_ch+1);
//fprintf(stderr, "channel-In : %d\n", wav_ch+1);
if ((bits_sample != 8) && (bits_sample != 16)) return -1;
if (bits_sample != 8 && bits_sample != 16 && bits_sample != 32) return -1;
return 0;
}
static int f32read_sample(FILE *fp, float *s) {
int i;
short b = 0;
unsigned int word = 0;
short *b = (short*)&word;
float *f = (float*)&word;
for (i = 0; i < channels; i++) {
if (fread( &b, bits_sample/8, 1, fp) != 1) return EOF;
if (fread( &word, bits_sample/8, 1, fp) != 1) return EOF;
if (i == wav_ch) { // i = 0: links bzw. mono
//if (bits_sample == 8) sint = b-128; // 8bit: 00..FF, centerpoint 0x80=128
//if (bits_sample == 16) sint = (short)b;
if (bits_sample == 8) { b -= 128; }
*s = b/128.0;
if (bits_sample == 16) { *s /= 256.0; }
if (bits_sample == 32) {
*s = *f;
}
else {
if (bits_sample == 8) { *b -= 128; }
*s = *b/128.0;
if (bits_sample == 16) { *s /= 256.0; }
}
}
}
return 0;
}
static int f32read_csample(FILE *fp, float complex *z) {
if (bits_sample == 32) {
float x = 0, y = 0;
if (fread( &x, bits_sample/8, 1, fp) != 1) return EOF;
if (fread( &y, bits_sample/8, 1, fp) != 1) return EOF;
*z = x + I*y;
}
else { // bits_sample == 8,16
short a = 0, b = 0;
if (fread( &a, bits_sample/8, 1, fp) != 1) return EOF;
if (fread( &b, bits_sample/8, 1, fp) != 1) return EOF;
*z = a + I*b;
if (bits_sample == 8) { *z -= 128 + I*128; }
*z /= 128.0;
if (bits_sample == 16) { *z /= 256.0; }
}
return 0;
}
// decimation
static ui32_t dsp__sr_base;
static ui32_t dsp__dectaps;
static ui32_t dsp__sample_dec;
static int dsp__decM = 1;
static float complex *dsp__decXbuffer;
static float complex *dsp__decMbuf;
static float complex *dsp__ex; // exp_lut
static ui32_t dsp__lut_len;
static float *ws_dec;
static double dsp__xlt_fq = 0.0;
static int f32read_cblock(FILE *fp) {
int n;
int len;
len = dsp__decM;
if (bits_sample == 8) {
ui8_t u[2*dsp__decM];
len = fread( u, bits_sample/8, 2*dsp__decM, fp) / 2;
for (n = 0; n < len; n++) dsp__decMbuf[n] = (u[2*n]-128)/128.0 + I*(u[2*n+1]-128)/128.0;
}
else if (bits_sample == 16) { // bits_sample == 16
short b[2*dsp__decM];
len = fread( b, bits_sample/8, 2*dsp__decM, fp) / 2;
for (n = 0; n < len; n++) dsp__decMbuf[n] = b[2*n]/32768.0 + I*b[2*n+1]/32768.0;
}
else { // bits_sample == 32 //float32
float f[2*dsp__decM];
len = fread( f, bits_sample/8, 2*dsp__decM, fp) / 2;
for (n = 0; n < len; n++) dsp__decMbuf[n] = f[2*n] + I*f[2*n+1];
}
return len;
}
static double sinc(double x) {
double y;
if (x == 0) y = 1;
else y = sin(M_PI*x)/(M_PI*x);
return y;
}
static int lowpass_init(float f, int taps, float **pws) {
double *h, *w;
double norm = 0;
int n;
float *ws = NULL;
if (taps % 2 == 0) taps++; // odd/symmetric
if ( taps < 1 ) taps = 1;
h = (double*)calloc( taps+1, sizeof(double)); if (h == NULL) return -1;
w = (double*)calloc( taps+1, sizeof(double)); if (w == NULL) return -1;
ws = (float*)calloc( taps+1, sizeof(float)); if (ws == NULL) return -1;
for (n = 0; n < taps; n++) {
w[n] = 7938/18608.0 - 9240/18608.0*cos(2*M_PI*n/(taps-1)) + 1430/18608.0*cos(4*M_PI*n/(taps-1)); // Blackmann
h[n] = 2*f*sinc(2*f*(n-(taps-1)/2));
ws[n] = w[n]*h[n];
norm += ws[n]; // 1-norm
}
for (n = 0; n < taps; n++) {
ws[n] /= norm; // 1-norm
}
*pws = ws;
free(h); h = NULL;
free(w); w = NULL;
return taps;
}
// struct { int taps; double *ws}
static float complex lowpass(float complex buffer[], ui32_t sample, ui32_t taps, float *ws) {
ui32_t n;
double complex w = 0;
for (n = 0; n < taps; n++) {
w += buffer[(sample+n+1)%taps]*ws[taps-1-n];
}
return (float complex)w;
}
static int f32buf_sample(FILE *fp, int inv) {
float s = 0.0;
float xneu, xalt;
float _s = 0.0;
float s[3];
static float complex z0_fm0;
static float complex z0_fm1;
static float complex z0;
float complex z_fm0=0, z_fm1=0;
float complex z, w;
double gain = 0.8;
int i;
if (option_iq)
{
if (option_iq == 5) { // baseband decimation
ui32_t s_reset = dsp__dectaps*dsp__lut_len;
int j;
if ( f32read_cblock(fp) < 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];
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 (f32read_sample(fp, &s) == EOF) return EOF;
}
else if ( f32read_csample(fp, &z) == EOF ) return EOF;
if (inv) s = -s;
bufs[sample_in % M] = s - dc_ofs;
// IF-lowpass
// a) detect signal bandwidth/center-fq (not reliable), or
// b) 3 FM-streams
//
lpIQ_buf[sample_in % dsp__lpIQtaps] = z;
z_fm0 = lowpass(lpIQ_buf, sample_in, dsp__lpIQtaps, ws_lpIQ[0]);
z_fm1 = lowpass(lpIQ_buf, sample_in, dsp__lpIQtaps, ws_lpIQ[1]);
// IQ: different modulation indices h=h(rs) -> FM-demod
w = z_fm0 * conj(z0_fm0);
s[0] = gain * carg(w)/M_PI;
z0_fm0 = z_fm0;
w = z_fm1 * conj(z0_fm1);
s[1] = gain * carg(w)/M_PI;
z0_fm1 = z_fm1;
w = z * conj(z0);
s[2] = gain * carg(w)/M_PI;
z0 = z;
}
else
{
if (f32read_sample(fp, &_s) == EOF) return EOF;
for (i = 0; i < 3; i++) s[i] = _s;
}
for (i = 0; i < 3; i++) {
if (inv) s[i]= -s[i];
buf_fm[i][sample_in % M] = s[i];
}
xneu = bufs[(sample_in ) % M];
xalt = bufs[(sample_in+M - Nvar) % M];
xsum += xneu - xalt; // + xneu - xalt
xs[sample_in % M] = xsum;
/*
qsum += (xneu - xalt)*(xneu + xalt); // + xneu*xneu - xalt*xalt
qs[sample_in % M] = qsum;
*/
sample_out = sample_in - delay;
@ -414,7 +594,7 @@ static int f32buf_sample(FILE *fp, int inv) {
return 0;
}
static int read_bufbit(int symlen, char *bits, unsigned int mvp, int reset, float dc, float spb) {
static int read_bufbit(int symlen, char *bits, unsigned int mvp, int reset, float dc, rsheader_t *rshd) {
// symlen==2: manchester2 0->10,1->01->1: 2.bit
static unsigned int rcount;
@ -422,6 +602,8 @@ static int read_bufbit(int symlen, char *bits, unsigned int mvp, int reset, floa
double sum = 0.0;
bufs = buf_fm[rshd->lpIQ];
if (reset) {
rcount = 0;
rbitgrenze = 0;
@ -430,14 +612,14 @@ static int read_bufbit(int symlen, char *bits, unsigned int mvp, int reset, floa
// bei symlen=2 (Manchester) kein dc noetig,
// allerdings M10-header mit symlen=1
rbitgrenze += spb;
rbitgrenze += rshd->spb;
do {
sum += bufs[(rcount + mvp + M) % M] - dc;
rcount++;
} while (rcount < rbitgrenze); // n < spb
if (symlen == 2) {
rbitgrenze += spb;
rbitgrenze += rshd->spb;
do {
sum -= bufs[(rcount + mvp + M) % M] - dc;
rcount++;
@ -464,23 +646,26 @@ static int headcmp(int symlen, unsigned int mvp, int inv, rsheader_t *rshd) {
char sign = 0;
int len = 0;
float dc = 0.0;
/*
double dc = 0.0;
if (option_dc)
{
/*
len = rshd->L;
for (pos = 0; pos < len; pos++) {
dc += bufs[(mvp - 1 - pos + M) % M];
dc += (double)bufs[(mvp - 1 - pos + M) % M];
}
dc /= (float)len;
}
dc /= (double)len;
*/
dc = rshd->dc;
}
if (symlen != 1) step = 2;
if (inv) sign=1;
len = rshd->hLen;
for (pos = 0; pos < len; pos += step) {
read_bufbit(symlen, rawbits+pos, mvp+1-(int)(rshd->hLen*rshd->spb), pos==0, dc, rshd->spb);
read_bufbit(symlen, rawbits+pos, mvp+1-(int)(rshd->hLen*rshd->spb), pos==0, dc, rshd);
}
rawbits[pos] = '\0';
@ -540,8 +725,116 @@ static int init_buffers() {
int hLen = 0;
int Lmax = 0;
if (option_iq == 5)
{
int IF_sr = 48000; // designated IF sample rate
int decM = 1; // decimate M:1
int sr_base = sample_rate;
float f_lp; // dec_lowpass: lowpass_bw/2
float t_bw; // dec_lowpass: transition_bw
int taps; // dec_lowpass: taps
if (IF_sr > sr_base) IF_sr = sr_base;
if (IF_sr < sr_base) {
while (sr_base % IF_sr) IF_sr += 1;
decM = sr_base / IF_sr;
}
f_lp = (IF_sr+20e3)/(4.0*sr_base);
t_bw = (IF_sr-20e3)/*/2.0*/; if (t_bw < 0) t_bw = 8e3;
t_bw /= sr_base;
taps = 4.0/t_bw; if (taps%2==0) taps++;
taps = lowpass_init(f_lp, taps, &ws_dec);
if (taps < 0) return -1;
dsp__dectaps = taps;
dsp__sr_base = sr_base;
sample_rate = IF_sr; // sr_base/decM
dsp__decM = decM;
fprintf(stderr, "IF: %d\n", IF_sr);
fprintf(stderr, "dec: %d\n", decM);
}
if (option_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
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;
}
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__decXbuffer = calloc( dsp__dectaps+1, sizeof(float complex));
if (dsp__decXbuffer == NULL) return -1;
dsp__decMbuf = calloc( dsp__decM+1, sizeof(float complex));
if (dsp__decMbuf == NULL) return -1;
}
if (option_iq)
{
float f_lp; // lowpass_bw
float f_lp0, f_lp1;
int taps; // lowpass taps: 4*sr/transition_bw
// FM lowpass -> xn[] in getCorrDFT()
f_lp = 4e3/(float)sample_rate; // RS41,DFM: 4kHz (FM-audio)
taps = 4*sample_rate/2e3; if (taps%2==0) taps++; // 2kHz transition
taps = lowpass_init(f_lp, taps, &ws_lpFM[0]);
if (taps < 0) return -1;
dsp__lpFMtaps[0] = taps;
//
f_lp = 10e3/(float)sample_rate; // M10: 10kHz (FM-audio)
taps = 4*sample_rate/2e3; if (taps%2==0) taps++; // 2kHz transition
taps = lowpass_init(f_lp, taps, &ws_lpFM[1]);
if (taps < 0) return -1;
dsp__lpFMtaps[1] = taps;
// IF lowpass
taps = 4*sample_rate/4e3; if (taps%2==0) taps++; // 4kHz transition
f_lp0 = 12e3/(float)sample_rate/2.0; // RS41,DFM: 12kHz (IF/IQ)
taps = lowpass_init(f_lp0, taps, &ws_lpIQ[0]); if (taps < 0) return -1;
f_lp1 = 22e3/(float)sample_rate/2.0; // M10: 22kHz (IF/IQ)
taps = lowpass_init(f_lp1, taps, &ws_lpIQ[1]); if (taps < 0) return -1;
dsp__lpIQtaps = taps;
lpIQ_buf = calloc( dsp__lpIQtaps+3, sizeof(float complex));
if (lpIQ_buf == NULL) return -1;
}
for (j = 0; j < Nrs; j++) {
rs_hdr[j].spb = sample_rate/(float)rs_hdr[j].bps;
rs_hdr[j].spb = sample_rate/(float)rs_hdr[j].sps;
rs_hdr[j].hLen = strlen(rs_hdr[j].header);
rs_hdr[j].L = rs_hdr[j].hLen * rs_hdr[j].spb + 0.5;
if (rs_hdr[j].hLen > hLen) hLen = rs_hdr[j].hLen;
@ -567,22 +860,21 @@ static int init_buffers() {
delay = L/16;
M = N_DFT + delay + 8; // L+K < M
Nvar = Lmax; // wenn Nvar fuer xnorm, dann Nvar=rshd.L
rawbits = (char *)calloc( hLen+1, sizeof(char)); if (rawbits == NULL) return -100;
bufs = (float *)calloc( M+1, sizeof(float)); if (bufs == NULL) return -100;
xs = (float *)calloc( M+1, sizeof(float)); if (xs == NULL) return -100;
/*
qs = (float *)calloc( M+1, sizeof(float)); if (qs == NULL) return -100;
*/
for (j = 0; j < 3; j++) {
buf_fm[j] = (float *)calloc( M+1, sizeof(float)); if (buf_fm[j] == NULL) return -100;
}
bufs = buf_fm[2];
xn = calloc(N_DFT+1, sizeof(float)); if (xn == NULL) return -1;
db = calloc(N_DFT+1, sizeof(float)); if (db == NULL) return -1;
ew = calloc(LOG2N+1, sizeof(complex float)); if (ew == NULL) return -1;
X = calloc(N_DFT+1, sizeof(complex float)); if (X == NULL) return -1;
Z = calloc(N_DFT+1, sizeof(complex float)); if (Z == NULL) return -1;
cx = calloc(N_DFT+1, sizeof(complex float)); if (cx == NULL) return -1;
ew = calloc(LOG2N+1, sizeof(float complex)); if (ew == NULL) return -1;
X = calloc(N_DFT+1, sizeof(float complex)); if (X == NULL) return -1;
Z = calloc(N_DFT+1, sizeof(float complex)); if (Z == NULL) return -1;
cx = calloc(N_DFT+1, sizeof(float complex)); if (cx == NULL) return -1;
for (n = 0; n < LOG2N; n++) {
k = 1 << n;
@ -595,7 +887,7 @@ static int init_buffers() {
for (j = 0; j < Nrs-1; j++)
{
rs_hdr[j].Fm = (float complex *)calloc(N_DFT+1, sizeof(complex float)); if (rs_hdr[j].Fm == NULL) return -1;
rs_hdr[j].Fm = (float complex *)calloc(N_DFT+1, sizeof(float complex)); if (rs_hdr[j].Fm == NULL) return -1;
bits = rs_hdr[j].header;
spb = rs_hdr[j].spb;
sigma = sqrt(log(2)) / (2*M_PI*rs_hdr[j].BT);
@ -633,6 +925,18 @@ static int init_buffers() {
}
if (option_iq)
{
for (j = 0; j < 2; j++) {
WS[j] = (float complex *)calloc(N_DFT+1, sizeof(float complex)); if (WS[j] == NULL) return -1;
for (i = 0; i < dsp__lpFMtaps[j]; i++) m[i] = ws_lpFM[j][i];
while (i < N_DFT) m[i++] = 0.0;
dft(m, WS[j]);
}
Y = (float complex *)calloc(N_DFT+1, sizeof(float complex)); if (Y == NULL) return -1;
}
free(match); match = NULL;
free(m); m = NULL;
@ -642,11 +946,10 @@ static int init_buffers() {
static int free_buffers() {
int j;
if (bufs) { free(bufs); bufs = NULL; }
if (xs) { free(xs); xs = NULL; }
/*
if (qs) { free(qs); qs = NULL; }
*/
for (j = 0; j < 3; j++) {
if (buf_fm[j]) { free(buf_fm[j]); buf_fm[j] = NULL; }
}
if (rawbits) { free(rawbits); rawbits = NULL; }
if (xn) { free(xn); xn = NULL; }
@ -660,6 +963,33 @@ static int free_buffers() {
if (rs_hdr[j].Fm) { free(rs_hdr[j].Fm); rs_hdr[j].Fm = NULL; }
}
// iq buffers
if (option_iq == 5)
{
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 (option_iq) {
for (j = 0; j < 2; j++) {
if (ws_lpFM[j]) { free(ws_lpFM[j]); ws_lpFM[j] = NULL; }
if (WS[j]) { free(WS[j]); WS[j] = NULL; }
}
if (Y) { free(Y); Y = NULL; }
if (iq_buf) { free(iq_buf); iq_buf = NULL; }
for (j = 0; j < 1; j++) {
if (ws_lpIQ[j]) { free(ws_lpIQ[j]); ws_lpIQ[j] = NULL; }
}
if (lpIQ_buf) { free(lpIQ_buf); lpIQ_buf = NULL; }
}
return 0;
}
@ -702,7 +1032,18 @@ int main(int argc, char **argv) {
else if ( (strcmp(*argv, "-v") == 0) || (strcmp(*argv, "--verbose") == 0) ) {
option_verbose = 1;
}
//else if ( (strcmp(*argv, "--dc") == 0) ) { option_dc = 1; }
else if ( (strcmp(*argv, "--iq") == 0) ) { option_iq = 1; }
else if (strcmp(*argv, "--IQ") == 0) { // fq baseband -> IF (rotate from and decimate)
double fq = 0.0; // --IQ <fq> , -0.5 < fq < 0.5
++argv;
if (*argv) fq = atof(*argv);
else return -1;
if (fq < -0.5) fq = -0.5;
if (fq > 0.5) fq = 0.5;
dsp__xlt_fq = -fq; // S(t) -> S(t)*exp(-f*2pi*I*t)
option_iq = 5;
}
else if ( (strcmp(*argv, "--dc") == 0) ) { option_dc = 1; }
else if ( (strcmp(*argv, "-s") == 0) || (strcmp(*argv, "--silent") == 0) ) {
option_silent = 1;
}
@ -723,9 +1064,6 @@ int main(int argc, char **argv) {
}
else return -50;
}
else if ( (strcmp(*argv, "--debug") == 0) ) {
option_debug = 1;
}
else {
fp = fopen(*argv, "rb");
if (fp == NULL) {
@ -746,6 +1084,10 @@ int main(int argc, char **argv) {
return -50;
}
if (option_iq && channels < 2) {
fprintf(stderr, "error: iq channels < 2\n");
return -50;
}
K = init_buffers();
if ( K < 0 ) {
@ -811,7 +1153,7 @@ int main(int argc, char **argv) {
if (f32buf_sample(fp, option_inv) == EOF) break;//goto ende;
xn[n % D] = bufs[sample_out % M];
xn[n % D] = buf_fm[rs_hdr[j].lpIQ][sample_out % M];
n++;
if (n % D == 0) {
@ -836,12 +1178,18 @@ int main(int argc, char **argv) {
mv[j] = fabs(mv[j]);
if (pow2200 > pow2400) { // IMET1RS
mv[idxRS] = mv[j];
mv[j] = 0; // IMET1 -> IMET1RS
mv_pos[idxRS] = mv_pos[j];
j = idxRS;
header_found = 1;
if (pow2200 > pow2400) { // IMET1RS: peak1: 1200Hz > peak2: 2200Hz > pow(800Hz)
int bin800 = freq2bin(800);
float pow800 = 0.0;
for (n = 0; n < m; n++) pow800 += db[ bin800 - m/4 + n ];
if (pow2200 > pow800) {
mv[idxRS] = mv[j];
mv[j] = 0; // IMET1 -> IMET1RS
mv_pos[idxRS] = mv_pos[j];
j = idxRS;
header_found = 1;
}
else mv[j] = 0.0;
}
else { // IMET1AB
mv[j] = 0;
@ -880,7 +1228,7 @@ int main(int argc, char **argv) {
}
if (header_found) {
if (!option_silent) {
if (!option_silent && (mv[j] > rs_hdr[j].thres || mv[j] < -rs_hdr[j].thres)) {
if (option_verbose) fprintf(stdout, "sample: %d\n", mv_pos[j]);
fprintf(stdout, "%s: %.4f\n", rs_hdr[j].type, mv[j]);
}