~ubuntu-branches/ubuntu/trusty/fldigi/trusty

« back to all changes in this revision

Viewing changes to src/cw_rtty/rtty.cxx

  • Committer: Package Import Robot
  • Author(s): Kamal Mostafa
  • Date: 2013-02-02 11:52:30 UTC
  • mfrom: (1.1.64)
  • Revision ID: package-import@ubuntu.com-20130202115230-kea12fgypzi0c2uk
Tags: 3.21.67-2
* Debian packaging:
  - debian/fldigi.menu: use absolute path to menu icons

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
// ----------------------------------------------------------------------------
2
2
// rtty.cxx  --  RTTY modem
3
3
//
4
 
// Copyright (C) 2006-2010
 
4
// Copyright (C) 2012
5
5
//              Dave Freese, W1HKJ
6
 
//
7
 
// This file is part of fldigi.  Adapted from code contained in gmfsk source code
8
 
// distribution.
9
 
//  gmfsk Copyright (C) 2001, 2002, 2003
10
 
//  Tomi Manninen (oh2bns@sral.fi)
 
6
//              Stefan Fendt, DO2SMF
 
7
//
 
8
// This file is part of fldigi.
 
9
//
 
10
// This code bears some resemblance to code contained in gmfsk from which
 
11
// it originated.  Much has been changed, but credit should still be
 
12
// given to Tomi Manninen (oh2bns@sral.fi), who so graciously distributed
 
13
// his gmfsk modem under the GPL.
11
14
//
12
15
// Fldigi is free software: you can redistribute it and/or modify
13
16
// it under the terms of the GNU General Public License as published by
37
40
#include "status.h"
38
41
#include "digiscope.h"
39
42
#include "trx.h"
 
43
#include "debug.h"
40
44
 
41
45
view_rtty *rttyviewer = (view_rtty *)0;
42
46
 
44
48
// Baudot support
45
49
//=====================================================================
46
50
 
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',    ' '
52
56
};
53
57
 
54
58
#if 0
55
59
/*
56
60
 * ITA-2 version of the figures case.
57
61
 */
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',
66
70
/*
67
71
 * U.S. version of the figures case.
68
72
 */
69
 
static unsigned char figures[32] = {
 
73
static char figures[32] = {
70
74
        '\0',   '3',    '\n',   '-',    ' ',    '\a',   '8',    '7',
71
75
        '\r',   '$',    '4',    '\'',   ',',    '!',    ':',    '(',
72
76
        '5',    '"',    ')',    '2',    '#',    '6',    '0',    '1',
73
 
        '9',    '?',    '&',    '�',    '.',    '/',    ';',    '�'
 
77
        '9',    '?',    '&',    ' ',    '.',    '/',    ';',    ' '
74
78
};
75
79
#endif
76
80
#if 0
92
96
 
93
97
const double rtty::SHIFT[] = {23, 85, 160, 170, 182, 200, 240, 350, 425, 850};
94
98
const double rtty::BAUD[]  = {45, 45.45, 50, 56, 75, 100, 110, 150, 200, 300};
95
 
const int    rtty::BITS[]  = {5, 7, 8};
 
99
const int       rtty::BITS[]  = {5, 7, 8};
96
100
 
97
101
void rtty::tx_init(SoundBase *sc)
98
102
{
114
118
        }
115
119
        bitfilt->reset();
116
120
        poserr = negerr = 0.0;
 
121
 
 
122
        mark_phase = 0;
 
123
        space_phase = 0;
 
124
        xy_phase = 0.0;
 
125
 
 
126
        mark_mag = 0;
 
127
        space_mag = 0;
 
128
        mark_env = 0;
 
129
        space_env = 0;
 
130
 
 
131
        inp_ptr = 0;
 
132
 
117
133
}
118
134
 
119
135
void rtty::init()
136
152
        rx_init();
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);
140
156
        else
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);
145
161
        else
146
162
                set_scope_mode(Digiscope::RTTY);
 
163
        for (int i = 0; i < MAXPIPE; i++) mark_history[i] = space_history[i] = complex(0,0);
147
164
}
148
165
 
149
166
rtty::~rtty()
150
167
{
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;
 
174
        delete m_Osc1;
 
175
        delete m_Osc2;
 
176
        delete m_SymShaper1;
 
177
        delete m_SymShaper2;
 
178
}
 
179
 
 
180
void rtty::reset_filters()
 
181
{
 
182
        if (progStatus.rtty_filter_changed) {
 
183
                delete mark_filt;
 
184
                mark_filt = 0;
 
185
                delete space_filt;
 
186
                space_filt = 0;
 
187
        }
 
188
 
 
189
// filter_length = 512 / 1024 / 2048
 
190
        int filter_length = (1 << progdefaults.rtty_filter_quality) * 512;
 
191
        if (mark_filt) {
 
192
                mark_filt->create_rttyfilt(rtty_BW/2.0/samplerate);
 
193
        } else {
 
194
                mark_filt = new fftfilt(rtty_BW/2.0/samplerate, filter_length);
 
195
                mark_filt->create_rttyfilt(rtty_BW/2.0/samplerate);
 
196
     }
 
197
 
 
198
        if (space_filt) {
 
199
                space_filt->create_rttyfilt(rtty_BW/2.0/samplerate);
 
200
        } else {
 
201
                space_filt = new fftfilt(rtty_BW/2.0/samplerate, filter_length);
 
202
                space_filt->create_rttyfilt(rtty_BW/2.0/samplerate);
 
203
     }
156
204
}
157
205
 
158
206
void rtty::restart()
160
208
        double stl;
161
209
 
162
210
        rtty_shift = shift = (progdefaults.rtty_shift >= 0 ?
163
 
                              SHIFT[progdefaults.rtty_shift] : progdefaults.rtty_custom_shift);
 
211
                                  SHIFT[progdefaults.rtty_shift] : progdefaults.rtty_custom_shift);
164
212
        rtty_baud = BAUD[progdefaults.rtty_baud];
165
213
        nbits = rtty_bits = BITS[progdefaults.rtty_bits];
166
214
        if (rtty_bits == 5)
181
229
        symbollen = (int) (samplerate / rtty_baud + 0.5);
182
230
        set_bandwidth(shift);
183
231
 
184
 
        if (progdefaults.RTTY_BW < rtty_baud)
185
 
                progdefaults.RTTY_BW = rtty_baud;
186
 
        rtty_BW = progdefaults.RTTY_BW;
 
232
//      if (progdefaults.RTTY_BW < rtty_baud)
 
233
//              progdefaults.RTTY_BW = rtty_baud;
 
234
        rtty_BW = progdefaults.RTTY_BW = rtty_baud * 2;
187
235
        sldrRTTYbandwidth->value(rtty_BW);
188
236
 
189
237
        wf->redraw_marker();
192
240
        if (bp_filt_lo < 0) bp_filt_lo = 0;
193
241
        bp_filt_hi = (shift/2.0 + rtty_BW/2.0) / samplerate;
194
242
 
195
 
        if (bpfilt)
196
 
                bpfilt->create_filter(bp_filt_lo, bp_filt_hi);
197
 
        else
198
 
                bpfilt = new fftfilt(bp_filt_lo, bp_filt_hi, 1024);
 
243
        reset_filters();
199
244
 
200
245
        bflen = symbollen/3;
201
246
        if (bitfilt)
203
248
        else
204
249
                bitfilt = new Cmovavg(bflen);
205
250
 
 
251
        if (bits)
 
252
                bits->setLength(symbollen / 2);
 
253
        else
 
254
                bits = new Cmovavg(symbollen / 2);
 
255
        mark_noise = space_noise = 0;
 
256
        bit = nubit = true;
 
257
 
206
258
// stop length = 1, 1.5 or 2 bits
207
259
        rtty_stop = progdefaults.rtty_stop;
208
260
        if (rtty_stop == 0) stl = 1.0;
218
270
        metric = 0.0;
219
271
 
220
272
        if ((rtty_baud - (int)rtty_baud) == 0)
221
 
                snprintf(msg1, sizeof(msg1), "%-3.0f / %-4.0f", rtty_baud, rtty_shift);
 
273
                snprintf(msg1, sizeof(msg1), "%-3.0f/%-4.0f", rtty_baud, rtty_shift);
222
274
        else
223
 
                snprintf(msg1, sizeof(msg1), "%-4.2f / %-4.0f", rtty_baud, rtty_shift);
 
275
                snprintf(msg1, sizeof(msg1), "%-4.2f/%-4.0f", rtty_baud, rtty_shift);
224
276
        put_Status1(msg1);
225
277
        put_MODEstatus(mode);
226
 
        for (int i = 0; i < 1024; i++) QI[i].re = QI[i].im = 0.0;
 
278
        for (int i = 0; i < MAXPIPE; i++) QI[i].re = QI[i].im = 0.0;
227
279
        sigpwr = 0.0;
228
280
        noisepwr = 0.0;
229
281
        freqerrlo = freqerrhi = 0.0;
232
284
 
233
285
        clear_zdata = true;
234
286
 
 
287
        // restart symbol-rtty_shaper
 
288
        m_SymShaper1->Preset(rtty_baud, rtty_stop, samplerate);
 
289
        m_SymShaper2->Preset(rtty_baud, rtty_stop, samplerate);
 
290
 
 
291
        mark_phase = 0;
 
292
        space_phase = 0;
 
293
        xy_phase = 0.0;
 
294
 
 
295
        mark_mag = 0;
 
296
        space_mag = 0;
 
297
        mark_env = 0;
 
298
        space_env = 0;
 
299
 
 
300
        inp_ptr = 0;
 
301
 
 
302
        for (int i = 0; i < MAXPIPE; i++) mark_history[i] = space_history[i] = complex(0,0);
 
303
 
235
304
        rttyviewer->restart();
 
305
        progStatus.rtty_filter_changed = false;
236
306
 
237
307
}
238
308
 
244
314
 
245
315
        samplerate = RTTY_SampleRate;
246
316
 
247
 
        bpfilt = (fftfilt *)0;
 
317
        mark_filt = (fftfilt *)0;
 
318
        space_filt = (fftfilt *)0;
248
319
 
249
320
        bitfilt = (Cmovavg *)0;
250
321
 
258
329
 
259
330
        ::rttyviewer = new view_rtty(mode);
260
331
 
 
332
        m_Osc1 = new Oscillator( samplerate );
 
333
        m_Osc2 = new Oscillator( samplerate );
 
334
 
 
335
        m_SymShaper1 = new SymbolShaper( 45, samplerate );
 
336
        m_SymShaper2 = new SymbolShaper( 45, samplerate );
 
337
 
261
338
        restart();
 
339
 
262
340
}
263
341
 
264
 
void rtty::update_syncscope()
 
342
void rtty::Update_syncscope()
265
343
{
266
344
        int j;
267
345
        for (int i = 0; i < symbollen; i++) {
272
350
        set_scope(dsppipe, symbollen, false);
273
351
}
274
352
 
275
 
void rtty::clear_syncscope()
 
353
void rtty::Clear_syncscope()
276
354
{
277
355
        set_scope(0, 0, false);
278
356
}
279
357
 
280
 
complex rtty::mixer(complex in)
 
358
complex rtty::mixer(double &phase, double f, complex in)
281
359
{
282
360
        complex z;
283
 
        z.re = cos(phaseacc);
284
 
        z.im = sin(phaseacc);
 
361
        z.re = cos(phase);
 
362
        z.im = sin(phase);
285
363
        z = z * in;
286
364
 
287
 
        phaseacc -= TWOPI * frequency / samplerate;
288
 
        if (phaseacc > M_PI)
289
 
                phaseacc -= TWOPI;
290
 
        else if (phaseacc < M_PI)
291
 
                phaseacc += TWOPI;
 
365
        phase -= TWOPI * f / samplerate;
 
366
        if (phase < -TWOPI) phase += TWOPI;
292
367
 
293
368
        return z;
294
369
}
295
370
 
296
 
unsigned char rtty::bitreverse(unsigned char in, int n)
 
371
unsigned char rtty::Bit_reverse(unsigned char in, int n)
297
372
{
298
373
        unsigned char out = 0;
299
374
 
358
433
bool rtty::rx(bool bit)
359
434
{
360
435
        bool flag = false;
361
 
        unsigned char c;
 
436
        unsigned char c = 0;
362
437
 
363
438
        switch (rxstate) {
364
439
        case RTTY_RX_STATE_IDLE:
409
484
        case RTTY_RX_STATE_STOP:
410
485
                if (--counter == 0) {
411
486
                        if (bit) {
412
 
                                if ((metric >= progStatus.sldrSquelchValue && progStatus.sqlonoff)|| !progStatus.sqlonoff) {
 
487
                                if ((metric >= progStatus.sldrSquelchValue && progStatus.sqlonoff) || !progStatus.sqlonoff) {
413
488
                                        c = decode_char();
414
 
                                        if ( c != 0 && c != '\r')
 
489
                                        if ( c != 0 && c != '\r') {
415
490
                                                put_rx_char(progdefaults.rx_lowercase ? tolower(c) : c);
 
491
                                        }
 
492
                                        flag = true;
416
493
                                }
417
 
                                flag = true;
418
494
                        }
419
495
                        rxstate = RTTY_RX_STATE_STOP2;
420
496
                        counter = symbollen / 2;
435
511
void rtty::Metric()
436
512
{
437
513
        double delta = rtty_baud/8.0;
438
 
        double np = wf->powerDensity(frequency, delta);
 
514
        double np = wf->powerDensity(frequency, delta) * 3000 / delta;
439
515
        double sp =
440
516
                wf->powerDensity(frequency - shift/2, delta) +
441
517
                wf->powerDensity(frequency + shift/2, delta) + 1e-10;
442
518
        double snr = 0;
443
519
 
444
 
        sigpwr = decayavg( sigpwr, sp, sp - sigpwr > 0 ? 2 : 8);
445
 
        noisepwr = decayavg( noisepwr, np, 32 );
446
 
        snr = 10*log10(sigpwr / noisepwr);//( noisepwr * (1500 / delta))); // 3000 Hz noise bw
 
520
        sigpwr = decayavg( sigpwr, sp, sp > sigpwr ? 2 : 8);
 
521
        noisepwr = decayavg( noisepwr, np, 16 );
 
522
        snr = 10*log10(sigpwr / noisepwr);
447
523
 
448
 
        snprintf(snrmsg, sizeof(snrmsg), "s/n %3.0f dB", snr);
 
524
        snprintf(snrmsg, sizeof(snrmsg), "s/n %-3.0f dB", snr);
449
525
        put_Status2(snrmsg);
450
 
        metric = CLAMP(sigpwr/noisepwr, 0.0, 100.0);
 
526
        metric = CLAMP((3000 / delta) * (sigpwr/noisepwr), 0.0, 100.0);
451
527
        display_metric(metric);
452
528
}
453
529
 
491
567
 
492
568
int rtty::rx_process(const double *buf, int len)
493
569
{
494
 
        complex z, *zp;
495
 
        double f = 0.0;
496
 
        double fin;
497
 
        static bool bit = true;
498
 
        int n = 0;
499
 
        double deadzone = shift/4;
500
 
        double rotate;
501
 
        double ferr = 0;
502
 
 
503
 
        if (progdefaults.RTTY_BW != rtty_BW) {
 
570
        const double *buffer = buf;
 
571
        int length = len;
 
572
 
 
573
        complex z, zmark, zspace, *zp_mark, *zp_space;
 
574
 
 
575
        int n_out = 0;
 
576
        static int bitcount = 5 * nbits * symbollen;
 
577
 
 
578
        if (rttyviewer && !bHistory &&
 
579
                (dlgViewer->visible() || progStatus.show_channels)) rttyviewer->rx_process(buf, len);
 
580
 
 
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);
 
584
                reset_filters();
 
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;
 
590
                bit = nubit = true;
510
591
        }
511
592
 
512
 
        if (rttyviewer && !bHistory) rttyviewer->rx_process(buf, len);
513
 
 
514
593
        Metric();
515
594
 
516
 
        while (len-- > 0) {
517
 
 
518
 
// create analytic signal from sound card input samples
519
 
 
520
 
                z.re = z.im = *buf++;
 
595
        while (length-- > 0) {
 
596
 
 
597
// Create analytic signal from sound card input samples
 
598
 
 
599
                z.re = z.im = *buffer++;
521
600
                hilbert->run(z, z);
522
601
 
523
 
// mix it with the audio carrier frequency to create a baseband signal
524
 
 
525
 
                z = mixer(z);
526
 
 
527
 
// bandpass filter using Windowed Sinc - Overlap-Add convolution filter
528
 
 
529
 
                n = bpfilt->run(z, &zp);
530
 
 
531
 
                if (n) {
532
 
                        for (int i = 0; i < n; i++) {
533
 
 
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 %
537
 
 
538
 
                                fin = (prevsmpl % zp[i]).arg() * samplerate / TWOPI;
539
 
                                prevsmpl = zp[i];
540
 
 
541
 
 
542
 
// track the + and - frequency excursions separately to derive an afc signal
543
 
 
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;
547
 
                xmix += 0.05;
548
 
                                if (fin > 0.0) {
549
 
                                        poscnt++;
550
 
                                        posfreq += fin;
551
 
                                        QI[i].re = zp[i].re;
552
 
                                        QI[i].im = xmix * zp[i].im;
553
 
                                }
554
 
                                if (fin < 0.0) {
555
 
                                        negcnt++;
556
 
                                        negfreq += fin;
557
 
                                        QI[i].re = xmix * zp[i].im;
558
 
                                        QI[i].im = zp[i].re;
559
 
                                }
560
 
                                QI[i] = QI[i] * complex(cos(rotate), sin(rotate));
561
 
                avgsig = decayavg(avgsig, 1.25 * zp[i].mag(), 128);//64);
562
 
 
563
 
                                if (avgsig > 0)
564
 
                                    QI[i] = QI[i] / avgsig;
565
 
 
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
570
 
                                if (f > deadzone )
 
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
 
608
 
 
609
                zmark = mixer(mark_phase, frequency + shift/2.0, z);
 
610
                mark_filt->run(zmark, &zp_mark);
 
611
 
 
612
                zspace = mixer(space_phase, frequency - shift/2.0, z);
 
613
                n_out = space_filt->run(zspace, &zp_space);
 
614
 
 
615
                if (n_out) {
 
616
                        for (int i = 0; i < n_out; i++) {
 
617
 
 
618
 
 
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);
 
624
 
 
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);
 
630
 
 
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();
 
635
 
 
636
} else {
 
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;
 
642
}
 
643
 
 
644
// XY scope signal generation
 
645
 
 
646
if (progdefaults.true_scope) {
 
647
//----------------------------------------------------------------------
 
648
// "true" scope implementation------------------------------------------
 
649
//----------------------------------------------------------------------
 
650
 
 
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);
 
654
 
 
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();
 
661
                                } else {
 
662
                                        xy.re /= zp_space[i].mag()/zp_mark[i].mag();
 
663
                                }
 
664
 
 
665
// now normalize the scope
 
666
                                double const norm = 1.3*(zp_mark [i].mag() + zp_space[i].mag());
 
667
                                xy /= norm;
 
668
 
 
669
} else {
 
670
//----------------------------------------------------------------------
 
671
// "ortho" scope implementation-----------------------------------------
 
672
//----------------------------------------------------------------------
 
673
// get magnitude of the baseband-signal
 
674
                                if (bit)
 
675
                                        xy = complex( mark_mag * cos(xy_phase), space_noise * sin(xy_phase) / 2.0);
 
676
                                else
 
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);
 
680
                                xy /= norm;
 
681
}
 
682
 
 
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));
 
687
 
 
688
                                QI[inp_ptr] = xy;
 
689
 
 
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
 
693
// block-size.
 
694
                                xy_phase += (TWOPI * (128.0 / samplerate));
 
695
 
 
696
                                double testbit = bits->run(nubit);
 
697
                                if (!bit && testbit > 0.75) {
571
698
                                        bit = true;
572
 
                                if (f < -deadzone)
 
699
                                        if (bitcount) set_zdata(QI, MAXPIPE);
 
700
                                } else if (bit && testbit < 0.25) {
573
701
                                        bit = false;
 
702
                                        if (bitcount) set_zdata(QI, MAXPIPE);
 
703
                                }
 
704
 
 
705
 
 
706
// end XY signal generation
 
707
 
 
708
                                mark_history[inp_ptr] = zp_mark[i];
 
709
                                space_history[inp_ptr] = zp_space[i];
 
710
 
 
711
                                inp_ptr = (inp_ptr + 1) % MAXPIPE;
574
712
 
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;
578
716
                                }
579
717
 
 
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);
582
 
 
583
 
                                        if (poscnt && negcnt) {
584
 
                                                poserr = posfreq/poscnt;
585
 
                                                negerr = negfreq/negcnt;
586
 
 
587
 
// compute the frequency error as the median of + and - relative freq's
588
 
                                                if (sigsearch) sigsearch--;
589
 
 
590
 
                                                ferr = -(poserr + negerr)/(2*(SIGSEARCH - sigsearch + 1));
591
 
 
592
 
                                                int fs = progdefaults.rtty_afcspeed;
593
 
                                                int avging;
594
 
                                                if (fs == 0) avging = 8;
595
 
                                                else if (fs == 1) avging = 4;
596
 
                                                else avging = 1;
597
 
                                                freqerr   = decayavg(freqerr, ferr,  avging);
598
 
 
599
 
                                        poscnt = 0; posfreq = 0.0;
600
 
                                        negcnt = 0; negfreq = 0.0;
601
 
 
602
 
                                        }
603
 
                                }
 
723
                                        Update_syncscope();
 
724
                                        bitcount = 5 * nbits * symbollen;
 
725
                                        clear_zdata = true;
 
726
                                        if (sigsearch) sigsearch--;
 
727
 
 
728
                                        int mp0 = inp_ptr - 2;
 
729
                                        int mp1 = mp0 + 1;
 
730
                                        if (mp0 < 0) mp0 += MAXPIPE;
 
731
                                        if (mp1 < 0) mp1 += MAXPIPE;
 
732
                                        double ferr = (TWOPI * samplerate / rtty_baud) *
 
733
                                                        (!reverse ?
 
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);
 
743
                                } else
 
744
                                        if (bitcount) --bitcount;
604
745
                        }
605
746
                }
 
747
                if (!bitcount && clear_zdata) {
 
748
                        clear_zdata = false;
 
749
                        Clear_syncscope();
 
750
                        for (int i = 0; i < MAXPIPE; i++) QI[i].re = QI[i].im = 0.0;
 
751
                        set_zdata(QI, MAXPIPE);
 
752
                }
606
753
        }
607
 
        if (progStatus.afconoff) {
608
 
        if (metric > progStatus.sldrSquelchValue || !progStatus.sqlonoff) // || sigsearch) {
609
 
            set_freq(frequency - ferr);
610
 
    }
611
 
    if (metric < progStatus.sldrSquelchValue && progStatus.sqlonoff) {
612
 
        if (clear_zdata) {
613
 
            for (int i = 0; i < MAX_ZLEN; i++) QI[i].re = QI[i].im = 0.0;
614
 
            set_zdata(QI, MAX_ZLEN);
615
 
            clear_zdata = false;
616
 
            clear_syncscope();
617
 
        }
618
 
    } else {
619
 
        clear_zdata = true;
620
 
        update_syncscope();
621
 
        set_zdata(QI, n);
622
 
    }
623
 
 
624
754
        return 0;
625
755
}
626
756
 
627
757
//=====================================================================
628
758
// RTTY transmit
629
759
//=====================================================================
 
760
double freq1;
 
761
double minamp = 100;
 
762
double maxamp = -100;
630
763
 
631
764
double rtty::nco(double freq)
632
765
{
650
783
 
651
784
}
652
785
 
 
786
 
653
787
void rtty::send_symbol(int symbol)
654
788
{
 
789
#if 0
655
790
        double freq;
656
791
 
657
792
        if (reverse)
670
805
                        FSKbuf[i] = 0.0 * FSKnco();
671
806
        }
672
807
 
 
808
#else
 
809
 
 
810
        double const freq1 = get_txfreq_woffset() + shift / 2.0;
 
811
        double const freq2 = get_txfreq_woffset() - shift / 2.0;
 
812
        double mark = 0, space = 0;
 
813
 
 
814
        if (reverse)
 
815
                symbol = !symbol;
 
816
 
 
817
        for( int i = 0; i < symbollen; ++i ) {
 
818
                mark  = m_SymShaper1->Update( symbol) * m_Osc1->Update( freq1 );
 
819
                space = m_SymShaper2->Update(!symbol) * m_Osc2->Update( freq2 );
 
820
                outbuf[i] = mark + space;
 
821
                if (symbol)
 
822
                        FSKbuf[i] = FSKnco();
 
823
                else
 
824
                        FSKbuf[i] = 0.0 * FSKnco();
 
825
                if (minamp > outbuf[i]) minamp = outbuf[i];
 
826
                if (maxamp < outbuf[i]) maxamp = outbuf[i];
 
827
        }
 
828
#endif
 
829
 
673
830
        if (progdefaults.PseudoFSK)
674
831
                ModulateStereo(outbuf, FSKbuf, symbollen);
675
832
        else
678
835
 
679
836
void rtty::send_stop()
680
837
{
 
838
#if 0
681
839
        double freq;
682
840
        bool invert = reverse;
683
841
 
693
851
                else
694
852
                        FSKbuf[i] = FSKnco();
695
853
        }
 
854
#else
 
855
 
 
856
        double const freq1 = get_txfreq_woffset() + shift / 2.0;
 
857
        double const freq2 = get_txfreq_woffset() - shift / 2.0;
 
858
        double mark = 0, space = 0;
 
859
 
 
860
        bool symbol = true;
 
861
 
 
862
        if (reverse)
 
863
                symbol = !symbol;
 
864
 
 
865
        for( int i = 0; i < stoplen; ++i ) {
 
866
                mark  = m_SymShaper1->Update( symbol)*m_Osc1->Update( freq1 );
 
867
                space = m_SymShaper2->Update(!symbol)*m_Osc2->Update( freq2 );
 
868
                outbuf[i] = mark + space;
 
869
                if (reverse)
 
870
                        FSKbuf[i] = 0.0 * FSKnco();
 
871
                else
 
872
                        FSKbuf[i] = FSKnco();
 
873
        }
 
874
#endif
 
875
 
696
876
        if (progdefaults.PseudoFSK)
697
877
                ModulateStereo(outbuf, FSKbuf, stoplen);
698
878
        else
699
879
                ModulateXmtr(outbuf, stoplen);
 
880
 
 
881
}
 
882
 
 
883
void rtty::flush_stream()
 
884
{
 
885
        double const freq1 = get_txfreq_woffset() + shift / 2.0;
 
886
        double const freq2 = get_txfreq_woffset() - shift / 2.0;
 
887
        double mark = 0, space = 0;
 
888
 
 
889
        for( int i = 0; i < symbollen * 6; ++i ) {
 
890
                mark  = m_SymShaper1->Update(0)*m_Osc1->Update( freq1 );
 
891
                space = m_SymShaper2->Update(0)*m_Osc2->Update( freq2 );
 
892
                outbuf[i] = mark + space;
 
893
                FSKbuf[i] = 0.0;
 
894
        }
 
895
 
 
896
        if (progdefaults.PseudoFSK)
 
897
                ModulateStereo(outbuf, FSKbuf, symbollen * 6);
 
898
        else
 
899
                ModulateXmtr(outbuf, symbollen * 6);
 
900
 
700
901
}
701
902
 
702
903
void rtty::send_char(int c)
710
911
                        c = 0x1B;
711
912
        }
712
913
 
 
914
// start bit
713
915
        send_symbol(0);
714
916
// data bits
715
917
        for (i = 0; i < nbits; i++) {
736
938
 
737
939
void rtty::send_idle()
738
940
{
739
 
 
740
941
        if (nbits == 5) {
741
942
                send_char(LETTERS);
742
943
                txmode = LETTERS;
751
952
        int c;
752
953
 
753
954
        if (preamble > 0) {
754
 
                for (int i = 0; i < preamble; i++)
755
 
                        send_symbol(1);
756
 
                if (nbits == 5) {
757
 
                        send_char(LETTERS);
758
 
                        txmode = LETTERS;
759
 
                }
 
955
                m_SymShaper1->reset();
 
956
                m_SymShaper2->reset();
 
957
                send_idle();
760
958
                preamble = 0;
 
959
                freq1 = get_txfreq_woffset() + shift / 2.0;
 
960
 
761
961
        }
762
 
 
763
962
        c = get_tx_char();
764
963
 
765
964
// TX buffer empty
767
966
                stopflag = false;
768
967
                line_char_count = 0;
769
968
                if (nbits != 5) {
770
 
                        send_char('\r');
 
969
                        if (progdefaults.rtty_crcrlf) send_char('\r');
771
970
                        send_char('\r');
772
971
                        send_char('\n');
773
972
                } else {
774
 
                        send_char(0x08);
 
973
                        if (progdefaults.rtty_crcrlf) send_char(0x08);
775
974
                        send_char(0x08);
776
975
                        send_char(0x02);
777
976
                }
 
977
#if 1
 
978
// if (progdefaults.rtty_shaper)
 
979
                flush_stream();
 
980
#endif
778
981
//              KeyLine->clearDTR();
779
982
                cwid();
780
983
                return -1;
797
1000
        }
798
1001
 
799
1002
        if (progdefaults.rtty_autocrlf && (c != '\n' && c != '\r') &&
800
 
            (line_char_count == progdefaults.rtty_autocount ||
801
 
             (line_char_count > progdefaults.rtty_autocount - 5 && c == ' '))) {
 
1003
                (line_char_count == progdefaults.rtty_autocount ||
 
1004
                 (line_char_count > progdefaults.rtty_autocount - 5 && c == ' '))) {
802
1005
                line_char_count = 0;
803
1006
                if (progdefaults.rtty_crcrlf)
804
1007
                        send_char(0x08); // CR-CR-LF triplet
837
1040
 
838
1041
// switch case if necessary
839
1042
 
840
 
        if ((c & 0x300) != txmode) {// == 0) {
 
1043
        if ((c & 0x300) != txmode) {
841
1044
                if (txmode == FIGURES) {
842
1045
                        send_char(LETTERS);
843
1046
                        txmode = LETTERS;
905
1108
        return out;
906
1109
}
907
1110
 
 
1111
//======================================================================
 
1112
// methods for class Oscillator and class SymbolShaper
 
1113
//======================================================================
 
1114
 
 
1115
Oscillator::Oscillator( double samplerate )
 
1116
{
 
1117
        m_phase = 0;
 
1118
        m_samplerate = samplerate;
 
1119
        std::cerr << "samplerate for Oscillator:"<<m_samplerate<<"\n";
 
1120
}
 
1121
 
 
1122
double Oscillator::Update( double frequency )
 
1123
{
 
1124
        m_phase += frequency/m_samplerate * TWOPI;
 
1125
        if ( m_phase > M_PI ) m_phase -= TWOPI;
 
1126
        return ( sin( m_phase ) );
 
1127
}
 
1128
 
 
1129
SymbolShaper::SymbolShaper(double baud, int stop, double sr)
 
1130
{
 
1131
        m_sinc_table = 0;
 
1132
        Preset( baud, stop, sr );
 
1133
}
 
1134
 
 
1135
void SymbolShaper::reset()
 
1136
{
 
1137
        m_State = false;
 
1138
        m_Accumulator = 0.0;
 
1139
        m_Counter0 = 1024;
 
1140
        m_Counter1 = 1024;
 
1141
        m_Counter2 = 1024;
 
1142
        m_Counter3 = 1024;
 
1143
        m_Counter4 = 1024;
 
1144
        m_Counter5 = 1024;
 
1145
        m_Factor0 = 0.0;
 
1146
        m_Factor1 = 0.0;
 
1147
        m_Factor2 = 0.0;
 
1148
        m_Factor3 = 0.0;
 
1149
        m_Factor4 = 0.0;
 
1150
        m_Factor5 = 0.0;
 
1151
}
 
1152
 
 
1153
void SymbolShaper::Preset(double baud, int stop, double sr)
 
1154
{
 
1155
        double baud_rate = baud;
 
1156
        double sample_rate = sr;
 
1157
 
 
1158
        LOG_INFO("Shaper::reset( %f, %f )",  baud_rate, sample_rate);
 
1159
 
 
1160
// calculate new table-size for six integrators ----------------------
 
1161
 
 
1162
        m_table_size = sample_rate / baud_rate * 5.49;
 
1163
        LOG_INFO("Shaper::m_table_size = %d", m_table_size);
 
1164
 
 
1165
// kill old sinc-table and get memory for the new one -----------------
 
1166
 
 
1167
        delete m_sinc_table;
 
1168
        m_sinc_table = new double[m_table_size];
 
1169
 
 
1170
// set up the new sinc-table based on the new parameters --------------
 
1171
 
 
1172
        long double sum = 0.0;
 
1173
 
 
1174
// if not using 1.5 stopbits, then place the second zero to the next symbol
 
1175
 
 
1176
        if( stop != 1) baud_rate/=1.5;
 
1177
 
 
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 );
 
1182
 
 
1183
                if( x != offset ) {
 
1184
// the sinc(x) itself...
 
1185
                        m_sinc_table[x] = sin( ( x - offset ) * sinc_scale ) /
 
1186
                                                                         ( ( x - offset ) * sinc_scale );
 
1187
 
 
1188
// add further zero
 
1189
                                m_sinc_table[x]  = sin( ( x - offset ) * sinc_scale * 1.5) /
 
1190
                                                                          ( ( x - offset ) * sinc_scale * 1.5);
 
1191
 
 
1192
// blackman-window
 
1193
                        m_sinc_table[x] *=
 
1194
                                  7938.0/18608.0
 
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) );
 
1197
 
 
1198
                } else {
 
1199
                        m_sinc_table[x] = 1.0;
 
1200
                }
 
1201
 
 
1202
// calculate integral
 
1203
                sum += m_sinc_table[x];
 
1204
        }
 
1205
 
 
1206
// scale the values in the table so that the integral over it is as
 
1207
// exactly 1.0000000 as we can do this...
 
1208
 
 
1209
        for( int x=0; x<m_table_size; ++x ) {
 
1210
                m_sinc_table[x] *= 1.0 / sum;
 
1211
        }
 
1212
 
 
1213
// reset internal states
 
1214
        reset();
 
1215
}
 
1216
 
 
1217
double SymbolShaper::Update( bool state )
 
1218
{
 
1219
        if( m_State != state ) {
 
1220
                m_State = state;
 
1221
                if( m_Counter0 >= m_table_size ) {
 
1222
                        m_Counter0 = 0;
 
1223
                        m_Factor0 = (state)? +1.0 : -1.0;
 
1224
                } else if( m_Counter1 >= m_table_size ) {
 
1225
                        m_Counter1 = 0;
 
1226
                        m_Factor1 = (state)? +1.0 : -1.0;
 
1227
                } else if( m_Counter2 >= m_table_size ) {
 
1228
                        m_Counter2 = 0;
 
1229
                        m_Factor2 = (state)? +1.0 : -1.0;
 
1230
                } else if( m_Counter3 >= m_table_size ) {
 
1231
                        m_Counter3 = 0;
 
1232
                        m_Factor3 = (state)? +1.0 : -1.0;
 
1233
                } else if( m_Counter4 >= m_table_size ) {
 
1234
                        m_Counter4 = 0;
 
1235
                        m_Factor4 = (state)? +1.0 : -1.0;
 
1236
                } else  if( m_Counter5 >= m_table_size ) {
 
1237
                        m_Counter5 = 0;
 
1238
                        m_Factor5 = (state)? +1.0 : -1.0;
 
1239
                }
 
1240
        }
 
1241
 
 
1242
        if( m_Counter0 < m_table_size )
 
1243
                m_Accumulator += m_Factor0 * m_sinc_table[m_Counter0++];
 
1244
 
 
1245
        if( m_Counter1 < m_table_size )
 
1246
                m_Accumulator += m_Factor1 * m_sinc_table[m_Counter1++];
 
1247
 
 
1248
        if( m_Counter2 < m_table_size )
 
1249
                m_Accumulator += m_Factor2 * m_sinc_table[m_Counter2++];
 
1250
 
 
1251
        if( m_Counter3 < m_table_size )
 
1252
                m_Accumulator += m_Factor3 * m_sinc_table[m_Counter3++];
 
1253
 
 
1254
        if( m_Counter4 < m_table_size )
 
1255
                m_Accumulator += m_Factor4 * m_sinc_table[m_Counter4++];
 
1256
 
 
1257
        if( m_Counter5 < m_table_size )
 
1258
                m_Accumulator += m_Factor5 * m_sinc_table[m_Counter5++];
 
1259
 
 
1260
        return ( m_Accumulator / sqrt(2) );
 
1261
}
 
1262
 
 
1263
void SymbolShaper::print_sinc_table()
 
1264
{
 
1265
        for (int i = 0; i < 1024; i++) printf("%f\n", m_SincTable[i]);
 
1266
}
 
1267