From 6a679e4b0ff57081e76446efdf420b8dece47d61 Mon Sep 17 00:00:00 2001 From: c vw Date: Wed, 5 Jan 2022 10:10:10 +0100 Subject: [PATCH] Finalized the "silence residual TX signal after TX/RX" option. --- radio.c | 42 +++++++++++++++++++++++++++++++++++++++--- receiver.c | 45 ++++++++++++++++++++++++++++++--------------- receiver.h | 8 +++++++- 3 files changed, 76 insertions(+), 19 deletions(-) diff --git a/radio.c b/radio.c index c2fab28..92c2430 100644 --- a/radio.c +++ b/radio.c @@ -1542,14 +1542,50 @@ static void rxtx(int state) { gtk_container_remove(GTK_CONTAINER(fixed), transmitter->panel); } if(!duplex) { + // + // Set parameters for the "silence first RXIQ samples after TX/RX transition" feature + // the default is "no silence", that is, fastest turnaround + // + int do_silence=0; + if (protocol == ORIGINAL_PROTOCOL && (device == DEVICE_HERMES_LITE2 || device == DEVICE_STEMLAB)) { + // + // These systems get a significant "tail" of the RX feedback signal into the RX after TX/RX, + // leading to AGC pumping. The problem is most severe if there is a carrier until the end of + // the TX phase (TUNE, AM, FM), the problem is virtually non-existent for CW, and of medium + // importance in SSB. On the other hand, one want a very fast turnaround in CW. + // So there is no "muting" for CW, 31 msec off "muting" for TUNE/AM/FM, and 16 msec for other modes. + // + switch(get_tx_mode()) { + case modeCWU: + case modeCWL: + do_silence=0; // no "silence" + break; + case modeAM: + case modeFMN: + do_silence=5; // leads to 31 ms "silence" + break; + default: + do_silence=6; // leads to 16 ms "silence" + break; + } + if (tune) do_silence=5; // 31 ms "silence" for TUNEing in any mode + } + for(i=0;ipanel,receiver[i]->x,receiver[i]->y); SetChannelState(receiver[i]->id,1,0); set_displaying(receiver[i],1); - receiver[i]->rxcount=0; - receiver[i]->maxcount=-1; - // if not duplex, clear RX iq buffer + // + // There might be some left-over samples in the RX buffer that were filled in + // *before* going TX, delete them + // receiver[i]->samples=0; + if (do_silence) { + receiver[i]->txrxmax = receiver[i]->sample_rate >> do_silence; + } else { + receiver[i]->txrxmax = 0; + } + receiver[i]->txrxcount = 0; } } } diff --git a/receiver.c b/receiver.c index 933cc5f..f3a8e38 100644 --- a/receiver.c +++ b/receiver.c @@ -1239,7 +1239,8 @@ g_print("%s: rx=%p id=%d local_audio=%d\n",__FUNCTION__,rx,rx->id,rx->local_audi // defer set_agc until here, otherwise the AGC threshold is not computed correctly set_agc(rx, rx->agc); - rx->rxcount=99999; + rx->txrxcount=0; + rx->txrxmax=0; return rx; } @@ -1252,7 +1253,6 @@ void receiver_change_sample_rate(RECEIVER *rx,int sample_rate) { g_mutex_lock(&rx->mutex); rx->sample_rate=sample_rate; - rx->samples=0; // clear RX iq buffer int scale=rx->sample_rate/48000; rx->output_samples=rx->buffer_size/scale; rx->hz_per_pixel=(double)rx->sample_rate/(double)rx->width; @@ -1500,17 +1500,21 @@ static int tx_buffer_seen=0; void add_iq_samples(RECEIVER *rx, double i_sample,double q_sample) { - if (rx->rxcount <= 20000) { - if (i_sample*i_sample + q_sample*q_sample > 0.01) rx->maxcount=rx->rxcount; - if (rx->rxcount < (int)(rx->sample_rate >> 5)) { - i_sample=0.0; - q_sample=0.0; - } - if (rx->rxcount == 20000) { - fprintf(stderr,"ID=%d MAXCOUNT=%d\n", rx->id, rx->maxcount); - rx->rxcount = 99999; - } - rx->rxcount++; + // + // At the end of a TX/RX transition, txrxcount is set to zero, + // and txrxmax to some suitable value. + // Then, the first txrxmax RXIQ samples are "silenced" + // This is necessary on systems where RX feedback samples + // from cross-talk at the TRX relay arrive with some delay. + // + // If txrxmax is zero, no "silencing" takes place here, + // this is the case for radios not showing this problem, + // and generally if in CW mode or using duplex. + // + if (rx->txrxcount < rx->txrxmax) { + i_sample=0.0; + q_sample=0.0; + rx->txrxcount++; } rx->iq_input_buffer[rx->samples*2]=i_sample; @@ -1526,8 +1530,19 @@ void add_iq_samples(RECEIVER *rx, double i_sample,double q_sample) { // Note that we sum the second channel onto the first one. // void add_div_iq_samples(RECEIVER *rx, double i0, double q0, double i1, double q1) { - rx->iq_input_buffer[rx->samples*2] = i0 + (div_cos*i1 - div_sin*q1); - rx->iq_input_buffer[(rx->samples*2)+1]= q0 + (div_sin*i1 + div_cos*q1); + double i_sample=i0 + (div_cos*i1 - div_sin*q1); + double q_sample=q0 + (div_sin*i1 + div_cos*q1); + // + // The rest of the code is copied from add_iq_samples() + // + if (rx->txrxcount < rx->txrxmax) { + i_sample=0.0; + q_sample=0.0; + rx->txrxcount++; + } + + rx->iq_input_buffer[rx->samples*2]=i_sample; + rx->iq_input_buffer[(rx->samples*2)+1]=q_sample; rx->samples=rx->samples+1; if(rx->samples>=rx->buffer_size) { full_rx_buffer(rx); diff --git a/receiver.h b/receiver.h index d72b0c6..41d580c 100644 --- a/receiver.h +++ b/receiver.h @@ -167,7 +167,13 @@ typedef struct _receiver { gint x; gint y; - int rxcount; int maxcount; + // two variables that implement the new + // "mute first RX IQ samples after TX/RX transition" + // feature that is relevant for HermesLite-II and STEMlab + // (and possibly some other radios) + // + guint txrxcount; + guint txrxmax; } RECEIVER; extern RECEIVER *create_pure_signal_receiver(int id, int buffer_size,int sample_rate,int pixels); -- 2.45.2