kopia lustrzana https://github.com/xaelsouth/rtl-wmbus
split signal processing chains
rodzic
70706c4c53
commit
7759518240
4
Makefile
4
Makefile
|
@ -14,7 +14,7 @@ $(shell $(MKDIR) -p $(OUTDIR))
|
||||||
|
|
||||||
# Create a version number based on the latest git tag.
|
# Create a version number based on the latest git tag.
|
||||||
COMMIT_HASH?=$(shell git log --pretty=format:'%H' -n 1)
|
COMMIT_HASH?=$(shell git log --pretty=format:'%H' -n 1)
|
||||||
TAG?=$(shell git describe --tags)
|
TAG?=$(shell git describe --tags --always)
|
||||||
BRANCH?=$(shell git rev-parse --abbrev-ref HEAD)
|
BRANCH?=$(shell git rev-parse --abbrev-ref HEAD)
|
||||||
CHANGES?=$(shell git status -s | grep -v '?? ')
|
CHANGES?=$(shell git status -s | grep -v '?? ')
|
||||||
|
|
||||||
|
@ -62,7 +62,7 @@ pi1:
|
||||||
rebuild: clean all
|
rebuild: clean all
|
||||||
|
|
||||||
install: release
|
install: release
|
||||||
cp $(OUTFILE) /usr/bin
|
cp -f $(OUTFILE) /usr/bin
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
$(RM) -rf "$(OUTDIR)"
|
$(RM) -rf "$(OUTDIR)"
|
||||||
|
|
Plik binarny nie jest wyświetlany.
Plik binarny nie jest wyświetlany.
366
rtl_wmbus.c
366
rtl_wmbus.c
|
@ -55,6 +55,14 @@
|
||||||
#include "net_support.h"
|
#include "net_support.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef TIME2_ALGORITHM_ENABLED
|
||||||
|
#define TIME2_ALGORITHM_ENABLED 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef RUN_LENGTH_ALGORITHM_ENABLED
|
||||||
|
#define RUN_LENGTH_ALGORITHM_ENABLED 1
|
||||||
|
#endif
|
||||||
|
|
||||||
static const uint32_t ACCESS_CODE_T1_C1 = 0b0101010101010000111101u;
|
static const uint32_t ACCESS_CODE_T1_C1 = 0b0101010101010000111101u;
|
||||||
static const uint32_t ACCESS_CODE_T1_C1_BITMASK = 0x3FFFFFu;
|
static const uint32_t ACCESS_CODE_T1_C1_BITMASK = 0x3FFFFFu;
|
||||||
static const unsigned ACCESS_CODE_T1_C1_ERRORS = 1u; // 0 if no errors allowed
|
static const unsigned ACCESS_CODE_T1_C1_ERRORS = 1u; // 0 if no errors allowed
|
||||||
|
@ -786,11 +794,13 @@ static void time2_algorithm_s1(unsigned bit, unsigned rssi, struct time2_algorit
|
||||||
|
|
||||||
|
|
||||||
static int opts_run_length_algorithm_enabled = 1;
|
static int opts_run_length_algorithm_enabled = 1;
|
||||||
static int opts_time2_algorithm_enabled = 1;
|
static int opts_time2_algorithm_enabled = TIME2_ALGORITHM_ENABLED;
|
||||||
static unsigned opts_decimation_rate = 2u;
|
static unsigned opts_decimation_rate = 2u;
|
||||||
static int opts_s1_t1_c1_simultaneously = 0;
|
static int opts_s1_t1_c1_simultaneously = 0;
|
||||||
static int opts_accurate_atan = 1;
|
static int opts_accurate_atan = 1;
|
||||||
int opts_show_used_algorithm = 0;
|
int opts_show_used_algorithm = 0;
|
||||||
|
static int opts_t1_c1_processing_enabled = 1;
|
||||||
|
static int opts_s1_processing_enabled = 1;
|
||||||
static const unsigned opts_CLOCK_LOCK_THRESHOLD_T1_C1 = 2; // Is not implemented as option yet.
|
static const unsigned opts_CLOCK_LOCK_THRESHOLD_T1_C1 = 2; // Is not implemented as option yet.
|
||||||
static const unsigned opts_CLOCK_LOCK_THRESHOLD_S1 = 2; // Is not implemented as option yet.
|
static const unsigned opts_CLOCK_LOCK_THRESHOLD_S1 = 2; // Is not implemented as option yet.
|
||||||
|
|
||||||
|
@ -806,6 +816,7 @@ static void print_usage(const char *program_name)
|
||||||
fprintf(stdout, "\t-v show used algorithm in the output\n");
|
fprintf(stdout, "\t-v show used algorithm in the output\n");
|
||||||
fprintf(stdout, "\t-V show version\n");
|
fprintf(stdout, "\t-V show version\n");
|
||||||
fprintf(stdout, "\t-s receive S1 and T1/C1 datagrams simultaneously. rtl_sdr _MUST_ be set to 868.625MHz (-f 868.625M)\n");
|
fprintf(stdout, "\t-s receive S1 and T1/C1 datagrams simultaneously. rtl_sdr _MUST_ be set to 868.625MHz (-f 868.625M)\n");
|
||||||
|
fprintf(stdout, "\t-p [T,S] to disable processing T1/C1 or S1 mode.\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void print_version(void)
|
static void print_version(void)
|
||||||
|
@ -818,13 +829,28 @@ static void process_options(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
int option;
|
int option;
|
||||||
|
|
||||||
while ((option = getopt(argc, argv, "ad:r:vVst:")) != -1)
|
while ((option = getopt(argc, argv, "ad:p:r:vVst:")) != -1)
|
||||||
{
|
{
|
||||||
switch (option)
|
switch (option)
|
||||||
{
|
{
|
||||||
case 'a':
|
case 'a':
|
||||||
opts_accurate_atan = 0;
|
opts_accurate_atan = 0;
|
||||||
break;
|
break;
|
||||||
|
case 'p':
|
||||||
|
if (strcmp(optarg, "T") == 0 || strcmp(optarg, "t") == 0)
|
||||||
|
{
|
||||||
|
opts_t1_c1_processing_enabled = 0;
|
||||||
|
}
|
||||||
|
else if (strcmp(optarg, "S") == 0 || strcmp(optarg, "s") == 0)
|
||||||
|
{
|
||||||
|
opts_s1_processing_enabled = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
print_usage(argv[0]);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
break;
|
||||||
case 'r':
|
case 'r':
|
||||||
if (strcmp(optarg, "0") == 0)
|
if (strcmp(optarg, "0") == 0)
|
||||||
{
|
{
|
||||||
|
@ -931,6 +957,190 @@ static void shift_freq_plus_minus325(float *iplus, float *qplus, float *iminus,
|
||||||
*qminus = qx - iz;
|
*qminus = qx - iz;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef void (*t1_c1_signal_chain_prototype)(float i_t1_c1, float q_t1_c1,
|
||||||
|
struct time2_algorithm_t1_c1 *t2_algo_t1_c1,
|
||||||
|
struct runlength_algorithm_t1_c1 *rl_algo_t1_c1,
|
||||||
|
float (*polar_discriminator_t1_c1_function)(float i, float q));
|
||||||
|
|
||||||
|
void t1_c1_signal_chain(float i_t1_c1, float q_t1_c1,
|
||||||
|
struct time2_algorithm_t1_c1 *t2_algo_t1_c1,
|
||||||
|
struct runlength_algorithm_t1_c1 *rl_algo_t1_c1,
|
||||||
|
float (*polar_discriminator_t1_c1_function)(float i, float q))
|
||||||
|
{
|
||||||
|
static int16_t old_clock_t1_c1 = INT16_MIN;
|
||||||
|
static unsigned clock_lock_t1_c1 = 0;
|
||||||
|
|
||||||
|
// Demodulate.
|
||||||
|
const float _delta_phi_t1_c1 = polar_discriminator_t1_c1_function(i_t1_c1, q_t1_c1);
|
||||||
|
//int16_t demodulated_signal = (INT16_MAX-1)*delta_phi;
|
||||||
|
//fwrite(&demodulated_signal, sizeof(demodulated_signal), 1, demod_out);
|
||||||
|
|
||||||
|
// Post-filtering to prevent bit errors because of signal jitter.
|
||||||
|
const float delta_phi_t1_c1 = lp_fir_butter_800kHz_100kHz_160kHz(_delta_phi_t1_c1);
|
||||||
|
//const float delta_phi_t1_c1 = equalizer_t1_c1(_delta_phi_t1_c1, _delta_phi_t1_c1 >= 0.f ? 1.f : -1.f);
|
||||||
|
//const float delta_phi_s1 = equalizer_s1(_delta_phi_s1, _delta_phi_s1 >= 0.f ? 1.f : -1.f);
|
||||||
|
//int16_t demodulated_signal = (INT16_MAX-1)*delta_phi;
|
||||||
|
//fwrite(&demodulated_signal, sizeof(demodulated_signal), 1, demod_out2);
|
||||||
|
|
||||||
|
// Get the bit!
|
||||||
|
unsigned bit_t1_c1 = (delta_phi_t1_c1 >= 0) ? (1u<<PACKET_DATABIT_SHIFT) : (0u<<PACKET_DATABIT_SHIFT);
|
||||||
|
//int16_t u = bit ? (INT16_MAX-1) : 0;
|
||||||
|
//fwrite(&u, sizeof(u), 1, rawbits_out);
|
||||||
|
|
||||||
|
// --- rssi filtering section begin ---
|
||||||
|
// We are using one simple filter to rssi value in order to
|
||||||
|
// prevent unexpected "splashes" in signal power.
|
||||||
|
float rssi_t1_c1 = sqrtf(i_t1_c1*i_t1_c1 + q_t1_c1*q_t1_c1);
|
||||||
|
rssi_t1_c1 = rssi_filter_t1_c1(rssi_t1_c1); // comment out, if rssi filtering is unwanted
|
||||||
|
// --- rssi filtering section end ---
|
||||||
|
|
||||||
|
// --- runlength algorithm section begin ---
|
||||||
|
#if RUN_LENGTH_ALGORITHM_ENABLED
|
||||||
|
if (opts_run_length_algorithm_enabled)
|
||||||
|
{
|
||||||
|
runlength_algorithm_t1_c1(bit_t1_c1, rssi_t1_c1, rl_algo_t1_c1);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
// --- runlength algorithm section end ---
|
||||||
|
|
||||||
|
|
||||||
|
// --- time2 algorithm section begin ---
|
||||||
|
#if TIME2_ALGORITHM_ENABLED
|
||||||
|
if (opts_time2_algorithm_enabled)
|
||||||
|
{
|
||||||
|
// --- clock recovery section begin ---
|
||||||
|
// The time-2 method is implemented: push squared signal through a bandpass
|
||||||
|
// tuned close to the symbol rate. Saturating band-pass output produces a
|
||||||
|
// rectangular pulses with the required timing information.
|
||||||
|
// Clock-Signal is crossing zero in half period.
|
||||||
|
const int16_t clock_t1_c1 = (bp_iir_cheb1_800kHz_90kHz_98kHz_102kHz_110kHz(delta_phi_t1_c1 * delta_phi_t1_c1) >= 0) ? INT16_MAX : INT16_MIN;
|
||||||
|
//fwrite(&clock, sizeof(clock), 1, clock_out);
|
||||||
|
|
||||||
|
if (clock_t1_c1 > old_clock_t1_c1)
|
||||||
|
{ // Clock signal rising edge detected.
|
||||||
|
clock_lock_t1_c1 = 1;
|
||||||
|
}
|
||||||
|
else if (clock_t1_c1 == INT16_MAX)
|
||||||
|
{ // Clock signal is still high.
|
||||||
|
if (clock_lock_t1_c1 < opts_CLOCK_LOCK_THRESHOLD_T1_C1)
|
||||||
|
{ // Skip up to (opts_CLOCK_LOCK_THRESHOLD_T1_C1 - 1) clock bits
|
||||||
|
// to get closer to the middle of the data bit.
|
||||||
|
clock_lock_t1_c1++;
|
||||||
|
}
|
||||||
|
else if (clock_lock_t1_c1 == opts_CLOCK_LOCK_THRESHOLD_T1_C1)
|
||||||
|
{ // Sample data bit at CLOCK_LOCK_THRESHOLD_T1_C1 clock bit position.
|
||||||
|
clock_lock_t1_c1++;
|
||||||
|
time2_algorithm_t1_c1(bit_t1_c1, rssi_t1_c1, t2_algo_t1_c1);
|
||||||
|
//int16_t u = bit ? (INT16_MAX-1) : 0;
|
||||||
|
//fwrite(&u, sizeof(u), 1, bits_out);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
old_clock_t1_c1 = clock_t1_c1;
|
||||||
|
// --- clock recovery section end ---
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
// --- time2 algorithm section end ---
|
||||||
|
}
|
||||||
|
|
||||||
|
void t1_c1_signal_chain_empty(float i_t1_c1, float q_t1_c1,
|
||||||
|
struct time2_algorithm_t1_c1 *t2_algo_t1_c1,
|
||||||
|
struct runlength_algorithm_t1_c1 *rl_algo_t1_c1,
|
||||||
|
float (*polar_discriminator_t1_c1_function)(float i, float q))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef void (*s1_signal_chain_prototype)(float i_s1, float q_s1,
|
||||||
|
struct time2_algorithm_s1 *t2_algo_s1,
|
||||||
|
struct runlength_algorithm_s1 *rl_algo_s1,
|
||||||
|
float (*polar_discriminator_s1_function)(float i, float q));
|
||||||
|
|
||||||
|
void s1_signal_chain(float i_s1, float q_s1,
|
||||||
|
struct time2_algorithm_s1 *t2_algo_s1,
|
||||||
|
struct runlength_algorithm_s1 *rl_algo_s1,
|
||||||
|
float (*polar_discriminator_s1_function)(float i, float q))
|
||||||
|
{
|
||||||
|
static int16_t old_clock_s1 = INT16_MIN;
|
||||||
|
static unsigned clock_lock_s1 = 0;
|
||||||
|
|
||||||
|
// Demodulate.
|
||||||
|
const float _delta_phi_s1 = polar_discriminator_s1_function(i_s1, q_s1);
|
||||||
|
//int16_t demodulated_signal = (INT16_MAX-1)*delta_phi;
|
||||||
|
//fwrite(&demodulated_signal, sizeof(demodulated_signal), 1, demod_out);
|
||||||
|
|
||||||
|
// Post-filtering to prevent bit errors because of signal jitter.
|
||||||
|
const float delta_phi_s1 = lp_fir_butter_800kHz_32kHz_36kHz(_delta_phi_s1);
|
||||||
|
//const float delta_phi_t1_c1 = equalizer_t1_c1(_delta_phi_t1_c1, _delta_phi_t1_c1 >= 0.f ? 1.f : -1.f);
|
||||||
|
//const float delta_phi_s1 = equalizer_s1(_delta_phi_s1, _delta_phi_s1 >= 0.f ? 1.f : -1.f);
|
||||||
|
//int16_t demodulated_signal = (INT16_MAX-1)*delta_phi;
|
||||||
|
//fwrite(&demodulated_signal, sizeof(demodulated_signal), 1, demod_out2);
|
||||||
|
|
||||||
|
// Get the bit!
|
||||||
|
unsigned bit_s1 = (delta_phi_s1 >= 0) ? (1u<<PACKET_DATABIT_SHIFT) : (0u<<PACKET_DATABIT_SHIFT);
|
||||||
|
//int16_t u = bit ? (INT16_MAX-1) : 0;
|
||||||
|
//fwrite(&u, sizeof(u), 1, rawbits_out);
|
||||||
|
|
||||||
|
// --- rssi filtering section begin ---
|
||||||
|
// We are using one simple filter to rssi value in order to
|
||||||
|
// prevent unexpected "splashes" in signal power.
|
||||||
|
float rssi_s1 = sqrtf(i_s1*i_s1 + q_s1*q_s1);
|
||||||
|
rssi_s1 = rssi_filter_s1(rssi_s1); // comment out, if rssi filtering is unwanted
|
||||||
|
// --- rssi filtering section end ---
|
||||||
|
|
||||||
|
// --- runlength algorithm section begin ---
|
||||||
|
#if RUN_LENGTH_ALGORITHM_ENABLED
|
||||||
|
if (opts_run_length_algorithm_enabled)
|
||||||
|
{
|
||||||
|
runlength_algorithm_s1(bit_s1, rssi_s1, rl_algo_s1);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
// --- runlength algorithm section end ---
|
||||||
|
|
||||||
|
|
||||||
|
// --- time2 algorithm section begin ---
|
||||||
|
#if TIME2_ALGORITHM_ENABLED
|
||||||
|
if (opts_time2_algorithm_enabled)
|
||||||
|
{
|
||||||
|
// --- clock recovery section begin ---
|
||||||
|
// The time-2 method is implemented: push squared signal through a bandpass
|
||||||
|
// tuned close to the symbol rate. Saturating band-pass output produces a
|
||||||
|
// rectangular pulses with the required timing information.
|
||||||
|
// Clock-Signal is crossing zero in half period.
|
||||||
|
const int16_t clock_s1 = (bp_iir_cheb1_800kHz_22kHz_30kHz_34kHz_42kHz(delta_phi_s1 * delta_phi_s1) >= 0) ? INT16_MAX : INT16_MIN;
|
||||||
|
//fwrite(&clock, sizeof(clock), 1, clock_out);
|
||||||
|
|
||||||
|
if (clock_s1 > old_clock_s1)
|
||||||
|
{ // Clock signal rising edge detected.
|
||||||
|
clock_lock_s1 = 1;
|
||||||
|
}
|
||||||
|
else if (clock_s1 == INT16_MAX)
|
||||||
|
{ // Clock signal is still high.
|
||||||
|
if (clock_lock_s1 < opts_CLOCK_LOCK_THRESHOLD_S1)
|
||||||
|
{ // Skip up to (opts_CLOCK_LOCK_THRESHOLD_S1 - 1) clock bits
|
||||||
|
// to get closer to the middle of the data bit.
|
||||||
|
clock_lock_s1++;
|
||||||
|
}
|
||||||
|
else if (clock_lock_s1 == opts_CLOCK_LOCK_THRESHOLD_S1)
|
||||||
|
{ // Sample data bit at CLOCK_LOCK_THRESHOLD_S1 clock bit position.
|
||||||
|
clock_lock_s1++;
|
||||||
|
time2_algorithm_s1(bit_s1, rssi_s1, t2_algo_s1);
|
||||||
|
//int16_t u = bit ? (INT16_MAX-1) : 0;
|
||||||
|
//fwrite(&u, sizeof(u), 1, bits_out);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
old_clock_s1 = clock_s1;
|
||||||
|
// --- clock recovery section end ---
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
// --- time2 algorithm section end ---
|
||||||
|
}
|
||||||
|
|
||||||
|
void s1_signal_chain_empty(float i_s1, float q_s1,
|
||||||
|
struct time2_algorithm_s1 *t2_algo_s1,
|
||||||
|
struct runlength_algorithm_s1 *rl_algo_s1,
|
||||||
|
float (*polar_discriminator_s1_function)(float i, float q))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
#if WINDOWS_BUILD == 1
|
#if WINDOWS_BUILD == 1
|
||||||
|
@ -943,9 +1153,9 @@ int main(int argc, char *argv[])
|
||||||
const int fs_kHz = opts_decimation_rate*800; // Sample rate [kHz] as a multiple of 800 kHz.
|
const int fs_kHz = opts_decimation_rate*800; // Sample rate [kHz] as a multiple of 800 kHz.
|
||||||
float i_t1_c1, q_t1_c1;
|
float i_t1_c1, q_t1_c1;
|
||||||
float i_s1, q_s1;
|
float i_s1, q_s1;
|
||||||
|
|
||||||
|
|
||||||
unsigned decimation_rate_index = 0;
|
unsigned decimation_rate_index = 0;
|
||||||
int16_t old_clock_t1_c1 = INT16_MIN, old_clock_s1 = INT16_MIN;
|
|
||||||
unsigned clock_lock_t1_c1 = 0, clock_lock_s1 = 0;
|
|
||||||
|
|
||||||
struct time2_algorithm_t1_c1 t2_algo_t1_c1;
|
struct time2_algorithm_t1_c1 t2_algo_t1_c1;
|
||||||
time2_algorithm_t1_c1_reset(&t2_algo_t1_c1);
|
time2_algorithm_t1_c1_reset(&t2_algo_t1_c1);
|
||||||
|
@ -959,6 +1169,9 @@ int main(int argc, char *argv[])
|
||||||
struct runlength_algorithm_s1 rl_algo_s1;
|
struct runlength_algorithm_s1 rl_algo_s1;
|
||||||
runlength_algorithm_reset_s1(&rl_algo_s1);
|
runlength_algorithm_reset_s1(&rl_algo_s1);
|
||||||
|
|
||||||
|
t1_c1_signal_chain_prototype process_t1_c1_chain = opts_t1_c1_processing_enabled ? t1_c1_signal_chain: t1_c1_signal_chain_empty;
|
||||||
|
s1_signal_chain_prototype process_s1_chain = opts_s1_processing_enabled ? s1_signal_chain : s1_signal_chain_empty;
|
||||||
|
|
||||||
float (*polar_discriminator_t1_c1_function)(float i, float q) = opts_accurate_atan ? polar_discriminator_t1_c1 : polar_discriminator_t1_c1_inaccurate;
|
float (*polar_discriminator_t1_c1_function)(float i, float q) = opts_accurate_atan ? polar_discriminator_t1_c1 : polar_discriminator_t1_c1_inaccurate;
|
||||||
float (*polar_discriminator_s1_function)(float i, float q) = opts_accurate_atan ? polar_discriminator_s1 : polar_discriminator_s1_inaccurate;
|
float (*polar_discriminator_s1_function)(float i, float q) = opts_accurate_atan ? polar_discriminator_s1 : polar_discriminator_s1_inaccurate;
|
||||||
|
|
||||||
|
@ -995,8 +1208,8 @@ int main(int argc, char *argv[])
|
||||||
|
|
||||||
for (size_t k = 0; k < sizeof(samples)/sizeof(samples[0]); k += 2) // +2 : i and q interleaved
|
for (size_t k = 0; k < sizeof(samples)/sizeof(samples[0]); k += 2) // +2 : i and q interleaved
|
||||||
{
|
{
|
||||||
const float i_unfilt = ((float)samples[k] - 127.5f);
|
const float i_unfilt = ((float)(samples[k]) - 127.5f);
|
||||||
const float q_unfilt = ((float)samples[k + 1] - 127.5f);
|
const float q_unfilt = ((float)(samples[k + 1]) - 127.5f);
|
||||||
|
|
||||||
// rtl_sdr -f 868.35M -s 2400000 - 2>/dev/null | build/rtl_wmbus -d 3
|
// rtl_sdr -f 868.35M -s 2400000 - 2>/dev/null | build/rtl_wmbus -d 3
|
||||||
//shift_freq(&i_unfilt, &q_unfilt, 600, 2400);
|
//shift_freq(&i_unfilt, &q_unfilt, 600, 2400);
|
||||||
|
@ -1015,145 +1228,30 @@ int main(int argc, char *argv[])
|
||||||
|
|
||||||
// Low-Pass-Filtering before decimation is necessary, to ensure
|
// Low-Pass-Filtering before decimation is necessary, to ensure
|
||||||
// that i and q signals don't contain frequencies above new sample
|
// that i and q signals don't contain frequencies above new sample
|
||||||
// rate.
|
// rate. Moving average can be viewed as a low pass filter.
|
||||||
// The sample rate decimation is realised as sum over i and q,
|
|
||||||
// which must not be divided by decimation factor before
|
|
||||||
// demodulating (atan2(q,i)).
|
|
||||||
#if 0
|
|
||||||
i_t1_c1 = lp_fir_butter_1600kHz_160kHz_200kHz_t1_c1(i_t1_c1_unfilt, 0);
|
|
||||||
q_t1_c1 = lp_fir_butter_1600kHz_160kHz_200kHz_t1_c1(q_t1_c1_unfilt, 1);
|
|
||||||
|
|
||||||
i_s1 = lp_fir_butter_1600kHz_160kHz_200kHz_s1(i_s1_unfilt, 0);
|
|
||||||
q_s1 = lp_fir_butter_1600kHz_160kHz_200kHz_s1(q_s1_unfilt, 1);
|
|
||||||
#elif 0
|
|
||||||
i = lp_ppf_butter_1600kHz_160kHz_200kHz(i_unfilt, 0);
|
|
||||||
q = lp_ppf_butter_1600kHz_160kHz_200kHz(q_unfilt, 1);
|
|
||||||
#elif 0
|
|
||||||
i = lp_firfp_butter_1600kHz_160kHz_200kHz(i_unfilt, 0);
|
|
||||||
q = lp_firfp_butter_1600kHz_160kHz_200kHz(q_unfilt, 1);
|
|
||||||
#elif 0
|
|
||||||
i = lp_ppffp_butter_1600kHz_160kHz_200kHz(i_unfilt, 0);
|
|
||||||
q = lp_ppffp_butter_1600kHz_160kHz_200kHz(q_unfilt, 1);
|
|
||||||
#else
|
|
||||||
// Moving average can be viewed as a low pass filter.
|
|
||||||
|
|
||||||
i_t1_c1 = moving_average_t1_c1(i_t1_c1_unfilt, 0);
|
i_t1_c1 = moving_average_t1_c1(i_t1_c1_unfilt, 0);
|
||||||
q_t1_c1 = moving_average_t1_c1(q_t1_c1_unfilt, 1);
|
q_t1_c1 = moving_average_t1_c1(q_t1_c1_unfilt, 1);
|
||||||
|
|
||||||
i_s1 = moving_average_s1(i_s1_unfilt, 0);
|
|
||||||
q_s1 = moving_average_s1(q_s1_unfilt, 1);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
equalizer_complex_t1_c1(&i_t1_c1, &q_t1_c1);
|
equalizer_complex_t1_c1(&i_t1_c1, &q_t1_c1);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Low-Pass-Filtering before decimation is necessary, to ensure
|
||||||
|
// that i and q signals don't contain frequencies above new sample
|
||||||
|
// rate. Moving average can be viewed as a low pass filter.
|
||||||
|
i_s1 = moving_average_s1(i_s1_unfilt, 0);
|
||||||
|
q_s1 = moving_average_s1(q_s1_unfilt, 1);
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
equalizer_complex_s1(&i_s1, &q_s1); // FIXME: Function does not exist.
|
||||||
|
#endif
|
||||||
|
|
||||||
++decimation_rate_index;
|
++decimation_rate_index;
|
||||||
if (decimation_rate_index < opts_decimation_rate) continue;
|
if (decimation_rate_index < opts_decimation_rate) continue;
|
||||||
decimation_rate_index = 0;
|
decimation_rate_index = 0;
|
||||||
|
|
||||||
// Demodulate.
|
process_t1_c1_chain(i_t1_c1, q_t1_c1, &t2_algo_t1_c1, &rl_algo_t1_c1, polar_discriminator_t1_c1_function);
|
||||||
const float _delta_phi_t1_c1 = polar_discriminator_t1_c1_function(i_t1_c1, q_t1_c1);
|
process_s1_chain(i_s1, q_s1, &t2_algo_s1, &rl_algo_s1, polar_discriminator_s1_function);
|
||||||
const float _delta_phi_s1 = polar_discriminator_s1_function(i_s1, q_s1);
|
|
||||||
//int16_t demodulated_signal = (INT16_MAX-1)*delta_phi;
|
|
||||||
//fwrite(&demodulated_signal, sizeof(demodulated_signal), 1, demod_out);
|
|
||||||
|
|
||||||
// Post-filtering to prevent bit errors because of signal jitter.
|
|
||||||
const float delta_phi_t1_c1 = lp_fir_butter_800kHz_100kHz_160kHz(_delta_phi_t1_c1);
|
|
||||||
const float delta_phi_s1 = lp_fir_butter_800kHz_32kHz_36kHz(_delta_phi_s1);
|
|
||||||
//const float delta_phi_t1_c1 = equalizer_t1_c1(_delta_phi_t1_c1, _delta_phi_t1_c1 >= 0.f ? 1.f : -1.f);
|
|
||||||
//const float delta_phi_s1 = equalizer_s1(_delta_phi_s1, _delta_phi_s1 >= 0.f ? 1.f : -1.f);
|
|
||||||
//int16_t demodulated_signal = (INT16_MAX-1)*delta_phi;
|
|
||||||
//fwrite(&demodulated_signal, sizeof(demodulated_signal), 1, demod_out2);
|
|
||||||
|
|
||||||
// Get the bit!
|
|
||||||
unsigned bit_t1_c1 = (delta_phi_t1_c1 >= 0) ? (1u<<PACKET_DATABIT_SHIFT) : (0u<<PACKET_DATABIT_SHIFT);
|
|
||||||
unsigned bit_s1 = (delta_phi_s1 >= 0) ? (1u<<PACKET_DATABIT_SHIFT) : (0u<<PACKET_DATABIT_SHIFT);
|
|
||||||
//int16_t u = bit ? (INT16_MAX-1) : 0;
|
|
||||||
//fwrite(&u, sizeof(u), 1, rawbits_out);
|
|
||||||
|
|
||||||
|
|
||||||
// --- rssi filtering section begin ---
|
|
||||||
// We are using one simple filter to rssi value in order to
|
|
||||||
// prevent unexpected "splashes" in signal power.
|
|
||||||
float rssi_t1_c1 = sqrtf(i_t1_c1*i_t1_c1 + q_t1_c1*q_t1_c1);
|
|
||||||
rssi_t1_c1 = rssi_filter_t1_c1(rssi_t1_c1); // comment out, if rssi filtering is unwanted
|
|
||||||
|
|
||||||
float rssi_s1 = sqrtf(i_s1*i_s1 + q_s1*q_s1);
|
|
||||||
rssi_s1 = rssi_filter_s1(rssi_s1); // comment out, if rssi filtering is unwanted
|
|
||||||
// --- rssi filtering section end ---
|
|
||||||
|
|
||||||
|
|
||||||
// --- runlength algorithm section begin ---
|
|
||||||
#if 1
|
|
||||||
if (opts_run_length_algorithm_enabled)
|
|
||||||
{
|
|
||||||
runlength_algorithm_t1_c1(bit_t1_c1, rssi_t1_c1, &rl_algo_t1_c1);
|
|
||||||
|
|
||||||
runlength_algorithm_s1(bit_s1, rssi_s1, &rl_algo_s1);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
// --- runlength algorithm section end ---
|
|
||||||
|
|
||||||
|
|
||||||
// --- time2 algorithm section begin ---
|
|
||||||
#if 1
|
|
||||||
if (opts_time2_algorithm_enabled)
|
|
||||||
{
|
|
||||||
// --- clock recovery section begin ---
|
|
||||||
// The time-2 method is implemented: push squared signal through a bandpass
|
|
||||||
// tuned close to the symbol rate. Saturating band-pass output produces a
|
|
||||||
// rectangular pulses with the required timing information.
|
|
||||||
// Clock-Signal is crossing zero in half period.
|
|
||||||
const int16_t clock_t1_c1 = (bp_iir_cheb1_800kHz_90kHz_98kHz_102kHz_110kHz(delta_phi_t1_c1 * delta_phi_t1_c1) >= 0) ? INT16_MAX : INT16_MIN;
|
|
||||||
const int16_t clock_s1 = (bp_iir_cheb1_800kHz_22kHz_30kHz_34kHz_42kHz(delta_phi_s1 * delta_phi_s1) >= 0) ? INT16_MAX : INT16_MIN;
|
|
||||||
//fwrite(&clock, sizeof(clock), 1, clock_out);
|
|
||||||
|
|
||||||
if (clock_t1_c1 > old_clock_t1_c1)
|
|
||||||
{ // Clock signal rising edge detected.
|
|
||||||
clock_lock_t1_c1 = 1;
|
|
||||||
}
|
|
||||||
else if (clock_t1_c1 == INT16_MAX)
|
|
||||||
{ // Clock signal is still high.
|
|
||||||
if (clock_lock_t1_c1 < opts_CLOCK_LOCK_THRESHOLD_T1_C1)
|
|
||||||
{ // Skip up to (opts_CLOCK_LOCK_THRESHOLD_T1_C1 - 1) clock bits
|
|
||||||
// to get closer to the middle of the data bit.
|
|
||||||
clock_lock_t1_c1++;
|
|
||||||
}
|
|
||||||
else if (clock_lock_t1_c1 == opts_CLOCK_LOCK_THRESHOLD_T1_C1)
|
|
||||||
{ // Sample data bit at CLOCK_LOCK_THRESHOLD_T1_C1 clock bit position.
|
|
||||||
clock_lock_t1_c1++;
|
|
||||||
time2_algorithm_t1_c1(bit_t1_c1, rssi_t1_c1, &t2_algo_t1_c1);
|
|
||||||
//int16_t u = bit ? (INT16_MAX-1) : 0;
|
|
||||||
//fwrite(&u, sizeof(u), 1, bits_out);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
old_clock_t1_c1 = clock_t1_c1;
|
|
||||||
|
|
||||||
if (clock_s1 > old_clock_s1)
|
|
||||||
{ // Clock signal rising edge detected.
|
|
||||||
clock_lock_s1 = 1;
|
|
||||||
}
|
|
||||||
else if (clock_s1 == INT16_MAX)
|
|
||||||
{ // Clock signal is still high.
|
|
||||||
if (clock_lock_s1 < opts_CLOCK_LOCK_THRESHOLD_S1)
|
|
||||||
{ // Skip up to (opts_CLOCK_LOCK_THRESHOLD_S1 - 1) clock bits
|
|
||||||
// to get closer to the middle of the data bit.
|
|
||||||
clock_lock_s1++;
|
|
||||||
}
|
|
||||||
else if (clock_lock_s1 == opts_CLOCK_LOCK_THRESHOLD_S1)
|
|
||||||
{ // Sample data bit at CLOCK_LOCK_THRESHOLD_S1 clock bit position.
|
|
||||||
clock_lock_s1++;
|
|
||||||
time2_algorithm_s1(bit_s1, rssi_s1, &t2_algo_s1);
|
|
||||||
//int16_t u = bit ? (INT16_MAX-1) : 0;
|
|
||||||
//fwrite(&u, sizeof(u), 1, bits_out);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
old_clock_s1 = clock_s1;
|
|
||||||
// --- clock recovery section end ---
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
// --- time2 algorithm section end ---
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,73 @@
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import traceback
|
||||||
|
import subprocess
|
||||||
|
import psutil
|
||||||
|
import signal
|
||||||
|
from time import time
|
||||||
|
|
||||||
|
|
||||||
|
__rtl_sdr = None
|
||||||
|
__rtl_wmbus = None
|
||||||
|
|
||||||
|
|
||||||
|
def __signal_handler(signal, frame):
|
||||||
|
global __rtl_sdr, __rtl_wmbus
|
||||||
|
|
||||||
|
if __rtl_wmbus:
|
||||||
|
#print("Terminating rtl_wmbus")
|
||||||
|
__rtl_wmbus.kill()
|
||||||
|
__rtl_wmbus.wait()
|
||||||
|
|
||||||
|
if __rtl_sdr:
|
||||||
|
#print("Terminating rtl_sdr")
|
||||||
|
__rtl_sdr.kill()
|
||||||
|
__rtl_sdr.wait()
|
||||||
|
|
||||||
|
|
||||||
|
def _main(args):
|
||||||
|
global __rtl_sdr, __rtl_wmbus
|
||||||
|
|
||||||
|
#"/C/Program Files/PothosSDR/bin/rtl_sdr" -f 868.95M -s 1600000 - 2>/dev/null | build/rtl_wmbus_x64.exe -v
|
||||||
|
#"C:\Program Files\PothosSDR\bin\rtl_sdr" -f 868.95M -s 1600000 - 2>NUL | build\rtl_wmbus_x64.exe -v
|
||||||
|
|
||||||
|
try:
|
||||||
|
signal.signal(signal.SIGINT, __signal_handler)
|
||||||
|
|
||||||
|
__rtl_sdr = subprocess.Popen([r"c:\Program Files\PothosSDR\bin\rtl_sdr", "-f", "868.95M", "-s", "1600000", "-"], stdin=subprocess.DEVNULL, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL)
|
||||||
|
psutil.Process(__rtl_sdr.pid).nice(psutil.REALTIME_PRIORITY_CLASS)
|
||||||
|
|
||||||
|
__rtl_wmbus = subprocess.Popen([r"d:\rtl-wmbus\build\rtl_wmbus_x64.exe", "-v"], stdin=__rtl_sdr.stdout, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL)
|
||||||
|
psutil.Process(__rtl_wmbus.pid).nice(psutil.REALTIME_PRIORITY_CLASS)
|
||||||
|
|
||||||
|
psutil.Process(os.getpid()).nice(psutil.REALTIME_PRIORITY_CLASS)
|
||||||
|
|
||||||
|
#__rtl_sdr.stdout.close() # Allow rtl_sdr to receive a SIGPIPE if rtl_wmbus exits.
|
||||||
|
|
||||||
|
t1 = time()
|
||||||
|
rate = 0
|
||||||
|
while __rtl_sdr.poll() is None and __rtl_wmbus.poll() is None:
|
||||||
|
s = __rtl_wmbus.stdout.readline().decode('utf-8').rstrip('\n').rstrip('\r')
|
||||||
|
t2 = time()
|
||||||
|
|
||||||
|
if s.find("T1;1") >= 0 or s.find("C1;1") >= 0 or s.find("S1;1") >= 0:
|
||||||
|
rate += 1
|
||||||
|
print(s)
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
|
||||||
|
dt = t2 - t1
|
||||||
|
if dt >= 10:
|
||||||
|
#print(rate/dt, file=sys.stderr)
|
||||||
|
t1 = t2
|
||||||
|
rate = 0
|
||||||
|
|
||||||
|
return 0
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(traceback.print_exc())
|
||||||
|
return 1
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
sys.exit(_main(sys.argv))
|
Ładowanie…
Reference in New Issue