]> git.rkrishnan.org Git - dttsp.git/blobdiff - jDttSP/sdr.c
Major changes. Added metering and power spectrum, other fixes. Rearranged headers...
[dttsp.git] / jDttSP / sdr.c
index ead39f0e61391978bd1f065ad70de6c3497f1be3..aad64d3f50f12469f2e0ff4ace01dce398084646 100644 (file)
@@ -36,25 +36,45 @@ Bridgewater, NJ 08807
 //========================================================================
 /* initialization and termination */
 
+void
+reset_meters(void) {  
+  if (uni.meter.flag) { // reset metering completely
+    int i, k;
+    for (i = 0; i < RXMETERPTS; i++)
+      for (k = 0; k < MAXRX; k++)
+       uni.meter.rx.val[k][i] = uni.meter.rx.avg[k][i] = -200.0;
+    for (i = 0; i < TXMETERPTS; i++)
+      uni.meter.tx.val[i] = uni.meter.tx.avg[i] = -200.0;
+  }
+}
+
+void
+reset_spectrum(void) {  
+  if (uni.spec.flag)
+    reinit_spectrum(&uni.spec);
+}
+
+void
+reset_counters(void) {
+  int k;
+  for (k = 0; k < uni.multirx.nrx; k++) rx[k].tick = 0;
+  tx.tick = 0;
+}
+
+//========================================================================
+
 /* global and general info,
    not specifically attached to
    tx, rx, or scheduling */
 
 PRIVATE void
 setup_all(void) {
-
+  
   uni.samplerate = loc.def.rate;
   uni.buflen = loc.def.size;
   uni.mode.sdr = loc.def.mode;
   uni.mode.trx = RX;
-
-  if (uni.meter.flag) {
-    uni.meter.chan.path = loc.path.meter;
-    uni.meter.chan.size = loc.mult.ring * sizeof(REAL);
-    uni.meter.val = -200.0;
-    uni.meter.chan.c = openChan(uni.meter.chan.path, uni.meter.chan.size);
-  }
-
+  
   uni.wisdom.path = loc.path.wisdom;
   uni.wisdom.bits = FFTW_OUT_OF_PLACE | FFTW_ESTIMATE;
   {
@@ -72,13 +92,29 @@ setup_all(void) {
       fclose(f);
     }
   }
-
+  
+  if (uni.meter.flag) {
+    uni.meter.rx.type = SIGNAL_STRENGTH;
+    uni.meter.tx.type = SIGNAL_STRENGTH;
+    reset_meters();
+  }
+  
+  uni.spec.rxk = 0;
+  uni.spec.buflen = uni.buflen;
+  uni.spec.scale = SPEC_PWR;
+  uni.spec.type = SPEC_POST_FILT;
+  uni.spec.size = loc.def.spec;
+  uni.spec.planbits = uni.wisdom.bits;
+  init_spectrum(&uni.spec);
+  
+  // set which receiver is listening to commands
   uni.multirx.lis = 0;
   uni.multirx.nrx = loc.def.nrx;
-
+  
+  // set mixing of input from aux ports
   uni.mix.rx.flag = uni.mix.tx.flag = FALSE;
   uni.mix.rx.gain = uni.mix.tx.gain = 1.0;
-
+  
   uni.tick = 0;
 }
 
@@ -86,7 +122,7 @@ setup_all(void) {
 
 PRIVATE void
 setup_rx(int k) {
-
+  
   /* conditioning */
   rx[k].iqfix = newCorrectIQ(0.0, 1.0);
   rx[k].filt.coef = newFIR_Bandpass_COMPLEX(-4800.0,
@@ -297,7 +333,7 @@ setup_workspace(void) {
   }
   uni.multirx.act[0] = TRUE;
   uni.multirx.nac = 1;
-
+  
   setup_tx();
 }
 
@@ -336,8 +372,7 @@ destroy_workspace(void) {
   }
   
   /* all */
-  if (uni.meter.flag)
-    closeChan(uni.meter.chan.c);
+  finish_spectrum(&uni.spec);
 }
 
 //////////////////////////////////////////////////////////////////////////
@@ -359,43 +394,99 @@ CXBnorm(CXB buff) {
 //========================================================================
 /* all */
 
-/* tap off S-meter from some buf */
+// unfortunate duplication here, due to
+// multirx vs monotx
 
 PRIVATE void
-do_meter(COMPLEX *vec, int len) {
-  int i;
+do_rx_meter(int k, CXB buf, int tap) {
+  COMPLEX *vec = CXBbase(buf);
+  int i, len = CXBhave(buf);
+  
+  uni.meter.rx.val[k][tap] = 0;
+  
+  switch (uni.meter.rx.type) {
+  case AVG_SIGNAL_STRENGTH:
+    for (i = 0; i < len; i++)
+      uni.meter.rx.val[k][tap] += Csqrmag(vec[i]);
+    uni.meter.rx.val[k][tap] =
+      uni.meter.rx.avg[k][tap] =
+        0.9 * uni.meter.rx.avg[k][tap] + log10(uni.meter.rx.val[k][tap] + 1e-20);
+    break;
+  case SIGNAL_STRENGTH:
+    for (i = 0; i < len; i++)
+      uni.meter.rx.val[k][tap] += Csqrmag(vec[i]);
+    uni.meter.rx.avg[k][tap] =
+      uni.meter.rx.val[k][tap] =
+        10.0 * log10(uni.meter.rx.val[k][tap] + 1e-20);
+    break;
+  case ADC_REAL:
+    for(i = 0; i < len; i++)
+      uni.meter.rx.val[k][tap] = max(fabs(vec[i].re), uni.meter.rx.val[k][tap]);
+    uni.meter.rx.val[k][tap] = 20.0 * log10(uni.meter.rx.val[k][tap] + 1e-10);
+    break;
+  case ADC_IMAG:
+    for(i = 0; i < len; i++)
+      uni.meter.rx.val[k][tap] = max(fabs(vec[i].im), uni.meter.rx.val[k][tap]);
+    uni.meter.rx.val[k][tap] = 20.0 * log10(uni.meter.rx.val[k][tap] + 1e-10);
+    break;
+  default:
+    break;
+  }
+}
+
+PRIVATE void
+do_tx_meter(CXB buf, int tap) {
+  COMPLEX *vec = CXBbase(buf);
+  int i, len = CXBhave(buf);
   
-  uni.meter.val = 0;
+  uni.meter.tx.val[tap] = 0;
 
-  switch (uni.meter.type) {
+  switch (uni.meter.tx.type) {
   case AVG_SIGNAL_STRENGTH:
     for (i = 0; i < len; i++)
-      uni.meter.val += Csqrmag(vec[i]);
-    uni.meter.val =
-      uni.meter.avgval = 0.9 * uni.meter.avgval + log10(uni.meter.val + 1e-20);
+      uni.meter.tx.val[tap] += Csqrmag(vec[i]);
+    uni.meter.tx.val[tap] =
+      uni.meter.tx.avg[tap] =
+        0.9 * uni.meter.tx.avg[tap] + log10(uni.meter.tx.val[tap] + 1e-20);
     break;
   case SIGNAL_STRENGTH:
     for (i = 0; i < len; i++)
-      uni.meter.val += Csqrmag(vec[i]);
-    uni.meter.avgval = uni.meter.val = 10.0 * log10(uni.meter.val + 1e-20);
+      uni.meter.tx.val[tap] += Csqrmag(vec[i]);
+    uni.meter.tx.avg[tap] =
+      uni.meter.tx.val[tap] =
+        10.0 * log10(uni.meter.tx.val[tap] + 1e-20);
     break;
   case ADC_REAL:
     for(i = 0; i < len; i++)
-      uni.meter.val = max(fabs(vec[i].re), uni.meter.val);
-    uni.meter.val = 20.0 * log10(uni.meter.val + 1e-10);
+      uni.meter.tx.val[tap] = max(fabs(vec[i].re), uni.meter.tx.val[tap]);
+    uni.meter.tx.val[tap] = 20.0 * log10(uni.meter.tx.val[tap] + 1e-10);
     break;
   case ADC_IMAG:
     for(i = 0; i < len; i++)
-      uni.meter.val = max(fabs(vec[i].im), uni.meter.val);
-    uni.meter.val = 20.0 * log10(uni.meter.val + 1e-10);
+      uni.meter.tx.val[tap] = max(fabs(vec[i].im), uni.meter.tx.val[tap]);
+    uni.meter.tx.val[tap] = 20.0 * log10(uni.meter.tx.val[tap] + 1e-10);
     break;
   default:
     break;
   }
+}
 
-  putChan_nowait(uni.meter.chan.c,
-                (char *) &uni.meter.val,
-                sizeof(uni.meter.val));
+PRIVATE BOOLEAN
+do_rx_spectrum(int k, CXB buf, int type) {
+  if (uni.spec.flag && k == uni.spec.rxk && type == uni.spec.type) {
+    memcpy((char *) &CXBdata(uni.spec.accum, uni.spec.fill),
+          (char *) CXBbase(buf),
+          CXBhave(buf)); 
+    uni.spec.fill = (uni.spec.fill + uni.spec.buflen) % uni.spec.size;
+  }
+}
+
+PRIVATE void
+do_tx_spectrum(CXB buf) {
+  memcpy((char *) &CXBdata(uni.spec.accum, uni.spec.fill),
+        (char *) CXBbase(buf),
+        CXBhave(buf));
+  uni.spec.fill = (uni.spec.fill + uni.spec.buflen) % uni.spec.size;
 }
 
 //========================================================================
@@ -448,10 +539,6 @@ PRIVATE void
 do_rx_pre(int k) {
   int i, n = min(CXBhave(rx[k].buf.i), uni.buflen);
 
-  //
-  // do shrinkage here?
-  //
-
   if (rx[k].scl.pre.flag)
     for (i = 0; i < n; i++)
       CXBdata(rx[k].buf.i, i) = Cscl(CXBdata(rx[k].buf.i, i),
@@ -460,6 +547,10 @@ do_rx_pre(int k) {
   if (rx[k].nb.flag) noiseblanker(rx[k].nb.gen);
   if (rx[k].nb_sdrom.flag) SDROMnoiseblanker(rx[k].nb_sdrom.gen);
 
+  // metering for uncorrected values here
+
+  do_rx_meter(k, rx[k].buf.i, RXMETER_PRE_CONV);
+
   correctIQ(rx[k].buf.i, rx[k].iqfix);
 
   /* 2nd IF conversion happens here */
@@ -471,33 +562,39 @@ do_rx_pre(int k) {
                                     OSCCdata(rx[k].osc.gen, i));
   } 
 
-  /* filtering, metering, squelch, & AGC */
-
-  if (rx[k].mode != SPEC) {
-
+  /* filtering, metering, spectrum, squelch, & AGC */
+  
+  if (rx[k].mode == SPEC)
+    
+    do_rx_spectrum(k, rx[k].buf.i, SPEC_SEMI_RAW);
+  
+  else {
+    
+    do_rx_meter(k, rx[k].buf.i, RXMETER_PRE_FILT);
+    do_rx_spectrum(k, rx[k].buf.i, SPEC_PRE_FILT);
+    
     if (rx[k].tick == 0)
       reset_OvSv(rx[k].filt.ovsv);
     
     filter_OvSv(rx[k].filt.ovsv);
     CXBhave(rx[k].buf.o) = CXBhave(rx[k].buf.i);
-
-    if (uni.meter.flag)
-      do_meter(CXBbase(rx[k].buf.o), uni.buflen);
-
+    
+    do_rx_meter(k, rx[k].buf.o, RXMETER_POST_FILT);
+    do_rx_spectrum(k, rx[k].buf.o, SPEC_POST_FILT);
+    
     if (should_do_rx_squelch(k))
       do_squelch(k);
-
+    
     else if (rx[k].agc.flag)
       DigitalAgc(rx[k].agc.gen, rx[k].tick);
-
-  } else if (uni.meter.flag)
-    do_meter(CXBbase(rx[k].buf.o), uni.buflen);
+    
+  }
 }
 
 PRIVATE void
 do_rx_post(int k) {
   int i, n = CXBhave(rx[k].buf.o);
-
+  
   if (!rx[k].squelch.set)  {
     no_squelch(k);
     // spotting tone
@@ -509,17 +606,17 @@ do_rx_post(int k) {
                                       CXBdata(rx[k].spot.gen->buf, i));
     }
   }
-
+  
   // final scaling
-
+  
   if (rx[k].scl.post.flag)
     for (i = 0; i < n; i++)
       CXBdata(rx[k].buf.o, i) = Cscl(CXBdata(rx[k].buf.o, i),
                                     rx[k].scl.post.val);
-
+  
   // not binaural?
   // position in stereo field
-
+  
   if (!rx[k].bin.flag)
     for (i = 0; i < n; i++)
       CXBdata(rx[k].buf.o, i) = Cscl(rx[k].azim, CXBreal(rx[k].buf.o, i));
@@ -585,8 +682,8 @@ do_rx(int k) {
 PRIVATE void
 do_tx_pre(void) {
 
-  if (tx.scl.pre.flag) {
-    int i, n = CXBhave(tx.buf.i);
+if (tx.scl.pre.flag) {
+int i, n = CXBhave(tx.buf.i);
     for (i = 0; i < n; i++)
       CXBdata(tx.buf.i, i) = Cmplx(CXBreal(tx.buf.i, i) * tx.scl.pre.val, 0.0);
   }
@@ -604,12 +701,20 @@ do_tx_post(void) {
   CXBhave(tx.buf.o) = CXBhave(tx.buf.i);
 
   if (tx.agc.flag) DigitalAgc(tx.agc.gen, tx.tick);
+
+  // meter modulated signal
+
+  do_tx_meter(tx.buf.o, TXMETER_POST_MOD);
+
   if (tx.scl.post.flag) {
     int i, n = CXBhave(tx.buf.o);
     for (i = 0; i < n; i++)
       CXBdata(tx.buf.o, i) = Cscl(CXBdata(tx.buf.o, i), tx.scl.post.val);
   }
-  if (uni.meter.flag) do_meter(CXBbase(tx.buf.o), uni.buflen);
+
+  if (uni.spec.flag)
+    do_tx_spectrum(tx.buf.o);
+
   if (tx.osc.gen->Frequency != 0.0) {
     int i;
     ComplexOSC(tx.osc.gen);
@@ -697,11 +802,11 @@ process_samples(float *bufl, float *bufr,
                float *auxl, float *auxr,
                int n) {
   int i, k;
-
+  
   switch (uni.mode.trx) {
-
+    
   case RX:
-
+    
     // make copies of the input for all receivers
     for (k = 0; k < uni.multirx.nrx; k++)
       if (uni.multirx.act[k]) {
@@ -720,11 +825,12 @@ process_samples(float *bufl, float *bufr,
        do_rx(k), rx[k].tick++;
        // mix
        for (i = 0; i < n; i++)
-         bufl[i] += CXBimag(rx[k].buf.o, i),
+          bufl[i] += CXBimag(rx[k].buf.o, i),
          bufr[i] += CXBreal(rx[k].buf.o, i);
        CXBhave(rx[k].buf.o) = n;
       }
 
+    // late mixing of aux buffers
     if (uni.mix.rx.flag)
       for (i = 0; i < n; i++)
        bufl[i] += auxl[i] * uni.mix.rx.gain,
@@ -734,6 +840,7 @@ process_samples(float *bufl, float *bufr,
 
   case TX:
 
+    // early mixing of aux buffers
     if (uni.mix.tx.flag)
       for (i = 0; i < n; i++)
        bufl[i] += auxl[i] * uni.mix.tx.gain,