]> git.rkrishnan.org Git - pihpsdr.git/commitdiff
Use a moving average of the forward and reverse power to calculate SWR,
authorDL1YCF <dl1ycf@darc.de>
Sun, 2 May 2021 18:04:46 +0000 (20:04 +0200)
committerDL1YCF <dl1ycf@darc.de>
Sun, 2 May 2021 18:04:46 +0000 (20:04 +0200)
since the fwd and rev values are not taken at the same time.

new_protocol.c
old_protocol.c
radio.c
radio.h
transmitter.c

index 41cbb9b29ae556bd93184e6e232a6ebe38191543..aab24a1ab098c69bee107fabfc2014a5a6cdd4b5 100644 (file)
@@ -1918,6 +1918,16 @@ static void process_high_priority() {
     exciter_power=((buffer[6]&0xFF)<<8)|(buffer[7]&0xFF);
     alex_forward_power=((buffer[14]&0xFF)<<8)|(buffer[15]&0xFF);
     alex_reverse_power=((buffer[22]&0xFF)<<8)|(buffer[23]&0xFF);
+    //
+    //  calculate moving averages of fwd and rev voltages to have a correct SWR
+    //  at the edges of an RF pulse. Otherwise a false trigger of the SWR
+    //  protection may occur. Note that during TX, a HighPrio package from the radio
+    //  is sent every milli-second.
+    //  This exponential average means that the power drops to 1 percent within 16 hits
+    //  (at most 16 msec).
+    //
+    alex_forward_power_average = (alex_forward_power + 3*alex_forward_power_average) >> 2;
+    alex_reverse_power_average = (alex_reverse_power + 3*alex_reverse_power_average) >> 2;
     supply_volts=((buffer[49]&0xFF)<<8)|(buffer[50]&0xFF);
 
     if (cw_keyer_internal) {
index 7a3e92935992b62e0ecedb100c387aad89a0262b..fab5d03cd7e81882f35c2c002fdda0d5a6b68c0a 100644 (file)
@@ -804,231 +804,6 @@ static int how_many_receivers() {
     return ret;
 }
 
-//OLDCODE   static void process_ozy_input_buffer(unsigned char  *buffer) {
-//OLDCODE     int i;
-//OLDCODE     int r;
-//OLDCODE     int b=0;
-//OLDCODE     int previous_ptt;
-//OLDCODE     int previous_dot;
-//OLDCODE     int previous_dash;
-//OLDCODE     int left_sample;
-//OLDCODE     int right_sample;
-//OLDCODE     short mic_sample;
-//OLDCODE     float fsample;
-//OLDCODE     double left_sample_double;
-//OLDCODE     double right_sample_double;
-//OLDCODE     double gain=pow(10.0, mic_gain / 20.0);
-//OLDCODE     double left_sample_double_rx;
-//OLDCODE     double right_sample_double_rx;
-//OLDCODE     double left_sample_double_tx;
-//OLDCODE     double right_sample_double_tx;
-//OLDCODE     double left_sample_double_main;
-//OLDCODE     double right_sample_double_main;
-//OLDCODE     double left_sample_double_aux;
-//OLDCODE     double right_sample_double_aux;
-//OLDCODE   
-//OLDCODE     int id=active_receiver->id;
-//OLDCODE   
-//OLDCODE     int num_hpsdr_receivers=how_many_receivers();
-//OLDCODE     int rxfdbk = rx_feedback_channel();
-//OLDCODE     int txfdbk = tx_feedback_channel();
-//OLDCODE     int rx1channel = first_receiver_channel();
-//OLDCODE     int rx2channel = second_receiver_channel();
-//OLDCODE   
-//OLDCODE     if(buffer[b++]==SYNC && buffer[b++]==SYNC && buffer[b++]==SYNC) {
-//OLDCODE       // extract control bytes
-//OLDCODE       control_in[0]=buffer[b++];
-//OLDCODE       control_in[1]=buffer[b++];
-//OLDCODE       control_in[2]=buffer[b++];
-//OLDCODE       control_in[3]=buffer[b++];
-//OLDCODE       control_in[4]=buffer[b++];
-//OLDCODE   
-//OLDCODE       // do not set ptt. In PURESIGNAL, this would stop the
-//OLDCODE       // receiver sending samples to WDSP abruptly.
-//OLDCODE       // Do the RX-TX change only via ext_mox_update.
-//OLDCODE       previous_ptt=local_ptt;
-//OLDCODE       previous_dot=dot;
-//OLDCODE       previous_dash=dash;
-//OLDCODE       local_ptt=(control_in[0]&0x01)==0x01;
-//OLDCODE       dash=(control_in[0]&0x02)==0x02;
-//OLDCODE       dot=(control_in[0]&0x04)==0x04;
-//OLDCODE   
-//OLDCODE       if (cw_keyer_internal) {
-//OLDCODE         // Stops CAT cw transmission if paddle hit in "internal" CW
-//OLDCODE         if ((dash || dot) && cw_keyer_internal) cw_key_hit=1;
-//OLDCODE       } else {
-//OLDCODE   #ifdef LOCALCW
-//OLDCODE         //
-//OLDCODE         // report "key hit" event to the local keyer
-//OLDCODE         // (local keyer will stop CAT cw if necessary)
-//OLDCODE         if (dash != previous_dash) keyer_event(0, dash);
-//OLDCODE         if (dot  != previous_dot ) keyer_event(1, dot );
-//OLDCODE   #endif
-//OLDCODE       }
-//OLDCODE   
-//OLDCODE       if(previous_ptt!=local_ptt) {
-//OLDCODE         g_idle_add(ext_mox_update,(gpointer)(long)(local_ptt));
-//OLDCODE       }
-//OLDCODE   
-//OLDCODE       switch((control_in[0]>>3)&0x1F) {
-//OLDCODE         case 0:
-//OLDCODE           adc_overload=control_in[1]&0x01;
-//OLDCODE           if (device != DEVICE_HERMES_LITE2) {
-//OLDCODE        //
-//OLDCODE        // HL2 uses these bits of the protocol for a different purpose:
-//OLDCODE        // C1 unused except the ADC overload bit
-//OLDCODE             // C2/C3 contains underflow/overflow and TX FIFO count
-//OLDCODE        //
-//OLDCODE             IO1=(control_in[1]&0x02)?0:1;
-//OLDCODE             IO2=(control_in[1]&0x04)?0:1;
-//OLDCODE             IO3=(control_in[1]&0x08)?0:1;
-//OLDCODE             if(mercury_software_version!=control_in[2]) {
-//OLDCODE               mercury_software_version=control_in[2];
-//OLDCODE               g_print("  Mercury Software version: %d (0x%0X)\n",mercury_software_version,mercury_software_version);
-//OLDCODE             }
-//OLDCODE             if(penelope_software_version!=control_in[3]) {
-//OLDCODE               penelope_software_version=control_in[3];
-//OLDCODE               g_print("  Penelope Software version: %d (0x%0X)\n",penelope_software_version,penelope_software_version);
-//OLDCODE             }
-//OLDCODE           }
-//OLDCODE           if(ozy_software_version!=control_in[4]) {
-//OLDCODE             ozy_software_version=control_in[4];
-//OLDCODE             g_print("FPGA firmware version: %d.%d\n",ozy_software_version/10,ozy_software_version%10);
-//OLDCODE           }
-//OLDCODE           break;
-//OLDCODE         case 1:
-//OLDCODE           if (device != DEVICE_HERMES_LITE2) {
-//OLDCODE        //
-//OLDCODE        // HL2 uses C1/C2 for measuring the temperature
-//OLDCODE        //
-//OLDCODE             exciter_power=((control_in[1]&0xFF)<<8)|(control_in[2]&0xFF); // from Penelope or Hermes
-//OLDCODE             temperature=0;
-//OLDCODE           } else {
-//OLDCODE             exciter_power=0;
-//OLDCODE             temperature+=((control_in[1]&0xFF)<<8)|(control_in[2]&0xFF); // HL2
-//OLDCODE             n_temperature++;
-//OLDCODE             if(n_temperature==10) {
-//OLDCODE               average_temperature=temperature/10;
-//OLDCODE               temperature=0;
-//OLDCODE               n_temperature=0;
-//OLDCODE             }
-//OLDCODE      } 
-//OLDCODE           alex_forward_power=((control_in[3]&0xFF)<<8)|(control_in[4]&0xFF); // from Alex or Apollo
-//OLDCODE           break;
-//OLDCODE         case 2:
-//OLDCODE           alex_reverse_power=((control_in[1]&0xFF)<<8)|(control_in[2]&0xFF); // from Alex or Apollo
-//OLDCODE           if (device != DEVICE_HERMES_LITE2) {
-//OLDCODE             AIN3=((control_in[3]&0xFF)<<8)|(control_in[4]&0xFF); // For Penelope or Hermes
-//OLDCODE             current=0;
-//OLDCODE           } else {
-//OLDCODE             AIN3=0;
-//OLDCODE             current+=((control_in[3]&0xFF)<<8)|(control_in[4]&0xFF); // HL2
-//OLDCODE             n_current++;
-//OLDCODE             if(n_current==10) {
-//OLDCODE               average_current=current/10;
-//OLDCODE               current=0;
-//OLDCODE               n_current=0;
-//OLDCODE             }
-//OLDCODE           }
-//OLDCODE           break;
-//OLDCODE         case 3:
-//OLDCODE           AIN4=((control_in[1]&0xFF)<<8)|(control_in[2]&0xFF); // For Penelope or Hermes
-//OLDCODE           AIN6=((control_in[3]&0xFF)<<8)|(control_in[4]&0xFF); // For Penelope or Hermes
-//OLDCODE           break;
-//OLDCODE       }
-//OLDCODE   
-//OLDCODE       int iq_samples=(512-8)/((num_hpsdr_receivers*6)+2);
-//OLDCODE   
-//OLDCODE       for(i=0;i<iq_samples;i++) {
-//OLDCODE         for(r=0;r<num_hpsdr_receivers;r++) {
-//OLDCODE           left_sample   = (int)((signed char) buffer[b++])<<16;
-//OLDCODE           left_sample  |= (int)((((unsigned char)buffer[b++])<<8)&0xFF00);
-//OLDCODE           left_sample  |= (int)((unsigned char)buffer[b++]&0xFF);
-//OLDCODE           right_sample  = (int)((signed char)buffer[b++]) << 16;
-//OLDCODE           right_sample |= (int)((((unsigned char)buffer[b++])<<8)&0xFF00);
-//OLDCODE           right_sample |= (int)((unsigned char)buffer[b++]&0xFF);
-//OLDCODE   
-//OLDCODE           left_sample_double=(double)left_sample/8388607.0; // 24 bit sample 2^23-1
-//OLDCODE           right_sample_double=(double)right_sample/8388607.0; // 24 bit sample 2^23-1
-//OLDCODE   
-//OLDCODE      if (isTransmitting() && transmitter->puresignal) {
-//OLDCODE        //
-//OLDCODE        // transmitting with PURESIGNAL. Get sample pairs and feed to pscc
-//OLDCODE        //
-//OLDCODE        if (r == rxfdbk) {
-//OLDCODE               left_sample_double_rx=left_sample_double;
-//OLDCODE               right_sample_double_rx=right_sample_double;
-//OLDCODE             } else if (r == txfdbk) {
-//OLDCODE               left_sample_double_tx=left_sample_double;
-//OLDCODE               right_sample_double_tx=right_sample_double;
-//OLDCODE             }
-//OLDCODE        // this is pure paranoia, it allows for txfdbk < rxfdbk
-//OLDCODE             if (r+1 == num_hpsdr_receivers) {
-//OLDCODE               add_ps_iq_samples(transmitter, left_sample_double_tx,right_sample_double_tx,left_sample_double_rx,right_sample_double_rx);
-//OLDCODE             }
-//OLDCODE           }
-//OLDCODE   
-//OLDCODE      if (!isTransmitting() && diversity_enabled) {
-//OLDCODE        //
-//OLDCODE        // receiving with DIVERSITY. Get sample pairs and feed to diversity mixer
-//OLDCODE        //
-//OLDCODE             if (r == rx1channel) {
-//OLDCODE               left_sample_double_main=left_sample_double;
-//OLDCODE               right_sample_double_main=right_sample_double;
-//OLDCODE             } else if (r == rx2channel) {
-//OLDCODE               left_sample_double_aux=left_sample_double;
-//OLDCODE               right_sample_double_aux=right_sample_double;
-//OLDCODE             }
-//OLDCODE        // this is pure paranoia, it allows for rx2channel < rx1channel
-//OLDCODE             if (r+1 == num_hpsdr_receivers) {
-//OLDCODE               add_div_iq_samples(receiver[0], left_sample_double_main,right_sample_double_main,left_sample_double_aux,right_sample_double_aux);
-//OLDCODE          // if we have a second receiver, display "auxiliary" receiver as well
-//OLDCODE               if (receivers >1) add_iq_samples(receiver[1], left_sample_double_aux,right_sample_double_aux);
-//OLDCODE             }
-//OLDCODE      }
-//OLDCODE   
-//OLDCODE           if ((!isTransmitting() || duplex) && !diversity_enabled) {
-//OLDCODE        //
-//OLDCODE        // RX without DIVERSITY. Feed samples to RX1 and RX2
-//OLDCODE        //
-//OLDCODE             if (r == rx1channel) {
-//OLDCODE                add_iq_samples(receiver[0], left_sample_double,right_sample_double);
-//OLDCODE             } else if (r == rx2channel && receivers > 1) {
-//OLDCODE                add_iq_samples(receiver[1], left_sample_double,right_sample_double);
-//OLDCODE             }
-//OLDCODE           }
-//OLDCODE         } // end of loop over the receiver channels
-//OLDCODE   
-//OLDCODE         //
-//OLDCODE         // Process mic samples. Take them from radio or from
-//OLDCODE         // "local microphone" ring buffer
-//OLDCODE         //
-//OLDCODE         mic_sample  = (short)(buffer[b++]<<8);
-//OLDCODE         mic_sample |= (short)(buffer[b++]&0xFF);
-//OLDCODE   
-//OLDCODE         mic_samples++;
-//OLDCODE         if(mic_samples>=mic_sample_divisor) { // reduce to 48000
-//OLDCODE           fsample = transmitter->local_microphone ? audio_get_next_mic_sample() : (float) mic_sample * 0.00003051;
-//OLDCODE           add_mic_sample(transmitter,fsample);
-//OLDCODE           mic_samples=0;
-//OLDCODE         }
-//OLDCODE   
-//OLDCODE       }
-//OLDCODE     } else {
-//OLDCODE       time_t t;
-//OLDCODE       struct tm* gmt;
-//OLDCODE       time(&t);
-//OLDCODE       gmt=gmtime(&t);
-//OLDCODE   
-//OLDCODE       g_print("%s: process_ozy_input_buffer: did not find sync: restarting\n",
-//OLDCODE               asctime(gmt));
-//OLDCODE   
-//OLDCODE   
-//OLDCODE       metis_start_stop(0);
-//OLDCODE       metis_restart();
-//OLDCODE     }
-//OLDCODE   }
-
 static int nreceiver;
 static int left_sample;
 static int right_sample;
@@ -1157,10 +932,20 @@ static void process_control_bytes() {
           n_temperature=0;
         }
       }
+      //
+      //  calculate moving averages of fwd and rev voltages to have a correct SWR
+      //  at the edges of an RF pulse. Otherwise a false trigger of the SWR 
+      //  protection may occur. Note that the rate at which these packets arrive strongly
+      //  depend on the sample rate and the number of receivers.
+      //  This exponential average means that the power drops to 1 percent within 16 hits
+      //  (at most 16 msec).
+      //
       alex_forward_power=((control_in[3]&0xFF)<<8)|(control_in[4]&0xFF); // from Alex or Apollo
+      alex_forward_power_average = (alex_forward_power + 3*alex_forward_power_average) >> 2;
       break;
     case 2:
       alex_reverse_power=((control_in[1]&0xFF)<<8)|(control_in[2]&0xFF); // from Alex or Apollo
+      alex_reverse_power_average = (alex_reverse_power + 3*alex_reverse_power_average) >> 2;
       if (device != DEVICE_HERMES_LITE2) {
         AIN3=((control_in[3]&0xFF)<<8)|(control_in[4]&0xFF); // For Penelope or Hermes
         current=0;
diff --git a/radio.c b/radio.c
index c86aa7d86baad36c63d6cf5237a3a82652c379fa..2e7c64984cdb72a67e883fae218eae026e9c094c 100644 (file)
--- a/radio.c
+++ b/radio.c
@@ -257,6 +257,8 @@ unsigned int tx_fifo_underrun;
 unsigned int tx_fifo_overrun;
 unsigned int alex_forward_power;
 unsigned int alex_reverse_power;
+unsigned int alex_forward_power_average=0;
+unsigned int alex_reverse_power_average=0;
 unsigned int AIN3;
 unsigned int AIN4;
 unsigned int AIN6;
diff --git a/radio.h b/radio.h
index 82f1491bd12199d371ae1ee754233dd94cda895c..564c9064892ae3601c7f63390ba8353729da0432 100644 (file)
--- a/radio.h
+++ b/radio.h
@@ -248,6 +248,8 @@ extern unsigned int tx_fifo_underrun;
 extern unsigned int tx_fifo_overrun;
 extern unsigned int alex_forward_power;
 extern unsigned int alex_reverse_power;
+extern unsigned int alex_forward_power_average;
+extern unsigned int alex_reverse_power_average;
 extern unsigned int IO1;
 extern unsigned int IO2;
 extern unsigned int IO3;
index 0ad0b0a6a4ebaf5837421383aae84d057d062b9f..9eb1d0e8db8ed6ff6f36810e8a7c7077274ebf36 100644 (file)
@@ -486,11 +486,15 @@ static gboolean update_display(gpointer data) {
 
     int fwd_power;
     int rev_power;
+    int fwd_average;  // only used for SWR calculation, VOLTAGE value
+    int rev_average;  // only used for SWR calculation, VOLTAGE value
     int ex_power;
     double v1;
 
     fwd_power=alex_forward_power;
     rev_power=alex_reverse_power;
+    fwd_average=alex_forward_power_average;
+    rev_average=alex_reverse_power_average;
     if(device==DEVICE_HERMES_LITE || device==DEVICE_HERMES_LITE2) {
       ex_power=0;
     } else {
@@ -520,7 +524,7 @@ static gboolean update_display(gpointer data) {
           case DEVICE_ORION2:
             constant1=5.0;
             constant2=0.08;
-            fwd_cal_offset=18;  // On Anan-7000 I measured 36
+            fwd_cal_offset=18;
             break;
           case DEVICE_HERMES_LITE:
           case DEVICE_HERMES_LITE2:
@@ -528,6 +532,8 @@ static gboolean update_display(gpointer data) {
             if(rev_power>fwd_power) {
               fwd_power=alex_reverse_power;
               rev_power=alex_forward_power;
+              fwd_average=alex_reverse_power_average;
+              rev_average=alex_forward_power_average;
             }
             constant1=3.3;
             constant2=1.4;
@@ -539,7 +545,6 @@ static gboolean update_display(gpointer data) {
           fwd_power=ex_power;
         }
         fwd_power=fwd_power-fwd_cal_offset;
-        // should be applied to rev_power as well
         v1=((double)fwd_power/4095.0)*constant1;
         tx->fwd=(v1*v1)/constant2;
 
@@ -556,6 +561,15 @@ static gboolean update_display(gpointer data) {
           v1=((double)rev_power/4095.0)*constant1;
           tx->rev=(v1*v1)/constant2;
         }
+
+        //
+        // we apply the offset but no further calculation
+        // since only the ratio of rev_average and fwd_average is needed
+        //
+        fwd_average=fwd_average-fwd_cal_offset;
+        rev_average=rev_average-fwd_cal_offset;
+        if (rev_average < 0) rev_average=0;
+
         break;
       case NEW_PROTOCOL:
         switch(device) {
@@ -597,7 +611,6 @@ static gboolean update_display(gpointer data) {
           fwd_power=exciter_power;
         }
         fwd_power=fwd_power-fwd_cal_offset;
-        // should be applied to rev_power as well
         v1=((double)fwd_power/4095.0)*constant1;
         tx->fwd=(v1*v1)/constant2;
 
@@ -612,6 +625,15 @@ static gboolean update_display(gpointer data) {
           v1=((double)rev_power/4095.0)*constant1;
           tx->rev=(v1*v1)/constant2;
         }
+
+        //
+        // we apply the offset but no further calculation
+        // since only the ratio of rev_average and fwd_average is needed
+        //
+        fwd_average=fwd_average-fwd_cal_offset;
+        rev_average=rev_average-fwd_cal_offset;
+        if (rev_average < 0) rev_average=0;
+
         break;
 
 #ifdef SOAPYSDR
@@ -619,6 +641,8 @@ static gboolean update_display(gpointer data) {
         tx->fwd=0.0;
         tx->exciter=0.0;
         tx->rev=0.0;
+        fwd_average=0;
+        rev_average=0;
         break;
 #endif
     }
@@ -637,20 +661,21 @@ static gboolean update_display(gpointer data) {
     tx->rev=rev;
 
     //
-    // Calculate SWR here such that it is available in DUPLEX mode
+    // Calculate SWR and store as tx->swr.
     // tx->swr can be used in other parts of the program to
     // implement SWR protection etc.
+    // The SWR is calculated from the (time-averaged) forward and reverse voltages.
     //
-    if (tx->fwd > 0.01 && tx->fwd > 1.01*tx->rev) {
+    if (tx->fwd > 0.1) {
         //
         // SWR means VSWR (voltage based) but we have the forward and
         // reflected power, so correct for that
         //
-        double gamma=sqrt(tx->rev/tx->fwd);
+        double gamma=(double) rev_average / (double) fwd_average;
         tx->swr=0.7*(1+gamma)/(1-gamma) + 0.3*tx->swr;
     } else {
         //
-        // This value may be used for auto SWR protection, so move towards 1.0
+        // During RX, move towards 1.0
         //
         tx->swr = 0.7 + 0.3*tx->swr;
     }
@@ -906,6 +931,14 @@ fprintf(stderr,"transmitter: allocate buffers: mic_input_buffer=%d iq_output_buf
           tx->mic_dsp_rate,
           tx->iq_output_rate);
 
+  //
+  // Experimental: set last parameter "bfo" to 1
+  // this should eliminate the "fexchange0: error=-2" messages sometimes seen
+  // BUT this means that wdsp "waits" in fexchange0 for data to become ready.
+  // perhaps this requires moving the fexchange0 call to a separate thread:
+  // add_mic_sample produces that data and sends a signal to the TX thread
+  // that a buffer needs processing.
+  //
   OpenChannel(tx->id,
               tx->buffer_size,
               2048, // tx->fft_size,
@@ -914,7 +947,7 @@ fprintf(stderr,"transmitter: allocate buffers: mic_input_buffer=%d iq_output_buf
               tx->iq_output_rate,
               1, // transmit
               0, // run
-              0.010, 0.025, 0.0, 0.010, 0);
+              0.010, 0.025, 0.0, 0.010, 1);
 
   TXASetNC(tx->id, tx->fft_size);
   TXASetMP(tx->id, tx->low_latency);