[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