1
/***************************************************************************
2
rttydemodulator.cpp - description
5
copyright : (C) 2001 by Volker Schroer
7
***************************************************************************/
9
/***************************************************************************
11
* This program is free software; you can redistribute it and/or modify *
12
* it under the terms of the GNU General Public License as published by *
13
* the Free Software Foundation; either version 2 of the License, or *
14
* (at your option) any later version. *
15
***************************************************************************/
17
#include "rttydemodulator.h"
18
#include "firfilter.h"
19
#include "constants.h"
21
//#define CC1 0.9491 // 0.875 0.125 0.9125 0.0875 0.2 0.8
22
//#define CC3 0.05518// 0.9 0.02
24
#define CC1 0.95 /// 1. 0.1 0.7 , 0.775 0.1 0.7 , 0.8 0.08 0.575
25
#define CC3 0.15 /// 0.975 0.05 0.55 , 0.95 0.06 0.4 , 0.975 0.2 0.625
29
RTTYDemodulator::RTTYDemodulator():FSKDemodulator(2)
35
RxFrequency=0.0; // Will be set correctly in setFrequency !
36
//Initialize ExtraParameter
37
extraParameter.stopbits=Onepoint5;
38
extraParameter.parity=None;
39
extraParameter.reverse=true;
40
extraParameter.offset=170;
45
RTTYDemodulator::~RTTYDemodulator()
60
/** returns the asci char corresponding to the baudot code */
61
char RTTYDemodulator::baudot_code(char data)
63
/** Table of letters */
65
static const char letters[32] = {0x00,'E','\r','A',' ','S','I','U',
66
'\n','D','R','J','N','F','C','K',
67
'T','Z','L','W','H','Y','P','Q',
68
'O','B','G','^','M','X','V','^'};
71
/** Table of symbols */
72
static const char symbols[32] = {0x00,'3','\r','-',' ','\'','8','7',
73
'\n','$','4','#',',','!',':','(',
74
'5','"',')','2','#','6','0','1',
75
'9','?','&','^','.','/',';','^'};
82
ShiftOn = false; //LTRS
86
ShiftOn = true; //FIGS
91
c=letters[(int) data];
93
c=symbols[(int) data];
98
if ( c == ' ') // Unshift on Space
104
bool RTTYDemodulator::Init(double FS,int NumberofSamples)
106
double coeffs[NumberofProbes], x0;
108
FSKDemodulator::Init(FS,NumberofSamples);
111
SymbolLength=int (FS/Baudrate+0.5);
112
Status = WaitingForMark;
113
FrequencyChanged = false;
116
setFilter(Baudrate,SymbolLength,Distance);
117
setRxFrequency(1000.);
120
x0 = PI2*85./(11025./Distance);
121
for(i=0; i < NumberofProbes; i++)
123
if( i != (NumberofProbes-1)/2 )
124
coeffs[i]=sin(x0*(i-(NumberofProbes-1)/2))/(i-(NumberofProbes-1)/2);
127
coeffs[i] *=(0.42-0.5*cos((PI2*i)/(NumberofProbes-1))
128
+0.08*cos((PI2*(i+i))/(NumberofProbes-1)));
130
// Normalize for unity at DC
132
for(i=0;i<NumberofProbes;i++)
134
for(i=0;i<NumberofProbes;i++)
136
DiscriminatorThreshold=0.;
144
void RTTYDemodulator::ProcessInput(double *input, double *)
148
int StartBitCount,StopBit2Length, StartBitLength;
151
int SamplestoProcess;
153
double F0in[MaxSamplestoProcess], F1in[MaxSamplestoProcess];
154
//, F0out[MaxSamplestoProcess], F1out[MaxSamplestoProcess];
155
//double ThresholdInput[MaxSamplestoProcess],ThresholdOutput[MaxSamplestoProcess];
157
float xx,xSum,StartBitValue, StopBit2Value;
160
SamplestoProcess=lpDownSample();
161
for(i=0;i <SamplestoProcess;i++)
163
F0in[i]=abs(FilterOutput[0][i]);
164
F1in[i]=abs(FilterOutput[1][i]);
168
while ( actSample < SamplestoProcess )
170
if( (BufferCount < SampleBufferLength ) )
172
while ( (BufferCount < SampleBufferLength ) && ( actSample < SamplestoProcess ) )
176
ellipseDisplay[DisplayPointer]=complex<float>(0.,5.);
177
DisplayPointer = (DisplayPointer +1 )% 512;
178
if (extraParameter.reverse)
180
MarkBuffer[BufferPointer]=F1in[actSample];
181
SpaceBuffer[BufferPointer]=F0in[actSample];
185
MarkBuffer[BufferPointer]=F0in[actSample];
186
SpaceBuffer[BufferPointer]=F1in[actSample];
188
if(MarkMax < MarkBuffer[BufferPointer] )
190
MarkMax = MarkMax + C1 * ( MarkBuffer[BufferPointer]-MarkMax);
195
if ( holdCount1 == HoldLimit )
196
MarkMax = MarkMax - C3 * ( MarkMax -MarkBuffer[BufferPointer]);
200
if(SpaceMax < SpaceBuffer[BufferPointer] )
202
SpaceMax = SpaceMax + C1 * ( SpaceBuffer[BufferPointer]-SpaceMax);
207
if ( holdCount2 == HoldLimit )
208
SpaceMax = SpaceMax - C3 * ( SpaceMax -SpaceBuffer[BufferPointer]);
212
MarkBuffer[BufferPointer] -= MarkMax/2;
213
SpaceBuffer[BufferPointer] -= SpaceMax/2;
215
CharacterData[BufferPointer]=MarkBuffer[BufferPointer]-SpaceBuffer[BufferPointer];
217
BufferPointer=BufferPointer%SampleBufferLength;
219
} // End of filling CharacterData
221
while (BufferCount == SampleBufferLength)
223
switch (Status) // Now let's analyze the data
225
case WaitingForMark: // Waiting for Stopbit, previous state undefined
227
switch(extraParameter.stopbits)
230
StopBit1Length=NumberofProbes;
233
StopBit1Length =(3*NumberofProbes)/2;
237
StopBit1Length=2*NumberofProbes;
240
// Check, if we are possibly at the beginning of a stop bit
243
while ( (i < BufferCount ) && (CharacterData[(BufferPointer + i) % SampleBufferLength] <= DiscriminatorThreshold ) )
245
if ( i == 0 ) // At the beginning
250
while ( i < StopBit1Length )
252
if (CharacterData[(BufferPointer + i) % SampleBufferLength] > DiscriminatorThreshold )
254
StopBit1Value +=MarkBuffer[(BufferPointer + i) % SampleBufferLength];
255
xSum += CharacterData[(BufferPointer + i) % SampleBufferLength];
258
StopBit1Value= StopBit1Value/StopBit1Length;
259
xSum = xSum / StopBit1Length;
260
if ( xSum > DiscriminatorThreshold )
261
Status = WaitingForSpace;
263
BufferCount -= StopBit1Count;
265
else // Refill the buffer
269
case WaitingForSpace: // Stopbit seems to be found, now waiting for transition
272
while( (i < SampleBufferLength) && (CharacterData[(BufferPointer + i) % SampleBufferLength ]
273
> DiscriminatorThreshold ) )
275
if (i == SampleBufferLength )
277
BufferCount= StopBit1Length; // No Space found, keep only StopBit1Length Samples
278
DiscriminatorThreshold /=DOWN;
279
CalcQuality((float)0.);
283
Status=CheckingStartBit;
284
i = i - StopBit1Length;
285
BufferCount -=i; // Refill buffer
289
case CheckingStartBit:
291
j = StopBit1Length + BufferPointer;
295
StartBitLength = NumberofProbes;
296
for ( i= 0; i < NumberofProbes; i++)
298
if (CharacterData[( i + j ) % SampleBufferLength] < DiscriminatorThreshold )
300
StartBitValue += SpaceBuffer[( i + j ) % SampleBufferLength];
301
xSum += CharacterData[( i + j ) % SampleBufferLength];
304
StartBitValue= StartBitValue / StartBitLength;
305
xSum = xSum/StartBitLength;
306
if ( xSum < DiscriminatorThreshold ) // Super, Startbit fits very well
308
Status = CheckingStopBits;
309
DiscriminatorThreshold = B1 * DiscriminatorThreshold + (1.-B1) * (StopBit1Value - StartBitValue ) /2;
311
CalcQuality(abs(StartBitValue/xSum));
313
CalcQuality(abs(xSum));
317
Status = WaitingForMark; // Was'nt the correct start bit, neither number nor value fits
318
BufferCount -= StopBit1Length;
319
CalcQuality((float)0.);
326
for(i=0;i < NumberOfBits; i++)
328
j=(BufferPointer + StopBit1Length + StartBitLength + i * NumberofProbes ) % SampleBufferLength;
331
for(int j1=j;j1 <j + NumberofProbes; j1++)
332
xx += CharacterData[j1];
333
xx /= NumberofProbes;
335
if ( xx > DiscriminatorThreshold )
338
DiscriminatorThreshold =B1 * DiscriminatorThreshold + (1.-B1) * (xx - StopBit1Value)/2 ;
343
DiscriminatorThreshold =B1 * DiscriminatorThreshold + (1.-B1) * (StartBitValue-xx)/2 ;
347
if ( (c1 > 0 ) && (!Squelch || (Squelch && ( (unsigned int)(100.*ave1)>CDemodulator::Threshold))))
349
c1 = baudot_code(c1);
350
if ( c1 > 0) // FIGS or LTRS result in c1 = 0 !
351
emit newSymbol( c1 );
354
if (extraParameter.parity != None)
355
Status = CheckingParity;
358
if ( xSum > DiscriminatorThreshold ) //|| (StopBit2Value > DiscriminatorThreshold) )
359
Status = WaitingForSpace;
361
Status=WaitingForMark;
362
BufferCount -= (StopBit1Length + StartBitLength + 5*NumberofProbes );
363
StopBit1Length=StopBit2Length;
364
StopBit1Count=StopBit2Count;
365
StopBit1Value=StopBit2Value;
369
case CheckingParity: // Here we need BitsInData
372
case CheckingStopBits:
373
switch(extraParameter.stopbits)
376
StopBit2Length=NumberofProbes;
379
StopBit2Length =(3*NumberofProbes)/2;
383
StopBit2Length=2*NumberofProbes;
390
j = BufferPointer+StopBit1Length + StartBitLength + NumberOfBits*NumberofProbes;
391
for ( i=0; i < StopBit2Length;i++)
393
xx = CharacterData[(j+i)%SampleBufferLength];
394
StopBit2Value += MarkBuffer[(j+i)%SampleBufferLength];
395
if ( xx > DiscriminatorThreshold)
399
StopBit2Value = StopBit2Value/StopBit2Length;
400
xSum /= StopBit2Length;
401
if ( xSum > DiscriminatorThreshold ) //|| ( StopBit2avgThreshold > DiscriminatorThreshold ) )
402
Status = CollectingByte;
405
if (StartBitValue < DiscriminatorThreshold )
408
Status = CollectingByte;
412
// StartBit was not Ok, can we correct ?
413
Status = WaitingForMark;
414
BufferCount -= (StopBit1Length+ StartBitLength/2);
422
void RTTYDemodulator::setRxFrequency(double freq)
424
if ( freq != RxFrequency)
427
mixerfreqinc[0]=PI2*(RxFrequency)/SampleRate;
428
mixerfreqinc[1]=PI2*(RxFrequency+extraParameter.offset)/SampleRate;
431
void RTTYDemodulator::CalcQuality(float x)
434
ave1=0.3*ave1 + 0.15 *ave2 + 0.55 * x;
435
// ave1 = 0.4899*ave1 + 0.9165 *ave2 + 0.916572 *x;
437
void RTTYDemodulator::CalcQuality(int pointer)
441
pointer = pointer % SampleBufferLength;
442
diff=abs(CharacterData[pointer]);
443
sum=MarkBuffer[pointer]+SpaceBuffer[pointer];
446
ave1=0.7*ave1 + 0.25 * ave2 + 0.05 * diff/sum;
448
// ave1 = 0.5*ave1 + 0.3 *ave2;
451
int RTTYDemodulator::getSquelchValue()
453
return (int)(100.*ave1);
456
double RTTYDemodulator::get2RxFrequency()
458
return RxFrequency+extraParameter.offset;
461
void RTTYDemodulator::setParameter(RxTxParameterType Type,void *Value)
466
extraParameter.reverse = * (bool *) Value;
469
extraParameter.offset = * (int *) Value;
472
extraParameter.parity = * (Paritaet *) Value;
475
extraParameter = * (ExtraParameter *) Value;
481
void *RTTYDemodulator::getParameter(RxTxParameterType Type)
486
return (void *) &extraParameter.reverse;
489
return (void *) &extraParameter.offset;
492
return (void *) &extraParameter.parity;
495
return (void *) &extraParameter;
502
void *RTTYDemodulator::getBuffer()
504
return (void *) ellipseDisplay;
506
AfcMode RTTYDemodulator::AfcProperties()