Compare commits
1 Commits
wfm
..
81f7750def
| Author | SHA1 | Date | |
|---|---|---|---|
| 81f7750def |
@@ -144,8 +144,6 @@ utilities.c \
|
|||||||
varsamp.c \
|
varsamp.c \
|
||||||
version.c \
|
version.c \
|
||||||
wcpAGC.c \
|
wcpAGC.c \
|
||||||
wfmd.c \
|
|
||||||
wfmmod.c \
|
|
||||||
wisdom.c \
|
wisdom.c \
|
||||||
zetaHat.c
|
zetaHat.c
|
||||||
|
|
||||||
|
|||||||
@@ -119,8 +119,6 @@ utilities.c \
|
|||||||
varsamp.c \
|
varsamp.c \
|
||||||
version.c \
|
version.c \
|
||||||
wcpAGC.c \
|
wcpAGC.c \
|
||||||
wfmd.c \
|
|
||||||
wfmmod.c \
|
|
||||||
wisdom.c \
|
wisdom.c \
|
||||||
zetaHat.c
|
zetaHat.c
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -86,7 +86,7 @@ SOURCES = \
|
|||||||
matchedCW.c meter.c meterlog10.c nbp.c nob.c nobII.c osctrl.c \
|
matchedCW.c meter.c meterlog10.c nbp.c nob.c nobII.c osctrl.c \
|
||||||
patchpanel.c resample.c rmatch.c rnnr.c RXA.c sbnr.c sender.c \
|
patchpanel.c resample.c rmatch.c rnnr.c RXA.c sbnr.c sender.c \
|
||||||
shift.c siphon.c slew.c snb.c ssql.c syncbuffs.c TXA.c \
|
shift.c siphon.c slew.c snb.c ssql.c syncbuffs.c TXA.c \
|
||||||
utilities.c varsamp.c version.c wcpAGC.c wfmd.c wfmmod.c wisdom.c zetaHat.c
|
utilities.c varsamp.c version.c wcpAGC.c wisdom.c zetaHat.c
|
||||||
|
|
||||||
OBJS := $(addprefix $(OBJDIR)/, $(SOURCES:.c=.o))
|
OBJS := $(addprefix $(OBJDIR)/, $(SOURCES:.c=.o))
|
||||||
|
|
||||||
|
|||||||
@@ -233,23 +233,6 @@ void create_rxa (int channel)
|
|||||||
max(2048, ch[channel].dsp_size), // number of coefficients for noise filter
|
max(2048, ch[channel].dsp_size), // number of coefficients for noise filter
|
||||||
0); // minimum phase flag
|
0); // minimum phase flag
|
||||||
|
|
||||||
// WFM demod
|
|
||||||
rxa[channel].wfmd.p = create_wfmd (
|
|
||||||
0, // run
|
|
||||||
ch[channel].dsp_size, // buffer size
|
|
||||||
rxa[channel].midbuff, // pointer to input buffer
|
|
||||||
rxa[channel].midbuff, // pointer to output buffer
|
|
||||||
ch[channel].dsp_rate, // sample rate
|
|
||||||
75000.0, // deviation
|
|
||||||
20.0, // f_low
|
|
||||||
15000.0, // f_high
|
|
||||||
0.02, // tau - for dc removal
|
|
||||||
1, // run de-emphasis
|
|
||||||
75.0e-6, // de-emphasis time constant
|
|
||||||
0.5, // audio gain
|
|
||||||
max(2048, ch[channel].dsp_size), // # coefs for audio cutoff filter
|
|
||||||
0); // min phase flag for audio cutoff filter
|
|
||||||
|
|
||||||
// snba
|
// snba
|
||||||
rxa[channel].snba.p = create_snba (
|
rxa[channel].snba.p = create_snba (
|
||||||
0, // run
|
0, // run
|
||||||
@@ -596,7 +579,6 @@ void destroy_rxa (int channel)
|
|||||||
destroy_anf (rxa[channel].anf.p);
|
destroy_anf (rxa[channel].anf.p);
|
||||||
destroy_eqp (rxa[channel].eqp.p);
|
destroy_eqp (rxa[channel].eqp.p);
|
||||||
destroy_snba (rxa[channel].snba.p);
|
destroy_snba (rxa[channel].snba.p);
|
||||||
destroy_wfmd (rxa[channel].wfmd.p);
|
|
||||||
destroy_fmsq (rxa[channel].fmsq.p);
|
destroy_fmsq (rxa[channel].fmsq.p);
|
||||||
destroy_fmd (rxa[channel].fmd.p);
|
destroy_fmd (rxa[channel].fmd.p);
|
||||||
destroy_amd (rxa[channel].amd.p);
|
destroy_amd (rxa[channel].amd.p);
|
||||||
@@ -632,7 +614,6 @@ void flush_rxa (int channel)
|
|||||||
flush_amd (rxa[channel].amd.p);
|
flush_amd (rxa[channel].amd.p);
|
||||||
flush_fmd (rxa[channel].fmd.p);
|
flush_fmd (rxa[channel].fmd.p);
|
||||||
flush_fmsq (rxa[channel].fmsq.p);
|
flush_fmsq (rxa[channel].fmsq.p);
|
||||||
flush_wfmd (rxa[channel].wfmd.p);
|
|
||||||
flush_snba (rxa[channel].snba.p);
|
flush_snba (rxa[channel].snba.p);
|
||||||
flush_eqp (rxa[channel].eqp.p);
|
flush_eqp (rxa[channel].eqp.p);
|
||||||
flush_anf (rxa[channel].anf.p);
|
flush_anf (rxa[channel].anf.p);
|
||||||
@@ -668,7 +649,6 @@ void xrxa (int channel)
|
|||||||
xamd (rxa[channel].amd.p);
|
xamd (rxa[channel].amd.p);
|
||||||
xfmd (rxa[channel].fmd.p);
|
xfmd (rxa[channel].fmd.p);
|
||||||
xfmsq (rxa[channel].fmsq.p);
|
xfmsq (rxa[channel].fmsq.p);
|
||||||
xwfmd (rxa[channel].wfmd.p);
|
|
||||||
xbpsnbain (rxa[channel].bpsnba.p, 1);
|
xbpsnbain (rxa[channel].bpsnba.p, 1);
|
||||||
xbpsnbaout (rxa[channel].bpsnba.p, 1);
|
xbpsnbaout (rxa[channel].bpsnba.p, 1);
|
||||||
xsnba (rxa[channel].snba.p);
|
xsnba (rxa[channel].snba.p);
|
||||||
@@ -753,7 +733,6 @@ void setDSPSamplerate_rxa (int channel)
|
|||||||
setSamplerate_fmd (rxa[channel].fmd.p, ch[channel].dsp_rate);
|
setSamplerate_fmd (rxa[channel].fmd.p, ch[channel].dsp_rate);
|
||||||
setBuffers_fmsq (rxa[channel].fmsq.p, rxa[channel].midbuff, rxa[channel].midbuff, rxa[channel].fmd.p->audio);
|
setBuffers_fmsq (rxa[channel].fmsq.p, rxa[channel].midbuff, rxa[channel].midbuff, rxa[channel].fmd.p->audio);
|
||||||
setSamplerate_fmsq (rxa[channel].fmsq.p, ch[channel].dsp_rate);
|
setSamplerate_fmsq (rxa[channel].fmsq.p, ch[channel].dsp_rate);
|
||||||
setSamplerate_wfmd (rxa[channel].wfmd.p, ch[channel].dsp_rate);
|
|
||||||
setSamplerate_snba (rxa[channel].snba.p, ch[channel].dsp_rate);
|
setSamplerate_snba (rxa[channel].snba.p, ch[channel].dsp_rate);
|
||||||
setSamplerate_eqp (rxa[channel].eqp.p, ch[channel].dsp_rate);
|
setSamplerate_eqp (rxa[channel].eqp.p, ch[channel].dsp_rate);
|
||||||
setSamplerate_anf (rxa[channel].anf.p, ch[channel].dsp_rate);
|
setSamplerate_anf (rxa[channel].anf.p, ch[channel].dsp_rate);
|
||||||
@@ -815,8 +794,6 @@ void setDSPBuffsize_rxa (int channel)
|
|||||||
setSize_fmd (rxa[channel].fmd.p, ch[channel].dsp_size);
|
setSize_fmd (rxa[channel].fmd.p, ch[channel].dsp_size);
|
||||||
setBuffers_fmsq (rxa[channel].fmsq.p, rxa[channel].midbuff, rxa[channel].midbuff, rxa[channel].fmd.p->audio);
|
setBuffers_fmsq (rxa[channel].fmsq.p, rxa[channel].midbuff, rxa[channel].midbuff, rxa[channel].fmd.p->audio);
|
||||||
setSize_fmsq (rxa[channel].fmsq.p, ch[channel].dsp_size);
|
setSize_fmsq (rxa[channel].fmsq.p, ch[channel].dsp_size);
|
||||||
setBuffers_wfmd (rxa[channel].wfmd.p, rxa[channel].midbuff, rxa[channel].midbuff);
|
|
||||||
setSize_wfmd (rxa[channel].wfmd.p, ch[channel].dsp_size);
|
|
||||||
setBuffers_snba (rxa[channel].snba.p, rxa[channel].midbuff, rxa[channel].midbuff);
|
setBuffers_snba (rxa[channel].snba.p, rxa[channel].midbuff, rxa[channel].midbuff);
|
||||||
setSize_snba (rxa[channel].snba.p, ch[channel].dsp_size);
|
setSize_snba (rxa[channel].snba.p, ch[channel].dsp_size);
|
||||||
setBuffers_eqp (rxa[channel].eqp.p, rxa[channel].midbuff, rxa[channel].midbuff);
|
setBuffers_eqp (rxa[channel].eqp.p, rxa[channel].midbuff, rxa[channel].midbuff);
|
||||||
@@ -880,7 +857,6 @@ void SetRXAMode (int channel, int mode)
|
|||||||
rxa[channel].mode = mode;
|
rxa[channel].mode = mode;
|
||||||
rxa[channel].amd.p->run = 0;
|
rxa[channel].amd.p->run = 0;
|
||||||
rxa[channel].fmd.p->run = 0;
|
rxa[channel].fmd.p->run = 0;
|
||||||
rxa[channel].wfmd.p->run = 0;
|
|
||||||
rxa[channel].agc.p->run = 1;
|
rxa[channel].agc.p->run = 1;
|
||||||
switch (mode)
|
switch (mode)
|
||||||
{
|
{
|
||||||
@@ -899,10 +875,6 @@ void SetRXAMode (int channel, int mode)
|
|||||||
rxa[channel].fmd.p->run = 1;
|
rxa[channel].fmd.p->run = 1;
|
||||||
rxa[channel].agc.p->run = 0;
|
rxa[channel].agc.p->run = 0;
|
||||||
break;
|
break;
|
||||||
case RXA_WFM:
|
|
||||||
rxa[channel].wfmd.p->run = 1;
|
|
||||||
rxa[channel].agc.p->run = 0;
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@@ -989,7 +961,6 @@ void RXAbpsnbaCheck (int channel, int mode, int notch_run)
|
|||||||
run_notches = 0;
|
run_notches = 0;
|
||||||
break;
|
break;
|
||||||
case RXA_FM:
|
case RXA_FM:
|
||||||
case RXA_WFM:
|
|
||||||
f_low = +a->abs_low_freq;
|
f_low = +a->abs_low_freq;
|
||||||
f_high = +a->abs_high_freq;
|
f_high = +a->abs_high_freq;
|
||||||
run_notches = 0;
|
run_notches = 0;
|
||||||
@@ -1039,7 +1010,6 @@ void RXAbpsnbaSet (int channel)
|
|||||||
a->position = 1;
|
a->position = 1;
|
||||||
break;
|
break;
|
||||||
case RXA_FM:
|
case RXA_FM:
|
||||||
case RXA_WFM:
|
|
||||||
a->run = rxa[channel].snba.p->run;
|
a->run = rxa[channel].snba.p->run;
|
||||||
a->position = 1;
|
a->position = 1;
|
||||||
break;
|
break;
|
||||||
@@ -1076,7 +1046,6 @@ void RXASetNC (int channel, int nc)
|
|||||||
SetRXAFMSQNC (channel, nc);
|
SetRXAFMSQNC (channel, nc);
|
||||||
SetRXAFMNCde (channel, nc);
|
SetRXAFMNCde (channel, nc);
|
||||||
SetRXAFMNCaud (channel, nc);
|
SetRXAFMNCaud (channel, nc);
|
||||||
SetRXAWFMNCaud (channel, nc);
|
|
||||||
SetChannelState (channel, oldstate, 0);
|
SetChannelState (channel, oldstate, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1090,5 +1059,4 @@ void RXASetMP (int channel, int mp)
|
|||||||
SetRXAFMSQMP (channel, mp);
|
SetRXAFMSQMP (channel, mp);
|
||||||
SetRXAFMMPde (channel, mp);
|
SetRXAFMMPde (channel, mp);
|
||||||
SetRXAFMMPaud (channel, mp);
|
SetRXAFMMPaud (channel, mp);
|
||||||
SetRXAWFMMPaud (channel, mp);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,8 +41,7 @@ enum rxaMode
|
|||||||
RXA_SPEC,
|
RXA_SPEC,
|
||||||
RXA_DIGL,
|
RXA_DIGL,
|
||||||
RXA_SAM,
|
RXA_SAM,
|
||||||
RXA_DRM,
|
RXA_DRM
|
||||||
RXA_WFM
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum rxaMeterType
|
enum rxaMeterType
|
||||||
@@ -122,10 +121,6 @@ struct _rxa
|
|||||||
FMSQ p;
|
FMSQ p;
|
||||||
} fmsq;
|
} fmsq;
|
||||||
struct
|
struct
|
||||||
{
|
|
||||||
WFMD p;
|
|
||||||
} wfmd;
|
|
||||||
struct
|
|
||||||
{
|
{
|
||||||
EQP p;
|
EQP p;
|
||||||
} eqp;
|
} eqp;
|
||||||
|
|||||||
@@ -358,21 +358,6 @@ void create_txa (int channel)
|
|||||||
max(2048, ch[channel].dsp_size), // number coefficients for bandpass filter
|
max(2048, ch[channel].dsp_size), // number coefficients for bandpass filter
|
||||||
0); // minimum phase flag
|
0); // minimum phase flag
|
||||||
|
|
||||||
txa[channel].wfmmod.p = create_wfmmod (
|
|
||||||
0, // run - OFF by default
|
|
||||||
ch[channel].dsp_size, // size
|
|
||||||
txa[channel].midbuff, // pointer to input buffer
|
|
||||||
txa[channel].midbuff, // pointer to output buffer
|
|
||||||
ch[channel].dsp_rate, // samplerate
|
|
||||||
75000.0, // deviation
|
|
||||||
20.0, // low cutoff frequency
|
|
||||||
15000.0, // high cutoff frequency
|
|
||||||
1, // run pre-emphasis
|
|
||||||
75.0e-6, // pre-emphasis time constant
|
|
||||||
1, // run bandpass filter
|
|
||||||
max(2048, ch[channel].dsp_size), // number coefficients for bandpass filter
|
|
||||||
0); // minimum phase flag
|
|
||||||
|
|
||||||
txa[channel].gen1.p = create_gen (
|
txa[channel].gen1.p = create_gen (
|
||||||
0, // run
|
0, // run
|
||||||
ch[channel].dsp_size, // buffer size
|
ch[channel].dsp_size, // buffer size
|
||||||
@@ -505,7 +490,6 @@ void destroy_txa (int channel)
|
|||||||
destroy_meter (txa[channel].alcmeter.p);
|
destroy_meter (txa[channel].alcmeter.p);
|
||||||
destroy_uslew (txa[channel].uslew.p);
|
destroy_uslew (txa[channel].uslew.p);
|
||||||
destroy_gen (txa[channel].gen1.p);
|
destroy_gen (txa[channel].gen1.p);
|
||||||
destroy_wfmmod (txa[channel].wfmmod.p);
|
|
||||||
destroy_fmmod (txa[channel].fmmod.p);
|
destroy_fmmod (txa[channel].fmmod.p);
|
||||||
destroy_ammod (txa[channel].ammod.p);
|
destroy_ammod (txa[channel].ammod.p);
|
||||||
destroy_wcpagc (txa[channel].alc.p);
|
destroy_wcpagc (txa[channel].alc.p);
|
||||||
@@ -560,7 +544,6 @@ void flush_txa (int channel)
|
|||||||
flush_wcpagc (txa[channel].alc.p);
|
flush_wcpagc (txa[channel].alc.p);
|
||||||
flush_ammod (txa[channel].ammod.p);
|
flush_ammod (txa[channel].ammod.p);
|
||||||
flush_fmmod (txa[channel].fmmod.p);
|
flush_fmmod (txa[channel].fmmod.p);
|
||||||
flush_wfmmod (txa[channel].wfmmod.p);
|
|
||||||
flush_gen (txa[channel].gen1.p);
|
flush_gen (txa[channel].gen1.p);
|
||||||
flush_uslew (txa[channel].uslew.p);
|
flush_uslew (txa[channel].uslew.p);
|
||||||
flush_meter (txa[channel].alcmeter.p);
|
flush_meter (txa[channel].alcmeter.p);
|
||||||
@@ -597,7 +580,6 @@ void xtxa (int channel)
|
|||||||
xammod (txa[channel].ammod.p); // AM Modulator
|
xammod (txa[channel].ammod.p); // AM Modulator
|
||||||
xemphp (txa[channel].preemph.p, 1); // FM pre-emphasis (second option)
|
xemphp (txa[channel].preemph.p, 1); // FM pre-emphasis (second option)
|
||||||
xfmmod (txa[channel].fmmod.p); // FM Modulator
|
xfmmod (txa[channel].fmmod.p); // FM Modulator
|
||||||
xwfmmod (txa[channel].wfmmod.p); // WFM Modulator (pre-emphasis is internal)
|
|
||||||
xgen (txa[channel].gen1.p); // output signal generator (TUN and Two-tone)
|
xgen (txa[channel].gen1.p); // output signal generator (TUN and Two-tone)
|
||||||
xuslew (txa[channel].uslew.p); // up-slew for AM, FM, and gens
|
xuslew (txa[channel].uslew.p); // up-slew for AM, FM, and gens
|
||||||
xmeter (txa[channel].alcmeter.p); // ALC Meter
|
xmeter (txa[channel].alcmeter.p); // ALC Meter
|
||||||
@@ -671,7 +653,6 @@ void setDSPSamplerate_txa (int channel)
|
|||||||
setSamplerate_wcpagc (txa[channel].alc.p, ch[channel].dsp_rate);
|
setSamplerate_wcpagc (txa[channel].alc.p, ch[channel].dsp_rate);
|
||||||
setSamplerate_ammod (txa[channel].ammod.p, ch[channel].dsp_rate);
|
setSamplerate_ammod (txa[channel].ammod.p, ch[channel].dsp_rate);
|
||||||
setSamplerate_fmmod (txa[channel].fmmod.p, ch[channel].dsp_rate);
|
setSamplerate_fmmod (txa[channel].fmmod.p, ch[channel].dsp_rate);
|
||||||
setSamplerate_wfmmod (txa[channel].wfmmod.p, ch[channel].dsp_rate);
|
|
||||||
setSamplerate_gen (txa[channel].gen1.p, ch[channel].dsp_rate);
|
setSamplerate_gen (txa[channel].gen1.p, ch[channel].dsp_rate);
|
||||||
setSamplerate_uslew (txa[channel].uslew.p, ch[channel].dsp_rate);
|
setSamplerate_uslew (txa[channel].uslew.p, ch[channel].dsp_rate);
|
||||||
setSamplerate_meter (txa[channel].alcmeter.p, ch[channel].dsp_rate);
|
setSamplerate_meter (txa[channel].alcmeter.p, ch[channel].dsp_rate);
|
||||||
@@ -742,8 +723,6 @@ void setDSPBuffsize_txa (int channel)
|
|||||||
setSize_ammod (txa[channel].ammod.p, ch[channel].dsp_size);
|
setSize_ammod (txa[channel].ammod.p, ch[channel].dsp_size);
|
||||||
setBuffers_fmmod (txa[channel].fmmod.p, txa[channel].midbuff, txa[channel].midbuff);
|
setBuffers_fmmod (txa[channel].fmmod.p, txa[channel].midbuff, txa[channel].midbuff);
|
||||||
setSize_fmmod (txa[channel].fmmod.p, ch[channel].dsp_size);
|
setSize_fmmod (txa[channel].fmmod.p, ch[channel].dsp_size);
|
||||||
setBuffers_wfmmod (txa[channel].wfmmod.p, txa[channel].midbuff, txa[channel].midbuff);
|
|
||||||
setSize_wfmmod (txa[channel].wfmmod.p, ch[channel].dsp_size);
|
|
||||||
setBuffers_gen (txa[channel].gen1.p, txa[channel].midbuff, txa[channel].midbuff);
|
setBuffers_gen (txa[channel].gen1.p, txa[channel].midbuff, txa[channel].midbuff);
|
||||||
setSize_gen (txa[channel].gen1.p, ch[channel].dsp_size);
|
setSize_gen (txa[channel].gen1.p, ch[channel].dsp_size);
|
||||||
setBuffers_uslew (txa[channel].uslew.p, txa[channel].midbuff, txa[channel].midbuff);
|
setBuffers_uslew (txa[channel].uslew.p, txa[channel].midbuff, txa[channel].midbuff);
|
||||||
@@ -779,7 +758,6 @@ void SetTXAMode (int channel, int mode)
|
|||||||
txa[channel].mode = mode;
|
txa[channel].mode = mode;
|
||||||
txa[channel].ammod.p->run = 0;
|
txa[channel].ammod.p->run = 0;
|
||||||
txa[channel].fmmod.p->run = 0;
|
txa[channel].fmmod.p->run = 0;
|
||||||
txa[channel].wfmmod.p->run = 0;
|
|
||||||
txa[channel].preemph.p->run = 0;
|
txa[channel].preemph.p->run = 0;
|
||||||
switch (mode)
|
switch (mode)
|
||||||
{
|
{
|
||||||
@@ -801,10 +779,6 @@ void SetTXAMode (int channel, int mode)
|
|||||||
txa[channel].fmmod.p->run = 1;
|
txa[channel].fmmod.p->run = 1;
|
||||||
txa[channel].preemph.p->run = 1;
|
txa[channel].preemph.p->run = 1;
|
||||||
break;
|
break;
|
||||||
case TXA_WFM:
|
|
||||||
// wfmmod carries its own RC pre-emphasis; the shared emphp stays off
|
|
||||||
txa[channel].wfmmod.p->run = 1;
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@@ -846,7 +820,6 @@ int TXAUslewCheck (int channel)
|
|||||||
{
|
{
|
||||||
return (txa[channel].ammod.p->run == 1) ||
|
return (txa[channel].ammod.p->run == 1) ||
|
||||||
(txa[channel].fmmod.p->run == 1) ||
|
(txa[channel].fmmod.p->run == 1) ||
|
||||||
(txa[channel].wfmmod.p->run == 1) ||
|
|
||||||
(txa[channel].gen0.p->run == 1) ||
|
(txa[channel].gen0.p->run == 1) ||
|
||||||
(txa[channel].gen1.p->run == 1);
|
(txa[channel].gen1.p->run == 1);
|
||||||
}
|
}
|
||||||
@@ -882,7 +855,6 @@ void TXASetupBPFilters (int channel)
|
|||||||
case TXA_AM:
|
case TXA_AM:
|
||||||
case TXA_SAM:
|
case TXA_SAM:
|
||||||
case TXA_FM:
|
case TXA_FM:
|
||||||
case TXA_WFM:
|
|
||||||
if (txa[channel].compressor.p->run)
|
if (txa[channel].compressor.p->run)
|
||||||
{
|
{
|
||||||
CalcBandpassFilter (txa[channel].bp0.p, 0.0, txa[channel].f_high, 2.0);
|
CalcBandpassFilter (txa[channel].bp0.p, 0.0, txa[channel].f_high, 2.0);
|
||||||
@@ -942,7 +914,6 @@ void TXASetNC (int channel, int nc)
|
|||||||
SetTXAFMEmphNC (channel, nc);
|
SetTXAFMEmphNC (channel, nc);
|
||||||
SetTXAEQNC (channel, nc);
|
SetTXAEQNC (channel, nc);
|
||||||
SetTXAFMNC (channel, nc);
|
SetTXAFMNC (channel, nc);
|
||||||
SetTXAWFMNC (channel, nc);
|
|
||||||
SetTXACFIRNC (channel, nc);
|
SetTXACFIRNC (channel, nc);
|
||||||
SetChannelState (channel, oldstate, 0);
|
SetChannelState (channel, oldstate, 0);
|
||||||
}
|
}
|
||||||
@@ -954,7 +925,6 @@ void TXASetMP (int channel, int mp)
|
|||||||
SetTXAFMEmphMP (channel, mp);
|
SetTXAFMEmphMP (channel, mp);
|
||||||
SetTXAEQMP (channel, mp);
|
SetTXAEQMP (channel, mp);
|
||||||
SetTXAFMMP (channel, mp);
|
SetTXAFMMP (channel, mp);
|
||||||
SetTXAWFMMP (channel, mp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PORT
|
PORT
|
||||||
|
|||||||
@@ -43,8 +43,7 @@ enum txaMode
|
|||||||
TXA_SAM,
|
TXA_SAM,
|
||||||
TXA_DRM,
|
TXA_DRM,
|
||||||
TXA_AM_LSB,
|
TXA_AM_LSB,
|
||||||
TXA_AM_USB,
|
TXA_AM_USB
|
||||||
TXA_WFM
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum txaMeterType
|
enum txaMeterType
|
||||||
@@ -136,10 +135,6 @@ struct _txa
|
|||||||
FMMOD p;
|
FMMOD p;
|
||||||
} fmmod;
|
} fmmod;
|
||||||
struct
|
struct
|
||||||
{
|
|
||||||
WFMMOD p;
|
|
||||||
} wfmmod;
|
|
||||||
struct
|
|
||||||
{
|
{
|
||||||
SIPHON p;
|
SIPHON p;
|
||||||
} sip1;
|
} sip1;
|
||||||
|
|||||||
@@ -138,7 +138,6 @@ CALCC create_calcc (int channel, int runcal, int size, int rate, int ints, int s
|
|||||||
a->stbl = stbl;
|
a->stbl = stbl;
|
||||||
a->npsamps = npsamps;
|
a->npsamps = npsamps;
|
||||||
a->alpha = alpha;
|
a->alpha = alpha;
|
||||||
a->outlier_sigma = 0.0;
|
|
||||||
|
|
||||||
a->info = (int *) malloc0 (16 * sizeof (int));
|
a->info = (int *) malloc0 (16 * sizeof (int));
|
||||||
a->binfo = (int *) malloc0 (16 * sizeof (int));
|
a->binfo = (int *) malloc0 (16 * sizeof (int));
|
||||||
@@ -322,125 +321,6 @@ void rxscheck (int rints, double* tvec, double* coef, int* info)
|
|||||||
if (out < 0.00) *info |= 0x0020;
|
if (out < 0.00) *info |= 0x0020;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Yurij_eu2av: fallback rx_scale estimator. It averages the top few
|
|
||||||
// amplitude intervals (ignoring overrange samples) and linearly extrapolates
|
|
||||||
// to full TX scale (env_TX = 1/hw_scale). Used only if the cubic xbuilder
|
|
||||||
// fit fails or is rejected by rxscheck.
|
|
||||||
static int estimate_rx_scale_from_top_intervals(CALCC a, double* rx_scale_out)
|
|
||||||
{
|
|
||||||
const int n_top = 4;
|
|
||||||
double sx[4], sy[4], sw[4];
|
|
||||||
int valid = 0;
|
|
||||||
int b, j;
|
|
||||||
for (b = a->ints - 1; b >= 0 && valid < n_top; b--)
|
|
||||||
{
|
|
||||||
int base = b * a->spi;
|
|
||||||
double sum_x = 0.0, sum_y = 0.0;
|
|
||||||
int n = 0;
|
|
||||||
for (j = 0; j < a->spi; j++)
|
|
||||||
{
|
|
||||||
int k = base + j;
|
|
||||||
double nx = a->env_TX[k] * a->hw_scale;
|
|
||||||
if (nx > 1.0 || nx < 0.0) continue;
|
|
||||||
if (a->env_TX[k] < 1.0e-30 || a->env_RX[k] < 1.0e-30) continue;
|
|
||||||
sum_x += a->env_TX[k];
|
|
||||||
sum_y += a->env_RX[k];
|
|
||||||
n++;
|
|
||||||
}
|
|
||||||
if (n == 0) continue;
|
|
||||||
sx[valid] = sum_x / (double)n;
|
|
||||||
sy[valid] = sum_y / (double)n;
|
|
||||||
sw[valid] = (double)n;
|
|
||||||
valid++;
|
|
||||||
}
|
|
||||||
if (valid < 2) return -1;
|
|
||||||
{
|
|
||||||
double s_w = 0.0, s_x = 0.0, s_y = 0.0, s_xx = 0.0, s_xy = 0.0;
|
|
||||||
double det, aa, bb, target_x, y_at_target;
|
|
||||||
int i;
|
|
||||||
for (i = 0; i < valid; i++)
|
|
||||||
{
|
|
||||||
double w = sw[i];
|
|
||||||
s_w += w;
|
|
||||||
s_x += w * sx[i];
|
|
||||||
s_y += w * sy[i];
|
|
||||||
s_xx += w * sx[i] * sx[i];
|
|
||||||
s_xy += w * sx[i] * sy[i];
|
|
||||||
}
|
|
||||||
det = s_w * s_xx - s_x * s_x;
|
|
||||||
if (fabs(det) < 1e-30) return -1;
|
|
||||||
bb = (s_w * s_xy - s_x * s_y) / det;
|
|
||||||
aa = (s_y - bb * s_x) / s_w;
|
|
||||||
target_x = 1.0 / a->hw_scale;
|
|
||||||
y_at_target = aa + bb * target_x;
|
|
||||||
if (y_at_target <= 1e-15) return -1;
|
|
||||||
*rx_scale_out = 1.0 / y_at_target;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Yurij_eu2av: robust outlier rejection for the cubic-spline xbuilder.
|
|
||||||
// Fits rx = k*tx through the origin via median ratio, then rejects points
|
|
||||||
// whose residual exceeds sigma * MAD.
|
|
||||||
static int cmp_double(const void* a, const void* b)
|
|
||||||
{
|
|
||||||
double da = *(const double*)a;
|
|
||||||
double db = *(const double*)b;
|
|
||||||
if (da < db) return -1;
|
|
||||||
if (da > db) return 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static double median_double(double* v, int n)
|
|
||||||
{
|
|
||||||
if (n <= 0) return 0.0;
|
|
||||||
if (n % 2 == 1)
|
|
||||||
return v[n / 2];
|
|
||||||
else
|
|
||||||
return 0.5 * (v[n / 2 - 1] + v[n / 2]);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int reject_outliers(double* tx, double* rx, int n, double sigma)
|
|
||||||
{
|
|
||||||
const int min_points = 32;
|
|
||||||
int i, keep = 0;
|
|
||||||
double* ratios;
|
|
||||||
double* absres;
|
|
||||||
double med_ratio, med_absres, thr;
|
|
||||||
|
|
||||||
if (n < min_points || sigma <= 0.0) return n;
|
|
||||||
|
|
||||||
ratios = (double*)malloc0(n * sizeof(double));
|
|
||||||
for (i = 0; i < n; i++)
|
|
||||||
ratios[i] = (tx[i] > 1.0e-30) ? rx[i] / tx[i] : 0.0;
|
|
||||||
qsort(ratios, n, sizeof(double), cmp_double);
|
|
||||||
med_ratio = median_double(ratios, n);
|
|
||||||
_aligned_free(ratios);
|
|
||||||
|
|
||||||
if (fabs(med_ratio) < 1.0e-30) return n;
|
|
||||||
|
|
||||||
absres = (double*)malloc0(n * sizeof(double));
|
|
||||||
for (i = 0; i < n; i++)
|
|
||||||
absres[i] = fabs(rx[i] - med_ratio * tx[i]);
|
|
||||||
qsort(absres, n, sizeof(double), cmp_double);
|
|
||||||
med_absres = median_double(absres, n);
|
|
||||||
_aligned_free(absres);
|
|
||||||
|
|
||||||
if (med_absres < 1.0e-30) return n;
|
|
||||||
|
|
||||||
thr = sigma * med_absres;
|
|
||||||
for (i = 0; i < n; i++)
|
|
||||||
{
|
|
||||||
if (fabs(rx[i] - med_ratio * tx[i]) <= thr)
|
|
||||||
{
|
|
||||||
tx[keep] = tx[i];
|
|
||||||
rx[keep] = rx[i];
|
|
||||||
keep++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (keep >= min_points) ? keep : n;
|
|
||||||
}
|
|
||||||
|
|
||||||
void calc (CALCC a)
|
void calc (CALCC a)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
@@ -456,60 +336,21 @@ void calc (CALCC a)
|
|||||||
double tvec[3];
|
double tvec[3];
|
||||||
double txrxcoefs[4 * 2];
|
double txrxcoefs[4 * 2];
|
||||||
double rx_scale;
|
double rx_scale;
|
||||||
int xb_ok = 0;
|
|
||||||
double* tx_filt;
|
|
||||||
double* rx_filt;
|
|
||||||
int n_filt = 0;
|
|
||||||
if (a->ints < 16) rints = 1;
|
if (a->ints < 16) rints = 1;
|
||||||
else rints = 2;
|
else rints = 2;
|
||||||
ix = rints - 1;
|
ix = rints - 1;
|
||||||
for (i = 0; i <= rints; i++)
|
for (i = 0; i <= rints; i++)
|
||||||
tvec[i] = (double)i / (double)rints / a->hw_scale;
|
tvec[i] = (double)i / (double)rints / a->hw_scale;
|
||||||
dx = tvec[rints] - tvec[rints - 1];
|
dx = tvec[rints] - tvec[rints - 1];
|
||||||
|
xbuilder(a->ccbld, a->nsamps, a->env_TX, a->env_RX, rints, tvec, &(a->binfo[0]), txrxcoefs, a->ptol);
|
||||||
// Yurij_eu2av: build a filtered dataset with overrange samples removed
|
|
||||||
// before running xbuilder. Overrange env_TX*hw_scale > 1.0 can distort
|
|
||||||
// the cubic fit and produce an incorrect rx_scale.
|
|
||||||
tx_filt = (double*)malloc0(a->nsamps * sizeof(double));
|
|
||||||
rx_filt = (double*)malloc0(a->nsamps * sizeof(double));
|
|
||||||
for (i = 0; i < a->nsamps; i++)
|
|
||||||
{
|
|
||||||
double nx = a->env_TX[i] * a->hw_scale;
|
|
||||||
if (nx > 1.0 || nx < 0.0) continue;
|
|
||||||
if (a->env_TX[i] < 1.0e-30 || a->env_RX[i] < 1.0e-30) continue;
|
|
||||||
tx_filt[n_filt] = a->env_TX[i];
|
|
||||||
rx_filt[n_filt] = a->env_RX[i];
|
|
||||||
n_filt++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Yurij_eu2av: optional outlier rejection before cubic-spline fit.
|
|
||||||
if (a->outlier_sigma > 0.0)
|
|
||||||
n_filt = reject_outliers(tx_filt, rx_filt, n_filt, a->outlier_sigma);
|
|
||||||
|
|
||||||
xbuilder(a->ccbld, n_filt, tx_filt, rx_filt, rints, tvec, &(a->binfo[0]), txrxcoefs, a->ptol);
|
|
||||||
rxscheck (rints, tvec, txrxcoefs, &a->binfo[7]);
|
rxscheck (rints, tvec, txrxcoefs, &a->binfo[7]);
|
||||||
if ((a->binfo[0] == 0) && (a->binfo[7] == 0))
|
if ((a->binfo[0] == 0) && (a->binfo[7] == 0))
|
||||||
{
|
|
||||||
rx_scale = 1.0 / (txrxcoefs[4 * ix + 0] + dx * (txrxcoefs[4 * ix + 1] + dx * (txrxcoefs[4 * ix + 2] + dx * txrxcoefs[4 * ix + 3])));
|
rx_scale = 1.0 / (txrxcoefs[4 * ix + 0] + dx * (txrxcoefs[4 * ix + 1] + dx * (txrxcoefs[4 * ix + 2] + dx * txrxcoefs[4 * ix + 3])));
|
||||||
xb_ok = 1;
|
else
|
||||||
}
|
|
||||||
else if (estimate_rx_scale_from_top_intervals(a, &rx_scale) == 0)
|
|
||||||
{
|
|
||||||
// Yurij_eu2av: xbuilder failed, but the bucket-average fallback
|
|
||||||
// gave a usable rx_scale. Keep binfo[0] bit 0 set for diagnostics.
|
|
||||||
a->binfo[0] |= 0x0001;
|
|
||||||
xb_ok = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
_aligned_free(tx_filt);
|
|
||||||
_aligned_free(rx_filt);
|
|
||||||
|
|
||||||
if (!xb_ok)
|
|
||||||
{
|
{
|
||||||
a->scOK = 0;
|
a->scOK = 0;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (a->stbl && _InterlockedAnd (&a->ctrl.running, 1))
|
if (a->stbl && _InterlockedAnd (&a->ctrl.running, 1))
|
||||||
a->rx_scale = a->alpha * a->rx_scale + (1.0 - a->alpha) * rx_scale;
|
a->rx_scale = a->alpha * a->rx_scale + (1.0 - a->alpha) * rx_scale;
|
||||||
else
|
else
|
||||||
@@ -1205,16 +1046,6 @@ void SetPSPtol (int channel, double ptol)
|
|||||||
LeaveCriticalSection (&txa[channel].calcc.cs_update);
|
LeaveCriticalSection (&txa[channel].calcc.cs_update);
|
||||||
}
|
}
|
||||||
|
|
||||||
PORT
|
|
||||||
void SetPSOutlierSigma (int channel, double sigma)
|
|
||||||
{
|
|
||||||
// Yurij_eu2av: 0.0 disables the pre-xbuilder outlier filter.
|
|
||||||
if (sigma < 0.0) sigma = 0.0;
|
|
||||||
EnterCriticalSection (&txa[channel].calcc.cs_update);
|
|
||||||
txa[channel].calcc.p->outlier_sigma = sigma;
|
|
||||||
LeaveCriticalSection (&txa[channel].calcc.cs_update);
|
|
||||||
}
|
|
||||||
|
|
||||||
PORT
|
PORT
|
||||||
void GetPSDisp (int channel, double* x, double* ym, double* yc, double* ys, double* cm, double* cc, double* cs)
|
void GetPSDisp (int channel, double* x, double* ym, double* yc, double* ys, double* cm, double* cc, double* cs)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -48,7 +48,6 @@ typedef struct _calcc
|
|||||||
double hw_scale;
|
double hw_scale;
|
||||||
double rx_scale;
|
double rx_scale;
|
||||||
double alpha;
|
double alpha;
|
||||||
double outlier_sigma;
|
|
||||||
|
|
||||||
int tsamps;
|
int tsamps;
|
||||||
double* env_TX;
|
double* env_TX;
|
||||||
|
|||||||
@@ -82,8 +82,6 @@ warren@wpratt.com
|
|||||||
#include "fmd.h"
|
#include "fmd.h"
|
||||||
#include "fmmod.h"
|
#include "fmmod.h"
|
||||||
#include "fmsq.h"
|
#include "fmsq.h"
|
||||||
#include "wfmd.h"
|
|
||||||
#include "wfmmod.h"
|
|
||||||
#include "gain.h"
|
#include "gain.h"
|
||||||
#include "gaussian.h"
|
#include "gaussian.h"
|
||||||
#include "gen.h"
|
#include "gen.h"
|
||||||
|
|||||||
@@ -277,7 +277,6 @@ extern void SetPSHWPeak (int channel, double peak);
|
|||||||
extern void GetPSHWPeak (int channel, double* peak);
|
extern void GetPSHWPeak (int channel, double* peak);
|
||||||
extern void GetPSMaxTX (int channel, double* maxtx);
|
extern void GetPSMaxTX (int channel, double* maxtx);
|
||||||
extern void SetPSPtol (int channel, double ptol);
|
extern void SetPSPtol (int channel, double ptol);
|
||||||
extern void SetPSOutlierSigma (int channel, double sigma);
|
|
||||||
extern void GetPSDisp (int channel, double* x, double* ym, double* yc, double* ys, double* cm, double* cc, double* cs);
|
extern void GetPSDisp (int channel, double* x, double* ym, double* yc, double* ys, double* cm, double* cc, double* cs);
|
||||||
extern void SetPSFeedbackRate (int channel, int rate);
|
extern void SetPSFeedbackRate (int channel, int rate);
|
||||||
extern void SetPSPinMode (int channel, int pin);
|
extern void SetPSPinMode (int channel, int pin);
|
||||||
@@ -518,30 +517,6 @@ extern void SetTXAFMNC (int channel, int nc);
|
|||||||
extern void SetTXAFMMP (int channel, int mp);
|
extern void SetTXAFMMP (int channel, int mp);
|
||||||
extern void SetTXAFMAFFreqs (int channel, double low, double high);
|
extern void SetTXAFMAFFreqs (int channel, double low, double high);
|
||||||
|
|
||||||
//
|
|
||||||
// Interfaces from wfmd.c
|
|
||||||
//
|
|
||||||
|
|
||||||
extern void SetRXAWFMDeviation (int channel, double deviation);
|
|
||||||
extern void SetRXAWFMNCaud (int channel, int nc);
|
|
||||||
extern void SetRXAWFMMPaud (int channel, int mp);
|
|
||||||
extern void SetRXAWFMAFFilter (int channel, double low, double high);
|
|
||||||
extern void SetRXAWFMDeemphRun (int channel, int run);
|
|
||||||
extern void SetRXAWFMDeemphTau (int channel, double tau);
|
|
||||||
extern void SetRXAWFMLimRun (int channel, int run);
|
|
||||||
extern void SetRXAWFMLimGain (int channel, double gaindB);
|
|
||||||
|
|
||||||
//
|
|
||||||
// Interfaces from wfmmod.c
|
|
||||||
//
|
|
||||||
|
|
||||||
extern void SetTXAWFMDeviation (int channel, double deviation);
|
|
||||||
extern void SetTXAWFMNC (int channel, int nc);
|
|
||||||
extern void SetTXAWFMMP (int channel, int mp);
|
|
||||||
extern void SetTXAWFMAFFreqs (int channel, double low, double high);
|
|
||||||
extern void SetTXAWFMPreEmphRun (int channel, int run);
|
|
||||||
extern void SetTXAWFMPreEmphTau (int channel, double tau);
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Interfaces from fmsq.c
|
// Interfaces from fmsq.c
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -1,322 +0,0 @@
|
|||||||
/* wfmd.c
|
|
||||||
|
|
||||||
This file is part of a program that implements a Software-Defined Radio.
|
|
||||||
|
|
||||||
Copyright (C) 2013, 2023 Warren Pratt, NR0V
|
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU General Public License
|
|
||||||
as published by the Free Software Foundation; either version 2
|
|
||||||
of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
||||||
|
|
||||||
The author can be reached by email at
|
|
||||||
|
|
||||||
warren@wpratt.com
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "comm.h"
|
|
||||||
|
|
||||||
void calc_wfmd (WFMD a)
|
|
||||||
{
|
|
||||||
// discriminator
|
|
||||||
a->pre_i = 0.0;
|
|
||||||
a->pre_q = 0.0;
|
|
||||||
a->again = a->rate / (a->deviation * TWOPI);
|
|
||||||
// dc removal
|
|
||||||
a->mtau = exp(-1.0 / (a->rate * a->tau));
|
|
||||||
a->onem_mtau = 1.0 - a->mtau;
|
|
||||||
a->fmdc = 0.0;
|
|
||||||
// de-emphasis
|
|
||||||
if (a->tau_de > 0.0) a->mde = exp(-1.0 / (a->rate * a->tau_de));
|
|
||||||
else a->mde = 0.0;
|
|
||||||
a->onem_mde = 1.0 - a->mde;
|
|
||||||
a->deemph_z = 0.0;
|
|
||||||
// detector limiter
|
|
||||||
a->plim = create_wcpagc (
|
|
||||||
1, // run - always ON
|
|
||||||
5, // mode
|
|
||||||
1, // 0 for max(I,Q), 1 for envelope
|
|
||||||
a->out, // input buff pointer
|
|
||||||
a->out, // output buff pointer
|
|
||||||
a->size, // io_buffsize
|
|
||||||
(int)a->rate, // sample rate
|
|
||||||
0.001, // tau_attack
|
|
||||||
0.008, // tau_decay
|
|
||||||
4, // n_tau
|
|
||||||
a->lim_gain, // max_gain (sets threshold, initial value)
|
|
||||||
1.0, // var_gain / slope
|
|
||||||
1.0, // fixed_gain
|
|
||||||
1.0, // max_input
|
|
||||||
0.9, // out_targ
|
|
||||||
0.250, // tau_fast_backaverage
|
|
||||||
0.004, // tau_fast_decay
|
|
||||||
4.0, // pop_ratio
|
|
||||||
0, // hang_enable
|
|
||||||
0.500, // tau_hang_backmult
|
|
||||||
0.500, // hangtime
|
|
||||||
2.000, // hang_thresh
|
|
||||||
0.100); // tau_hang_decay
|
|
||||||
}
|
|
||||||
|
|
||||||
void decalc_wfmd (WFMD a)
|
|
||||||
{
|
|
||||||
destroy_wcpagc(a->plim);
|
|
||||||
}
|
|
||||||
|
|
||||||
WFMD create_wfmd (int run, int size, double* in, double* out, int rate, double deviation, double f_low, double f_high,
|
|
||||||
double tau, int deemph_run, double tau_de, double afgain, int nc_aud, int mp_aud)
|
|
||||||
{
|
|
||||||
WFMD a = (WFMD) malloc0 (sizeof (wfmd));
|
|
||||||
double* impulse;
|
|
||||||
a->run = run;
|
|
||||||
a->size = size;
|
|
||||||
a->in = in;
|
|
||||||
a->out = out;
|
|
||||||
a->rate = (double)rate;
|
|
||||||
a->deviation = deviation;
|
|
||||||
a->f_low = f_low;
|
|
||||||
a->f_high = f_high;
|
|
||||||
a->tau = tau;
|
|
||||||
a->deemph_run = deemph_run;
|
|
||||||
a->tau_de = tau_de;
|
|
||||||
a->afgain = afgain;
|
|
||||||
a->nc_aud = nc_aud;
|
|
||||||
a->mp_aud = mp_aud;
|
|
||||||
a->lim_run = 0;
|
|
||||||
a->lim_pre_gain = 0.4;
|
|
||||||
a->lim_gain = 2.5;
|
|
||||||
calc_wfmd (a);
|
|
||||||
a->audio = (double *) malloc0 (a->size * sizeof (complex));
|
|
||||||
// audio filter
|
|
||||||
impulse = fir_bandpass(a->nc_aud, 0.8 * a->f_low, 1.1 * a->f_high, a->rate, 0, 1, a->afgain / (2.0 * a->size));
|
|
||||||
a->paud = create_fircore (a->size, a->audio, a->out, a->nc_aud, a->mp_aud, impulse);
|
|
||||||
_aligned_free (impulse);
|
|
||||||
return a;
|
|
||||||
}
|
|
||||||
|
|
||||||
void destroy_wfmd (WFMD a)
|
|
||||||
{
|
|
||||||
destroy_fircore (a->paud);
|
|
||||||
_aligned_free (a->audio);
|
|
||||||
decalc_wfmd (a);
|
|
||||||
_aligned_free (a);
|
|
||||||
}
|
|
||||||
|
|
||||||
void flush_wfmd (WFMD a)
|
|
||||||
{
|
|
||||||
memset (a->audio, 0, a->size * sizeof (complex));
|
|
||||||
flush_fircore (a->paud);
|
|
||||||
a->pre_i = 0.0;
|
|
||||||
a->pre_q = 0.0;
|
|
||||||
a->fmdc = 0.0;
|
|
||||||
a->deemph_z = 0.0;
|
|
||||||
flush_wcpagc (a->plim);
|
|
||||||
}
|
|
||||||
|
|
||||||
void xwfmd (WFMD a)
|
|
||||||
{
|
|
||||||
if (a->run)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
double si, sq, cr, ci, det, aud;
|
|
||||||
for (i = 0; i < a->size; i++)
|
|
||||||
{
|
|
||||||
// quadrature discriminator: det = arg (x[n] * conj (x[n-1]))
|
|
||||||
si = a->in[2 * i + 0];
|
|
||||||
sq = a->in[2 * i + 1];
|
|
||||||
cr = + si * a->pre_i + sq * a->pre_q;
|
|
||||||
ci = - si * a->pre_q + sq * a->pre_i;
|
|
||||||
a->pre_i = si;
|
|
||||||
a->pre_q = sq;
|
|
||||||
det = atan2 (ci, cr);
|
|
||||||
// dc removal, gain, & demod output
|
|
||||||
a->fmdc = a->mtau * a->fmdc + a->onem_mtau * det;
|
|
||||||
aud = a->again * (det - a->fmdc);
|
|
||||||
// de-emphasis
|
|
||||||
if (a->deemph_run)
|
|
||||||
{
|
|
||||||
a->deemph_z = a->mde * a->deemph_z + a->onem_mde * aud;
|
|
||||||
aud = a->deemph_z;
|
|
||||||
}
|
|
||||||
a->audio[2 * i + 0] = aud;
|
|
||||||
a->audio[2 * i + 1] = aud;
|
|
||||||
}
|
|
||||||
// audio filter
|
|
||||||
xfircore (a->paud);
|
|
||||||
if (a->lim_run)
|
|
||||||
{
|
|
||||||
for (i = 0; i < 2 * a->size; i++)
|
|
||||||
a->out[i] *= a->lim_pre_gain;
|
|
||||||
xwcpagc (a->plim);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (a->in != a->out)
|
|
||||||
memcpy (a->out, a->in, a->size * sizeof (complex));
|
|
||||||
}
|
|
||||||
|
|
||||||
void setBuffers_wfmd (WFMD a, double* in, double* out)
|
|
||||||
{
|
|
||||||
decalc_wfmd (a);
|
|
||||||
a->in = in;
|
|
||||||
a->out = out;
|
|
||||||
calc_wfmd (a);
|
|
||||||
setBuffers_fircore (a->paud, a->audio, a->out);
|
|
||||||
setBuffers_wcpagc (a->plim, a->out, a->out);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setSamplerate_wfmd (WFMD a, int rate)
|
|
||||||
{
|
|
||||||
double* impulse;
|
|
||||||
decalc_wfmd (a);
|
|
||||||
a->rate = rate;
|
|
||||||
calc_wfmd (a);
|
|
||||||
// audio filter
|
|
||||||
impulse = fir_bandpass(a->nc_aud, 0.8 * a->f_low, 1.1 * a->f_high, a->rate, 0, 1, a->afgain / (2.0 * a->size));
|
|
||||||
setImpulse_fircore (a->paud, impulse, 1);
|
|
||||||
_aligned_free (impulse);
|
|
||||||
setSamplerate_wcpagc (a->plim, (int)a->rate);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setSize_wfmd (WFMD a, int size)
|
|
||||||
{
|
|
||||||
double* impulse;
|
|
||||||
decalc_wfmd (a);
|
|
||||||
_aligned_free (a->audio);
|
|
||||||
a->size = size;
|
|
||||||
calc_wfmd (a);
|
|
||||||
a->audio = (double *) malloc0 (a->size * sizeof (complex));
|
|
||||||
// audio filter
|
|
||||||
destroy_fircore (a->paud);
|
|
||||||
impulse = fir_bandpass(a->nc_aud, 0.8 * a->f_low, 1.1 * a->f_high, a->rate, 0, 1, a->afgain / (2.0 * a->size));
|
|
||||||
a->paud = create_fircore (a->size, a->audio, a->out, a->nc_aud, a->mp_aud, impulse);
|
|
||||||
_aligned_free (impulse);
|
|
||||||
setSize_wcpagc (a->plim, a->size);
|
|
||||||
}
|
|
||||||
|
|
||||||
/********************************************************************************************************
|
|
||||||
* *
|
|
||||||
* RXA Properties *
|
|
||||||
* *
|
|
||||||
********************************************************************************************************/
|
|
||||||
|
|
||||||
PORT
|
|
||||||
void SetRXAWFMDeviation (int channel, double deviation)
|
|
||||||
{
|
|
||||||
WFMD a;
|
|
||||||
EnterCriticalSection (&ch[channel].csDSP);
|
|
||||||
a = rxa[channel].wfmd.p;
|
|
||||||
a->deviation = deviation;
|
|
||||||
a->again = a->rate / (a->deviation * TWOPI);
|
|
||||||
LeaveCriticalSection (&ch[channel].csDSP);
|
|
||||||
}
|
|
||||||
|
|
||||||
PORT
|
|
||||||
void SetRXAWFMNCaud (int channel, int nc)
|
|
||||||
{
|
|
||||||
WFMD a;
|
|
||||||
double* impulse;
|
|
||||||
EnterCriticalSection (&ch[channel].csDSP);
|
|
||||||
a = rxa[channel].wfmd.p;
|
|
||||||
if (a->nc_aud != nc)
|
|
||||||
{
|
|
||||||
a->nc_aud = nc;
|
|
||||||
impulse = fir_bandpass(a->nc_aud, 0.8 * a->f_low, 1.1 * a->f_high, a->rate, 0, 1, a->afgain / (2.0 * a->size));
|
|
||||||
setNc_fircore (a->paud, a->nc_aud, impulse);
|
|
||||||
_aligned_free (impulse);
|
|
||||||
}
|
|
||||||
LeaveCriticalSection (&ch[channel].csDSP);
|
|
||||||
}
|
|
||||||
|
|
||||||
PORT
|
|
||||||
void SetRXAWFMMPaud (int channel, int mp)
|
|
||||||
{
|
|
||||||
WFMD a;
|
|
||||||
a = rxa[channel].wfmd.p;
|
|
||||||
if (a->mp_aud != mp)
|
|
||||||
{
|
|
||||||
a->mp_aud = mp;
|
|
||||||
setMp_fircore (a->paud, a->mp_aud);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PORT
|
|
||||||
void SetRXAWFMAFFilter (int channel, double low, double high)
|
|
||||||
{
|
|
||||||
WFMD a = rxa[channel].wfmd.p;
|
|
||||||
double* impulse;
|
|
||||||
EnterCriticalSection (&ch[channel].csDSP);
|
|
||||||
if (a->f_low != low || a->f_high != high)
|
|
||||||
{
|
|
||||||
a->f_low = low;
|
|
||||||
a->f_high = high;
|
|
||||||
impulse = fir_bandpass (a->nc_aud, 0.8 * a->f_low, 1.1 * a->f_high, a->rate, 0, 1, a->afgain / (2.0 * a->size));
|
|
||||||
setImpulse_fircore (a->paud, impulse, 1);
|
|
||||||
_aligned_free (impulse);
|
|
||||||
}
|
|
||||||
LeaveCriticalSection (&ch[channel].csDSP);
|
|
||||||
}
|
|
||||||
|
|
||||||
PORT
|
|
||||||
void SetRXAWFMDeemphRun (int channel, int run)
|
|
||||||
{
|
|
||||||
WFMD a = rxa[channel].wfmd.p;
|
|
||||||
EnterCriticalSection (&ch[channel].csDSP);
|
|
||||||
if (a->deemph_run != run)
|
|
||||||
{
|
|
||||||
a->deemph_run = run;
|
|
||||||
a->deemph_z = 0.0;
|
|
||||||
}
|
|
||||||
LeaveCriticalSection (&ch[channel].csDSP);
|
|
||||||
}
|
|
||||||
|
|
||||||
PORT
|
|
||||||
void SetRXAWFMDeemphTau (int channel, double tau)
|
|
||||||
{
|
|
||||||
WFMD a = rxa[channel].wfmd.p;
|
|
||||||
EnterCriticalSection (&ch[channel].csDSP);
|
|
||||||
if (a->tau_de != tau && tau > 0.0)
|
|
||||||
{
|
|
||||||
a->tau_de = tau;
|
|
||||||
a->mde = exp(-1.0 / (a->rate * a->tau_de));
|
|
||||||
a->onem_mde = 1.0 - a->mde;
|
|
||||||
a->deemph_z = 0.0;
|
|
||||||
}
|
|
||||||
LeaveCriticalSection (&ch[channel].csDSP);
|
|
||||||
}
|
|
||||||
|
|
||||||
PORT
|
|
||||||
void SetRXAWFMLimRun (int channel, int run)
|
|
||||||
{
|
|
||||||
WFMD a = rxa[channel].wfmd.p;
|
|
||||||
EnterCriticalSection (&ch[channel].csDSP);
|
|
||||||
if (a->lim_run != run)
|
|
||||||
{
|
|
||||||
a->lim_run = run;
|
|
||||||
}
|
|
||||||
LeaveCriticalSection (&ch[channel].csDSP);
|
|
||||||
}
|
|
||||||
|
|
||||||
PORT
|
|
||||||
void SetRXAWFMLimGain (int channel, double gaindB)
|
|
||||||
{
|
|
||||||
double gain = pow(10.0, gaindB / 20.0);
|
|
||||||
WFMD a = rxa[channel].wfmd.p;
|
|
||||||
EnterCriticalSection (&ch[channel].csDSP);
|
|
||||||
if (a->lim_gain != gain)
|
|
||||||
{
|
|
||||||
decalc_wfmd (a);
|
|
||||||
a->lim_gain = gain;
|
|
||||||
calc_wfmd (a);
|
|
||||||
}
|
|
||||||
LeaveCriticalSection (&ch[channel].csDSP);
|
|
||||||
}
|
|
||||||
@@ -1,103 +0,0 @@
|
|||||||
/* wfmd.h
|
|
||||||
|
|
||||||
This file is part of a program that implements a Software-Defined Radio.
|
|
||||||
|
|
||||||
Copyright (C) 2013 Warren Pratt, NR0V
|
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU General Public License
|
|
||||||
as published by the Free Software Foundation; either version 2
|
|
||||||
of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
||||||
|
|
||||||
The author can be reached by email at
|
|
||||||
|
|
||||||
warren@wpratt.com
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _wfmd_h
|
|
||||||
#define _wfmd_h
|
|
||||||
#include "firmin.h"
|
|
||||||
#include "wcpAGC.h"
|
|
||||||
typedef struct _wfmd
|
|
||||||
{
|
|
||||||
int run;
|
|
||||||
int size;
|
|
||||||
double* in;
|
|
||||||
double* out;
|
|
||||||
double rate;
|
|
||||||
double f_low; // audio low cutoff
|
|
||||||
double f_high; // audio high cutoff
|
|
||||||
// quadrature discriminator
|
|
||||||
double deviation; // peak deviation, Hz
|
|
||||||
double again; // discriminator output gain
|
|
||||||
double pre_i; // previous sample, I
|
|
||||||
double pre_q; // previous sample, Q
|
|
||||||
// for dc removal
|
|
||||||
double tau;
|
|
||||||
double mtau;
|
|
||||||
double onem_mtau;
|
|
||||||
double fmdc;
|
|
||||||
// de-emphasis, single-pole RC
|
|
||||||
int deemph_run;
|
|
||||||
double tau_de; // 75.0e-6 (Americas) or 50.0e-6 (elsewhere)
|
|
||||||
double mde;
|
|
||||||
double onem_mde;
|
|
||||||
double deemph_z;
|
|
||||||
// for audio filter
|
|
||||||
double* audio;
|
|
||||||
FIRCORE paud;
|
|
||||||
int nc_aud;
|
|
||||||
int mp_aud;
|
|
||||||
double afgain;
|
|
||||||
// detector limiter
|
|
||||||
WCPAGC plim;
|
|
||||||
int lim_run;
|
|
||||||
double lim_gain;
|
|
||||||
double lim_pre_gain;
|
|
||||||
} wfmd, *WFMD;
|
|
||||||
|
|
||||||
extern WFMD create_wfmd ( int run, int size, double* in, double* out, int rate, double deviation,
|
|
||||||
double f_low, double f_high, double tau, int deemph_run, double tau_de, double afgain,
|
|
||||||
int nc_aud, int mp_aud);
|
|
||||||
|
|
||||||
extern void destroy_wfmd (WFMD a);
|
|
||||||
|
|
||||||
extern void flush_wfmd (WFMD a);
|
|
||||||
|
|
||||||
extern void xwfmd (WFMD a);
|
|
||||||
|
|
||||||
extern void setBuffers_wfmd (WFMD a, double* in, double* out);
|
|
||||||
|
|
||||||
extern void setSamplerate_wfmd (WFMD a, int rate);
|
|
||||||
|
|
||||||
extern void setSize_wfmd (WFMD a, int size);
|
|
||||||
|
|
||||||
// RXA Properties
|
|
||||||
|
|
||||||
extern __declspec (dllexport) void SetRXAWFMDeviation (int channel, double deviation);
|
|
||||||
|
|
||||||
extern __declspec (dllexport) void SetRXAWFMNCaud (int channel, int nc);
|
|
||||||
|
|
||||||
extern __declspec (dllexport) void SetRXAWFMMPaud (int channel, int mp);
|
|
||||||
|
|
||||||
extern __declspec (dllexport) void SetRXAWFMAFFilter (int channel, double low, double high);
|
|
||||||
|
|
||||||
extern __declspec (dllexport) void SetRXAWFMDeemphRun (int channel, int run);
|
|
||||||
|
|
||||||
extern __declspec (dllexport) void SetRXAWFMDeemphTau (int channel, double tau);
|
|
||||||
|
|
||||||
extern __declspec (dllexport) void SetRXAWFMLimRun (int channel, int run);
|
|
||||||
|
|
||||||
extern __declspec (dllexport) void SetRXAWFMLimGain (int channel, double gaindB);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,250 +0,0 @@
|
|||||||
/* wfmmod.c
|
|
||||||
|
|
||||||
This file is part of a program that implements a Software-Defined Radio.
|
|
||||||
|
|
||||||
Copyright (C) 2013, 2016, 2023 Warren Pratt, NR0V
|
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU General Public License
|
|
||||||
as published by the Free Software Foundation; either version 2
|
|
||||||
of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
||||||
|
|
||||||
The author can be reached by email at
|
|
||||||
|
|
||||||
warren@wpratt.com
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "comm.h"
|
|
||||||
|
|
||||||
// the modulated spectrum spans +/-(deviation + f_high); at the sample rates used for
|
|
||||||
// narrowband modes that exceeds Nyquist, so the bandpass degenerates to a passthrough.
|
|
||||||
static double bpfc_wfmmod (double samplerate, double deviation, double f_high)
|
|
||||||
{
|
|
||||||
double fc = deviation + f_high;
|
|
||||||
double max_fc = 0.45 * samplerate;
|
|
||||||
if (fc > max_fc) fc = max_fc;
|
|
||||||
return fc;
|
|
||||||
}
|
|
||||||
|
|
||||||
void calc_wfmmod (WFMMOD a)
|
|
||||||
{
|
|
||||||
// pre-emphasis
|
|
||||||
if (a->tau_pre > 0.0) a->pmult = exp(-1.0 / (a->samplerate * a->tau_pre));
|
|
||||||
else a->pmult = 0.0;
|
|
||||||
a->pnorm = 1.0 / (1.0 - a->pmult);
|
|
||||||
a->pre_z = 0.0;
|
|
||||||
// mod
|
|
||||||
a->sphase = 0.0;
|
|
||||||
a->sdelta = TWOPI * a->deviation / a->samplerate;
|
|
||||||
// bandpass
|
|
||||||
a->bp_fc = bpfc_wfmmod (a->samplerate, a->deviation, a->f_high);
|
|
||||||
}
|
|
||||||
|
|
||||||
WFMMOD create_wfmmod (int run, int size, double* in, double* out, int rate, double dev, double f_low, double f_high,
|
|
||||||
int pre_run, double tau_pre, int bp_run, int nc, int mp)
|
|
||||||
{
|
|
||||||
WFMMOD a = (WFMMOD) malloc0 (sizeof (wfmmod));
|
|
||||||
double* impulse;
|
|
||||||
a->run = run;
|
|
||||||
a->size = size;
|
|
||||||
a->in = in;
|
|
||||||
a->out = out;
|
|
||||||
a->samplerate = (double)rate;
|
|
||||||
a->deviation = dev;
|
|
||||||
a->f_low = f_low;
|
|
||||||
a->f_high = f_high;
|
|
||||||
a->pre_run = pre_run;
|
|
||||||
a->tau_pre = tau_pre;
|
|
||||||
a->bp_run = bp_run;
|
|
||||||
a->nc = nc;
|
|
||||||
a->mp = mp;
|
|
||||||
calc_wfmmod (a);
|
|
||||||
impulse = fir_bandpass(a->nc, -a->bp_fc, +a->bp_fc, a->samplerate, 0, 1, 1.0 / (2 * a->size));
|
|
||||||
a->p = create_fircore (a->size, a->out, a->out, a->nc, a->mp, impulse);
|
|
||||||
_aligned_free (impulse);
|
|
||||||
return a;
|
|
||||||
}
|
|
||||||
|
|
||||||
void destroy_wfmmod (WFMMOD a)
|
|
||||||
{
|
|
||||||
destroy_fircore (a->p);
|
|
||||||
_aligned_free (a);
|
|
||||||
}
|
|
||||||
|
|
||||||
void flush_wfmmod (WFMMOD a)
|
|
||||||
{
|
|
||||||
a->pre_z = 0.0;
|
|
||||||
a->sphase = 0.0;
|
|
||||||
flush_fircore (a->p);
|
|
||||||
}
|
|
||||||
|
|
||||||
void xwfmmod (WFMMOD a)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
double aud, dp;
|
|
||||||
if (a->run)
|
|
||||||
{
|
|
||||||
for (i = 0; i < a->size; i++)
|
|
||||||
{
|
|
||||||
aud = a->in[2 * i + 0];
|
|
||||||
if (a->pre_run)
|
|
||||||
{
|
|
||||||
dp = a->pnorm * (aud - a->pmult * a->pre_z);
|
|
||||||
a->pre_z = aud;
|
|
||||||
aud = dp;
|
|
||||||
}
|
|
||||||
dp = aud * a->sdelta;
|
|
||||||
a->sphase += dp;
|
|
||||||
// at the wide deviation, |dp| exceeds TWOPI once samplerate < deviation,
|
|
||||||
// so one subtraction is not enough to bring sphase back into range
|
|
||||||
while (a->sphase >= TWOPI) a->sphase -= TWOPI;
|
|
||||||
while (a->sphase < 0.0 ) a->sphase += TWOPI;
|
|
||||||
a->out[2 * i + 0] = 0.7071 * cos (a->sphase);
|
|
||||||
a->out[2 * i + 1] = 0.7071 * sin (a->sphase);
|
|
||||||
}
|
|
||||||
if (a->bp_run)
|
|
||||||
xfircore (a->p);
|
|
||||||
}
|
|
||||||
else if (a->in != a->out)
|
|
||||||
memcpy (a->out, a->in, a->size * sizeof (complex));
|
|
||||||
}
|
|
||||||
|
|
||||||
void setBuffers_wfmmod (WFMMOD a, double* in, double* out)
|
|
||||||
{
|
|
||||||
a->in = in;
|
|
||||||
a->out = out;
|
|
||||||
calc_wfmmod (a);
|
|
||||||
setBuffers_fircore (a->p, a->out, a->out);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setSamplerate_wfmmod (WFMMOD a, int rate)
|
|
||||||
{
|
|
||||||
double* impulse;
|
|
||||||
a->samplerate = rate;
|
|
||||||
calc_wfmmod (a);
|
|
||||||
impulse = fir_bandpass(a->nc, -a->bp_fc, +a->bp_fc, a->samplerate, 0, 1, 1.0 / (2 * a->size));
|
|
||||||
setImpulse_fircore (a->p, impulse, 1);
|
|
||||||
_aligned_free (impulse);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setSize_wfmmod (WFMMOD a, int size)
|
|
||||||
{
|
|
||||||
double* impulse;
|
|
||||||
a->size = size;
|
|
||||||
calc_wfmmod (a);
|
|
||||||
setSize_fircore (a->p, a->size);
|
|
||||||
impulse = fir_bandpass(a->nc, -a->bp_fc, +a->bp_fc, a->samplerate, 0, 1, 1.0 / (2 * a->size));
|
|
||||||
setImpulse_fircore (a->p, impulse, 1);
|
|
||||||
_aligned_free (impulse);
|
|
||||||
}
|
|
||||||
|
|
||||||
/********************************************************************************************************
|
|
||||||
* *
|
|
||||||
* TXA Properties *
|
|
||||||
* *
|
|
||||||
********************************************************************************************************/
|
|
||||||
|
|
||||||
PORT
|
|
||||||
void SetTXAWFMDeviation (int channel, double deviation)
|
|
||||||
{
|
|
||||||
WFMMOD a = txa[channel].wfmmod.p;
|
|
||||||
double bp_fc = bpfc_wfmmod (a->samplerate, deviation, a->f_high);
|
|
||||||
double* impulse = fir_bandpass (a->nc, -bp_fc, +bp_fc, a->samplerate, 0, 1, 1.0 / (2 * a->size));
|
|
||||||
setImpulse_fircore (a->p, impulse, 0);
|
|
||||||
_aligned_free (impulse);
|
|
||||||
EnterCriticalSection (&ch[channel].csDSP);
|
|
||||||
a->deviation = deviation;
|
|
||||||
// mod
|
|
||||||
a->sphase = 0.0;
|
|
||||||
a->sdelta = TWOPI * a->deviation / a->samplerate;
|
|
||||||
// bandpass
|
|
||||||
a->bp_fc = bp_fc;
|
|
||||||
setUpdate_fircore (a->p);
|
|
||||||
LeaveCriticalSection (&ch[channel].csDSP);
|
|
||||||
}
|
|
||||||
|
|
||||||
PORT
|
|
||||||
void SetTXAWFMNC (int channel, int nc)
|
|
||||||
{
|
|
||||||
WFMMOD a;
|
|
||||||
double* impulse;
|
|
||||||
EnterCriticalSection (&ch[channel].csDSP);
|
|
||||||
a = txa[channel].wfmmod.p;
|
|
||||||
if (a->nc != nc)
|
|
||||||
{
|
|
||||||
a->nc = nc;
|
|
||||||
impulse = fir_bandpass (a->nc, -a->bp_fc, +a->bp_fc, a->samplerate, 0, 1, 1.0 / (2 * a->size));
|
|
||||||
setNc_fircore (a->p, a->nc, impulse);
|
|
||||||
_aligned_free (impulse);
|
|
||||||
}
|
|
||||||
LeaveCriticalSection (&ch[channel].csDSP);
|
|
||||||
}
|
|
||||||
|
|
||||||
PORT
|
|
||||||
void SetTXAWFMMP (int channel, int mp)
|
|
||||||
{
|
|
||||||
WFMMOD a;
|
|
||||||
a = txa[channel].wfmmod.p;
|
|
||||||
if (a->mp != mp)
|
|
||||||
{
|
|
||||||
a->mp = mp;
|
|
||||||
setMp_fircore (a->p, a->mp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PORT
|
|
||||||
void SetTXAWFMAFFreqs (int channel, double low, double high)
|
|
||||||
{
|
|
||||||
WFMMOD a;
|
|
||||||
double* impulse;
|
|
||||||
EnterCriticalSection (&ch[channel].csDSP);
|
|
||||||
a = txa[channel].wfmmod.p;
|
|
||||||
if (a->f_low != low || a->f_high != high)
|
|
||||||
{
|
|
||||||
a->f_low = low;
|
|
||||||
a->f_high = high;
|
|
||||||
a->bp_fc = bpfc_wfmmod (a->samplerate, a->deviation, a->f_high);
|
|
||||||
impulse = fir_bandpass (a->nc, -a->bp_fc, +a->bp_fc, a->samplerate, 0, 1, 1.0 / (2 * a->size));
|
|
||||||
setImpulse_fircore (a->p, impulse, 1);
|
|
||||||
_aligned_free (impulse);
|
|
||||||
}
|
|
||||||
LeaveCriticalSection (&ch[channel].csDSP);
|
|
||||||
}
|
|
||||||
|
|
||||||
PORT
|
|
||||||
void SetTXAWFMPreEmphRun (int channel, int run)
|
|
||||||
{
|
|
||||||
WFMMOD a = txa[channel].wfmmod.p;
|
|
||||||
EnterCriticalSection (&ch[channel].csDSP);
|
|
||||||
if (a->pre_run != run)
|
|
||||||
{
|
|
||||||
a->pre_run = run;
|
|
||||||
a->pre_z = 0.0;
|
|
||||||
}
|
|
||||||
LeaveCriticalSection (&ch[channel].csDSP);
|
|
||||||
}
|
|
||||||
|
|
||||||
PORT
|
|
||||||
void SetTXAWFMPreEmphTau (int channel, double tau)
|
|
||||||
{
|
|
||||||
WFMMOD a = txa[channel].wfmmod.p;
|
|
||||||
EnterCriticalSection (&ch[channel].csDSP);
|
|
||||||
if (a->tau_pre != tau && tau > 0.0)
|
|
||||||
{
|
|
||||||
a->tau_pre = tau;
|
|
||||||
a->pmult = exp(-1.0 / (a->samplerate * a->tau_pre));
|
|
||||||
a->pnorm = 1.0 / (1.0 - a->pmult);
|
|
||||||
a->pre_z = 0.0;
|
|
||||||
}
|
|
||||||
LeaveCriticalSection (&ch[channel].csDSP);
|
|
||||||
}
|
|
||||||
@@ -1,86 +0,0 @@
|
|||||||
/* wfmmod.h
|
|
||||||
|
|
||||||
This file is part of a program that implements a Software-Defined Radio.
|
|
||||||
|
|
||||||
Copyright (C) 2013, 2016, 2023 Warren Pratt, NR0V
|
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU General Public License
|
|
||||||
as published by the Free Software Foundation; either version 2
|
|
||||||
of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
||||||
|
|
||||||
The author can be reached by email at
|
|
||||||
|
|
||||||
warren@wpratt.com
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _wfmmod_h
|
|
||||||
#define _wfmmod_h
|
|
||||||
#include "firmin.h"
|
|
||||||
typedef struct _wfmmod
|
|
||||||
{
|
|
||||||
int run;
|
|
||||||
int size;
|
|
||||||
double* in;
|
|
||||||
double* out;
|
|
||||||
double samplerate;
|
|
||||||
double deviation;
|
|
||||||
double f_low;
|
|
||||||
double f_high;
|
|
||||||
// pre-emphasis, single-pole RC; inverse of the receiver's de-emphasis
|
|
||||||
int pre_run;
|
|
||||||
double tau_pre; // 75.0e-6 (Americas) or 50.0e-6 (elsewhere)
|
|
||||||
double pmult;
|
|
||||||
double pnorm;
|
|
||||||
double pre_z;
|
|
||||||
// mod
|
|
||||||
double sphase;
|
|
||||||
double sdelta;
|
|
||||||
// bandpass
|
|
||||||
int bp_run;
|
|
||||||
double bp_fc;
|
|
||||||
int nc;
|
|
||||||
int mp;
|
|
||||||
FIRCORE p;
|
|
||||||
}wfmmod, *WFMMOD;
|
|
||||||
|
|
||||||
extern WFMMOD create_wfmmod (int run, int size, double* in, double* out, int rate, double dev, double f_low, double f_high,
|
|
||||||
int pre_run, double tau_pre, int bp_run, int nc, int mp);
|
|
||||||
|
|
||||||
extern void destroy_wfmmod (WFMMOD a);
|
|
||||||
|
|
||||||
extern void flush_wfmmod (WFMMOD a);
|
|
||||||
|
|
||||||
extern void xwfmmod (WFMMOD a);
|
|
||||||
|
|
||||||
extern void setBuffers_wfmmod (WFMMOD a, double* in, double* out);
|
|
||||||
|
|
||||||
extern void setSamplerate_wfmmod (WFMMOD a, int rate);
|
|
||||||
|
|
||||||
extern void setSize_wfmmod (WFMMOD a, int size);
|
|
||||||
|
|
||||||
// TXA Properties
|
|
||||||
|
|
||||||
extern __declspec (dllexport) void SetTXAWFMDeviation (int channel, double deviation);
|
|
||||||
|
|
||||||
extern __declspec (dllexport) void SetTXAWFMNC (int channel, int nc);
|
|
||||||
|
|
||||||
extern __declspec (dllexport) void SetTXAWFMMP (int channel, int mp);
|
|
||||||
|
|
||||||
extern __declspec (dllexport) void SetTXAWFMAFFreqs (int channel, double low, double high);
|
|
||||||
|
|
||||||
extern __declspec (dllexport) void SetTXAWFMPreEmphRun (int channel, int run);
|
|
||||||
|
|
||||||
extern __declspec (dllexport) void SetTXAWFMPreEmphTau (int channel, double tau);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
Reference in New Issue
Block a user