[FFmpeg-devel] [PATCH 1/2] avradio/sdr: Add CQUAM support

Michael Niedermayer michael at niedermayer.cc
Fri Jul 28 01:38:36 EEST 2023


untested as i have no clean signal from a CQUAM station

Signed-off-by: Michael Niedermayer <michael at niedermayer.cc>
---
 libavradio/sdr.h      |  1 +
 libavradio/sdrdemux.c | 37 +++++++++++++++++++++++++++++++------
 2 files changed, 32 insertions(+), 6 deletions(-)

diff --git a/libavradio/sdr.h b/libavradio/sdr.h
index 6d11ef794f..b27e6a719e 100644
--- a/libavradio/sdr.h
+++ b/libavradio/sdr.h
@@ -50,6 +50,7 @@ typedef enum AMMode {
     AMLeftRight,
     AMInPhase,
     AMEnvelope,
+    AMCQUAM,
     AMModeNB,
 } AMMode;
 
diff --git a/libavradio/sdrdemux.c b/libavradio/sdrdemux.c
index 3b24cfedef..78c933f6f1 100644
--- a/libavradio/sdrdemux.c
+++ b/libavradio/sdrdemux.c
@@ -805,13 +805,35 @@ static int demodulate_am(SDRContext *sdr, Station *station, AVStream *st, AVPack
         wamp = amp/stamp;
 
         mm = (AVComplexFloat){dc1.re * amp, -dc1.im * amp};
-        for(i = 0; i<2*sdr->am_block_size; i++) {
-            AVComplexFloat v = sdr->am_iblock[i];
-            sdr->am_iblock[i].re = v.re*mm.re - v.im*mm.im - sdr->am_window[i] * wamp;
-            sdr->am_iblock[i].im = v.re*mm.im + v.im*mm.re;
-        }
+        if (am_mode == AMCQUAM) {
+            double vdotw = 0;
+            for(i = 0; i<2*sdr->am_block_size; i++) {
+                AVComplexFloat v = sdr->am_iblock[i];
+                float I = v.re*mm.re - v.im*mm.im;
+                float Q = v.re*mm.im + v.im*mm.re;
+                float m = sqrt(I*I + Q*Q);
+                //An ideal signal needs no limit but a real noisy signal can become 0 and negative, The limit of 2.0 is arbitrary and still needs to be tuned once we have real world test signals
+                float s = Q * FFMIN(m / fabs(I), 2.0);
+
+                sdr->am_iblock[i].re = m;
+                sdr->am_iblock[i].im = s;
+                vdotw += sdr->am_window[i] * m;
+            }
+            vdotw /= dcw ;
+            for (i = 0; i<2*sdr->am_block_size; i++) {
+                float w = sdr->am_window[i];
+                sdr->am_iblock[i].re -= w*vdotw;
+            }
 
-        scale = 0.9;
+            scale = 0.9/vdotw;
+        } else {
+            for(i = 0; i<2*sdr->am_block_size; i++) {
+                AVComplexFloat v = sdr->am_iblock[i];
+                sdr->am_iblock[i].re = v.re*mm.re - v.im*mm.im - sdr->am_window[i] * wamp;
+                sdr->am_iblock[i].im = v.re*mm.im + v.im*mm.re;
+            }
+            scale = 0.9;
+        }
     }
 
     for(i = 0; i<2*sdr->am_block_size; i++) {
@@ -832,10 +854,12 @@ static int demodulate_am(SDRContext *sdr, Station *station, AVStream *st, AVPack
         switch(am_mode) {
         case AMMidSide:
         case AMLeftRight:
+        case AMCQUAM:
             q = sst->out_buf[2*i+1] +  sdr->am_iblock[i                     ].im * sdr->am_window[i                     ] * scale;
             newbuf[2*i+1]           =  sdr->am_iblock[i + sdr->am_block_size].im * sdr->am_window[i + sdr->am_block_size] * scale;
             switch(am_mode) {
             case AMMidSide:
+            case AMCQUAM:
                 q *= 0.5;
                 sst->out_buf[2*i+0] = m + q;
                 sst->out_buf[2*i+1] = m - q;
@@ -2316,6 +2340,7 @@ const AVOption ff_sdr_options[] = {
         { "am_midside", "AM Demodulation Mid Side", 0, AV_OPT_TYPE_CONST,   {.i64 = AMMidSide}, 0, 0, DEC, "am_mode"},
         { "am_inphase", "AM Demodulation In Phase", 0, AV_OPT_TYPE_CONST,   {.i64 = AMInPhase}, 0, 0, DEC, "am_mode"},
         { "am_envelope","AM Demodulation EnvelopeDC", 0, AV_OPT_TYPE_CONST, {.i64 = AMEnvelope}, 0, 0, DEC, "am_mode"},
+        { "am_cquam","CQUAM Stereo Demodulation", 0, AV_OPT_TYPE_CONST, {.i64 = AMCQUAM}, 0, 0, DEC, "am_mode"},
 
     { "am_fft_ref", "Use FFT Based carrier for AM demodulation", OFFSET(am_fft_ref), AV_OPT_TYPE_INT , {.i64 = 0}, 0, 1, DEC},
 
-- 
2.31.1



More information about the ffmpeg-devel mailing list