RTTY decoder mods

Changed prefilter from lowpass to bandpass.
    Filter adjustment visible on both Mark & Space tones
    Increased AFC low pass filter time constant
pull/2/head
David Freese 2010-01-21 12:27:00 -06:00
rodzic 93bedef1ca
commit d84b060522
5 zmienionych plików z 114 dodań i 57 usunięć

Wyświetl plik

@ -4,7 +4,7 @@
// Copyright (C) 2006
// Dave Freese, W1HKJ
//
// This file is part of fldigi. Adapted from code contained in gmfsk source code
// This file is part of fldigi. Adapted from code contained in gmfsk source code
// distribution.
// gmfsk Copyright (C) 2001, 2002, 2003
// Tomi Manninen (oh2bns@sral.fi)
@ -120,9 +120,9 @@ void rtty::init()
modem::init();
rx_init();
put_MODEstatus(mode);
snprintf(msg1, sizeof(msg1), "Shft %-4.0f", rtty_shift);
snprintf(msg1, sizeof(msg1), "Shft %-4.0f", rtty_shift);
put_Status1(msg1);
snprintf(msg2, sizeof(msg2), "Baud %-4.1f", rtty_baud);
snprintf(msg2, sizeof(msg2), "Baud %-4.1f", rtty_baud);
put_Status2(msg2);
if (progdefaults.PreferXhairScope)
set_scope_mode(Digiscope::XHAIRS);
@ -142,7 +142,7 @@ rtty::~rtty()
void rtty::restart()
{
double stl;
rtty_shift = shift = _SHIFT[progdefaults.rtty_shift];
rtty_baud = _BAUD[progdefaults.rtty_baud];
nbits = rtty_bits = _BITS[progdefaults.rtty_bits];
@ -163,22 +163,27 @@ void rtty::restart()
rxmode = LETTERS;
symbollen = (int) (samplerate / rtty_baud + 0.5);
set_bandwidth(shift);
rtty_BW = shift + 3*rtty_baud;
rtty_BW = 0.75 * rtty_baud;
progdefaults.RTTY_BW = rtty_BW;
sldrRTTYbandwidth->value(rtty_BW);
wf->redraw_marker();
if (bpfilt)
bpfilt->create_filter(0, rtty_BW / samplerate / 2.0);
else
bpfilt = new fftfilt(0, rtty_BW / samplerate / 2.0, 1024);
bp_filt_lo = (shift/2.0 - rtty_BW) / samplerate;
if (bp_filt_lo < 0) bp_filt_lo = 0;
bp_filt_hi = (shift/2.0 + rtty_BW) / samplerate;
if (bitfilt)
bitfilt->setLength(symbollen / 8);//4);
if (bpfilt)
bpfilt->create_filter(bp_filt_lo, bp_filt_hi);
else
bitfilt = new Cmovavg(symbollen / 8);//4);
bpfilt = new fftfilt(bp_filt_lo, bp_filt_hi, 1024);
bflen = symbollen/2;
if (bitfilt)
bitfilt->setLength(bflen);
else
bitfilt = new Cmovavg(bflen);
// stop length = 1, 1.5 or 2 bits
rtty_stop = progdefaults.rtty_stop;
@ -191,12 +196,12 @@ void rtty::restart()
pipeptr = 0;
poscnt = negcnt = 0;
posfreq = negfreq = 0.0;
metric = 0.0;
snprintf(msg1, sizeof(msg1), "Shft %-4.0f", rtty_shift);
snprintf(msg1, sizeof(msg1), "Shft %-4.0f", rtty_shift);
put_Status1(msg1);
snprintf(msg2, sizeof(msg2), "Baud %-4.1f", rtty_baud);
snprintf(msg2, sizeof(msg2), "Baud %-4.1f", rtty_baud);
put_Status2(msg2);
put_MODEstatus(mode);
for (int i = 0; i < 1024; i++) QI[i].re = QI[i].im = 0.0;
@ -205,7 +210,7 @@ void rtty::restart()
freqerrlo = freqerrhi = 0.0;
sigsearch = 0;
dspcnt = 2*(nbits + 2);//nbits + 2; //2 * symbollen * (nbits + 2);
clear_zdata = true;
}
@ -216,18 +221,18 @@ rtty::rtty(trx_mode tty_mode)
mode = tty_mode;
samplerate = RTTY_SampleRate;
fragmentsize = 256;
// fragmentsize = 256; // not needed in any modem implementation for fldigi
bpfilt = (fftfilt *)0;
bitfilt = (Cmovavg *)0;
hilbert = new C_FIR_filter();
hilbert->init_hilbert(37, 1);
pipe = new double[MAXPIPE];
dsppipe = new double [MAXPIPE];
restart();
}
@ -255,9 +260,9 @@ complex rtty::mixer(complex in)
z = z * in;
phaseacc -= TWOPI * frequency / samplerate;
if (phaseacc > M_PI)
if (phaseacc > M_PI)
phaseacc -= TWOPI;
else if (phaseacc < M_PI)
else if (phaseacc < M_PI)
phaseacc += TWOPI;
return z;
@ -381,7 +386,7 @@ int rtty::rx(bool bit)
case RTTY_RX_STATE_STOP:
if (--counter == 0) {
if (bit) {
if ((metric >= progStatus.sldrSquelchValue && progStatus.sqlonoff)|| !progStatus.sqlonoff) {
if ((metric >= progStatus.sldrSquelchValue && progStatus.sqlonoff)|| !progStatus.sqlonoff) {
c = decode_char();
if ( c != 0 )
put_rx_char(c);
@ -467,16 +472,19 @@ int rtty::rx_process(const double *buf, int len)
if (progdefaults.RTTY_BW != rtty_BW) {
rtty_BW = progdefaults.RTTY_BW;
bpfilt->create_filter(0, rtty_BW / samplerate / 2.0);
bp_filt_lo = (shift/2.0 - rtty_BW) / samplerate;
if (bp_filt_lo < 0) bp_filt_lo = 0;
bp_filt_hi = (shift/2.0 + rtty_BW) / samplerate;
bpfilt->create_filter(bp_filt_lo, bp_filt_hi);
wf->redraw_marker();
}
Metric();
while (len-- > 0) {
// create analytic signal from sound card input samples
z.re = z.im = *buf++;
hilbert->run(z, z);
@ -489,18 +497,18 @@ int rtty::rx_process(const double *buf, int len)
n = bpfilt->run(z, &zp);
if (n) {
for (int i = 0; i < n; i++) {
// measure phase difference between successive samples to determine
// the frequency of the baseband signal (+rtty_baud or -rtty_baud)
// see class complex definiton for operator %
fin = (prevsmpl % zp[i]).arg() * samplerate / TWOPI;
prevsmpl = zp[i];
// filter the result with a moving average filter
f = bitfilt->run(fin);
// track the + and - frequency excursions separately to derive an afc signal
rotate = -4.0 * M_PI * freqerr / rtty_shift;
@ -512,7 +520,7 @@ int rtty::rx_process(const double *buf, int len)
posfreq += fin;
QI[i].re = zp[i].re;
QI[i].im = xmix * zp[i].im;
}
}
if (fin < 0.0) {
negcnt++;
negfreq += fin;
@ -520,25 +528,28 @@ int rtty::rx_process(const double *buf, int len)
QI[i].im = zp[i].re;
}
QI[i] = QI[i] * complex(cos(rotate), sin(rotate));
avgsig = decayavg(avgsig, 1.25 * zp[i].mag(), 64);
if (avgsig > 0)
avgsig = decayavg(avgsig, 1.25 * zp[i].mag(), 128);//64);
if (avgsig > 0)
QI[i] = QI[i] / avgsig;
// hysterisis dead zone in frequency discriminator bit detector
if (dspcnt && (--dspcnt % (nbits + 2) == 0)) {
pipe[pipeptr] = f / shift; // display filtered signal
pipeptr = (pipeptr + 1) % symbollen;
}
if (f > deadzone )
bit = true;
if (f < -deadzone)
bit = false;
if (dspcnt && (--dspcnt % (nbits + 2) == 0)) {
// pipe[pipeptr] = bit ? .5 : -.5;
pipe[pipeptr] = f / shift;
// pipe[pipeptr] = fin / shift;//f / shift; // display filtered signal
pipeptr = (pipeptr + 1) % symbollen;
}
// if (!progdefaults.RTTY_USB)
// bit = !bit;
rxflag = rx (reverse ? !bit : bit);
if (rxflag == 2) {
@ -547,7 +558,7 @@ int rtty::rx_process(const double *buf, int len)
if (poscnt && negcnt) {
poserr = posfreq/poscnt;
negerr = negfreq/negcnt;
// compute the frequency error as the median of + and - relative freq's
if (sigsearch) sigsearch--;
@ -618,7 +629,7 @@ double rtty::FSKnco()
void rtty::send_symbol(int symbol)
{
double freq;
if (reverse)
symbol = !symbol;
@ -626,7 +637,7 @@ void rtty::send_symbol(int symbol)
freq = get_txfreq_woffset() + shift / 2.0;
else
freq = get_txfreq_woffset() - shift / 2.0;
for (int i = 0; i < symbollen; i++) {
outbuf[i] = nco(freq);
if (symbol)
@ -645,7 +656,7 @@ void rtty::send_stop()
{
double freq;
bool invert = reverse;
if (invert)
freq = get_txfreq_woffset() - shift / 2.0;
else
@ -693,7 +704,7 @@ void rtty::send_char(int c)
c = letters[c];
else
c = figures[c];
if (c)
if (c)
put_echo_char(c);
}
}
@ -800,7 +811,7 @@ int rtty::tx_process()
return 0;
// switch case if necessary
if ((c & 0x300) != txmode) {// == 0) {
if (txmode == FIGURES) {
send_char(LETTERS);

Wyświetl plik

@ -3249,6 +3249,7 @@ an merging"));
cntCWdash2dot->type(1);
cntCWdash2dot->minimum(2.5);
cntCWdash2dot->maximum(4);
cntCWdash2dot->step(0.1);
cntCWdash2dot->value(3);
cntCWdash2dot->callback((Fl_Callback*)cb_cntCWdash2dot);
cntCWdash2dot->align(FL_ALIGN_RIGHT);
@ -3259,6 +3260,7 @@ an merging"));
cntCWrisetime->type(1);
cntCWrisetime->minimum(0);
cntCWrisetime->maximum(15);
cntCWrisetime->step(0.1);
cntCWrisetime->value(4);
cntCWrisetime->callback((Fl_Callback*)cb_cntCWrisetime);
cntCWrisetime->align(FL_ALIGN_RIGHT);
@ -3362,6 +3364,7 @@ an merging"));
valDominoEX_BW->type(1);
valDominoEX_BW->minimum(1);
valDominoEX_BW->maximum(2);
valDominoEX_BW->step(0.1);
valDominoEX_BW->value(1.5);
valDominoEX_BW->callback((Fl_Callback*)cb_valDominoEX_BW);
valDominoEX_BW->align(FL_ALIGN_RIGHT);
@ -3376,6 +3379,7 @@ an merging"));
{ Fl_Value_Slider* o = valDomCWI = new Fl_Value_Slider(15, 207, 260, 20, _("CWI threshold"));
valDomCWI->tooltip(_("CWI detection and suppression"));
valDomCWI->type(1);
valDomCWI->step(0.01);
valDomCWI->textsize(14);
valDomCWI->callback((Fl_Callback*)cb_valDomCWI);
valDomCWI->align(FL_ALIGN_TOP);
@ -3862,10 +3866,10 @@ an merging"));
{ Fl_Value_Slider* o = sldrRTTYbandwidth = new Fl_Value_Slider(100, 295, 300, 20, _("Receive filter bandwidth"));
sldrRTTYbandwidth->tooltip(_("Adjust the DSP bandwidth"));
sldrRTTYbandwidth->type(1);
sldrRTTYbandwidth->minimum(50);
sldrRTTYbandwidth->maximum(1200);
sldrRTTYbandwidth->step(5);
sldrRTTYbandwidth->value(400);
sldrRTTYbandwidth->minimum(5);
sldrRTTYbandwidth->maximum(200);
sldrRTTYbandwidth->step(1);
sldrRTTYbandwidth->value(25);
sldrRTTYbandwidth->textsize(14);
sldrRTTYbandwidth->callback((Fl_Callback*)cb_sldrRTTYbandwidth);
sldrRTTYbandwidth->align(FL_ALIGN_TOP_LEFT);
@ -3906,6 +3910,7 @@ an merging"));
valTHOR_BW->type(1);
valTHOR_BW->minimum(1);
valTHOR_BW->maximum(2);
valTHOR_BW->step(0.1);
valTHOR_BW->value(1.5);
valTHOR_BW->callback((Fl_Callback*)cb_valTHOR_BW);
valTHOR_BW->align(FL_ALIGN_RIGHT);
@ -3914,6 +3919,7 @@ an merging"));
{ Fl_Value_Slider* o = valThorCWI = new Fl_Value_Slider(15, 194, 260, 20, _("CWI threshold"));
valThorCWI->tooltip(_("CWI detection and suppression"));
valThorCWI->type(1);
valThorCWI->step(0.01);
valThorCWI->textsize(14);
valThorCWI->callback((Fl_Callback*)cb_valThorCWI);
valThorCWI->align(FL_ALIGN_TOP);
@ -4503,6 +4509,7 @@ ll with your audio device."));
valPCMvolume->tooltip(_("Set the sound card PCM level"));
valPCMvolume->type(1);
valPCMvolume->selection_color((Fl_Color)FL_SELECTION_COLOR);
valPCMvolume->step(0.01);
valPCMvolume->value(0.8);
valPCMvolume->textsize(14);
valPCMvolume->callback((Fl_Callback*)cb_valPCMvolume);

Wyświetl plik

@ -1605,7 +1605,7 @@ progdefaults.changed = true;}
Fl_Value_Slider sldrRTTYbandwidth {
label {Receive filter bandwidth}
callback {progdefaults.RTTY_BW = o->value();}
tooltip {Adjust the DSP bandwidth} xywh {100 295 300 20} type Horizontal align 5 minimum 50 maximum 1200 step 5 value 400 textsize 14
tooltip {Adjust the DSP bandwidth} xywh {100 295 300 20} type Horizontal align 5 minimum 5 maximum 200 step 1 value 25 textsize 14
code0 {o->value(progdefaults.RTTY_BW);}
}
}

Wyświetl plik

@ -95,6 +95,10 @@ private:
Cmovavg *bitfilt;
fftfilt *bpfilt;
int bflen;
double bp_filt_lo;
double bp_filt_hi;
double *pipe;
double *dsppipe;
int pipeptr;

Wyświetl plik

@ -67,6 +67,7 @@
#include "confdialog.h"
#include "flmisc.h"
#include "gettext.h"
#include "rtty.h"
using namespace std;
@ -199,13 +200,46 @@ void WFdisp::initMarkers() {
// draw a marker of specified width and colour centred at freq and clrM
inline void WFdisp::makeMarker_(int width, const RGB* color, int freq, const RGB* clrMin, RGB* clrM, const RGB* clrMax)
{
// clamp marker to image width
if (active_modem->get_mode() == MODE_RTTY) {
// rtty has two bandwidth indicators on the waterfall
// upper and lower frequency
int bw_limit_hi = (int)((_SHIFT[progdefaults.rtty_shift]/2 + progdefaults.RTTY_BW));
int bw_limit_lo = (int)((_SHIFT[progdefaults.rtty_shift]/2 - progdefaults.RTTY_BW));
int bw_freq = static_cast<int>(freq + 0.5);
int bw_lower1 = -bw_limit_hi;
int bw_upper1 = -bw_limit_lo;
int bw_lower2 = bw_limit_lo;
int bw_upper2 = bw_limit_hi;
if (bw_lower1 + bw_freq < 0)
bw_lower1 -= bw_lower1 + bw_freq;
if (bw_upper1 + bw_freq < 0)
bw_lower2 -= bw_lower2 + bw_freq;
if (bw_upper2 + bw_freq > scale_width)
bw_upper2 -= bw_upper2 + bw_freq - scale_width;
if (bw_lower2 + bw_freq > scale_width)
bw_lower2 -= bw_lower2 + bw_freq - scale_width;
// draw it
RGB* clrPos;
for (int y = 0; y < WFMARKER - 2; y++) {
for (int x = bw_lower1; x < bw_upper1; x++) {
clrPos = clrM + x + y * scale_width;
if (clrPos > clrMin && clrPos < clrMax)
*clrPos = *color;
}
for (int x = bw_lower2; x < bw_upper2; x++) {
clrPos = clrM + x + y * scale_width;
if (clrPos > clrMin && clrPos < clrMax)
*clrPos = *color;
}
}
return;
}
int bw_lower = -width, bw_upper = width;
if (bw_lower + static_cast<int>(freq+0.5) < 0)
bw_lower -= bw_lower + static_cast<int>(freq+0.5);
if (bw_upper + static_cast<int>(freq+0.5) > scale_width)
bw_upper -= bw_upper + static_cast<int>(freq+0.5) - scale_width;
// draw it
RGB* clrPos;
for (int y = 0; y < WFMARKER - 2; y++) {
@ -236,7 +270,7 @@ void WFdisp::makeMarker()
else if (mode >= MODE_FELDHELL && mode <= MODE_HELL80)
marker_width = (int)progdefaults.HELL_BW;
else if (mode == MODE_RTTY)
marker_width = (int)progdefaults.RTTY_BW;
marker_width = (int)_SHIFT[progdefaults.rtty_shift];
marker_width = (int)(marker_width / 2.0 + 1);
RGBmarker.R = progdefaults.bwTrackRGBI.R;
@ -244,6 +278,7 @@ void WFdisp::makeMarker()
RGBmarker.B = progdefaults.bwTrackRGBI.B;
makeMarker_(marker_width, &RGBmarker, carrierfreq, clrMin, clrM, clrMax);
if (unlikely(active_modem->freqlocked())) {
int txfreq = active_modem->get_txfreq();
adjust_color_inv(RGBmarker.R, RGBmarker.G, RGBmarker.B, FL_BLACK, FL_RED);