45
49
//=====================================================================
47
static unsigned char letters[32] = {
51
static char letters[32] = {
48
52
'\0', 'E', '\n', 'A', ' ', 'S', 'I', 'U',
49
53
'\r', 'D', 'R', 'J', 'N', 'F', 'C', 'K',
50
54
'T', 'Z', 'L', 'W', 'H', 'Y', 'P', 'Q',
51
'O', 'B', 'G', '�', 'M', 'X', 'V', '�'
55
'O', 'B', 'G', ' ', 'M', 'X', 'V', ' '
56
60
* ITA-2 version of the figures case.
58
static unsigned char figures[32] = {
62
static char figures[32] = {
59
63
'\0', '3', '\n', '-', ' ', '\'', '8', '7',
60
64
'\r', '�', '4', '\a', ',', '�', ':', '(',
61
65
'5', '+', ')', '2', '�', '6', '0', '1',
137
153
put_MODEstatus(mode);
138
154
if ((rtty_baud - (int)rtty_baud) == 0)
139
snprintf(msg1, sizeof(msg1), "%-3.0f / %-4.0f", rtty_baud, rtty_shift);
155
snprintf(msg1, sizeof(msg1), "%-3.0f/%-4.0f", rtty_baud, rtty_shift);
141
snprintf(msg1, sizeof(msg1), "%-4.2f / %-4.0f", rtty_baud, rtty_shift);
157
snprintf(msg1, sizeof(msg1), "%-4.2f/%-4.0f", rtty_baud, rtty_shift);
142
158
put_Status1(msg1);
143
159
if (progdefaults.PreferXhairScope)
144
160
set_scope_mode(Digiscope::XHAIRS);
146
162
set_scope_mode(Digiscope::RTTY);
163
for (int i = 0; i < MAXPIPE; i++) mark_history[i] = space_history[i] = complex(0,0);
151
168
if (hilbert) delete hilbert;
152
169
if (bitfilt) delete bitfilt;
153
if (bpfilt) delete bpfilt;
170
if (mark_filt) delete mark_filt;
171
if (space_filt) delete space_filt;
154
172
if (pipe) delete [] pipe;
155
173
if (dsppipe) delete [] dsppipe;
180
void rtty::reset_filters()
182
if (progStatus.rtty_filter_changed) {
189
// filter_length = 512 / 1024 / 2048
190
int filter_length = (1 << progdefaults.rtty_filter_quality) * 512;
192
mark_filt->create_rttyfilt(rtty_BW/2.0/samplerate);
194
mark_filt = new fftfilt(rtty_BW/2.0/samplerate, filter_length);
195
mark_filt->create_rttyfilt(rtty_BW/2.0/samplerate);
199
space_filt->create_rttyfilt(rtty_BW/2.0/samplerate);
201
space_filt = new fftfilt(rtty_BW/2.0/samplerate, filter_length);
202
space_filt->create_rttyfilt(rtty_BW/2.0/samplerate);
158
206
void rtty::restart()
492
568
int rtty::rx_process(const double *buf, int len)
497
static bool bit = true;
499
double deadzone = shift/4;
503
if (progdefaults.RTTY_BW != rtty_BW) {
570
const double *buffer = buf;
573
complex z, zmark, zspace, *zp_mark, *zp_space;
576
static int bitcount = 5 * nbits * symbollen;
578
if (rttyviewer && !bHistory &&
579
(dlgViewer->visible() || progStatus.show_channels)) rttyviewer->rx_process(buf, len);
581
if (progdefaults.RTTY_BW != rtty_BW ||
582
progStatus.rtty_filter_changed) {
504
583
rtty_BW = progdefaults.RTTY_BW;
505
bp_filt_lo = (shift/2.0 - rtty_BW/2.0) / samplerate;
506
if (bp_filt_lo < 0) bp_filt_lo = 0;
507
bp_filt_hi = (shift/2.0 + rtty_BW/2.0) / samplerate;
508
bpfilt->create_filter(bp_filt_lo, bp_filt_hi);
585
progStatus.rtty_filter_changed = false;
509
586
wf->redraw_marker();
587
for (int i = 0; i < MAXPIPE; i++) mark_history[i] = space_history[i] = complex(0,0);
588
bits->setLength(symbollen / 2);
589
mark_noise = space_noise = 0;
512
if (rttyviewer && !bHistory) rttyviewer->rx_process(buf, len);
518
// create analytic signal from sound card input samples
520
z.re = z.im = *buf++;
595
while (length-- > 0) {
597
// Create analytic signal from sound card input samples
599
z.re = z.im = *buffer++;
521
600
hilbert->run(z, z);
523
// mix it with the audio carrier frequency to create a baseband signal
527
// bandpass filter using Windowed Sinc - Overlap-Add convolution filter
529
n = bpfilt->run(z, &zp);
532
for (int i = 0; i < n; i++) {
534
// measure phase difference between successive samples to determine
535
// the frequency of the baseband signal (+rtty_baud or -rtty_baud)
536
// see class complex definiton for operator %
538
fin = (prevsmpl % zp[i]).arg() * samplerate / TWOPI;
542
// track the + and - frequency excursions separately to derive an afc signal
544
rotate = -4.0 * M_PI * freqerr / rtty_shift;
545
double xmix = fabs(4.0 * freqerr / rtty_shift);
546
if (xmix > 0.5) xmix = 0.5;
552
QI[i].im = xmix * zp[i].im;
557
QI[i].re = xmix * zp[i].im;
560
QI[i] = QI[i] * complex(cos(rotate), sin(rotate));
561
avgsig = decayavg(avgsig, 1.25 * zp[i].mag(), 128);//64);
564
QI[i] = QI[i] / avgsig;
566
fin = CLAMP(fin, - rtty_shift, rtty_shift);
567
// filter the result with a moving average filter
568
f = bitfilt->run(fin);
569
// hysterisis dead zone in frequency discriminator bit detector
602
// Mix it with the audio carrier frequency to create two baseband signals
603
// mark and space are separated and processed independently
604
// lowpass Windowed Sinc - Overlap-Add convolution filters.
605
// The two fftfilt's are the same size and processed in sync
606
// therefore the mark and space filters will concurrently have the
607
// same size outputs available for further processing
609
zmark = mixer(mark_phase, frequency + shift/2.0, z);
610
mark_filt->run(zmark, &zp_mark);
612
zspace = mixer(space_phase, frequency - shift/2.0, z);
613
n_out = space_filt->run(zspace, &zp_space);
616
for (int i = 0; i < n_out; i++) {
619
mark_mag = zp_mark[i].mag();
620
mark_env = decayavg (mark_env, mark_mag,
621
(mark_mag > mark_env) ? symbollen / 4 : symbollen * 16);
622
mark_noise = decayavg (mark_noise, mark_mag,
623
(mark_mag < mark_noise) ? symbollen / 4 : symbollen * 48);
625
space_mag = zp_space[i].mag();
626
space_env = decayavg (space_env, space_mag,
627
(space_mag > space_env) ? symbollen / 4 : symbollen * 16);
628
space_noise = decayavg (space_noise, space_mag,
629
(space_mag < space_noise) ? symbollen / 4 : symbollen * 48);
631
if (progdefaults.kahn_demod == 0) {
632
// Kahn Square Law demodulator
633
// KISS - outperforms the ATC implementation
634
nubit = zp_mark[i].norm() > zp_space[i].norm();
637
// ATC signal envelope detector iaw Kok Chen, W7AY, technical paper
638
// "Improved Automatic Threshold Correction Methods for FSK"
639
// www.w7ay.net/site/Technical/ATC, dated 16 December 2012
640
nubit = mark_env * mark_mag - 0.5 * mark_env * mark_env >
641
space_env * space_mag - 0.5 * space_env * space_env;
644
// XY scope signal generation
646
if (progdefaults.true_scope) {
647
//----------------------------------------------------------------------
648
// "true" scope implementation------------------------------------------
649
//----------------------------------------------------------------------
651
// get the baseband-signal and...
652
xy.re = zp_mark[i].re * cos(xy_phase) + zp_mark[i].im * sin(xy_phase);
653
xy.im = zp_space[i].re * cos(xy_phase) + zp_space[i].im * sin(xy_phase);
655
// if mark-tone has a higher magnitude than the space-tone,
656
// further reduce the scope's space-amplitude and vice versa
657
// this makes the scope looking a little bit nicer, too...
658
// aka: less noisy...
659
if( zp_mark[i].mag() > zp_space[i].mag() ) {
660
xy.im *= zp_space[i].mag()/zp_mark[i].mag();
662
xy.re /= zp_space[i].mag()/zp_mark[i].mag();
665
// now normalize the scope
666
double const norm = 1.3*(zp_mark [i].mag() + zp_space[i].mag());
670
//----------------------------------------------------------------------
671
// "ortho" scope implementation-----------------------------------------
672
//----------------------------------------------------------------------
673
// get magnitude of the baseband-signal
675
xy = complex( mark_mag * cos(xy_phase), space_noise * sin(xy_phase) / 2.0);
677
xy = complex( mark_noise * cos(xy_phase) / 2.0, space_mag * sin(xy_phase));
678
// now normalize the scope
679
double const norm = (mark_env + space_env);
683
// Rotate the scope x-y iaw frequency error. Old scopes were not capable
684
// of this, but it should be very handy, so... who cares of realism anyways?
685
double const rotate = 8 * TWOPI * freqerr / rtty_shift;
686
xy = xy * complex(cos(rotate), sin(rotate));
690
// shift it to 128Hz(!) and not to it's original position.
691
// this makes it more pretty and does not remove it's other
692
// qualities. Reason is that this is a fraction of the used
694
xy_phase += (TWOPI * (128.0 / samplerate));
696
double testbit = bits->run(nubit);
697
if (!bit && testbit > 0.75) {
699
if (bitcount) set_zdata(QI, MAXPIPE);
700
} else if (bit && testbit < 0.25) {
702
if (bitcount) set_zdata(QI, MAXPIPE);
706
// end XY signal generation
708
mark_history[inp_ptr] = zp_mark[i];
709
space_history[inp_ptr] = zp_space[i];
711
inp_ptr = (inp_ptr + 1) % MAXPIPE;
575
713
if (dspcnt && (--dspcnt % (nbits + 2) == 0)) {
576
pipe[pipeptr] = f / shift;
714
pipe[pipeptr] = bit - 0.5; //testbit - 0.5;
577
715
pipeptr = (pipeptr + 1) % symbollen;
718
// detect TTY signal transitions
719
// rx(...) returns true if valid TTY bit stream detected
720
// either character or idle signal
580
721
if ( rx( reverse ? !bit : bit ) ) {
581
722
dspcnt = symbollen * (nbits + 2);
583
if (poscnt && negcnt) {
584
poserr = posfreq/poscnt;
585
negerr = negfreq/negcnt;
587
// compute the frequency error as the median of + and - relative freq's
588
if (sigsearch) sigsearch--;
590
ferr = -(poserr + negerr)/(2*(SIGSEARCH - sigsearch + 1));
592
int fs = progdefaults.rtty_afcspeed;
594
if (fs == 0) avging = 8;
595
else if (fs == 1) avging = 4;
597
freqerr = decayavg(freqerr, ferr, avging);
599
poscnt = 0; posfreq = 0.0;
600
negcnt = 0; negfreq = 0.0;
724
bitcount = 5 * nbits * symbollen;
726
if (sigsearch) sigsearch--;
728
int mp0 = inp_ptr - 2;
730
if (mp0 < 0) mp0 += MAXPIPE;
731
if (mp1 < 0) mp1 += MAXPIPE;
732
double ferr = (TWOPI * samplerate / rtty_baud) *
734
(mark_history[mp1] % mark_history[mp0]).arg() :
735
(space_history[mp1] % space_history[mp0]).arg());
736
if (fabs(ferr) > rtty_baud / 2) ferr = 0;
737
freqerr = decayavg ( freqerr, ferr / 8,
738
progdefaults.rtty_afcspeed == 0 ? 8 :
739
progdefaults.rtty_afcspeed == 1 ? 4 : 1 );
740
if (progStatus.afconoff &&
741
(metric > progStatus.sldrSquelchValue || !progStatus.sqlonoff))
742
set_freq(frequency - freqerr);
744
if (bitcount) --bitcount;
747
if (!bitcount && clear_zdata) {
750
for (int i = 0; i < MAXPIPE; i++) QI[i].re = QI[i].im = 0.0;
751
set_zdata(QI, MAXPIPE);
607
if (progStatus.afconoff) {
608
if (metric > progStatus.sldrSquelchValue || !progStatus.sqlonoff) // || sigsearch) {
609
set_freq(frequency - ferr);
611
if (metric < progStatus.sldrSquelchValue && progStatus.sqlonoff) {
613
for (int i = 0; i < MAX_ZLEN; i++) QI[i].re = QI[i].im = 0.0;
614
set_zdata(QI, MAX_ZLEN);
627
757
//=====================================================================
629
759
//=====================================================================
762
double maxamp = -100;
631
764
double rtty::nco(double freq)
1111
//======================================================================
1112
// methods for class Oscillator and class SymbolShaper
1113
//======================================================================
1115
Oscillator::Oscillator( double samplerate )
1118
m_samplerate = samplerate;
1119
std::cerr << "samplerate for Oscillator:"<<m_samplerate<<"\n";
1122
double Oscillator::Update( double frequency )
1124
m_phase += frequency/m_samplerate * TWOPI;
1125
if ( m_phase > M_PI ) m_phase -= TWOPI;
1126
return ( sin( m_phase ) );
1129
SymbolShaper::SymbolShaper(double baud, int stop, double sr)
1132
Preset( baud, stop, sr );
1135
void SymbolShaper::reset()
1138
m_Accumulator = 0.0;
1153
void SymbolShaper::Preset(double baud, int stop, double sr)
1155
double baud_rate = baud;
1156
double sample_rate = sr;
1158
LOG_INFO("Shaper::reset( %f, %f )", baud_rate, sample_rate);
1160
// calculate new table-size for six integrators ----------------------
1162
m_table_size = sample_rate / baud_rate * 5.49;
1163
LOG_INFO("Shaper::m_table_size = %d", m_table_size);
1165
// kill old sinc-table and get memory for the new one -----------------
1167
delete m_sinc_table;
1168
m_sinc_table = new double[m_table_size];
1170
// set up the new sinc-table based on the new parameters --------------
1172
long double sum = 0.0;
1174
// if not using 1.5 stopbits, then place the second zero to the next symbol
1176
if( stop != 1) baud_rate/=1.5;
1178
for( int x=0; x<m_table_size; ++x ) {
1179
int const offset = m_table_size/2;
1180
double const symbol_len = sample_rate / baud_rate;
1181
double const sinc_scale = TWOPI * ( 1.0 / symbol_len );
1184
// the sinc(x) itself...
1185
m_sinc_table[x] = sin( ( x - offset ) * sinc_scale ) /
1186
( ( x - offset ) * sinc_scale );
1189
m_sinc_table[x] = sin( ( x - offset ) * sinc_scale * 1.5) /
1190
( ( x - offset ) * sinc_scale * 1.5);
1195
- 9240.0/18608.0 * cos( 2.0*M_PI*(x)/(m_table_size-1.0) )
1196
+ 1430.0/18608.0 * cos( 4.0*M_PI*(x)/(m_table_size-1.0) );
1199
m_sinc_table[x] = 1.0;
1202
// calculate integral
1203
sum += m_sinc_table[x];
1206
// scale the values in the table so that the integral over it is as
1207
// exactly 1.0000000 as we can do this...
1209
for( int x=0; x<m_table_size; ++x ) {
1210
m_sinc_table[x] *= 1.0 / sum;
1213
// reset internal states
1217
double SymbolShaper::Update( bool state )
1219
if( m_State != state ) {
1221
if( m_Counter0 >= m_table_size ) {
1223
m_Factor0 = (state)? +1.0 : -1.0;
1224
} else if( m_Counter1 >= m_table_size ) {
1226
m_Factor1 = (state)? +1.0 : -1.0;
1227
} else if( m_Counter2 >= m_table_size ) {
1229
m_Factor2 = (state)? +1.0 : -1.0;
1230
} else if( m_Counter3 >= m_table_size ) {
1232
m_Factor3 = (state)? +1.0 : -1.0;
1233
} else if( m_Counter4 >= m_table_size ) {
1235
m_Factor4 = (state)? +1.0 : -1.0;
1236
} else if( m_Counter5 >= m_table_size ) {
1238
m_Factor5 = (state)? +1.0 : -1.0;
1242
if( m_Counter0 < m_table_size )
1243
m_Accumulator += m_Factor0 * m_sinc_table[m_Counter0++];
1245
if( m_Counter1 < m_table_size )
1246
m_Accumulator += m_Factor1 * m_sinc_table[m_Counter1++];
1248
if( m_Counter2 < m_table_size )
1249
m_Accumulator += m_Factor2 * m_sinc_table[m_Counter2++];
1251
if( m_Counter3 < m_table_size )
1252
m_Accumulator += m_Factor3 * m_sinc_table[m_Counter3++];
1254
if( m_Counter4 < m_table_size )
1255
m_Accumulator += m_Factor4 * m_sinc_table[m_Counter4++];
1257
if( m_Counter5 < m_table_size )
1258
m_Accumulator += m_Factor5 * m_sinc_table[m_Counter5++];
1260
return ( m_Accumulator / sqrt(2) );
1263
void SymbolShaper::print_sinc_table()
1265
for (int i = 0; i < 1024; i++) printf("%f\n", m_SincTable[i]);