C-Netz: Improve clock speed measurements.

Sound card's clock measurements only requires a few minutes to get sub-ppm
accuracy results.
This commit is contained in:
Andreas Eversberg
2017-02-01 17:57:09 +01:00
parent 54ed5d5f82
commit 5f1d7bc970
4 changed files with 30 additions and 43 deletions

View File

@@ -50,12 +50,11 @@ struct clock_speed {
double meas_ti; /* time stamp for measurement interval */ double meas_ti; /* time stamp for measurement interval */
double start_ti[4]; /* time stamp for start of counting */ double start_ti[4]; /* time stamp for start of counting */
double last_ti[4]; /* time stamp of last received time */ double last_ti[4]; /* time stamp of last received time */
uint64_t spl_count[4]; /* sample counter for sound card */ double spl_count[4]; /* sample counter for sound card */
/* making average of measurement values */ /* making average of measurement values */
double speed_ppm_rx[2][256]; /* history of clock speed measurements */ double speed_ppm[4][256]; /* history of clock speed measurements */
double speed_ppm_tx[2][256]; int idx[4]; /* index of current value */
int idx; /* index of current value */ int num[4]; /* total num of values so far */
int num; /* total num of values so far */
}; };
/* instance of cnetz sender */ /* instance of cnetz sender */

View File

@@ -195,19 +195,17 @@ void dsp_cleanup_sender(cnetz_t *cnetz)
/* receive sample time and calculate speed against system clock /* receive sample time and calculate speed against system clock
* tx: indicates transmit stream * tx: indicates transmit stream
* result: if set the actual signal speed is used (instead of sample rate) */ * result: if set the actual signal speed is used (instead of sample rate) */
void calc_clock_speed(cnetz_t *cnetz, uint64_t samples, int tx, int result) void calc_clock_speed(cnetz_t *cnetz, double samples, int tx, int result)
{ {
struct clock_speed *cs = &cnetz->clock_speed; struct clock_speed *cs = &cnetz->clock_speed;
double ti; double ti;
double speed_ppm_rx_avg[2], speed_ppm_tx_avg[2]; double speed_ppm_avg[4];
int index = (result << 1) | tx;
int i; int i;
if (!cnetz->measure_speed) if (!cnetz->measure_speed)
return; return;
if (result)
tx += 2;
ti = get_time(); ti = get_time();
/* skip some time to avoid false mesurement due to filling of buffers */ /* skip some time to avoid false mesurement due to filling of buffers */
@@ -219,46 +217,36 @@ void calc_clock_speed(cnetz_t *cnetz, uint64_t samples, int tx, int result)
return; return;
/* start sample counting */ /* start sample counting */
if (cs->start_ti[tx] == 0.0) { if (cs->start_ti[index] == 0.0) {
cs->start_ti[tx] = ti; cs->start_ti[index] = ti;
cs->spl_count[tx] = 0; cs->spl_count[index] = 0.0;
return; return;
} }
/* add elapsed time */ /* add elapsed time */
cs->last_ti[tx] = ti; cs->last_ti[index] = ti;
cs->spl_count[tx] += samples; cs->spl_count[index] += samples;
/* only calculate speed, if one second has elapsed */ /* only calculate speed, if one second has elapsed */
if (ti - cs->meas_ti <= 1.0) if (ti - cs->meas_ti <= 2.0)
return; return;
cs->meas_ti += 1.0; cs->meas_ti += 2.0;
if (!cs->spl_count[2] || !cs->spl_count[3]) /* add to ring buffer */
if (!cs->spl_count[0] || !cs->spl_count[1] || !cs->spl_count[2] || !cs->spl_count[3])
return; return;
cs->speed_ppm_rx[0][cs->idx & 0xff] = ((double)cs->spl_count[0] / (double)cnetz->sender.samplerate) / (cs->last_ti[0] - cs->start_ti[0]) * 1000000.0 - 1000000.0;
cs->speed_ppm_tx[0][cs->idx & 0xff] = ((double)cs->spl_count[1] / (double)cnetz->sender.samplerate) / (cs->last_ti[1] - cs->start_ti[1]) * 1000000.0 - 1000000.0; for (index = 0; index < 4; index++) {
cs->speed_ppm_rx[1][cs->idx & 0xff] = ((double)cs->spl_count[2] / (double)cnetz->sender.samplerate) / (cs->last_ti[2] - cs->start_ti[2]) * 1000000.0 - 1000000.0; cs->speed_ppm[index][cs->idx[index] & 0xff] = (cs->spl_count[index] / (double)cnetz->sender.samplerate) / (cs->last_ti[index] - cs->start_ti[index]) * 1000000.0 - 1000000.0;
cs->speed_ppm_tx[1][cs->idx & 0xff] = ((double)cs->spl_count[3] / (double)cnetz->sender.samplerate) / (cs->last_ti[3] - cs->start_ti[3]) * 1000000.0 - 1000000.0; cs->idx[index]++;
cs->idx++; if (cs->num[index]++ > 30)
cs->num++; cs->num[index] = 30;
if (cs->num > 30) speed_ppm_avg[index] = 0.0;
cs->num = 30; for (i = 0; i < cs->num[index]; i++)
speed_ppm_rx_avg[0] = 0.0; speed_ppm_avg[index] += cs->speed_ppm[index][(cs->idx[index] - i - 1) & 0xff];
speed_ppm_tx_avg[0] = 0.0; speed_ppm_avg[index] /= (double)cs->num[index];
speed_ppm_rx_avg[1] = 0.0;
speed_ppm_tx_avg[1] = 0.0;
for (i = 0; i < cs->num; i++) {
speed_ppm_rx_avg[0] += cs->speed_ppm_rx[0][(cs->idx - i - 1) & 0xff];
speed_ppm_tx_avg[0] += cs->speed_ppm_tx[0][(cs->idx - i - 1) & 0xff];
speed_ppm_rx_avg[1] += cs->speed_ppm_rx[1][(cs->idx - i - 1) & 0xff];
speed_ppm_tx_avg[1] += cs->speed_ppm_tx[1][(cs->idx - i - 1) & 0xff];
} }
speed_ppm_rx_avg[0] /= (double)cs->num; PDEBUG_CHAN(DDSP, DEBUG_NOTICE, "Clock: RX=%.3f TX=%.3f; Signal: RX=%.3f TX=%.3f ppm\n", speed_ppm_avg[0], speed_ppm_avg[1], speed_ppm_avg[2], speed_ppm_avg[3]);
speed_ppm_tx_avg[0] /= (double)cs->num;
speed_ppm_rx_avg[1] /= (double)cs->num;
speed_ppm_tx_avg[1] /= (double)cs->num;
PDEBUG_CHAN(DDSP, DEBUG_NOTICE, "Clock: RX=%.2f TX=%.2f; Signal: RX=%.2f TX=%.2f ppm\n", speed_ppm_rx_avg[0], speed_ppm_tx_avg[0], speed_ppm_rx_avg[1], speed_ppm_tx_avg[1]);
} }
static int fsk_testtone_encode(cnetz_t *cnetz) static int fsk_testtone_encode(cnetz_t *cnetz)
@@ -622,7 +610,7 @@ again:
/* a new hyper frame starts */ /* a new hyper frame starts */
if (cnetz->sched_ts == 0 && cnetz->sched_r_m == 0) { if (cnetz->sched_ts == 0 && cnetz->sched_r_m == 0) {
/* measure actual signal speed */ /* measure actual signal speed */
calc_clock_speed(cnetz, cnetz->sender.samplerate * 24 / 10, 1, 1); calc_clock_speed(cnetz, (double)cnetz->sender.samplerate * 2.4, 1, 1);
/* sync TX (might not be required, if there is no error in math calculation) */ /* sync TX (might not be required, if there is no error in math calculation) */
if (!cnetz->sender.master) { /* if no link to a master, we are master */ if (!cnetz->sender.master) { /* if no link to a master, we are master */
/* we are master, so we store sample count and phase */ /* we are master, so we store sample count and phase */

View File

@@ -2,7 +2,7 @@
void dsp_init(void); void dsp_init(void);
int dsp_init_sender(cnetz_t *cnetz, int measure_speed, double clock_speed[2]); int dsp_init_sender(cnetz_t *cnetz, int measure_speed, double clock_speed[2]);
void dsp_cleanup_sender(cnetz_t *cnetz); void dsp_cleanup_sender(cnetz_t *cnetz);
void calc_clock_speed(cnetz_t *cnetz, uint64_t samples, int tx, int result); void calc_clock_speed(cnetz_t *cnetz, double samples, int tx, int result);
void unshrink_speech(cnetz_t *cnetz, sample_t *speech_buffer, int count); void unshrink_speech(cnetz_t *cnetz, sample_t *speech_buffer, int count);
void cnetz_set_dsp_mode(cnetz_t *cnetz, enum dsp_mode mode); void cnetz_set_dsp_mode(cnetz_t *cnetz, enum dsp_mode mode);
void cnetz_set_sched_dsp_mode(cnetz_t *cnetz, enum dsp_mode mode, int frames_ahead); void cnetz_set_sched_dsp_mode(cnetz_t *cnetz, enum dsp_mode mode, int frames_ahead);

View File

@@ -475,7 +475,7 @@ void fsk_fm_demod(fsk_fm_demod_t *fsk, sample_t *samples, int length)
fsk->bit_time_uncorrected += fsk->bits_per_sample; fsk->bit_time_uncorrected += fsk->bits_per_sample;
if (fsk->bit_time_uncorrected >= BITS_PER_SUPERFRAME) { if (fsk->bit_time_uncorrected >= BITS_PER_SUPERFRAME) {
fsk->bit_time_uncorrected -= BITS_PER_SUPERFRAME; fsk->bit_time_uncorrected -= BITS_PER_SUPERFRAME;
calc_clock_speed(fsk->cnetz, fsk->cnetz->sender.samplerate * 24 / 10, 0, 1); calc_clock_speed(fsk->cnetz, (double)fsk->cnetz->sender.samplerate * 2.4, 0, 1);
} }
} }
} }