mirror of
https://github.com/n5ac/mmvari.git
synced 2025-12-06 04:12:03 +01:00
6641 lines
172 KiB
C++
6641 lines
172 KiB
C++
|
|
//Copyright+LGPL
|
|||
|
|
|
|||
|
|
//-----------------------------------------------------------------------------------------------------------------------------------------------
|
|||
|
|
// Copyright 2000-2013 Makoto Mori, Nobuyuki Oba
|
|||
|
|
//-----------------------------------------------------------------------------------------------------------------------------------------------
|
|||
|
|
// This file is part of MMVARI.
|
|||
|
|
|
|||
|
|
// MMVARI is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License
|
|||
|
|
// as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
|||
|
|
|
|||
|
|
// MMVARI 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 Lesser General Public License for more details.
|
|||
|
|
|
|||
|
|
// You should have received a copy of the GNU Lesser General Public License along with MMTTY. If not, see
|
|||
|
|
// <http://www.gnu.org/licenses/>.
|
|||
|
|
//-----------------------------------------------------------------------------------------------------------------------------------------------
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
#include <vcl.h>
|
|||
|
|
#pragma hdrstop
|
|||
|
|
#include <stdlib.h>
|
|||
|
|
|
|||
|
|
#include "DSP.h"
|
|||
|
|
#include "ComLib.h"
|
|||
|
|
#include "Main.h"
|
|||
|
|
double SAMPFREQ=11025;
|
|||
|
|
int SAMPBASE=11025;
|
|||
|
|
double SAMPTXOFFSET=0;
|
|||
|
|
int SAMPTYPE=0;
|
|||
|
|
double DEMSAMPFREQ=11025*0.5;
|
|||
|
|
|
|||
|
|
CVARICODE g_VariCode;
|
|||
|
|
CSinTable g_SinTable;
|
|||
|
|
int g_tBpfTaps[]={64, 80, 128, 256};
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
#pragma package(smart_init)
|
|||
|
|
|
|||
|
|
const DWORD _tBitData[]={
|
|||
|
|
0x00000001, 0x00000002, 0x00000004, 0x00000008,
|
|||
|
|
0x00000010, 0x00000020, 0x00000040, 0x00000080,
|
|||
|
|
0x00000100, 0x00000200, 0x00000400, 0x00000800,
|
|||
|
|
0x00001000, 0x00002000, 0x00004000, 0x00008000,
|
|||
|
|
0x00010000, 0x00020000, 0x00040000, 0x00080000,
|
|||
|
|
0x00100000, 0x00200000, 0x00400000, 0x00800000,
|
|||
|
|
0x01000000, 0x02000000, 0x04000000, 0x08000000,
|
|||
|
|
0x10000000, 0x20000000, 0x40000000, 0x80000000,
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
const BYTE tQPSK_Viterbi[32]={
|
|||
|
|
2, 1, 3, 0, 3, 0, 2, 1, 0, 3, 1, 2, 1, 2, 0, 3,
|
|||
|
|
1, 2, 0, 3, 0, 3, 1, 2, 3, 0, 2, 1, 2, 1, 3, 0,
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
BOOL __fastcall IsRTTY(int m)
|
|||
|
|
{
|
|||
|
|
return (m==MODE_RTTY)||(m==MODE_U_RTTY);
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
BOOL __fastcall Is170(int m)
|
|||
|
|
{
|
|||
|
|
return (m==MODE_FSKW)||IsRTTY(m);
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
BOOL __fastcall IsBPSK(int m)
|
|||
|
|
{
|
|||
|
|
return (m==MODE_BPSK)||(m==MODE_N_BPSK);
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
BOOL __fastcall IsQPSK(int m)
|
|||
|
|
{
|
|||
|
|
return (m==MODE_qpsk_L)||(m==MODE_qpsk_U);
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
BOOL __fastcall IsPSK(int m)
|
|||
|
|
{
|
|||
|
|
return IsBPSK(m)||IsQPSK(m);
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
BOOL __fastcall IsFSK(int m)
|
|||
|
|
{
|
|||
|
|
return (m==MODE_GMSK)||(m==MODE_FSK);
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
BOOL __fastcall IsMFSK(int m)
|
|||
|
|
{
|
|||
|
|
return (m==MODE_mfsk_L)||(m==MODE_mfsk_U);
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
// <20>e<EFBFBD>h<EFBFBD>q<EFBFBD>t<EFBFBD>B<EFBFBD><42><EFBFBD>^<5E>̂<EFBFBD><CC82><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>݉<EFBFBD><DD89>Z
|
|||
|
|
double __fastcall DoFIR(double *hp, double *zp, double d, int tap)
|
|||
|
|
{
|
|||
|
|
memcpy(zp, &zp[1], sizeof(double)*tap);
|
|||
|
|
zp[tap] = d;
|
|||
|
|
d = 0.0;
|
|||
|
|
for( int i = 0; i <= tap; i++, hp++, zp++ ){
|
|||
|
|
d += (*zp) * (*hp);
|
|||
|
|
}
|
|||
|
|
return d;
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
//<2F>x<EFBFBD>b<EFBFBD>Z<EFBFBD><5A><EFBFBD><EFBFBD>
|
|||
|
|
static double __fastcall I0(double x)
|
|||
|
|
{
|
|||
|
|
double sum, xj;
|
|||
|
|
int j;
|
|||
|
|
|
|||
|
|
sum = 1.0;
|
|||
|
|
xj = 1.0;
|
|||
|
|
j = 1;
|
|||
|
|
while(1){
|
|||
|
|
xj *= ((0.5 * x) / (double)j);
|
|||
|
|
sum += (xj*xj);
|
|||
|
|
j++;
|
|||
|
|
if( ((0.00000001 * sum) - (xj*xj)) > 0 ) break;
|
|||
|
|
}
|
|||
|
|
return(sum);
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
//<2F>e<EFBFBD>h<EFBFBD>q<EFBFBD>t<EFBFBD>B<EFBFBD><42><EFBFBD>^<5E>̐v
|
|||
|
|
void __fastcall MakeFilter(double *HP, FIR *fp)
|
|||
|
|
{
|
|||
|
|
if( fp->n <= 1 ){
|
|||
|
|
HP[0] = 1.0;
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
if( fp->typ == ffGAUSSIAN ){
|
|||
|
|
MakeGaussian(HP, fp->n, fp->fcl, fp->fs, fp->gain);
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
int j, m;
|
|||
|
|
double alpha, win, fm, w0, sum;
|
|||
|
|
double *hp;
|
|||
|
|
|
|||
|
|
if( fp->typ == ffHPF ){
|
|||
|
|
fp->fc = 0.5*fp->fs - fp->fcl;
|
|||
|
|
}
|
|||
|
|
else if( fp->typ != ffLPF ){
|
|||
|
|
fp->fc = (fp->fch - fp->fcl)/2.0;
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
fp->fc = fp->fcl;
|
|||
|
|
}
|
|||
|
|
if( fp->att >= 50.0 ){
|
|||
|
|
alpha = 0.1102 * (fp->att - 8.7);
|
|||
|
|
}
|
|||
|
|
else if( fp->att >= 21 ){
|
|||
|
|
alpha = (0.5842 * pow(fp->att - 21.0, 0.4)) + (0.07886 * (fp->att - 21.0));
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
alpha = 0.0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
hp = fp->hp;
|
|||
|
|
sum = PI*2.0*fp->fc/fp->fs;
|
|||
|
|
if( fp->att >= 21 ){ // <20>C<EFBFBD><43><EFBFBD>p<EFBFBD><70><EFBFBD>X<EFBFBD><58><EFBFBD><EFBFBD><EFBFBD>Ƒ<EFBFBD><C691><EFBFBD><D690><EFBFBD><EFBFBD>v<EFBFBD>Z
|
|||
|
|
for( j = 0; j <= (fp->n/2); j++, hp++ ){
|
|||
|
|
fm = (double)(2 * j)/(double)fp->n;
|
|||
|
|
win = I0(alpha * sqrt(1.0-(fm*fm)))/I0(alpha);
|
|||
|
|
if( !j ){
|
|||
|
|
*hp = fp->fc * 2.0/fp->fs;
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
*hp = (1.0/(PI*(double)j))*sin((double)j*sum)*win;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else { // <20>C<EFBFBD><43><EFBFBD>p<EFBFBD><70><EFBFBD>X<EFBFBD><58><EFBFBD><EFBFBD><EFBFBD>̂v<DD8C>Z
|
|||
|
|
for( j = 0; j <= (fp->n/2); j++, hp++ ){
|
|||
|
|
if( !j ){
|
|||
|
|
*hp = fp->fc * 2.0/fp->fs;
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
*hp = (1.0/(PI*(double)j))*sin((double)j*sum);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
hp = fp->hp;
|
|||
|
|
sum = *hp++;
|
|||
|
|
for( j = 1; j <= (fp->n/2); j++, hp++ ) sum += 2.0 * (*hp);
|
|||
|
|
hp = fp->hp;
|
|||
|
|
if( sum > 0.0 ){
|
|||
|
|
for( j = 0; j <= (fp->n/2); j++, hp++ ) (*hp) /= sum;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// <20><><EFBFBD>g<EFBFBD><67><EFBFBD>ϊ<EFBFBD>
|
|||
|
|
|
|||
|
|
if( fp->typ == ffHPF ){
|
|||
|
|
hp = fp->hp;
|
|||
|
|
for( j = 0; j <= (fp->n/2); j++, hp++ ) (*hp) *= cos((double)j*PI);
|
|||
|
|
}
|
|||
|
|
else if( fp->typ != ffLPF ){
|
|||
|
|
w0 = PI * (fp->fcl + fp->fch) / fp->fs;
|
|||
|
|
if( fp->typ == ffBPF ){
|
|||
|
|
hp = fp->hp;
|
|||
|
|
for( j = 0; j <= (fp->n/2); j++, hp++ ) (*hp) *= 2.0*cos((double)j*w0);
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
hp = fp->hp;
|
|||
|
|
*hp = 1.0 - (2.0 * (*hp));
|
|||
|
|
for( hp++, j = 1; j <= (fp->n/2); j++, hp++ ) (*hp) *= -2.0*cos((double)j*w0);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
for( m = fp->n/2, hp = &fp->hp[m], j = m; j >= 0; j--, hp-- ){
|
|||
|
|
*HP++ = (*hp) * fp->gain;
|
|||
|
|
}
|
|||
|
|
for( hp = &fp->hp[1], j = 1; j <= (fp->n/2); j++, hp++ ){
|
|||
|
|
*HP++ = (*hp) * fp->gain;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
//<2F>e<EFBFBD>h<EFBFBD>q<EFBFBD>t<EFBFBD>B<EFBFBD><42><EFBFBD>^<5E>̐v
|
|||
|
|
void __fastcall MakeFilter(double *HP, int tap, int type, double fs, double fcl, double fch, double att, double gain)
|
|||
|
|
{
|
|||
|
|
FIR fir;
|
|||
|
|
|
|||
|
|
fir.typ = type;
|
|||
|
|
fir.n = tap;
|
|||
|
|
fir.fs = fs;
|
|||
|
|
fir.fcl = fcl;
|
|||
|
|
fir.fch = fch;
|
|||
|
|
fir.att = att;
|
|||
|
|
fir.gain = gain;
|
|||
|
|
MakeFilter(HP, &fir);
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
//<2F>e<EFBFBD>h<EFBFBD>q<EFBFBD>t<EFBFBD>B<EFBFBD><42><EFBFBD>^<5E>i<EFBFBD>q<EFBFBD><71><EFBFBD>x<EFBFBD><78><EFBFBD>g<EFBFBD>ϊ<EFBFBD><CF8A>t<EFBFBD>B<EFBFBD><42><EFBFBD>^<5E>j<EFBFBD>̐v
|
|||
|
|
//
|
|||
|
|
void __fastcall MakeHilbert(double *H, int N, double fs, double fc1, double fc2)
|
|||
|
|
{
|
|||
|
|
int L = N / 2;
|
|||
|
|
double T = 1.0 / fs;
|
|||
|
|
|
|||
|
|
double W1 = 2 * PI * fc1;
|
|||
|
|
double W2 = 2 * PI * fc2;
|
|||
|
|
|
|||
|
|
// 2*fc2*T*SA((n-L)*W2*T) - 2*fc1*T*SA((n-L)*W1*T)
|
|||
|
|
|
|||
|
|
double w;
|
|||
|
|
int n;
|
|||
|
|
double x1, x2;
|
|||
|
|
for( n = 0; n <= N; n++ ){
|
|||
|
|
if( n == L ){
|
|||
|
|
x1 = x2 = 0.0;
|
|||
|
|
}
|
|||
|
|
else if( (n - L) ){
|
|||
|
|
x1 = ((n - L) * W1 * T);
|
|||
|
|
x1 = cos(x1) / x1;
|
|||
|
|
x2 = ((n - L) * W2 * T);
|
|||
|
|
x2 = cos(x2) / x2;
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
x1 = x2 = 1.0;
|
|||
|
|
}
|
|||
|
|
w = 0.54 - 0.46 * cos(2*PI*n/(N));
|
|||
|
|
H[n] = -(2 * fc2 * T * x2 - 2 * fc1 * T * x1) * w;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if( N < 8 ){
|
|||
|
|
w = 0;
|
|||
|
|
for( n = 0; n <= N; n++ ){
|
|||
|
|
w += fabs(H[n]);
|
|||
|
|
}
|
|||
|
|
if( w ){
|
|||
|
|
w = 1.0 / w;
|
|||
|
|
for( n = 0; n <= N; n++ ){
|
|||
|
|
H[n] *= w;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------
|
|||
|
|
void __fastcall MakeGaussian(double *H, int N, double fc, double fs, double B)
|
|||
|
|
{
|
|||
|
|
double W = fc;
|
|||
|
|
double T = 1.0 / fs;
|
|||
|
|
double k = B * T * W;
|
|||
|
|
|
|||
|
|
double LN = 2.0/log(2.0);
|
|||
|
|
int L = N / 2;
|
|||
|
|
int i, n;
|
|||
|
|
double sum = 0;
|
|||
|
|
for( i = 0; i <= N; i++ ){
|
|||
|
|
n = i - L;
|
|||
|
|
if( n < 0 ) n = -n;
|
|||
|
|
double d = -sqrt(LN) * PI * k * n;
|
|||
|
|
H[i] = sqrt(LN*PI) * k * exp(d);
|
|||
|
|
sum += H[i];
|
|||
|
|
}
|
|||
|
|
if( sum ){
|
|||
|
|
sum = 1.0 / sum;
|
|||
|
|
for( i = 0; i <= N; i++ ){
|
|||
|
|
H[i] *= sum;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------
|
|||
|
|
// <20><><EFBFBD>g<EFBFBD><67><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>O<EFBFBD><4F><EFBFBD>t<EFBFBD>i<EFBFBD>t<EFBFBD>B<EFBFBD><42><EFBFBD>^<5E>X<EFBFBD><58><EFBFBD>b<EFBFBD>h<EFBFBD><68><EFBFBD>ŃR<C583>[<5B><><EFBFBD><EFBFBD><EFBFBD>Ă͂<C482><CD82><EFBFBD><EFBFBD>Ȃ<EFBFBD><C882>j
|
|||
|
|
//
|
|||
|
|
// H(ej<65><6A>T) = [<5B><>0]Hm cos(m<><6D>T) - j[<5B><>1]Hm sin(m<><6D>T)
|
|||
|
|
//
|
|||
|
|
void __fastcall DrawGraph(Graphics::TBitmap *pBitmap, const double *H, int Tap, int &nmax, int init, TColor col, double SampFreq)
|
|||
|
|
{
|
|||
|
|
int k, x, y;
|
|||
|
|
double f, gdb, g, pi2t, fs;
|
|||
|
|
double max;
|
|||
|
|
char bf[80];
|
|||
|
|
|
|||
|
|
TCanvas *tp = pBitmap->Canvas;
|
|||
|
|
TRect rc;
|
|||
|
|
rc.Left = 0;
|
|||
|
|
rc.Right = pBitmap->Width;
|
|||
|
|
rc.Top = 0;
|
|||
|
|
rc.Bottom = pBitmap->Height;
|
|||
|
|
if( init ){
|
|||
|
|
tp->Brush->Color = clWhite;
|
|||
|
|
tp->FillRect(rc);
|
|||
|
|
}
|
|||
|
|
int LM; // <20><><EFBFBD>g<EFBFBD><67><EFBFBD>\<5C><><EFBFBD>̂<EFBFBD><CC82>郉<EFBFBD>C<EFBFBD><43><EFBFBD><EFBFBD>
|
|||
|
|
int DM; // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>̐<EFBFBD>
|
|||
|
|
int MM; // <20><><EFBFBD><EFBFBD><EFBFBD>̊Ԋu
|
|||
|
|
max = 3000;
|
|||
|
|
fs = SampFreq;
|
|||
|
|
if( nmax ){
|
|||
|
|
max = nmax;
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
nmax = max;
|
|||
|
|
}
|
|||
|
|
#if 0
|
|||
|
|
LM = 4;
|
|||
|
|
DM = 19;
|
|||
|
|
MM = 5;
|
|||
|
|
#else
|
|||
|
|
switch(nmax){
|
|||
|
|
case 3000:
|
|||
|
|
LM = 3;
|
|||
|
|
DM = 14;
|
|||
|
|
MM = 5;
|
|||
|
|
break;
|
|||
|
|
case 100:
|
|||
|
|
case 200:
|
|||
|
|
case 2000:
|
|||
|
|
LM = 4;
|
|||
|
|
DM = 19;
|
|||
|
|
MM = 5;
|
|||
|
|
break;
|
|||
|
|
case 400:
|
|||
|
|
case 800:
|
|||
|
|
case 4000:
|
|||
|
|
LM = 4;
|
|||
|
|
DM = 19;
|
|||
|
|
MM = 5;
|
|||
|
|
break;
|
|||
|
|
default: // 6000
|
|||
|
|
LM = 3;
|
|||
|
|
DM = 11;
|
|||
|
|
MM = 4;
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
#endif
|
|||
|
|
int XL = 32;
|
|||
|
|
int XR = pBitmap->Width - 16;
|
|||
|
|
int YT = 16;
|
|||
|
|
int YB = pBitmap->Height - 24;
|
|||
|
|
|
|||
|
|
int i;
|
|||
|
|
if( init ){
|
|||
|
|
tp->Pen->Color = clBlack;
|
|||
|
|
tp->Font->Size = 8;
|
|||
|
|
tp->MoveTo(XL, YT); tp->LineTo(XR, YT); tp->LineTo(XR, YB); tp->LineTo(XL, YB); tp->LineTo(XL, YT);
|
|||
|
|
tp->Pen->Color = clGray;
|
|||
|
|
for( i = 0; i < 7; i++ ){
|
|||
|
|
tp->Pen->Style = (i & 1) ? psSolid : psDot;
|
|||
|
|
y = (int)(double(i + 1) * double(YB - YT)/8.0 + YT);
|
|||
|
|
tp->MoveTo(XL, y); tp->LineTo(XR, y);
|
|||
|
|
}
|
|||
|
|
for( i = 1; i < 5; i++ ){
|
|||
|
|
y = (int)(double(i) * double(YB - YT)/4.0 + YT);
|
|||
|
|
sprintf( bf, "-%2u", (80 / 4)*i );
|
|||
|
|
::SetBkMode(tp->Handle, TRANSPARENT);
|
|||
|
|
tp->TextOut(XL - 6 - tp->TextWidth(bf), y - (tp->TextHeight(bf)/2), bf);
|
|||
|
|
}
|
|||
|
|
strcpy(bf, "dB");
|
|||
|
|
tp->TextOut(XL - 6 - tp->TextWidth(bf), YT-(tp->TextHeight(bf)/2), bf);
|
|||
|
|
for( i = 1; i <= DM; i++ ){
|
|||
|
|
tp->Pen->Style = (i % MM) ? psDot : psSolid;
|
|||
|
|
x = (int)(double(i) * double(XR - XL)/double(DM+1) + XL);
|
|||
|
|
tp->MoveTo(x, YT); tp->LineTo(x, YB);
|
|||
|
|
}
|
|||
|
|
for( i = 0; i <= LM; i++ ){
|
|||
|
|
x = (int)(double(i) * double(XR - XL)/double(LM) + XL);
|
|||
|
|
sprintf(bf, "%4.0lf", (max*i)/LM);
|
|||
|
|
::SetBkMode(tp->Handle, TRANSPARENT);
|
|||
|
|
tp->TextOut(x - (tp->TextWidth(bf)/2), YB + 6, bf);
|
|||
|
|
}
|
|||
|
|
tp->Pen->Color = clRed;
|
|||
|
|
tp->Pen->Style = psDot;
|
|||
|
|
x = (int)(XL + (fs/2) * (double(XR-XL)/max));
|
|||
|
|
tp->MoveTo(x, YT); tp->LineTo(x, YB);
|
|||
|
|
|
|||
|
|
tp->Pen->Color = clBlue;
|
|||
|
|
tp->Pen->Style = psSolid;
|
|||
|
|
}
|
|||
|
|
int ay = 0;
|
|||
|
|
int apy = 0;
|
|||
|
|
double ra, im;
|
|||
|
|
pi2t = 2.0 * PI / fs;
|
|||
|
|
tp->Pen->Color = col;
|
|||
|
|
for( x = XL, f = 0.0; x < XR; x++, f += (max/double(XR-XL)) ){
|
|||
|
|
if( Tap ){
|
|||
|
|
ra = im = 0.0;
|
|||
|
|
for( k = 0; k <= Tap; k++ ){
|
|||
|
|
ra += H[k] * cos(pi2t*f*k);
|
|||
|
|
if( k ) im -= H[k] * sin(pi2t*f*k);
|
|||
|
|
}
|
|||
|
|
if( ra * im ){
|
|||
|
|
g = sqrt(ra * ra + im * im);
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
g = 0.0;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
g = 1.0;
|
|||
|
|
}
|
|||
|
|
if( g == 0 ) g = 1.0e-38;
|
|||
|
|
gdb = 20*0.4342944*log(fabs(g)) + 80.0;
|
|||
|
|
if( gdb < 0.0 ) gdb = 0.0;
|
|||
|
|
gdb = (gdb * double(YB-YT))/80.0;
|
|||
|
|
y = YB - (int)gdb;
|
|||
|
|
if( x == XL ){
|
|||
|
|
tp->MoveTo(x, y);
|
|||
|
|
tp->LineTo(x, y);
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
tp->MoveTo(x-1, ay);
|
|||
|
|
tp->LineTo(x, y);
|
|||
|
|
}
|
|||
|
|
ay = y;
|
|||
|
|
|
|||
|
|
double ph = 0;
|
|||
|
|
if( ra ){
|
|||
|
|
ph = atan2(im, ra);
|
|||
|
|
}
|
|||
|
|
int yc = (YB + YT) / 2;
|
|||
|
|
y = yc + (ph * (YB - YT) / (4*PI));
|
|||
|
|
if( x != XL ){
|
|||
|
|
tp->Pen->Color = clRed;
|
|||
|
|
tp->MoveTo(x-1, apy);
|
|||
|
|
tp->LineTo(x, y);
|
|||
|
|
tp->Pen->Color = clBlue;
|
|||
|
|
}
|
|||
|
|
apy = y;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
//---------------------------------------------------------------------
|
|||
|
|
// <20><><EFBFBD>g<EFBFBD><67><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>O<EFBFBD><4F><EFBFBD>t<EFBFBD>i<EFBFBD>t<EFBFBD>B<EFBFBD><42><EFBFBD>^<5E>X<EFBFBD><58><EFBFBD>b<EFBFBD>h<EFBFBD><68><EFBFBD>ŃR<C583>[<5B><><EFBFBD><EFBFBD><EFBFBD>Ă͂<C482><CD82><EFBFBD><EFBFBD>Ȃ<EFBFBD><C882>j
|
|||
|
|
//
|
|||
|
|
//
|
|||
|
|
void __fastcall DrawGraphIIR(Graphics::TBitmap *pBitmap, double a0, double a1, double a2, double b1, double b2, int &nmax, int init, TColor col, double SampFreq)
|
|||
|
|
{
|
|||
|
|
int x, y;
|
|||
|
|
double f, gdb, g, pi2t, pi4t, fs;
|
|||
|
|
double max;
|
|||
|
|
char bf[80];
|
|||
|
|
|
|||
|
|
TCanvas *tp = pBitmap->Canvas;
|
|||
|
|
TRect rc;
|
|||
|
|
rc.Left = 0;
|
|||
|
|
rc.Right = pBitmap->Width;
|
|||
|
|
rc.Top = 0;
|
|||
|
|
rc.Bottom = pBitmap->Height;
|
|||
|
|
if( init ){
|
|||
|
|
tp->Brush->Color = clWhite;
|
|||
|
|
tp->FillRect(rc);
|
|||
|
|
}
|
|||
|
|
int LM; // <20><><EFBFBD>g<EFBFBD><67><EFBFBD>\<5C><><EFBFBD>̂<EFBFBD><CC82>郉<EFBFBD>C<EFBFBD><43><EFBFBD><EFBFBD>
|
|||
|
|
int DM; // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>̐<EFBFBD>
|
|||
|
|
int MM; // <20><><EFBFBD><EFBFBD><EFBFBD>̊Ԋu
|
|||
|
|
max = 4000;
|
|||
|
|
fs = SampFreq;
|
|||
|
|
if( nmax ){
|
|||
|
|
max = nmax;
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
nmax = max;
|
|||
|
|
}
|
|||
|
|
switch(nmax){
|
|||
|
|
case 3000:
|
|||
|
|
LM = 3;
|
|||
|
|
DM = 14;
|
|||
|
|
MM = 5;
|
|||
|
|
break;
|
|||
|
|
case 100:
|
|||
|
|
case 200:
|
|||
|
|
case 2000:
|
|||
|
|
LM = 4;
|
|||
|
|
DM = 19;
|
|||
|
|
MM = 5;
|
|||
|
|
break;
|
|||
|
|
case 400:
|
|||
|
|
case 800:
|
|||
|
|
case 4000:
|
|||
|
|
LM = 4;
|
|||
|
|
DM = 19;
|
|||
|
|
MM = 5;
|
|||
|
|
break;
|
|||
|
|
default: // 6000
|
|||
|
|
LM = 3;
|
|||
|
|
DM = 11;
|
|||
|
|
MM = 4;
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
int XL = 32;
|
|||
|
|
int XR = pBitmap->Width - 16;
|
|||
|
|
int YT = 16;
|
|||
|
|
int YB = pBitmap->Height - 24;
|
|||
|
|
|
|||
|
|
int i;
|
|||
|
|
if( init ){
|
|||
|
|
tp->Pen->Color = clBlack;
|
|||
|
|
tp->Font->Size = 8;
|
|||
|
|
tp->MoveTo(XL, YT); tp->LineTo(XR, YT); tp->LineTo(XR, YB); tp->LineTo(XL, YB); tp->LineTo(XL, YT);
|
|||
|
|
tp->Pen->Color = clGray;
|
|||
|
|
for( i = 0; i < 5; i++ ){
|
|||
|
|
tp->Pen->Style = (i & 1) ? psSolid : psDot;
|
|||
|
|
y = (int)(double(i + 1) * double(YB - YT)/6.0 + YT);
|
|||
|
|
tp->MoveTo(XL, y); tp->LineTo(XR, y);
|
|||
|
|
}
|
|||
|
|
for( i = 1; i < 4; i++ ){
|
|||
|
|
y = (int)(double(i) * double(YB - YT)/3.0 + YT);
|
|||
|
|
sprintf( bf, "-%2u", (60 / 3)*i );
|
|||
|
|
::SetBkMode(tp->Handle, TRANSPARENT);
|
|||
|
|
tp->TextOut(XL - 6 - tp->TextWidth(bf), y - (tp->TextHeight(bf)/2), bf);
|
|||
|
|
}
|
|||
|
|
strcpy(bf, "dB");
|
|||
|
|
tp->TextOut(XL - 6 - tp->TextWidth(bf), YT-(tp->TextHeight(bf)/2), bf);
|
|||
|
|
for( i = 1; i <= DM; i++ ){
|
|||
|
|
tp->Pen->Style = (i % MM) ? psDot : psSolid;
|
|||
|
|
x = (int)(double(i) * double(XR - XL)/double(DM+1) + XL);
|
|||
|
|
tp->MoveTo(x, YT); tp->LineTo(x, YB);
|
|||
|
|
}
|
|||
|
|
for( i = 0; i <= LM; i++ ){
|
|||
|
|
x = (int)(double(i) * double(XR - XL)/double(LM) + XL);
|
|||
|
|
sprintf(bf, "%4.0lf", (max*i)/LM);
|
|||
|
|
::SetBkMode(tp->Handle, TRANSPARENT);
|
|||
|
|
tp->TextOut(x - (tp->TextWidth(bf)/2), YB + 6, bf);
|
|||
|
|
}
|
|||
|
|
tp->Pen->Color = clRed;
|
|||
|
|
tp->Pen->Style = psDot;
|
|||
|
|
x = (int)(XL + (fs/2) * (double(XR-XL)/max));
|
|||
|
|
tp->MoveTo(x, YT); tp->LineTo(x, YB);
|
|||
|
|
|
|||
|
|
tp->Pen->Color = clBlue;
|
|||
|
|
tp->Pen->Style = psSolid;
|
|||
|
|
}
|
|||
|
|
int ay = 0;
|
|||
|
|
pi2t = 2.0 * PI / fs;
|
|||
|
|
pi4t = 2.0 * pi2t;
|
|||
|
|
tp->Pen->Color = col;
|
|||
|
|
double A, B, C, D, P, R;
|
|||
|
|
double cosw, sinw, cos2w, sin2w;
|
|||
|
|
for( x = XL, f = 0.0; x < XR; x++, f += (max/double(XR-XL)) ){
|
|||
|
|
cosw = cos(pi2t*f);
|
|||
|
|
sinw = sin(pi2t*f);
|
|||
|
|
cos2w = cos(pi4t*f);
|
|||
|
|
sin2w = sin(pi4t*f);
|
|||
|
|
A = a0 + a1 * cosw + a2 * cos2w;
|
|||
|
|
B = 1 + b1 * cosw + b2 * cos2w;
|
|||
|
|
C = a1 * sinw + a2 * sin2w;
|
|||
|
|
D = b1 * sinw + b2 * sin2w;
|
|||
|
|
P = A*A + C*C;
|
|||
|
|
R = B*B + D*D;
|
|||
|
|
g = sqrt(P/R);
|
|||
|
|
if( g == 0 ) g = 1.0e-38;
|
|||
|
|
gdb = 20*0.4342944*log(fabs(g)) + 60.0;
|
|||
|
|
if( gdb < 0.0 ) gdb = 0.0;
|
|||
|
|
gdb = (gdb * double(YB-YT))/60.0;
|
|||
|
|
y = YB - (int)gdb;
|
|||
|
|
if( x == XL ){
|
|||
|
|
tp->MoveTo(x, y);
|
|||
|
|
tp->LineTo(x, y);
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
tp->MoveTo(x-1, ay);
|
|||
|
|
tp->LineTo(x, y);
|
|||
|
|
}
|
|||
|
|
ay = y;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//---------------------------------------------------------------------
|
|||
|
|
// <20><><EFBFBD>g<EFBFBD><67><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>O<EFBFBD><4F><EFBFBD>t<EFBFBD>i<EFBFBD>t<EFBFBD>B<EFBFBD><42><EFBFBD>^<5E>X<EFBFBD><58><EFBFBD>b<EFBFBD>h<EFBFBD><68><EFBFBD>ŃR<C583>[<5B><><EFBFBD><EFBFBD><EFBFBD>Ă͂<C482><CD82><EFBFBD><EFBFBD>Ȃ<EFBFBD><C882>j
|
|||
|
|
//
|
|||
|
|
//
|
|||
|
|
void __fastcall DrawGraphIIR(Graphics::TBitmap *pBitmap, CIIR *ip, int &nmax, int init, TColor col, double SampFreq)
|
|||
|
|
{
|
|||
|
|
int x, y;
|
|||
|
|
double f, gdb, g, pi2t, pi4t, fs;
|
|||
|
|
double max;
|
|||
|
|
char bf[80];
|
|||
|
|
|
|||
|
|
TCanvas *tp = pBitmap->Canvas;
|
|||
|
|
TRect rc;
|
|||
|
|
rc.Left = 0;
|
|||
|
|
rc.Right = pBitmap->Width;
|
|||
|
|
rc.Top = 0;
|
|||
|
|
rc.Bottom = pBitmap->Height;
|
|||
|
|
if( init ){
|
|||
|
|
tp->Brush->Color = clWhite;
|
|||
|
|
tp->FillRect(rc);
|
|||
|
|
}
|
|||
|
|
int LM; // <20><><EFBFBD>g<EFBFBD><67><EFBFBD>\<5C><><EFBFBD>̂<EFBFBD><CC82>郉<EFBFBD>C<EFBFBD><43><EFBFBD><EFBFBD>
|
|||
|
|
int DM; // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>̐<EFBFBD>
|
|||
|
|
int MM; // <20><><EFBFBD><EFBFBD><EFBFBD>̊Ԋu
|
|||
|
|
max = 4000;
|
|||
|
|
fs = SampFreq;
|
|||
|
|
if( nmax ){
|
|||
|
|
max = nmax;
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
nmax = max;
|
|||
|
|
}
|
|||
|
|
switch(nmax){
|
|||
|
|
case 3000:
|
|||
|
|
LM = 3;
|
|||
|
|
DM = 14;
|
|||
|
|
MM = 5;
|
|||
|
|
break;
|
|||
|
|
case 100:
|
|||
|
|
case 200:
|
|||
|
|
case 2000:
|
|||
|
|
LM = 4;
|
|||
|
|
DM = 19;
|
|||
|
|
MM = 5;
|
|||
|
|
break;
|
|||
|
|
case 400:
|
|||
|
|
case 800:
|
|||
|
|
case 4000:
|
|||
|
|
LM = 4;
|
|||
|
|
DM = 19;
|
|||
|
|
MM = 5;
|
|||
|
|
break;
|
|||
|
|
default: // 6000
|
|||
|
|
LM = 3;
|
|||
|
|
DM = 11;
|
|||
|
|
MM = 4;
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
int XL = 32;
|
|||
|
|
int XR = pBitmap->Width - 16;
|
|||
|
|
int YT = 16;
|
|||
|
|
int YB = pBitmap->Height - 24;
|
|||
|
|
|
|||
|
|
int i;
|
|||
|
|
if( init ){
|
|||
|
|
tp->Pen->Color = clBlack;
|
|||
|
|
tp->Font->Size = 8;
|
|||
|
|
tp->MoveTo(XL, YT); tp->LineTo(XR, YT); tp->LineTo(XR, YB); tp->LineTo(XL, YB); tp->LineTo(XL, YT);
|
|||
|
|
tp->Pen->Color = clGray;
|
|||
|
|
for( i = 0; i < 5; i++ ){
|
|||
|
|
tp->Pen->Style = (i & 1) ? psSolid : psDot;
|
|||
|
|
y = (int)(double(i + 1) * double(YB - YT)/6.0 + YT);
|
|||
|
|
tp->MoveTo(XL, y); tp->LineTo(XR, y);
|
|||
|
|
}
|
|||
|
|
for( i = 1; i < 4; i++ ){
|
|||
|
|
y = (int)(double(i) * double(YB - YT)/3.0 + YT);
|
|||
|
|
sprintf( bf, "-%2u", (60 / 3)*i );
|
|||
|
|
::SetBkMode(tp->Handle, TRANSPARENT);
|
|||
|
|
tp->TextOut(XL - 6 - tp->TextWidth(bf), y - (tp->TextHeight(bf)/2), bf);
|
|||
|
|
}
|
|||
|
|
strcpy(bf, "dB");
|
|||
|
|
tp->TextOut(XL - 6 - tp->TextWidth(bf), YT-(tp->TextHeight(bf)/2), bf);
|
|||
|
|
for( i = 1; i <= DM; i++ ){
|
|||
|
|
tp->Pen->Style = (i % MM) ? psDot : psSolid;
|
|||
|
|
x = (int)(double(i) * double(XR - XL)/double(DM+1) + XL);
|
|||
|
|
tp->MoveTo(x, YT); tp->LineTo(x, YB);
|
|||
|
|
}
|
|||
|
|
for( i = 0; i <= LM; i++ ){
|
|||
|
|
x = (int)(double(i) * double(XR - XL)/double(LM) + XL);
|
|||
|
|
sprintf(bf, "%4.0lf", (max*i)/LM);
|
|||
|
|
::SetBkMode(tp->Handle, TRANSPARENT);
|
|||
|
|
tp->TextOut(x - (tp->TextWidth(bf)/2), YB + 6, bf);
|
|||
|
|
}
|
|||
|
|
tp->Pen->Color = clRed;
|
|||
|
|
tp->Pen->Style = psDot;
|
|||
|
|
x = (int)(XL + (fs/2) * (double(XR-XL)/max));
|
|||
|
|
tp->MoveTo(x, YT); tp->LineTo(x, YB);
|
|||
|
|
|
|||
|
|
tp->Pen->Color = clBlue;
|
|||
|
|
tp->Pen->Style = psSolid;
|
|||
|
|
}
|
|||
|
|
int ay = 0;
|
|||
|
|
pi2t = 2.0 * PI / fs;
|
|||
|
|
pi4t = 2.0 * pi2t;
|
|||
|
|
tp->Pen->Color = col;
|
|||
|
|
double A, B, C, D, P, R;
|
|||
|
|
double cosw, sinw, cos2w, sin2w;
|
|||
|
|
for( x = XL, f = 0.0; x < XR; x++, f += (max/double(XR-XL)) ){
|
|||
|
|
cosw = cos(pi2t*f);
|
|||
|
|
sinw = sin(pi2t*f);
|
|||
|
|
cos2w = cos(pi4t*f);
|
|||
|
|
sin2w = sin(pi4t*f);
|
|||
|
|
g = 1.0;
|
|||
|
|
double *ap = ip->m_A;
|
|||
|
|
double *bp = ip->m_B;
|
|||
|
|
for( i = 0; i < ip->m_order/2; i++, ap += 2, bp += 3 ){
|
|||
|
|
/*
|
|||
|
|
A = a0 + a1 * cosw + a2 * cos2w;
|
|||
|
|
B = 1 + b1 * cosw + b2 * cos2w;
|
|||
|
|
C = a1 * sinw + a2 * sin2w;
|
|||
|
|
D = b1 * sinw + b2 * sin2w;
|
|||
|
|
*/
|
|||
|
|
A = bp[0] + bp[1] * cosw + bp[2] * cos2w;
|
|||
|
|
B = 1 + -ap[0] * cosw + -ap[1] * cos2w;
|
|||
|
|
C = bp[1] * sinw + bp[2] * sin2w;
|
|||
|
|
D = -ap[0] * sinw + -ap[1] * sin2w;
|
|||
|
|
P = A*A + C*C;
|
|||
|
|
R = B*B + D*D;
|
|||
|
|
g *= sqrt(P/R);
|
|||
|
|
}
|
|||
|
|
if( ip->m_order & 1 ){
|
|||
|
|
A = bp[0] + bp[1] * cosw;
|
|||
|
|
B = 1 + -ap[0] * cosw;
|
|||
|
|
C = bp[1] * sinw;
|
|||
|
|
D = -ap[0] * sinw;
|
|||
|
|
P = A*A + C*C;
|
|||
|
|
R = B*B + D*D;
|
|||
|
|
g *= sqrt(P/R);
|
|||
|
|
}
|
|||
|
|
if( g == 0 ) g = 1.0e-38;
|
|||
|
|
gdb = 20*0.4342944*log(fabs(g)) + 60.0;
|
|||
|
|
if( gdb < 0.0 ) gdb = 0.0;
|
|||
|
|
gdb = (gdb * double(YB-YT))/60.0;
|
|||
|
|
y = YB - (int)gdb;
|
|||
|
|
if( x == XL ){
|
|||
|
|
tp->MoveTo(x, y);
|
|||
|
|
tp->LineTo(x, y);
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
tp->MoveTo(x-1, ay);
|
|||
|
|
tp->LineTo(x, y);
|
|||
|
|
}
|
|||
|
|
ay = y;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
// CSinTable<6C>N<EFBFBD><4E><EFBFBD>X
|
|||
|
|
__fastcall CSinTable::CSinTable()
|
|||
|
|
{
|
|||
|
|
m_Size = 48000;
|
|||
|
|
m_tSin = new double[m_Size];
|
|||
|
|
double pi2t = 2 * PI / double(m_Size);
|
|||
|
|
for( int i = 0; i < m_Size; i++ ){
|
|||
|
|
m_tSin[i] = sin(double(i) * pi2t);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
__fastcall CSinTable::~CSinTable()
|
|||
|
|
{
|
|||
|
|
delete m_tSin;
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
// VCO<43>N<EFBFBD><4E><EFBFBD>X
|
|||
|
|
__fastcall CVCO::CVCO()
|
|||
|
|
{
|
|||
|
|
m_SampleFreq = SAMPFREQ;
|
|||
|
|
m_FreeFreq = 2000.0;
|
|||
|
|
m_TableSize = g_SinTable.m_Size;
|
|||
|
|
m_TableCOS = m_TableSize / 4;
|
|||
|
|
m_c1 = 0.0;
|
|||
|
|
m_c2 = double(m_TableSize) * m_FreeFreq / m_SampleFreq;
|
|||
|
|
m_z = 0.0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
__fastcall CVCO::~CVCO()
|
|||
|
|
{
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void __fastcall CVCO::SetGain(double gain)
|
|||
|
|
{
|
|||
|
|
m_c1 = double(m_TableSize) * gain / m_SampleFreq;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void __fastcall CVCO::SetSampleFreq(double f)
|
|||
|
|
{
|
|||
|
|
m_SampleFreq = f;
|
|||
|
|
SetFreeFreq(m_FreeFreq);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void __fastcall CVCO::SetFreeFreq(double f)
|
|||
|
|
{
|
|||
|
|
m_FreeFreq = f;
|
|||
|
|
m_c2 = double(m_TableSize) * m_FreeFreq / m_SampleFreq;
|
|||
|
|
if( f < 1.0 ) m_z = 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void __fastcall CVCO::InitPhase(void)
|
|||
|
|
{
|
|||
|
|
m_z = 0.0;
|
|||
|
|
}
|
|||
|
|
//------------------------------------------------------------------
|
|||
|
|
double __fastcall CVCO::Do(void)
|
|||
|
|
{
|
|||
|
|
m_z += m_c2;
|
|||
|
|
if( m_z >= m_TableSize ){
|
|||
|
|
m_z -= m_TableSize;
|
|||
|
|
}
|
|||
|
|
if( m_z < 0 ){
|
|||
|
|
m_z += m_TableSize;
|
|||
|
|
}
|
|||
|
|
return g_SinTable.m_tSin[int(m_z)];
|
|||
|
|
}
|
|||
|
|
//------------------------------------------------------------------
|
|||
|
|
double __fastcall CVCO::Do(double d)
|
|||
|
|
{
|
|||
|
|
#if DEBUG
|
|||
|
|
if( ABS(d) >= 2.0 ) Application->MainForm->Caption = "VCO over range";
|
|||
|
|
#endif
|
|||
|
|
// -1 to 1
|
|||
|
|
m_z += (d * m_c1 + m_c2);
|
|||
|
|
while( m_z >= m_TableSize ){
|
|||
|
|
m_z -= m_TableSize;
|
|||
|
|
}
|
|||
|
|
while( m_z < 0 ){
|
|||
|
|
m_z += m_TableSize;
|
|||
|
|
}
|
|||
|
|
return g_SinTable.m_tSin[int(m_z)];
|
|||
|
|
}
|
|||
|
|
//------------------------------------------------------------------
|
|||
|
|
double __fastcall CVCO::DoCos(void)
|
|||
|
|
{
|
|||
|
|
double z = m_z + m_TableCOS;
|
|||
|
|
if(z >= m_TableSize ) z -= m_TableSize;
|
|||
|
|
return g_SinTable.m_tSin[int(z)];
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//------------------------------------------------------------------
|
|||
|
|
static double __fastcall asinh(double x)
|
|||
|
|
{
|
|||
|
|
return log(x + sqrt(x*x+1.0));
|
|||
|
|
}
|
|||
|
|
//------------------------------------------------------------------
|
|||
|
|
// bc : 0-<2D>o<EFBFBD>^<5E>[<5B><><EFBFBD>[<5B>X, 1-<2D>`<60>F<EFBFBD>r<EFBFBD>V<EFBFBD>t
|
|||
|
|
// rp : <20>ʉ߈<CA89><DF88>̃<EFBFBD><CC83>b<EFBFBD>v<EFBFBD><76>
|
|||
|
|
void __fastcall MakeIIR(int type, double *A, double *B, double fc, double fs, int order, int bc, double rp)
|
|||
|
|
{
|
|||
|
|
double w0, wa, u, zt, x;
|
|||
|
|
int j, n;
|
|||
|
|
|
|||
|
|
if( bc ){ // <20>`<60>F<EFBFBD>r<EFBFBD>V<EFBFBD>t
|
|||
|
|
u = 1.0/double(order) * asinh(1.0/sqrt(pow(10.0,0.1*rp)-1.0));
|
|||
|
|
}
|
|||
|
|
wa = tan(PI*fc/fs);
|
|||
|
|
w0 = 1.0;
|
|||
|
|
n = (order & 1) + 1;
|
|||
|
|
double *pA = A;
|
|||
|
|
double *pB = B;
|
|||
|
|
double s, d, d1, d2;
|
|||
|
|
for( j = 1; j <= order/2; j++, pA+=2, pB+=3 ){
|
|||
|
|
if( bc ){ // <20>`<60>F<EFBFBD>r<EFBFBD>V<EFBFBD>t
|
|||
|
|
d1 = sinh(u)*cos(n*PI/(2*order));
|
|||
|
|
d2 = cosh(u)*sin(n*PI/(2*order));
|
|||
|
|
w0 = sqrt(d1 * d1 + d2 * d2);
|
|||
|
|
zt = sinh(u)*cos(n*PI/(2*order))/w0;
|
|||
|
|
}
|
|||
|
|
else { // <20>o<EFBFBD>^<5E>[<5B><><EFBFBD>[<5B>X
|
|||
|
|
w0 = 1.0;
|
|||
|
|
zt = cos(n*PI/(2*order));
|
|||
|
|
}
|
|||
|
|
switch(type){
|
|||
|
|
case ffLPF:
|
|||
|
|
s = wa * w0;
|
|||
|
|
d = 1 + s*2*zt + s*s;
|
|||
|
|
pA[0] = -2 * (s*s - 1)/d;
|
|||
|
|
pA[1] = -(1.0 - s*2*zt + s*s)/d;
|
|||
|
|
pB[0] = s*s / d;
|
|||
|
|
pB[1] = 2*pB[0];
|
|||
|
|
pB[2] = pB[0];
|
|||
|
|
break;
|
|||
|
|
case ffHPF:
|
|||
|
|
s = wa / w0;
|
|||
|
|
d = 1 + s*2*zt + s*s;
|
|||
|
|
pA[0] = -2 * (s*s - 1)/d;
|
|||
|
|
pA[1] = -(1.0 - s*2*zt + s*s)/d;
|
|||
|
|
pB[0] = 1.0 / d;
|
|||
|
|
pB[1] = -2*pB[0];
|
|||
|
|
pB[2] = pB[0];
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
n += 2;
|
|||
|
|
}
|
|||
|
|
if( bc && !(order & 1) ){
|
|||
|
|
x = pow( 1.0/pow(10.0,rp/20.0), 1.0/double(order/2) );
|
|||
|
|
pB = B;
|
|||
|
|
for( j = 1; j <= order/2; j++, pB+=3 ){
|
|||
|
|
pB[0] *= x;
|
|||
|
|
pB[1] *= x;
|
|||
|
|
pB[2] *= x;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
if( order & 1 ){
|
|||
|
|
if( bc ) w0 = sinh(u);
|
|||
|
|
j = (order / 2);
|
|||
|
|
pA = A + (j*2);
|
|||
|
|
pB = B + (j*3);
|
|||
|
|
switch(type){
|
|||
|
|
case ffLPF:
|
|||
|
|
s = wa * w0;
|
|||
|
|
d = 1 + s;
|
|||
|
|
pA[0] = -(s - 1)/d;
|
|||
|
|
pB[0] = wa*w0/d;
|
|||
|
|
pB[1] = pB[0];
|
|||
|
|
break;
|
|||
|
|
case ffHPF:
|
|||
|
|
s = wa / w0;
|
|||
|
|
d = 1 + s;
|
|||
|
|
pA[0] = -(s - 1)/d;
|
|||
|
|
pB[0] = 1.0/d;
|
|||
|
|
pB[1] = -pB[0];
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
__fastcall CIIR::CIIR()
|
|||
|
|
{
|
|||
|
|
m_order = 0;
|
|||
|
|
memset(m_A, 0, sizeof(m_A));
|
|||
|
|
memset(m_B, 0, sizeof(m_B));
|
|||
|
|
memset(m_Z, 0, sizeof(m_Z));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
__fastcall CIIR::~CIIR()
|
|||
|
|
{
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void __fastcall CIIR::Clear(void)
|
|||
|
|
{
|
|||
|
|
memset(m_Z, 0, sizeof(m_Z));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void __fastcall CIIR::Create(int type, double fc, double fs, int order, int bc, double rp)
|
|||
|
|
{
|
|||
|
|
#if DEBUG
|
|||
|
|
if( order > IIRMAX ){
|
|||
|
|
Application->MainForm->Caption = "Over tap in CIIR";
|
|||
|
|
order = IIRMAX;
|
|||
|
|
}
|
|||
|
|
#endif
|
|||
|
|
m_bc = bc;
|
|||
|
|
m_rp = rp;
|
|||
|
|
m_order = order;
|
|||
|
|
m_orderH = order/2;
|
|||
|
|
::MakeIIR(type, m_A, m_B, fc, fs, order, bc, rp);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
double __fastcall CIIR::Do(double d)
|
|||
|
|
{
|
|||
|
|
double *pA = m_A;
|
|||
|
|
double *pB = m_B;
|
|||
|
|
double *pZ = m_Z;
|
|||
|
|
double o;
|
|||
|
|
for( int i = 0; i < m_orderH; i++, pA+=2, pB+=3, pZ+=2 ){
|
|||
|
|
d += pZ[0] * pA[0] + pZ[1] * pA[1];
|
|||
|
|
o = d * pB[0] + pZ[0] * pB[1] + pZ[1] * pB[2];
|
|||
|
|
pZ[1] = pZ[0];
|
|||
|
|
if( d < 0 ){
|
|||
|
|
if( d > -IIRVLIMIT ) d = 0.0;
|
|||
|
|
}
|
|||
|
|
else if( d < IIRVLIMIT ){
|
|||
|
|
d = 0.0;
|
|||
|
|
}
|
|||
|
|
pZ[0] = d;
|
|||
|
|
d = o;
|
|||
|
|
}
|
|||
|
|
if( m_order & 1 ){
|
|||
|
|
d += pZ[0] * pA[0];
|
|||
|
|
o = d * pB[0] + pZ[0] * pB[1];
|
|||
|
|
if( d < 0 ){
|
|||
|
|
if( d > -IIRVLIMIT ) d = 0.0;
|
|||
|
|
}
|
|||
|
|
else if( d < IIRVLIMIT ){
|
|||
|
|
d = 0.0;
|
|||
|
|
}
|
|||
|
|
pZ[0] = d;
|
|||
|
|
d = o;
|
|||
|
|
}
|
|||
|
|
return d;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
__fastcall CIIRTANK::CIIRTANK()
|
|||
|
|
{
|
|||
|
|
b1 = b2 = a0 = z1 = z2 = 0;
|
|||
|
|
m_SampleFreq = SAMPFREQ;
|
|||
|
|
m_Freq = CARRIERFREQ;
|
|||
|
|
m_BW = 100;
|
|||
|
|
Create();
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
void __fastcall CIIRTANK::Create(void)
|
|||
|
|
{
|
|||
|
|
SetFreq(m_Freq, m_SampleFreq, m_BW);
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
void __fastcall CIIRTANK::SetFreq(double f, double smp, double bw)
|
|||
|
|
{
|
|||
|
|
double lb1, lb2, la0;
|
|||
|
|
lb1 = 2 * exp(-PI * bw/smp) * cos(2 * PI * f / smp);
|
|||
|
|
lb2 = -exp(-2*PI*bw/smp);
|
|||
|
|
if( bw ){
|
|||
|
|
la0 = sin(2 * PI * f/smp) / ((smp/(PI*2.0)) / bw);
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
la0 = sin(2 * PI * f/smp);
|
|||
|
|
}
|
|||
|
|
b1 = lb1; b2 = lb2; a0 = la0;
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
double __fastcall CIIRTANK::Do(double d)
|
|||
|
|
{
|
|||
|
|
d *= a0;
|
|||
|
|
d += (z1 * b1);
|
|||
|
|
d += (z2 * b2);
|
|||
|
|
z2 = z1;
|
|||
|
|
if( d < 0 ){
|
|||
|
|
if( d > -IIRVLIMIT ) d = 0.0;
|
|||
|
|
}
|
|||
|
|
else if( d < IIRVLIMIT ){
|
|||
|
|
d = 0.0;
|
|||
|
|
}
|
|||
|
|
z1 = d;
|
|||
|
|
return d;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
__fastcall CIIRTANK2::CIIRTANK2()
|
|||
|
|
{
|
|||
|
|
m_SampleFreq = SAMPFREQ;
|
|||
|
|
m_Freq = CARRIERFREQ;
|
|||
|
|
m_BW = 100;
|
|||
|
|
Create();
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
void __fastcall CIIRTANK2::SetSampleFreq(double f)
|
|||
|
|
{
|
|||
|
|
m_SampleFreq = f;
|
|||
|
|
Create();
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
void __fastcall CIIRTANK2::Create(void)
|
|||
|
|
{
|
|||
|
|
m_Tank1.m_SampleFreq = m_SampleFreq;
|
|||
|
|
m_Tank1.m_Freq = m_Freq;
|
|||
|
|
m_Tank1.m_BW = m_BW;
|
|||
|
|
m_Tank2.m_SampleFreq = m_SampleFreq;
|
|||
|
|
m_Tank2.m_Freq = m_Freq;
|
|||
|
|
m_Tank2.m_BW = m_BW;
|
|||
|
|
m_Tank1.Create();
|
|||
|
|
m_Tank2.Create();
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
double __fastcall CIIRTANK2::Do(double d)
|
|||
|
|
{
|
|||
|
|
return m_Tank1.Do(m_Tank2.Do(d));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
// CFIR<49>N<EFBFBD><4E><EFBFBD>X
|
|||
|
|
__fastcall CFIR::CFIR()
|
|||
|
|
{
|
|||
|
|
m_pZ = NULL;
|
|||
|
|
m_pH = NULL;
|
|||
|
|
m_Tap = 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
__fastcall CFIR::~CFIR()
|
|||
|
|
{
|
|||
|
|
if( m_pZ ) delete m_pZ;
|
|||
|
|
if( m_pH ) delete m_pH;
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
void __fastcall CFIR::Create(int tap, int type, double fs, double fcl, double fch, double att, double gain)
|
|||
|
|
{
|
|||
|
|
m_Tap = tap;
|
|||
|
|
if( m_pZ ) delete m_pZ;
|
|||
|
|
if( m_pH ) delete m_pH;
|
|||
|
|
m_pZ = new double[tap+1];
|
|||
|
|
m_pH = new double[tap+1];
|
|||
|
|
memset(m_pZ, 0, sizeof(double)*(tap+1));
|
|||
|
|
::MakeFilter(m_pH, tap, type, fs, fcl, fch, att, gain);
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
double __fastcall CFIR::Do(double d)
|
|||
|
|
{
|
|||
|
|
return DoFIR(m_pH, m_pZ, d, m_Tap);
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
void __fastcall CFIR::SaveCoef(LPCSTR pName)
|
|||
|
|
{
|
|||
|
|
FILE *fp;
|
|||
|
|
if( (fp = fopen(pName, "wt")) != NULL ){
|
|||
|
|
int i;
|
|||
|
|
for( i = 0; i <= m_Tap; i++ ){
|
|||
|
|
fprintf(fp, "H[%u]=%lf\n", i, m_pH[i]);
|
|||
|
|
}
|
|||
|
|
fclose(fp);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
// CFIR2<52>N<EFBFBD><4E><EFBFBD>X
|
|||
|
|
__fastcall CFIR2::CFIR2()
|
|||
|
|
{
|
|||
|
|
m_pZ = NULL;
|
|||
|
|
m_pH = NULL;
|
|||
|
|
m_pZP = NULL;
|
|||
|
|
m_W = 0;
|
|||
|
|
m_Tap = 0;
|
|||
|
|
m_fs = 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
__fastcall CFIR2::~CFIR2()
|
|||
|
|
{
|
|||
|
|
if( m_pZ ) delete m_pZ;
|
|||
|
|
if( m_pH ) delete m_pH;
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
void __fastcall CFIR2::Delete(void)
|
|||
|
|
{
|
|||
|
|
if( m_pZ ) delete m_pZ;
|
|||
|
|
if( m_pH ) delete m_pH;
|
|||
|
|
m_pZ = NULL;
|
|||
|
|
m_pH = NULL;
|
|||
|
|
m_pZP = NULL;
|
|||
|
|
m_W = 0;
|
|||
|
|
m_Tap = 0;
|
|||
|
|
m_fs = 0;
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
void __fastcall CFIR2::Create(int tap, int type, double fs, double fcl, double fch, double att, double gain)
|
|||
|
|
{
|
|||
|
|
if( (m_Tap != tap) || !m_pZ || !m_pH ){
|
|||
|
|
if( m_pZ ) delete m_pZ;
|
|||
|
|
m_pZ = new double[(tap+1)*2];
|
|||
|
|
memset(m_pZ, 0, sizeof(double)*(tap+1)*2);
|
|||
|
|
if( m_pH ) delete m_pH;
|
|||
|
|
m_pH = new double[tap+1];
|
|||
|
|
m_W = 0;
|
|||
|
|
}
|
|||
|
|
m_Tap = tap;
|
|||
|
|
m_TapHalf = tap/2;
|
|||
|
|
m_fs = fs;
|
|||
|
|
::MakeFilter(m_pH, tap, type, fs, fcl, fch, att, gain);
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
void __fastcall CFIR2::Create(int tap, double fs, double fcl, double fch)
|
|||
|
|
{
|
|||
|
|
if( (m_Tap != tap) || !m_pZ || !m_pH ){
|
|||
|
|
if( m_pZ ) delete m_pZ;
|
|||
|
|
m_pZ = new double[(tap+1)*2];
|
|||
|
|
memset(m_pZ, 0, sizeof(double)*(tap+1)*2);
|
|||
|
|
if( m_pH ) delete m_pH;
|
|||
|
|
m_pH = new double[tap+1];
|
|||
|
|
m_W = 0;
|
|||
|
|
}
|
|||
|
|
m_Tap = tap;
|
|||
|
|
m_TapHalf = tap/2;
|
|||
|
|
m_fs = fs;
|
|||
|
|
::MakeHilbert(m_pH, tap, fs, fcl, fch);
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
void __fastcall CFIR2::CreateSamp(int tap, double fs, const double *pSmpFQ)
|
|||
|
|
{
|
|||
|
|
if( (m_Tap != tap) || !m_pZ || !m_pH ){
|
|||
|
|
if( m_pZ ) delete m_pZ;
|
|||
|
|
m_pZ = new double[(tap+1)*2];
|
|||
|
|
memset(m_pZ, 0, sizeof(double)*(tap+1)*2);
|
|||
|
|
if( m_pH ) delete m_pH;
|
|||
|
|
m_pH = new double[tap+1];
|
|||
|
|
m_W = 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
int htap = tap/2;
|
|||
|
|
int i, j;
|
|||
|
|
double *pSamp = new double[tap+1];
|
|||
|
|
memcpy(pSamp, pSmpFQ, sizeof(double)*(tap/2));
|
|||
|
|
for( i = 0; i < tap/2; i++ ){
|
|||
|
|
pSamp[tap-i] = pSamp[i];
|
|||
|
|
}
|
|||
|
|
pSamp[tap/2] = pSamp[tap/2 - 1];
|
|||
|
|
double *pH = new double[tap+1];
|
|||
|
|
double re, fm;
|
|||
|
|
|
|||
|
|
for( i = 0; i <= htap; i++ ){
|
|||
|
|
re = 0.0;
|
|||
|
|
for( j = 0; j < tap; j++ ){
|
|||
|
|
fm = 2.0 * PI * double((i*j)%tap)/double(tap);
|
|||
|
|
re += pSamp[j] * cos(fm);
|
|||
|
|
}
|
|||
|
|
pH[i] = re / tap;
|
|||
|
|
}
|
|||
|
|
#if 0
|
|||
|
|
fm = 0;
|
|||
|
|
for( i = 0; i <= htap; i++ ){
|
|||
|
|
fm += pH[i];
|
|||
|
|
}
|
|||
|
|
fm = 0.5 / fm;
|
|||
|
|
for( i = 0; i <= htap; i++ ){
|
|||
|
|
pH[i] *= fm;
|
|||
|
|
}
|
|||
|
|
#endif
|
|||
|
|
for( i = 0; i <= htap; i++ ) m_pH[htap-i] = pH[i];
|
|||
|
|
for( i = 0; i < htap; i++ ) m_pH[tap-i] = m_pH[i];
|
|||
|
|
delete pH;
|
|||
|
|
delete pSamp;
|
|||
|
|
|
|||
|
|
m_Tap = tap;
|
|||
|
|
m_TapHalf = htap;
|
|||
|
|
m_fs = fs;
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
void __fastcall CFIR2::Clear(void)
|
|||
|
|
{
|
|||
|
|
if( m_pZ ) memset(m_pZ, 0, sizeof(double)*(m_Tap+1)*2);
|
|||
|
|
m_W = 0;
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
double __fastcall CFIR2::Do(double d)
|
|||
|
|
{
|
|||
|
|
double *dp1 = &m_pZ[m_W+m_Tap+1];
|
|||
|
|
m_pZP = dp1;
|
|||
|
|
*dp1 = d;
|
|||
|
|
m_pZ[m_W] = d;
|
|||
|
|
d = 0;
|
|||
|
|
double *hp = m_pH;
|
|||
|
|
for( int i = 0; i <= m_Tap; i++ ){
|
|||
|
|
d += (*dp1--) * (*hp++);
|
|||
|
|
}
|
|||
|
|
m_W++;
|
|||
|
|
if( m_W > m_Tap ) m_W = 0;
|
|||
|
|
return d;
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
double __fastcall CFIR2::Do(double *hp)
|
|||
|
|
{
|
|||
|
|
double d = 0;
|
|||
|
|
double *dp = m_pZP;
|
|||
|
|
for( int i = 0; i <= m_Tap; i++ ){
|
|||
|
|
d += (*dp--) * (*hp++);
|
|||
|
|
}
|
|||
|
|
return d;
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
void __fastcall CFIR2::Do(CLX &z, double d)
|
|||
|
|
{
|
|||
|
|
double *dp1 = &m_pZ[m_W+m_Tap+1];
|
|||
|
|
m_pZP = dp1;
|
|||
|
|
*dp1 = d;
|
|||
|
|
m_pZ[m_W] = d;
|
|||
|
|
d = 0;
|
|||
|
|
double *hp = m_pH;
|
|||
|
|
for( int i = 0; i <= m_Tap; i++ ){
|
|||
|
|
d += (*dp1--) * (*hp++);
|
|||
|
|
}
|
|||
|
|
z.j = d;
|
|||
|
|
z.r = m_pZ[m_W+m_TapHalf+1];
|
|||
|
|
m_W++;
|
|||
|
|
if( m_W > m_Tap ) m_W = 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
// CFIRX<52>N<EFBFBD><4E><EFBFBD>X
|
|||
|
|
__fastcall CFIRX::CFIRX()
|
|||
|
|
{
|
|||
|
|
m_pZ = NULL;
|
|||
|
|
m_pH = NULL;
|
|||
|
|
m_pZP = NULL;
|
|||
|
|
m_W = 0;
|
|||
|
|
m_Tap = 0;
|
|||
|
|
m_fs = 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
__fastcall CFIRX::~CFIRX()
|
|||
|
|
{
|
|||
|
|
if( m_pZ ) delete m_pZ;
|
|||
|
|
if( m_pH ) delete m_pH;
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
void __fastcall CFIRX::Create(int tap, int type, double fs, double fcl, double fch, double att, double gain)
|
|||
|
|
{
|
|||
|
|
if( (m_Tap != tap) || !m_pZ || !m_pH ){
|
|||
|
|
if( m_pZ ) delete m_pZ;
|
|||
|
|
m_pZ = new CLX[(tap+1)*2];
|
|||
|
|
memset(m_pZ, 0, sizeof(CLX)*(tap+1)*2);
|
|||
|
|
if( m_pH ) delete m_pH;
|
|||
|
|
m_pH = new double[tap+1];
|
|||
|
|
m_W = 0;
|
|||
|
|
}
|
|||
|
|
m_Tap = tap;
|
|||
|
|
m_TapHalf = tap/2;
|
|||
|
|
m_fs = fs;
|
|||
|
|
::MakeFilter(m_pH, tap, type, fs, fcl, fch, att, gain);
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
void __fastcall CFIRX::CreateSamp(int tap, double fs, const double *pSmpFQ, int wDB)
|
|||
|
|
{
|
|||
|
|
if( (m_Tap != tap) || !m_pZ || !m_pH ){
|
|||
|
|
if( m_pZ ) delete m_pZ;
|
|||
|
|
m_pZ = new CLX[(tap+1)*2];
|
|||
|
|
memset(m_pZ, 0, sizeof(CLX)*(tap+1)*2);
|
|||
|
|
if( m_pH ) delete m_pH;
|
|||
|
|
m_pH = new double[tap+1];
|
|||
|
|
m_W = 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
int htap = tap/2;
|
|||
|
|
int i, j;
|
|||
|
|
double *pSamp = new double[tap+1];
|
|||
|
|
memcpy(pSamp, pSmpFQ, sizeof(double)*(tap/2));
|
|||
|
|
double maxAmp = 0;
|
|||
|
|
double *dp = pSamp;
|
|||
|
|
for( i = 0; i < tap/2; i++, dp++ ){
|
|||
|
|
pSamp[tap-i] = *dp;
|
|||
|
|
if( maxAmp < *dp ) maxAmp = *dp;
|
|||
|
|
}
|
|||
|
|
pSamp[tap/2] = pSamp[tap/2 - 1];
|
|||
|
|
double *pH = new double[tap+1];
|
|||
|
|
double re, fm;
|
|||
|
|
|
|||
|
|
for( i = 0; i <= htap; i++ ){
|
|||
|
|
re = 0.0;
|
|||
|
|
dp = pSamp;
|
|||
|
|
for( j = 0; j < tap; j++ ){
|
|||
|
|
fm = 2.0 * PI * double((i*j)%tap)/double(tap);
|
|||
|
|
re += (*dp++) * cos(fm);
|
|||
|
|
}
|
|||
|
|
pH[i] = re / tap;
|
|||
|
|
}
|
|||
|
|
if( wDB >= 21 ){
|
|||
|
|
double alpha, att;
|
|||
|
|
att = double(wDB);
|
|||
|
|
if( att >= 50.0 ){
|
|||
|
|
alpha = 0.1102 * (att - 8.7);
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
alpha = (0.5842*pow(att - 21.0, 0.4)) + (0.07886 * (att - 21.0));
|
|||
|
|
}
|
|||
|
|
dp = pH;
|
|||
|
|
for( i = 0; i <= htap; i++, dp++ ){
|
|||
|
|
double fm = double(2 * i)/double(tap);
|
|||
|
|
double win = I0(alpha * sqrt(1.0-(fm*fm)))/I0(alpha);
|
|||
|
|
*dp *= win;
|
|||
|
|
}
|
|||
|
|
fm = 0.000001;
|
|||
|
|
double f = 0.0;
|
|||
|
|
double g;
|
|||
|
|
double pi2t = 2.0 * PI / fs;
|
|||
|
|
int i, k;
|
|||
|
|
double fk = fs * 0.5 / tap;
|
|||
|
|
for( i = 0; i < tap; i++, f += fk ){
|
|||
|
|
g = pH[0];
|
|||
|
|
for( k = 1; k <= htap; k++ ){
|
|||
|
|
g += 2.0 * pH[k] * cos(pi2t*f*double(k));
|
|||
|
|
}
|
|||
|
|
if( fm < g ) fm = g;
|
|||
|
|
}
|
|||
|
|
fm = maxAmp / fm;
|
|||
|
|
dp = pH;
|
|||
|
|
for( i = 0; i <= htap; i++, dp++ ){
|
|||
|
|
*dp *= fm;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
for( i = 0; i <= htap; i++ ) m_pH[htap-i] = pH[i];
|
|||
|
|
for( i = 0; i < htap; i++ ) m_pH[tap-i] = m_pH[i];
|
|||
|
|
delete pH;
|
|||
|
|
delete pSamp;
|
|||
|
|
|
|||
|
|
m_Tap = tap;
|
|||
|
|
m_TapHalf = htap;
|
|||
|
|
m_fs = fs;
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
void __fastcall CFIRX::Clear(void)
|
|||
|
|
{
|
|||
|
|
if( m_pZ ) memset(m_pZ, 0, sizeof(CLX)*(m_Tap+1)*2);
|
|||
|
|
m_W = 0;
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
void __fastcall CFIRX::Do(CLX &d)
|
|||
|
|
{
|
|||
|
|
CLX *dp1 = &m_pZ[m_W+m_Tap+1];
|
|||
|
|
m_pZP = dp1;
|
|||
|
|
*dp1 = d;
|
|||
|
|
m_pZ[m_W] = d;
|
|||
|
|
CLX z = 0;
|
|||
|
|
double *hp = m_pH;
|
|||
|
|
for( int i = 0; i <= m_Tap; i++, dp1-- ){
|
|||
|
|
z.r += dp1->r * (*hp);
|
|||
|
|
z.j += dp1->j * (*hp++);
|
|||
|
|
}
|
|||
|
|
m_W++;
|
|||
|
|
if( m_W > m_Tap ) m_W = 0;
|
|||
|
|
d = z;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
/*=============================================================================
|
|||
|
|
CSlideFFT<EFBFBD>N<EFBFBD><EFBFBD><EFBFBD>X <EFBFBD>X<EFBFBD><EFBFBD><EFBFBD>C<EFBFBD>f<EFBFBD>B<EFBFBD><EFBFBD><EFBFBD>O<EFBFBD>@FFT
|
|||
|
|
=============================================================================*/
|
|||
|
|
#define SLIDE_WINDOW_COEFF 0.9999
|
|||
|
|
__fastcall CSlideFFT::CSlideFFT(void)
|
|||
|
|
{
|
|||
|
|
m_Length = 0;
|
|||
|
|
m_Base = 0;
|
|||
|
|
m_Tones = 0;
|
|||
|
|
m_kWindow = 0;
|
|||
|
|
m_pBase = NULL;
|
|||
|
|
m_pCur = m_pEnd = NULL;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//--------------------------------------------------------------------------
|
|||
|
|
__fastcall CSlideFFT::~CSlideFFT()
|
|||
|
|
{
|
|||
|
|
if( m_pBase ) delete m_pBase;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//--------------------------------------------------------------------------
|
|||
|
|
void __fastcall CSlideFFT::Create(int len, int base, int tones)
|
|||
|
|
{
|
|||
|
|
if( !m_pBase || (len != m_Length) ){
|
|||
|
|
if( m_pBase ) delete m_pBase;
|
|||
|
|
m_pBase = new CLX[len];
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#if DEBUG
|
|||
|
|
if( tones > MFSK_MAXTONES ){
|
|||
|
|
Application->MainForm->Caption = "Tones overflow in CSlideFFT";
|
|||
|
|
tones = MFSK_MAXTONES;
|
|||
|
|
}
|
|||
|
|
#endif
|
|||
|
|
|
|||
|
|
memset(m_pBase, 0, sizeof(CLX)*len);
|
|||
|
|
memset(m_tWindow, 0, sizeof(m_tWindow));
|
|||
|
|
memset(m_tData, 0, sizeof(m_tData));
|
|||
|
|
|
|||
|
|
m_Length = len;
|
|||
|
|
m_Base = base;
|
|||
|
|
m_Tones = tones;
|
|||
|
|
|
|||
|
|
double k = 2.0 * PI / double(len);
|
|||
|
|
for(int i = 0; i < tones; i++){
|
|||
|
|
m_tWindow[i].r = cos((i+base) * k) * SLIDE_WINDOW_COEFF;
|
|||
|
|
m_tWindow[i].j = sin((i+base) * k) * SLIDE_WINDOW_COEFF;
|
|||
|
|
}
|
|||
|
|
m_kWindow = pow(SLIDE_WINDOW_COEFF, len);
|
|||
|
|
m_pCur = m_pBase;
|
|||
|
|
m_pEnd = &m_pBase[m_Length];
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//--------------------------------------------------------------------------
|
|||
|
|
CLX* __fastcall CSlideFFT::Do(const CLX &zIn)
|
|||
|
|
{
|
|||
|
|
CLX z;
|
|||
|
|
|
|||
|
|
if( m_pCur >= m_pEnd ) m_pCur = m_pBase;
|
|||
|
|
z = *m_pCur;
|
|||
|
|
*m_pCur = zIn;
|
|||
|
|
m_pCur++;
|
|||
|
|
z *= m_kWindow;
|
|||
|
|
|
|||
|
|
CLX *pData = m_tData;
|
|||
|
|
CLX *pWindow = m_tWindow;
|
|||
|
|
for( int i = 0; i < m_Tones; i++, pData++ ){
|
|||
|
|
*pData -= z;
|
|||
|
|
*pData += zIn;
|
|||
|
|
*pData *= *pWindow++;
|
|||
|
|
}
|
|||
|
|
return m_tData;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#if DEBUG
|
|||
|
|
//--------------------------------------------------------
|
|||
|
|
// CQSB<53>N<EFBFBD><4E><EFBFBD>X
|
|||
|
|
__fastcall CQSB::CQSB()
|
|||
|
|
{
|
|||
|
|
m_vMin = 16384/32;
|
|||
|
|
m_vMax = 16384/4;
|
|||
|
|
m_fPhaseError = FALSE;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
__fastcall CQSB::~CQSB()
|
|||
|
|
{
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void __fastcall CQSB::Create(int min, int max, int msec, BOOL perr)
|
|||
|
|
{
|
|||
|
|
m_vMin = min;
|
|||
|
|
m_vMax = max;
|
|||
|
|
|
|||
|
|
m_VCO.SetSampleFreq(SAMPFREQ);
|
|||
|
|
m_VCO.SetFreeFreq(1000.0 / double(msec));
|
|||
|
|
m_VCOP.SetSampleFreq(SAMPFREQ);
|
|||
|
|
m_VCOP.SetFreeFreq(1000.0 / 10000.0);
|
|||
|
|
m_tap = 200;
|
|||
|
|
memset(m_Z, 0, sizeof(m_Z));
|
|||
|
|
|
|||
|
|
m_fPhaseError = perr;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
int __fastcall CQSB::Do(void)
|
|||
|
|
{
|
|||
|
|
int d = m_VCO.Do() * 16384.0;
|
|||
|
|
BOOL fm = d < 0;
|
|||
|
|
d = ABS(d);
|
|||
|
|
d = m_vMin + ((m_vMax - m_vMin) * d / 16384);
|
|||
|
|
if( d > 16384 ) d = 16384;
|
|||
|
|
if( fm && m_fPhaseError ) d *= -1.0;
|
|||
|
|
return d;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
double __fastcall CQSB::Do(double d)
|
|||
|
|
{
|
|||
|
|
double ds = m_VCO.Do();
|
|||
|
|
if( m_fPhaseError ){
|
|||
|
|
double dc = m_VCO.DoCos();
|
|||
|
|
m_Z[m_tap] = d;
|
|||
|
|
memcpy(m_Z, &m_Z[1], m_tap*sizeof(double));
|
|||
|
|
int n = m_tap * (0.6 + m_VCOP.Do(0.0)*0.4);
|
|||
|
|
if( n < 0 ) n = 0;
|
|||
|
|
if( n > m_tap ) n = m_tap;
|
|||
|
|
d = m_Z[0] * ds + m_Z[n] * dc;
|
|||
|
|
}
|
|||
|
|
if( m_vMin != m_vMax ){
|
|||
|
|
ds = m_vMin + ((m_vMax - m_vMin) * ABS(ds));
|
|||
|
|
if( d > 16384 ) d = 16384;
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
ds = m_vMax;
|
|||
|
|
}
|
|||
|
|
return d * ds;
|
|||
|
|
}
|
|||
|
|
//--------------------------------------------------------
|
|||
|
|
// CNoise<73>N<EFBFBD><4E><EFBFBD>X
|
|||
|
|
__fastcall CNoise::CNoise()
|
|||
|
|
{
|
|||
|
|
m_SampleFreq = SAMPFREQ;
|
|||
|
|
// m_reg = 0x12345;
|
|||
|
|
m_reg = 0x11111;
|
|||
|
|
Create(600, 2700);
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
void __fastcall CNoise::SetSampleFreq(double f)
|
|||
|
|
{
|
|||
|
|
m_SampleFreq = f;
|
|||
|
|
Create(100, 2700);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void __fastcall CNoise::Create(double f1, double f2)
|
|||
|
|
{
|
|||
|
|
m_HPF.Create(ffHPF, f1, m_SampleFreq, 3, 1, 0.3);
|
|||
|
|
m_LPF.Create(ffLPF, f2, m_SampleFreq, 7, 1, 0.3);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
DWORD __fastcall CNoise::Do(void)
|
|||
|
|
{
|
|||
|
|
DWORD r = m_reg >> 1;
|
|||
|
|
if( (m_reg ^ r) & 1 ){
|
|||
|
|
r |= 0xffe00000;
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
r &= 0x001fffff;
|
|||
|
|
}
|
|||
|
|
m_reg = r;
|
|||
|
|
return r >> 19;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
double __fastcall CNoise::DoLPF(void)
|
|||
|
|
{
|
|||
|
|
return m_LPF.Do(Do());
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
double __fastcall CNoise::DoHPF(void)
|
|||
|
|
{
|
|||
|
|
return m_LPF.Do(m_HPF.Do(Do()));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
void __fastcall AddGaussian(short *pData, int n, double gain)
|
|||
|
|
{
|
|||
|
|
int i = 0;
|
|||
|
|
double rad;
|
|||
|
|
double r;
|
|||
|
|
double u1;
|
|||
|
|
double u2;
|
|||
|
|
while( i < n ){
|
|||
|
|
do {
|
|||
|
|
u1 = 1.0 - 2.0 * (double)rand()/(double)RAND_MAX ;
|
|||
|
|
u2 = 1.0 - 2.0 * (double)rand()/(double)RAND_MAX ;
|
|||
|
|
r = u1*u1 + u2*u2;
|
|||
|
|
} while(r >= 1.0 || r == 0.0);
|
|||
|
|
rad = sqrt(-2.0*log(r)/r);
|
|||
|
|
pData[i++] += (gain*u1*rad);
|
|||
|
|
pData[i++] += (gain*u2*rad);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
#endif
|
|||
|
|
|
|||
|
|
//*********************************************************************
|
|||
|
|
// CDECM2 1/N<>f<EFBFBD>V<EFBFBD><56><EFBFBD>[<5B>^<5E><><EFBFBD><EFBFBD><EFBFBD>N<EFBFBD><4E><EFBFBD>X
|
|||
|
|
//
|
|||
|
|
/*
|
|||
|
|
Clock <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> FFT
|
|||
|
|
6000Hz 6000Hz 6000Hz 1024
|
|||
|
|
8000Hz 8000Hz 8000Hz 2048
|
|||
|
|
11025Hz 5513Hz 11025Hz 2048
|
|||
|
|
12000Hz 6000Hz 6000Hz 1024
|
|||
|
|
16000Hz 5333Hz 10667Hz 2048
|
|||
|
|
18000Hz 6000Hz 6000Hz 1024
|
|||
|
|
22050Hz 5513Hz 11025Hz 2048
|
|||
|
|
24000Hz 6000Hz 6000Hz 1024
|
|||
|
|
44100Hz 6300Hz 6300Hz 1024
|
|||
|
|
48000Hz 6000Hz 6000Hz 1024
|
|||
|
|
50000Hz 6250Hz 6250Hz 1024
|
|||
|
|
*/
|
|||
|
|
__fastcall CDECM2::CDECM2()
|
|||
|
|
{
|
|||
|
|
m_Type = 1;
|
|||
|
|
m_Count = 0;
|
|||
|
|
SetSampleFreq(m_Type, SAMPFREQ);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void __fastcall CDECM2::SetSampleFreq(int type, double f)
|
|||
|
|
{
|
|||
|
|
m_Type = type;
|
|||
|
|
m_SampleFreq = f;
|
|||
|
|
#if DECFIR
|
|||
|
|
switch(m_Type){
|
|||
|
|
case 2: // 16000, 18000
|
|||
|
|
case 3: // 22050, 24000
|
|||
|
|
case 4:
|
|||
|
|
case 5:
|
|||
|
|
m_FIR.Create(40, ffLPF, m_SampleFreq, 2900, 2900, 40, 1.0);
|
|||
|
|
break;
|
|||
|
|
case 6: // 44100,
|
|||
|
|
case 7: // 48000, 50000
|
|||
|
|
m_FIR.Create(44, ffLPF, m_SampleFreq, 3000, 3000, 40, 1.0);
|
|||
|
|
break;
|
|||
|
|
default: // 11025, 12000
|
|||
|
|
m_FIR.Create(36, ffLPF, m_SampleFreq, 2700, 2700, 40, 1.0);
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
#else
|
|||
|
|
m_IIR.Create(ffLPF, sys.m_DecCutOff, m_SampleFreq, 10, 1, 0.1);
|
|||
|
|
#endif
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
BOOL __fastcall CDECM2::Do(double d)
|
|||
|
|
{
|
|||
|
|
#if DECFIR
|
|||
|
|
m_O = m_FIR.Do(d);
|
|||
|
|
#else
|
|||
|
|
m_O = m_IIR.Do(d);
|
|||
|
|
#endif
|
|||
|
|
if( !m_Count ){
|
|||
|
|
m_Count = m_Type;
|
|||
|
|
return TRUE;
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
m_Count--;
|
|||
|
|
return FALSE;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//--------------------------------------------------------
|
|||
|
|
// CAGC<47>N<EFBFBD><4E><EFBFBD>X
|
|||
|
|
__fastcall CAGC::CAGC()
|
|||
|
|
{
|
|||
|
|
m_fc = 1000.0;
|
|||
|
|
m_MonitorFreq = SAMPFREQ/2048;
|
|||
|
|
m_SampleFreq = SAMPFREQ;
|
|||
|
|
m_CarrierFreq = CARRIERFREQ;
|
|||
|
|
m_LimitGain = 0.005;
|
|||
|
|
m_AvgOver.Create(4);
|
|||
|
|
Create();
|
|||
|
|
}
|
|||
|
|
//--------------------------------------------------------
|
|||
|
|
void __fastcall CAGC::Create(void)
|
|||
|
|
{
|
|||
|
|
m_Count = 0;
|
|||
|
|
m_Max = -1.0;
|
|||
|
|
m_Min = 1.0;
|
|||
|
|
m_d = 0;
|
|||
|
|
m_agc = 1.0;
|
|||
|
|
// m_Level.Create(ffLPF, 0.3, m_MonitorFreq, 3, 0, 0);
|
|||
|
|
SetCarrierFreq(m_CarrierFreq);
|
|||
|
|
}
|
|||
|
|
//--------------------------------------------------------
|
|||
|
|
void __fastcall CAGC::SetCarrierFreq(double f)
|
|||
|
|
{
|
|||
|
|
m_CarrierFreq = f;
|
|||
|
|
if( m_CarrierFreq >= 1000.0 ){
|
|||
|
|
m_Gain = (m_CarrierFreq / 1000.0);
|
|||
|
|
|
|||
|
|
/*
|
|||
|
|
500 0.003 333
|
|||
|
|
1000 0.0035 285 1.0 1.0
|
|||
|
|
1500 0.005 200 1.4 1.5
|
|||
|
|
1800 0.006 166 1.71
|
|||
|
|
2000 0.008 125 2.3 2.0
|
|||
|
|
2100 0.01 100 2.85 2.1
|
|||
|
|
2200 0.012 83 3.4 2.2
|
|||
|
|
2300 0.015 66 4.3 2.3
|
|||
|
|
2400 0.025 40 7.1 2.4
|
|||
|
|
2500 0.028 36 7.9 2.5
|
|||
|
|
2600 0.030 33 8.6 2.6
|
|||
|
|
*/
|
|||
|
|
if( m_Gain >= 2.35 ){
|
|||
|
|
m_Gain *= 7.1 / 2.4;
|
|||
|
|
}
|
|||
|
|
else if( m_Gain >= 2.25 ){
|
|||
|
|
m_Gain *= 4.3 / 2.3;
|
|||
|
|
}
|
|||
|
|
else if( m_Gain >= 2.15 ){
|
|||
|
|
m_Gain *= 3.4 / 2.2;
|
|||
|
|
}
|
|||
|
|
else if( m_Gain >= 2.05 ){
|
|||
|
|
m_Gain *= 2.9 / 2.1;
|
|||
|
|
}
|
|||
|
|
else if( m_Gain >= 1.8 ){
|
|||
|
|
m_Gain *= 2.3 / 2.2;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
m_Gain = 1.0;
|
|||
|
|
}
|
|||
|
|
SetFC(m_fc);
|
|||
|
|
}
|
|||
|
|
//--------------------------------------------------------
|
|||
|
|
void __fastcall CAGC::SetFC(double fc)
|
|||
|
|
{
|
|||
|
|
m_fc = fc;
|
|||
|
|
if( fc > m_CarrierFreq*0.45 ) fc = m_CarrierFreq*0.45;
|
|||
|
|
m_LPF.Create(ffLPF, fc, m_CarrierFreq, 1, 0, 0);
|
|||
|
|
m_d = 0;
|
|||
|
|
m_TLimit = m_SampleFreq*0.8/m_CarrierFreq;
|
|||
|
|
m_AvgOver.Reset(1.0);
|
|||
|
|
}
|
|||
|
|
//--------------------------------------------------------
|
|||
|
|
void __fastcall CAGC::Reset(void)
|
|||
|
|
{
|
|||
|
|
m_Max = -1.0;
|
|||
|
|
m_Min = 1.0;
|
|||
|
|
m_agc = 1.0;
|
|||
|
|
m_d = 0;
|
|||
|
|
m_Count = 0;
|
|||
|
|
for( int i = 0; i < 12; i++ ){
|
|||
|
|
m_LPF.Do(1.0);
|
|||
|
|
// m_Level.Do(0);
|
|||
|
|
}
|
|||
|
|
m_AvgOver.Reset(1.0);
|
|||
|
|
}
|
|||
|
|
//--------------------------------------------------------
|
|||
|
|
double __fastcall CAGC::Do(double d)
|
|||
|
|
{
|
|||
|
|
if( m_Max < d ) m_Max = d;
|
|||
|
|
if( m_Min > d ) m_Min = d;
|
|||
|
|
if( (d >= 0) && (m_d < 0) && (m_Count >= m_TLimit) ){
|
|||
|
|
double amp = m_Max - m_Min;
|
|||
|
|
if( amp > 0.1 ){
|
|||
|
|
m_agc = m_LPF.Do(5.0/amp);
|
|||
|
|
if( m_agc >= 1.0 ) m_agc = 1.0;
|
|||
|
|
m_Max = -32768.0;
|
|||
|
|
m_Min = 32768.0;
|
|||
|
|
}
|
|||
|
|
m_Count = 0;
|
|||
|
|
}
|
|||
|
|
m_Count++;
|
|||
|
|
m_d = d;
|
|||
|
|
d *= m_agc;
|
|||
|
|
if( d > 2.5 ){ d = 2.5; } else if( d < -2.5 ){ d = -2.5; }
|
|||
|
|
return d;
|
|||
|
|
}
|
|||
|
|
//--------------------------------------------------------
|
|||
|
|
BOOL __fastcall CAGC::GetOver(void)
|
|||
|
|
{
|
|||
|
|
// 5.0 / (65536 * 0.666)
|
|||
|
|
return (m_AvgOver.Do(m_agc) < 0.0001146);
|
|||
|
|
// return (m_agc < 0.0001146);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//--------------------------------------------------------
|
|||
|
|
__fastcall CAFC::CAFC()
|
|||
|
|
{
|
|||
|
|
m_Speed = SPEED;
|
|||
|
|
m_SampleFreq = SAMPFREQ;
|
|||
|
|
m_A = m_SampleFreq / (2 * PI);
|
|||
|
|
m_B = 0.0;
|
|||
|
|
SetTap(32);
|
|||
|
|
SetTone(CARRIERFREQ);
|
|||
|
|
m_LPF.Create(ffLPF, SPEED, m_SampleFreq, 1, 0, 0);
|
|||
|
|
m_d = 0;
|
|||
|
|
m_min = 65536.0;
|
|||
|
|
m_max = -65536.0;
|
|||
|
|
m_Max = m_Min = 0.0;
|
|||
|
|
m_Count = 0;
|
|||
|
|
m_LCount1 = m_SampleFreq * 1.8 / m_Speed;
|
|||
|
|
m_LCount2 = m_SampleFreq * 31.8 / m_Speed;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void __fastcall CAFC::SetPara(double a, double b)
|
|||
|
|
{
|
|||
|
|
m_A = a;
|
|||
|
|
m_B = b;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void __fastcall CAFC::SetTap(int tap)
|
|||
|
|
{
|
|||
|
|
m_Avg.Create(tap);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void __fastcall CAFC::SetTone(double fq)
|
|||
|
|
{
|
|||
|
|
m_fq = fq;
|
|||
|
|
m_Avg.Reset(fq);
|
|||
|
|
m_fChange = FALSE;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
BOOL __fastcall CAFC::Do(double d)
|
|||
|
|
{
|
|||
|
|
BOOL f = FALSE;
|
|||
|
|
d = m_LPF.Do(d);
|
|||
|
|
if( m_min > d ) m_min = d;
|
|||
|
|
if( m_max < d ) m_max = d;
|
|||
|
|
if( ((m_d < 0.0) && (d >= 0.0) && (m_Count > m_LCount1)) ||
|
|||
|
|
(m_Count > m_LCount2)
|
|||
|
|
){
|
|||
|
|
m_Max = m_max; m_Min = m_min;
|
|||
|
|
double dd = (m_max + m_min) * 0.5;
|
|||
|
|
m_min = m_max = d;
|
|||
|
|
dd = dd * m_A + m_B;
|
|||
|
|
|
|||
|
|
dd = m_Avg.Do(dd);
|
|||
|
|
if( (dd >= m_B-100) && (dd <= m_B+100) ){
|
|||
|
|
m_fq = dd;
|
|||
|
|
f = TRUE;
|
|||
|
|
}
|
|||
|
|
m_Count = 0;
|
|||
|
|
}
|
|||
|
|
m_d = d;
|
|||
|
|
m_Count++;
|
|||
|
|
return f;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
// CLMS<4D>N<EFBFBD><4E><EFBFBD>X
|
|||
|
|
__fastcall CLMS::CLMS()
|
|||
|
|
{
|
|||
|
|
m_Tap = 48;
|
|||
|
|
m_lmsDelay = 32;
|
|||
|
|
|
|||
|
|
memset(Z, 0, sizeof(Z));
|
|||
|
|
memset(H, 0, sizeof(H));
|
|||
|
|
memset(D, 0, sizeof(D));
|
|||
|
|
|
|||
|
|
m_lmsADJSC = 1.0 / double(32768 * 32768); // <20>X<EFBFBD>P<EFBFBD>[<5B><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>l
|
|||
|
|
|
|||
|
|
m_lmsMU2 = 0.003; // LMS 2<><32>
|
|||
|
|
m_lmsGM = 0.9999; // LMS <20><>
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//-------------------------------------------------
|
|||
|
|
// <20>K<EFBFBD><4B><EFBFBD>t<EFBFBD>B<EFBFBD><42><EFBFBD>^<5E>̉<EFBFBD><CC89>Z
|
|||
|
|
double __fastcall CLMS::Do(double d)
|
|||
|
|
{
|
|||
|
|
double a = 0.0;
|
|||
|
|
int i;
|
|||
|
|
double *zp = Z;
|
|||
|
|
double *hp = H;
|
|||
|
|
|
|||
|
|
// <20>g<EFBFBD><67><EFBFBD><EFBFBD><EFBFBD>X<EFBFBD>o<EFBFBD>[<5B>T<EFBFBD><54><EFBFBD>t<EFBFBD>B<EFBFBD><42><EFBFBD>^
|
|||
|
|
memcpy(Z, &Z[1], sizeof(double)*m_Tap);
|
|||
|
|
Z[m_Tap] = D[0];
|
|||
|
|
for( i = 0; i <= m_Tap; i++, zp++, hp++ ){
|
|||
|
|
a += (*zp) * (*hp);
|
|||
|
|
}
|
|||
|
|
// <20>덷<EFBFBD>v<EFBFBD>Z
|
|||
|
|
double err = d - a;
|
|||
|
|
double merr = err * m_lmsMU2 * m_lmsADJSC; // lmsADJSC = 1/(32768 * 32768) <20>X<EFBFBD>P<EFBFBD>[<5B><><EFBFBD><EFBFBD><EFBFBD>O<EFBFBD><4F><EFBFBD><EFBFBD><EFBFBD>l
|
|||
|
|
|
|||
|
|
// <20>x<EFBFBD><78><EFBFBD><EFBFBD><EFBFBD>̈ړ<CC88>
|
|||
|
|
if( m_lmsDelay ) memcpy(D, &D[1], sizeof(double)*m_lmsDelay);
|
|||
|
|
D[m_lmsDelay] = d;
|
|||
|
|
// <20>W<EFBFBD><57><EFBFBD>X<EFBFBD>V
|
|||
|
|
zp = Z;
|
|||
|
|
hp = H;
|
|||
|
|
double sum = 0;
|
|||
|
|
for( i = 0; i <= m_Tap; i++, zp++, hp++ ){
|
|||
|
|
*hp = (merr * (*zp)) + (*hp * m_lmsGM);
|
|||
|
|
sum += ABS(*hp);
|
|||
|
|
}
|
|||
|
|
if( sum ){
|
|||
|
|
sum = 1.0 / sum;
|
|||
|
|
hp = H;
|
|||
|
|
for( i = 0; i <= m_Tap; i++, hp++ ){
|
|||
|
|
*hp *= sum;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return a;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
// CDEMFSK<53>N<EFBFBD><4E><EFBFBD>X
|
|||
|
|
__fastcall CDEMFSK::CDEMFSK()
|
|||
|
|
{
|
|||
|
|
#if MEASIMD
|
|||
|
|
m_imd = 0.0;
|
|||
|
|
m_max = 0.0;
|
|||
|
|
m_min = 0.0;
|
|||
|
|
m_amax = 0.0;
|
|||
|
|
m_amin = 0.0;
|
|||
|
|
#endif
|
|||
|
|
|
|||
|
|
m_MFSK_TYPE = typMFSK16;
|
|||
|
|
m_MFSK_TONES = 16;
|
|||
|
|
m_MFSK_SPEED = 15.625;
|
|||
|
|
m_MFSK_BW = (m_MFSK_SPEED * (m_MFSK_TONES-1));
|
|||
|
|
m_MFSK_BITS = 4;
|
|||
|
|
|
|||
|
|
m_Type = MODE_GMSK;
|
|||
|
|
m_pBPF = NULL;
|
|||
|
|
m_Speed = SPEED;
|
|||
|
|
m_SampleFreq = DEMSAMPFREQ;
|
|||
|
|
// m_LoopFc = SPEED*6;
|
|||
|
|
// m_Gain = 1.0;
|
|||
|
|
m_Gain = 0.8;
|
|||
|
|
m_CarrierFreq = CARRIERFREQ;
|
|||
|
|
m_PreBPFTaps = 64;
|
|||
|
|
m_fAFC = TRUE;
|
|||
|
|
m_fEnableAFC = FALSE;
|
|||
|
|
m_out = m_err = 0.0;
|
|||
|
|
m_RTTYShift = 170.0;
|
|||
|
|
m_fRTTYTANK = TRUE;
|
|||
|
|
m_fRTTYFFT = FALSE;
|
|||
|
|
m_DemLevel = 1.0;
|
|||
|
|
m_SW = m_Speed * 0.5;
|
|||
|
|
m_pMFSK = NULL;
|
|||
|
|
m_fMFSK = FALSE;
|
|||
|
|
m_fQPSK = FALSE;
|
|||
|
|
m_BPFLimit = 4.0;
|
|||
|
|
Create();
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
__fastcall CDEMFSK::~CDEMFSK()
|
|||
|
|
{
|
|||
|
|
if( m_pMFSK ) delete m_pMFSK;
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
void __fastcall CDEMFSK::SetMFSKType(int type)
|
|||
|
|
{
|
|||
|
|
MFSK_SetPara(type, &m_MFSK_TONES, &m_MFSK_SPEED, &m_MFSK_BITS);
|
|||
|
|
m_MFSK_BW = (m_MFSK_SPEED * (m_MFSK_TONES-1));
|
|||
|
|
if( type == m_MFSK_TYPE ) return;
|
|||
|
|
m_MFSK_TYPE = type;
|
|||
|
|
if( m_pMFSK ) Create();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
#define AFC_LPFORDER 3
|
|||
|
|
#define OUT_LPFORDER 3
|
|||
|
|
void __fastcall CDEMFSK::Create(void)
|
|||
|
|
{
|
|||
|
|
m_fMFSK = IsMFSK(m_Type);
|
|||
|
|
m_fQPSK = IsQPSK(m_Type);
|
|||
|
|
m_fRTTYTANK = (m_Speed < m_RTTYShift);
|
|||
|
|
m_LPF1.Create(ffLPF, m_Speed, m_SampleFreq, AFC_LPFORDER, 0, 0);
|
|||
|
|
// m_LPF2.Create(ffLPF, m_Speed, m_SampleFreq, AFC_LPFORDER, 0, 0);
|
|||
|
|
m_LPF1.Clear();
|
|||
|
|
// m_LPF2.Clear();
|
|||
|
|
double fc = m_Speed * 6.0;
|
|||
|
|
if( fc > m_SampleFreq * 0.45 ) fc = m_SampleFreq * 0.45;
|
|||
|
|
m_LoopLPF.Create(ffLPF, fc, m_SampleFreq, 1, 0, 0);
|
|||
|
|
if( Is170(m_Type) ){
|
|||
|
|
m_FAVG.Create(128*45.45/m_Speed);
|
|||
|
|
}
|
|||
|
|
else if( IsFSK(m_Type) ){
|
|||
|
|
m_FAVG.Create(16);
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
m_FAVG.Create(8192*31.25/m_Speed);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
int nSmooz = int((m_SampleFreq * 45.45 / (m_Speed * 70.0)) + 0.5);
|
|||
|
|
m_SmoozM.SetCount(nSmooz);
|
|||
|
|
m_SmoozS.SetCount(nSmooz);
|
|||
|
|
|
|||
|
|
// m_CIC.Create(4, m_SampleFreq*0.5/m_Speed);
|
|||
|
|
m_OutLPF.Create(ffLPF, m_Speed*0.5, m_SampleFreq, OUT_LPFORDER, 0, 0);
|
|||
|
|
m_VCO.SetSampleFreq(m_SampleFreq);
|
|||
|
|
|
|||
|
|
m_AFC.m_Speed = m_Speed;
|
|||
|
|
m_AFC.SetTap(16*m_SampleFreq/11025);
|
|||
|
|
|
|||
|
|
m_Decode.SetSampleFreq(m_SampleFreq);
|
|||
|
|
m_Decode.SetType(m_Type);
|
|||
|
|
m_Decode.SetSpeed(m_Speed);
|
|||
|
|
m_Decode.Reset();
|
|||
|
|
|
|||
|
|
m_AGC.SetSampleFreq(m_SampleFreq);
|
|||
|
|
m_TankL.m_BW = m_TankH.m_BW = 60.0;
|
|||
|
|
m_TankL.SetSampleFreq(m_SampleFreq);
|
|||
|
|
m_TankH.SetSampleFreq(m_SampleFreq);
|
|||
|
|
m_PhaseX.SetSampleFreq(m_SampleFreq);
|
|||
|
|
|
|||
|
|
SetCarrierFreq(m_CarrierFreq);
|
|||
|
|
|
|||
|
|
m_fEnableAFC = FALSE;
|
|||
|
|
m_DemLevel = 1.0;
|
|||
|
|
/*
|
|||
|
|
31.25 88
|
|||
|
|
45.45 66
|
|||
|
|
62.5 53
|
|||
|
|
93.75 37
|
|||
|
|
125 30
|
|||
|
|
*/
|
|||
|
|
if( m_fMFSK ){
|
|||
|
|
if( !m_pMFSK ) m_pMFSK = new CDecMFSK;
|
|||
|
|
m_pMFSK->SetMFSKType(m_MFSK_TYPE);
|
|||
|
|
m_pMFSK->SetSampleFreq(m_SampleFreq);
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
delete m_pMFSK;
|
|||
|
|
m_pMFSK = NULL;
|
|||
|
|
}
|
|||
|
|
m_DecPSK.m_fLSB = (m_Type == MODE_qpsk_L);
|
|||
|
|
m_DecPSK.SetSampleFreq(m_SampleFreq);
|
|||
|
|
m_DecPSK.SetCarrierFreq(m_CarrierFreq);
|
|||
|
|
m_DecPSK.SetSpeed(m_Speed);
|
|||
|
|
double spd = m_Speed;
|
|||
|
|
if( spd < 30 ) spd = 30.0;
|
|||
|
|
switch(m_Type){
|
|||
|
|
case MODE_N_BPSK:
|
|||
|
|
case MODE_BPSK:
|
|||
|
|
case MODE_qpsk_L:
|
|||
|
|
case MODE_qpsk_U:
|
|||
|
|
m_LockTh = (2750*2/3)/spd;
|
|||
|
|
m_AGC.SetFC(500);
|
|||
|
|
break;
|
|||
|
|
case MODE_GMSK:
|
|||
|
|
m_LockTh = (2750*1/2)/spd;
|
|||
|
|
m_AGC.SetFC(500);
|
|||
|
|
break;
|
|||
|
|
case MODE_FSKW:
|
|||
|
|
case MODE_FSK:
|
|||
|
|
m_LockTh = (2750*1/3)/spd;
|
|||
|
|
m_AGC.SetFC(500);
|
|||
|
|
break;
|
|||
|
|
case MODE_RTTY:
|
|||
|
|
case MODE_U_RTTY:
|
|||
|
|
m_LockTh = (2750*1/3)/spd;
|
|||
|
|
m_AGC.SetFC(500);
|
|||
|
|
break;
|
|||
|
|
case MODE_mfsk_L:
|
|||
|
|
m_pMFSK->m_fLSB = TRUE;
|
|||
|
|
m_pMFSK->SetCarrierFreq(m_CarrierFreq);
|
|||
|
|
m_Lock = TRUE;
|
|||
|
|
break;
|
|||
|
|
case MODE_mfsk_U:
|
|||
|
|
m_pMFSK->m_fLSB = FALSE;
|
|||
|
|
m_pMFSK->SetCarrierFreq(m_CarrierFreq);
|
|||
|
|
m_Lock = TRUE;
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
m_out = m_err = 0.0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
double __fastcall GetRTTYBW(int taps)
|
|||
|
|
{
|
|||
|
|
int bw = 180.0;
|
|||
|
|
if( taps == g_tBpfTaps[1] ){
|
|||
|
|
bw = 120.0;
|
|||
|
|
}
|
|||
|
|
else if( taps == g_tBpfTaps[2] ){
|
|||
|
|
bw = 70.0;
|
|||
|
|
}
|
|||
|
|
else if( taps == g_tBpfTaps[3] ){
|
|||
|
|
bw = 30.0;
|
|||
|
|
}
|
|||
|
|
return bw;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
double __fastcall GetMFSKBW(int taps)
|
|||
|
|
{
|
|||
|
|
int bw = 200.0;
|
|||
|
|
if( taps == g_tBpfTaps[1] ){
|
|||
|
|
bw = 150.0;
|
|||
|
|
}
|
|||
|
|
else if( taps == g_tBpfTaps[2] ){
|
|||
|
|
bw = 100.0;
|
|||
|
|
}
|
|||
|
|
else if( taps == g_tBpfTaps[3] ){
|
|||
|
|
bw = 50.0;
|
|||
|
|
}
|
|||
|
|
return bw;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
void __fastcall CDEMFSK::MakeBPF(int taps)
|
|||
|
|
{
|
|||
|
|
int bw;
|
|||
|
|
m_PreBPFTaps = taps;
|
|||
|
|
m_PreBPFFC = m_CarrierFreq;
|
|||
|
|
switch(m_Type){
|
|||
|
|
case MODE_N_BPSK:
|
|||
|
|
case MODE_BPSK:
|
|||
|
|
case MODE_qpsk_L:
|
|||
|
|
case MODE_qpsk_U:
|
|||
|
|
case MODE_GMSK:
|
|||
|
|
m_inBPF.Create(m_PreBPFTaps, ffBPF, m_SampleFreq, m_PreBPFFC - m_Speed, m_PreBPFFC + m_Speed, 60, 1.0);
|
|||
|
|
m_BPFLimit = m_Speed * 0.125;
|
|||
|
|
break;
|
|||
|
|
case MODE_FSK:
|
|||
|
|
m_inBPF.Create(m_PreBPFTaps, ffBPF, m_SampleFreq, m_PreBPFFC - m_Speed*2, m_PreBPFFC + m_Speed*2, 60, 1.0);
|
|||
|
|
m_BPFLimit = m_Speed * 0.125;
|
|||
|
|
break;
|
|||
|
|
case MODE_FSKW:
|
|||
|
|
case MODE_RTTY:
|
|||
|
|
case MODE_U_RTTY:
|
|||
|
|
bw = GetRTTYBW(taps);
|
|||
|
|
m_inBPF.Create(m_PreBPFTaps, ffBPF, m_SampleFreq, m_PreBPFFC - m_RTTYShift*0.5 - bw, m_PreBPFFC + m_RTTYShift*0.5 + bw, 60, 1.0);
|
|||
|
|
m_BPFLimit = 5.0;
|
|||
|
|
break;
|
|||
|
|
case MODE_mfsk_L:
|
|||
|
|
bw = GetMFSKBW(taps);
|
|||
|
|
if( sys.m_MFSK_Center ){
|
|||
|
|
m_inBPF.Create(m_PreBPFTaps, ffBPF, m_SampleFreq, m_PreBPFFC - m_MFSK_BW*0.5 - bw, m_PreBPFFC + m_MFSK_BW*0.5 + bw, 60, 1.0);
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
m_inBPF.Create(m_PreBPFTaps, ffBPF, m_SampleFreq, m_PreBPFFC - m_MFSK_BW - bw, m_PreBPFFC + bw, 60, 1.0);
|
|||
|
|
}
|
|||
|
|
m_BPFLimit = 2.0;
|
|||
|
|
break;
|
|||
|
|
case MODE_mfsk_U:
|
|||
|
|
bw = GetMFSKBW(taps);
|
|||
|
|
if( sys.m_MFSK_Center ){
|
|||
|
|
m_inBPF.Create(m_PreBPFTaps, ffBPF, m_SampleFreq, m_PreBPFFC - m_MFSK_BW*0.5 - bw, m_PreBPFFC + m_MFSK_BW*0.5 + bw, 60, 1.0);
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
m_inBPF.Create(m_PreBPFTaps, ffBPF, m_SampleFreq, m_PreBPFFC - bw, m_PreBPFFC + m_MFSK_BW + bw, 60, 1.0);
|
|||
|
|
}
|
|||
|
|
m_BPFLimit = 2.0;
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
void __fastcall CDEMFSK::SetCarrierFreq(double f)
|
|||
|
|
{
|
|||
|
|
m_CarrierFreq = f;
|
|||
|
|
m_RxFreq = f;
|
|||
|
|
m_CarrierQPSK = f;
|
|||
|
|
m_RxFreqQPSK = f;
|
|||
|
|
|
|||
|
|
MakeBPF(m_PreBPFTaps);
|
|||
|
|
m_VCO.SetFreeFreq(m_CarrierFreq);
|
|||
|
|
switch(m_Type){
|
|||
|
|
case MODE_N_BPSK:
|
|||
|
|
case MODE_BPSK:
|
|||
|
|
case MODE_GMSK:
|
|||
|
|
case MODE_qpsk_L:
|
|||
|
|
case MODE_qpsk_U:
|
|||
|
|
m_VCO.SetGain(m_Speed * 0.5 * m_Gain);
|
|||
|
|
m_AFC.SetPara(m_Speed * 0.5 * m_Gain, m_CarrierFreq);
|
|||
|
|
m_SW = m_Speed*0.5;
|
|||
|
|
m_DecPSK.SetCarrierFreq(m_CarrierFreq);
|
|||
|
|
break;
|
|||
|
|
case MODE_FSK:
|
|||
|
|
m_VCO.SetGain(m_Speed * 1.0 * m_Gain);
|
|||
|
|
m_AFC.SetPara(m_Speed * 1.0 * m_Gain, m_CarrierFreq);
|
|||
|
|
m_SW = m_Speed;
|
|||
|
|
break;
|
|||
|
|
case MODE_FSKW:
|
|||
|
|
case MODE_RTTY:
|
|||
|
|
case MODE_U_RTTY:
|
|||
|
|
m_TankL.SetFreq(m_CarrierFreq - (m_RTTYShift * 0.5));
|
|||
|
|
m_TankH.SetFreq(m_CarrierFreq + (m_RTTYShift * 0.5));
|
|||
|
|
m_VCO.SetGain(m_RTTYShift * 1.0 * m_Gain);
|
|||
|
|
m_AFC.SetPara(m_RTTYShift * 1.0 * m_Gain, m_CarrierFreq);
|
|||
|
|
m_PhaseX.SetCarrierFreq(m_CarrierFreq - (m_RTTYShift * 0.5));
|
|||
|
|
m_PhaseX.SetShift(m_RTTYShift);
|
|||
|
|
m_SW = m_RTTYShift;
|
|||
|
|
break;
|
|||
|
|
case MODE_mfsk_L:
|
|||
|
|
case MODE_mfsk_U:
|
|||
|
|
if( m_pMFSK ){
|
|||
|
|
m_pMFSK->SetCarrierFreq(m_CarrierFreq);
|
|||
|
|
}
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
m_AFC.SetTone(m_CarrierFreq);
|
|||
|
|
m_AGC.SetCarrierFreq(m_CarrierFreq);
|
|||
|
|
if( IsFSK(m_Type) ) m_FAVG.Reset(m_CarrierFreq);
|
|||
|
|
m_fEnableAFC = FALSE;
|
|||
|
|
m_AFCCount = 0;
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
#define countBPFUPDATE (3*11025/2048)
|
|||
|
|
void __fastcall CDEMFSK::UpdateBPF(void)
|
|||
|
|
{
|
|||
|
|
double a = fabs(m_PreBPFFC - m_CarrierFreq);
|
|||
|
|
if( a >= m_BPFLimit ){
|
|||
|
|
m_AGC.SetCarrierFreq(m_CarrierFreq);
|
|||
|
|
MakeBPF(m_PreBPFTaps);
|
|||
|
|
}
|
|||
|
|
m_AFCCount++;
|
|||
|
|
// Application->MainForm->Caption = m_AFCCount;
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
double __fastcall CDEMFSK::GetFreqErr(void)
|
|||
|
|
{
|
|||
|
|
if( IsBPSK(m_Type) ){
|
|||
|
|
return m_FAVG.GetAvg();
|
|||
|
|
}
|
|||
|
|
else if( m_fMFSK ){
|
|||
|
|
return (m_RxFreq - m_CarrierFreq) / m_MFSK_SPEED;
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
return (m_RxFreq - m_CarrierFreq) / m_SW;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
void __fastcall CDEMFSK::DoAFC(double d)
|
|||
|
|
{
|
|||
|
|
if( m_AFC.Do(d) ){
|
|||
|
|
if( !m_fEnableAFC ) return;
|
|||
|
|
if( m_AFCCount < DEMAFCLIMIT ){
|
|||
|
|
m_RxFreq = m_AFC.GetFreq();
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
m_RxFreq = m_FAVG.Do(m_AFC.GetFreq());
|
|||
|
|
}
|
|||
|
|
if( !m_fAFC ) return;
|
|||
|
|
|
|||
|
|
double a = fabs(m_CarrierFreq - m_RxFreq);
|
|||
|
|
if( (a >= 0.1) && ( a <= (m_Speed*1.5)) ){
|
|||
|
|
m_CarrierFreq = m_RxFreq;
|
|||
|
|
if( m_AFCCount < DEMAFCLIMIT ) m_FAVG.Reset(m_RxFreq);
|
|||
|
|
m_VCO.SetFreeFreq(m_CarrierFreq);
|
|||
|
|
switch(m_Type){
|
|||
|
|
case MODE_GMSK:
|
|||
|
|
m_VCO.SetGain(m_Speed * 0.5 * m_Gain);
|
|||
|
|
m_AFC.SetPara(m_Speed * 0.5 * m_Gain, m_CarrierFreq);
|
|||
|
|
break;
|
|||
|
|
case MODE_FSK:
|
|||
|
|
m_VCO.SetGain(m_Speed * 1.0 * m_Gain);
|
|||
|
|
m_AFC.SetPara(m_Speed * 1.0 * m_Gain, m_CarrierFreq);
|
|||
|
|
break;
|
|||
|
|
case MODE_FSKW:
|
|||
|
|
case MODE_RTTY:
|
|||
|
|
case MODE_U_RTTY:
|
|||
|
|
// m_TankL.SetFreq(m_CarrierFreq - (m_RTTYShift * 0.5));
|
|||
|
|
// m_TankH.SetFreq(m_CarrierFreq + (m_RTTYShift * 0.5));
|
|||
|
|
m_VCO.SetGain(m_RTTYShift * 1.0 * m_Gain);
|
|||
|
|
m_AFC.SetPara(m_RTTYShift * 1.0 * m_Gain, m_CarrierFreq);
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
m_AFC.SetTone(m_CarrierFreq);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
void __fastcall CDEMFSK::DoAFCPSK(double d)
|
|||
|
|
{
|
|||
|
|
d = m_FAVG.DoZ(d);
|
|||
|
|
if( !m_fEnableAFC ) return;
|
|||
|
|
m_RxFreq = m_CarrierFreq + d * m_Speed * 0.5;
|
|||
|
|
if( !m_fAFC ) return;
|
|||
|
|
|
|||
|
|
double a = fabs(m_CarrierFreq - m_RxFreq);
|
|||
|
|
if( (a >= 0.1) && ( a <= (m_Speed*1.5)) ){
|
|||
|
|
m_CarrierFreq = m_RxFreq;
|
|||
|
|
m_VCO.SetFreeFreq(m_CarrierFreq);
|
|||
|
|
switch(m_Type){
|
|||
|
|
case MODE_N_BPSK:
|
|||
|
|
case MODE_BPSK:
|
|||
|
|
case MODE_GMSK:
|
|||
|
|
m_VCO.SetGain(m_Speed * 0.5 * m_Gain);
|
|||
|
|
m_AFC.SetPara(m_Speed * 0.5 * m_Gain, m_CarrierFreq);
|
|||
|
|
break;
|
|||
|
|
case MODE_FSK:
|
|||
|
|
m_VCO.SetGain(m_Speed * 1.0 * m_Gain);
|
|||
|
|
m_AFC.SetPara(m_Speed * 1.0 * m_Gain, m_CarrierFreq);
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
m_AFC.SetTone(m_CarrierFreq);
|
|||
|
|
m_out = 0;
|
|||
|
|
m_FAVG.Reset();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
void __fastcall CDEMFSK::DoAFCQPSK(double d)
|
|||
|
|
{
|
|||
|
|
d = m_FAVG.DoZ(d);
|
|||
|
|
if( !m_fEnableAFC ) return;
|
|||
|
|
m_RxFreqQPSK = m_CarrierQPSK + d * m_Speed * 0.5;
|
|||
|
|
if( !m_fAFC ) return;
|
|||
|
|
|
|||
|
|
double a = fabs(m_CarrierQPSK - m_RxFreqQPSK);
|
|||
|
|
if( (a >= 0.1) && ( a <= (m_Speed*1.5)) ){
|
|||
|
|
m_CarrierQPSK = m_RxFreqQPSK;
|
|||
|
|
m_VCO.SetFreeFreq(m_CarrierQPSK);
|
|||
|
|
m_VCO.SetGain(m_Speed * 0.5 * m_Gain);
|
|||
|
|
m_AFC.SetPara(m_Speed * 0.5 * m_Gain, m_CarrierQPSK);
|
|||
|
|
m_AFC.SetTone(m_CarrierFreq);
|
|||
|
|
m_out = 0;
|
|||
|
|
m_FAVG.Reset();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
void __fastcall CDEMFSK::DoAFCRTTY(double d)
|
|||
|
|
{
|
|||
|
|
if( m_AFC.Do(d) ){
|
|||
|
|
if( !m_fEnableAFC ) return;
|
|||
|
|
m_RxFreq = m_AFC.GetFreq();
|
|||
|
|
if( !m_fAFC ) return;
|
|||
|
|
|
|||
|
|
double a = fabs(m_CarrierFreq - m_RxFreq);
|
|||
|
|
if( (a >= 1.0) && ( a <= (150.0)) ){
|
|||
|
|
a *= 0.5;
|
|||
|
|
if( m_CarrierFreq < m_RxFreq ){
|
|||
|
|
m_CarrierFreq += a;
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
m_CarrierFreq -= a;
|
|||
|
|
}
|
|||
|
|
m_VCO.SetFreeFreq(m_CarrierFreq);
|
|||
|
|
m_TankL.SetFreq(m_CarrierFreq - (m_RTTYShift * 0.5));
|
|||
|
|
m_TankH.SetFreq(m_CarrierFreq + (m_RTTYShift * 0.5));
|
|||
|
|
m_VCO.SetGain(m_RTTYShift * 1.0 * m_Gain);
|
|||
|
|
m_AFC.SetPara(m_RTTYShift * 1.0 * m_Gain, m_CarrierFreq);
|
|||
|
|
m_AFC.SetTone(m_CarrierFreq);
|
|||
|
|
m_PhaseX.SetCarrierFreq(m_CarrierFreq - (m_RTTYShift * 0.5));
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
int __fastcall CDEMFSK::Do(double d)
|
|||
|
|
{
|
|||
|
|
EPHASE(P_DEMBPF);
|
|||
|
|
if( m_pBPF ){
|
|||
|
|
d = m_pBPF->Do(m_inBPF.GetHP());
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
d = m_inBPF.Do(d);
|
|||
|
|
}
|
|||
|
|
m_d = d;
|
|||
|
|
EPHASE(P_DEMAGC);
|
|||
|
|
d = m_AGC.Do(d);
|
|||
|
|
switch(m_Type){
|
|||
|
|
case MODE_GMSK: // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>g
|
|||
|
|
case MODE_FSK:
|
|||
|
|
EPHASE(P_DEMLPF);
|
|||
|
|
// Loop Filter
|
|||
|
|
m_out = m_LoopLPF.Do(m_err);
|
|||
|
|
EPHASE(P_DEMAFC);
|
|||
|
|
DoAFC(m_out);
|
|||
|
|
if( m_out > 1.5 ){ m_out = 1.5; } else if( m_out < -1.5 ){ m_out = -1.5;}
|
|||
|
|
EPHASE(P_DEMLOCK);
|
|||
|
|
m_Lock = (m_AFC.m_Max - m_AFC.m_Min) * 100;
|
|||
|
|
m_Lock = (m_Lock > m_LockTh);
|
|||
|
|
// m_FreqErr = (m_AFC.m_Max + m_AFC.m_Min) * 0.5;
|
|||
|
|
// VCO
|
|||
|
|
// <20>ʑ<EFBFBD><CA91><EFBFBD><EFBFBD>r
|
|||
|
|
EPHASE(P_DEMVCO);
|
|||
|
|
m_err = m_VCO.Do(m_out) * d;
|
|||
|
|
EPHASE(P_DEMOUT);
|
|||
|
|
d = m_OutLPF.Do(m_out);
|
|||
|
|
EPHASE(P_NULL);
|
|||
|
|
return d * 32768.0;
|
|||
|
|
case MODE_BPSK:
|
|||
|
|
case MODE_N_BPSK: // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>g
|
|||
|
|
{
|
|||
|
|
EPHASE(P_NULL);
|
|||
|
|
m_Lock = TRUE;
|
|||
|
|
double ds = d * m_VCO.Do(m_out);
|
|||
|
|
double dc = d * m_VCO.DoCos();
|
|||
|
|
// double dc = -ds;
|
|||
|
|
#if 0
|
|||
|
|
m_out = m_LPF1.Do(ABS(ds)) - m_LPF2.Do(ABS(dc));
|
|||
|
|
#else
|
|||
|
|
m_out = m_LPF1.Do(ABS(ds)-ABS(dc));
|
|||
|
|
#endif
|
|||
|
|
DoAFCPSK(m_out);
|
|||
|
|
#if MEASIMD
|
|||
|
|
double amp = ds * ds + dc * dc;
|
|||
|
|
if( m_min > amp ) m_min = amp;
|
|||
|
|
if( m_max < amp ) m_max = amp;
|
|||
|
|
#endif
|
|||
|
|
return m_OutLPF.Do(ds - dc) * 32768.0;
|
|||
|
|
}
|
|||
|
|
case MODE_qpsk_L:
|
|||
|
|
case MODE_qpsk_U: // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>g
|
|||
|
|
{
|
|||
|
|
EPHASE(P_NULL);
|
|||
|
|
m_Lock = TRUE;
|
|||
|
|
double ds = d * m_VCO.Do(m_out);
|
|||
|
|
double dc = d * m_VCO.DoCos();
|
|||
|
|
m_out = m_LPF1.Do(ABS(ds)-ABS(dc));
|
|||
|
|
DoAFCQPSK(m_out);
|
|||
|
|
return 0;
|
|||
|
|
}
|
|||
|
|
case MODE_FSKW:
|
|||
|
|
case MODE_RTTY:
|
|||
|
|
case MODE_U_RTTY:
|
|||
|
|
if( m_fRTTYTANK ){ // <20>N<EFBFBD>I<EFBFBD>h<EFBFBD><68><EFBFBD>`<60><><EFBFBD><EFBFBD><EFBFBD>g
|
|||
|
|
EPHASE(P_DEMLPF);
|
|||
|
|
// Loop Filter
|
|||
|
|
m_out = m_LoopLPF.Do(m_err);
|
|||
|
|
EPHASE(P_DEMAFC);
|
|||
|
|
DoAFCRTTY(m_out);
|
|||
|
|
if( m_out > 1.5 ){ m_out = 1.5; } else if( m_out < -1.5 ){ m_out = -1.5;}
|
|||
|
|
EPHASE(P_DEMLOCK);
|
|||
|
|
m_Lock = (m_AFC.m_Max - m_AFC.m_Min) * 100;
|
|||
|
|
m_Lock = (m_Lock > m_LockTh) && (m_DemLevel >= 0.5);
|
|||
|
|
// m_FreqErr = (m_AFC.m_Max + m_AFC.m_Min) * 0.5;
|
|||
|
|
// VCO
|
|||
|
|
// <20>ʑ<EFBFBD><CA91><EFBFBD><EFBFBD>r
|
|||
|
|
EPHASE(P_DEMVCO);
|
|||
|
|
m_err = m_VCO.Do(m_out) * d;
|
|||
|
|
EPHASE(P_NULL);
|
|||
|
|
|
|||
|
|
if( m_fRTTYFFT ){
|
|||
|
|
m_PhaseX.DoFSK(d);
|
|||
|
|
double ds = m_PhaseX.m_ds;
|
|||
|
|
double dm = m_PhaseX.m_dm;
|
|||
|
|
#if 1
|
|||
|
|
ds = m_SmoozM.Avg(ds);
|
|||
|
|
dm = m_SmoozS.Avg(dm);
|
|||
|
|
d = ds - dm;
|
|||
|
|
#else
|
|||
|
|
d = m_OutLPF.Do(m_LPF1.Do(ds-dm));
|
|||
|
|
#endif
|
|||
|
|
m_DemLevel = m_FAVG.Do(ABS(d)) * 4.0;
|
|||
|
|
if( m_DemLevel >= 1.0 ) m_DemLevel = 1.0;
|
|||
|
|
if( m_Type == MODE_RTTY ) d = -d;
|
|||
|
|
return d * 32768.0;
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
d *= 32.0;
|
|||
|
|
if( d > 1.0 ) d = 1.0;
|
|||
|
|
if( d < -1.0 ) d = -1.0;
|
|||
|
|
double ds = m_TankH.Do(d);
|
|||
|
|
double dm = m_TankL.Do(d);
|
|||
|
|
d = m_OutLPF.Do(m_LPF1.Do(ABS(ds)-ABS(dm)));
|
|||
|
|
m_DemLevel = m_FAVG.Do(ABS(d)) * 4.0;
|
|||
|
|
if( m_DemLevel >= 1.0 ) m_DemLevel = 1.0;
|
|||
|
|
if( m_Type == MODE_RTTY ) d = -d;
|
|||
|
|
return d * 32768.0;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else { // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>g
|
|||
|
|
EPHASE(P_DEMLPF);
|
|||
|
|
// Loop Filter
|
|||
|
|
m_out = m_LoopLPF.Do(m_err);
|
|||
|
|
EPHASE(P_DEMAFC);
|
|||
|
|
DoAFC(m_out);
|
|||
|
|
if( m_out > 1.5 ){ m_out = 1.5; } else if( m_out < -1.5 ){ m_out = -1.5;}
|
|||
|
|
EPHASE(P_DEMLOCK);
|
|||
|
|
m_Lock = (m_AFC.m_Max - m_AFC.m_Min) * 100;
|
|||
|
|
m_Lock = (m_Lock > m_LockTh);
|
|||
|
|
// VCO
|
|||
|
|
// <20>ʑ<EFBFBD><CA91><EFBFBD><EFBFBD>r
|
|||
|
|
EPHASE(P_DEMVCO);
|
|||
|
|
m_err = m_VCO.Do(m_out) * d;
|
|||
|
|
EPHASE(P_DEMOUT);
|
|||
|
|
d = m_OutLPF.Do(m_out);
|
|||
|
|
EPHASE(P_NULL);
|
|||
|
|
if( m_Type == MODE_RTTY ) d = -d;
|
|||
|
|
return d * 32768.0;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return 0;
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
int __fastcall CDEMFSK::Do(double d, BOOL fSQ, BOOL fATC)
|
|||
|
|
{
|
|||
|
|
if( m_fMFSK ){
|
|||
|
|
if( m_pBPF ){
|
|||
|
|
d = m_pBPF->Do(m_inBPF.GetHP());
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
d = m_inBPF.Do(d);
|
|||
|
|
}
|
|||
|
|
m_d = d;
|
|||
|
|
m_AGC.Do(d);
|
|||
|
|
return m_pMFSK->Do(m_pMFSK->m_Phase.Do(d), fSQ);
|
|||
|
|
}
|
|||
|
|
else if( m_fQPSK ){
|
|||
|
|
Do(d);
|
|||
|
|
int r = m_DecPSK.Do(m_d, fSQ, fATC);
|
|||
|
|
if( r ){
|
|||
|
|
m_Decode.m_dTmg2 = m_DecPSK.GetClockError();
|
|||
|
|
if( m_fEnableAFC ){
|
|||
|
|
d = m_CarrierQPSK - m_DecPSK.m_NextCarrierFreq;
|
|||
|
|
if( fabs(d) >= (m_Speed / (3.0 * PI)) ){
|
|||
|
|
m_RxFreq = m_CarrierQPSK;
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
m_RxFreq = m_DecPSK.m_NextCarrierFreq;
|
|||
|
|
}
|
|||
|
|
if( m_fAFC ){
|
|||
|
|
m_CarrierFreq = m_RxFreq;
|
|||
|
|
m_DecPSK.SetCarrierFreq(m_CarrierFreq);
|
|||
|
|
m_AFC.SetTone(m_CarrierFreq);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return r;
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
return m_Decode.Do(Do(d), fSQ && m_Lock, fATC );
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
int __fastcall CDEMFSK::GetData(void)
|
|||
|
|
{
|
|||
|
|
if( m_fMFSK ){
|
|||
|
|
if( !m_pMFSK ) return 0;
|
|||
|
|
return m_pMFSK->GetData();
|
|||
|
|
}
|
|||
|
|
else if( m_fQPSK ){
|
|||
|
|
return m_DecPSK.GetData();
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
return m_Decode.GetData();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
int __fastcall CDEMFSK::GetTmg(void)
|
|||
|
|
{
|
|||
|
|
if( m_fMFSK ){
|
|||
|
|
return m_pMFSK->GetTmg() ? 1 : -1;
|
|||
|
|
}
|
|||
|
|
else if( m_fQPSK ){
|
|||
|
|
return m_DecPSK.GetTmg() ? 1 : -1;
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
return m_Decode.GetTmg();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
int __fastcall CDEMFSK::GetTmgLock(void)
|
|||
|
|
{
|
|||
|
|
if( m_fMFSK ){
|
|||
|
|
return m_pMFSK->GetTmgLock();
|
|||
|
|
}
|
|||
|
|
else if( m_fQPSK ){
|
|||
|
|
return m_DecPSK.GetTmgLock();
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
return m_Decode.m_Lock;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
int __fastcall CDEMFSK::GetS(void)
|
|||
|
|
{
|
|||
|
|
if( m_fMFSK ){
|
|||
|
|
return (m_pMFSK->GetS() - (m_MFSK_TONES/2)) * 32768/m_MFSK_TONES;
|
|||
|
|
}
|
|||
|
|
else if( m_fQPSK ){
|
|||
|
|
return m_DecPSK.GetS();
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
return m_Decode.m_s ? 16384.0 : -16384.0;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
void __fastcall CDEMFSK::ResetMFSK(void)
|
|||
|
|
{
|
|||
|
|
if( m_pMFSK ){
|
|||
|
|
m_pMFSK->Reset();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
void __fastcall CDEMFSK::ResetMeasMFSK(void)
|
|||
|
|
{
|
|||
|
|
if( m_pMFSK ){
|
|||
|
|
m_pMFSK->ResetMeas();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
BOOL __fastcall CDEMFSK::GetSyncState(void)
|
|||
|
|
{
|
|||
|
|
if( m_fMFSK ){
|
|||
|
|
if( !m_pMFSK ) return FALSE;
|
|||
|
|
return m_pMFSK->GetSyncState();
|
|||
|
|
}
|
|||
|
|
else if( m_fQPSK ){
|
|||
|
|
return m_DecPSK.GetSyncState();
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
return m_Decode.GetSyncState();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
int __fastcall CDEMFSK::GetClockError(void)
|
|||
|
|
{
|
|||
|
|
if( m_fMFSK ){
|
|||
|
|
if( !m_pMFSK ) return 0;
|
|||
|
|
return m_pMFSK->GetClockError();
|
|||
|
|
}
|
|||
|
|
else if( m_fQPSK ){
|
|||
|
|
return m_DecPSK.GetClockError();
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
double d = m_Decode.m_dTmg2;
|
|||
|
|
if( d >= 0 ){d += 0.5;} else { d -= 0.5; }
|
|||
|
|
return d;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
void __fastcall CDEMFSK::SetTmg(int ppm)
|
|||
|
|
{
|
|||
|
|
if( m_fMFSK ){
|
|||
|
|
m_pMFSK->SetTmg(ppm);
|
|||
|
|
}
|
|||
|
|
else if( m_fQPSK ){
|
|||
|
|
m_DecPSK.SetTmg(ppm);
|
|||
|
|
}
|
|||
|
|
else if( !IsRTTY(m_Type) ){
|
|||
|
|
m_Decode.SetTmg(ppm);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
#if MEASIMD
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
void __fastcall CDEMFSK::CalcIMD(void)
|
|||
|
|
{
|
|||
|
|
if( m_max > m_min ){
|
|||
|
|
m_amax = m_max > 0.0 ? sqrt(m_max) : 0.1;
|
|||
|
|
m_amin = m_min > 0.0 ? sqrt(m_min) : 0.1;
|
|||
|
|
DoAvg(m_imd, 20.0*log10(m_amax / m_amin), 0.25);
|
|||
|
|
Application->MainForm->Caption = m_imd;
|
|||
|
|
}
|
|||
|
|
m_max = 0.0;
|
|||
|
|
m_min = 65536.0;
|
|||
|
|
}
|
|||
|
|
#endif
|
|||
|
|
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
__fastcall CMODFSK::CMODFSK()
|
|||
|
|
{
|
|||
|
|
m_MFSK_TYPE = typMFSK16;
|
|||
|
|
m_MFSK_TONES = 16;
|
|||
|
|
m_MFSK_SPEED = 15.625;
|
|||
|
|
m_MFSK_BW = (m_MFSK_SPEED * (m_MFSK_TONES-1));
|
|||
|
|
|
|||
|
|
m_MFSK_K = 1.0 / double(m_MFSK_TONES);
|
|||
|
|
m_fMFSK = FALSE;
|
|||
|
|
|
|||
|
|
m_fQPSK = FALSE;
|
|||
|
|
m_fLSB = FALSE;
|
|||
|
|
m_Type = 0;
|
|||
|
|
m_Speed = SPEED;
|
|||
|
|
m_CWSpeed = 20;
|
|||
|
|
m_SampleFreq = SAMPFREQ;
|
|||
|
|
m_CarrierFreq = CARRIERFREQ;
|
|||
|
|
m_Encode.SetVCO(&m_Carrier);
|
|||
|
|
m_OutVol = 1;
|
|||
|
|
m_RTTYShift = 170.0;
|
|||
|
|
Create();
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
__fastcall CMODFSK::~CMODFSK()
|
|||
|
|
{
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
void __fastcall CMODFSK::SetMFSKType(int type)
|
|||
|
|
{
|
|||
|
|
m_MFSK_TYPE = type;
|
|||
|
|
MFSK_SetPara(type, &m_MFSK_TONES, &m_MFSK_SPEED, NULL);
|
|||
|
|
m_MFSK_BW = (m_MFSK_SPEED * (m_MFSK_TONES-1));
|
|||
|
|
m_MFSK_K = 1.0 / double(m_MFSK_TONES);
|
|||
|
|
m_Encode.SetMFSKType(type);
|
|||
|
|
SetCarrierFreq(m_CarrierFreq);
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
void __fastcall CMODFSK::Reset(void)
|
|||
|
|
{
|
|||
|
|
SetCWSpeed(m_CWSpeed);
|
|||
|
|
m_OutVol = 1;
|
|||
|
|
m_AMPCW.Reset();
|
|||
|
|
m_AMPSIG.Reset();
|
|||
|
|
m_BPF.Clear();
|
|||
|
|
|
|||
|
|
m_Sym.r = 1;
|
|||
|
|
m_Sym.j = 0;
|
|||
|
|
m_PrevSym = m_Sym;
|
|||
|
|
m_SHDATA = 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
void __fastcall CMODFSK::CreateGMSK(void)
|
|||
|
|
{
|
|||
|
|
// Gaussian<61><6E><EFBFBD><EFBFBD><EFBFBD>̃e<CC83>[<5B>u<EFBFBD><75><EFBFBD><EFBFBD><EFBFBD>쐬<EFBFBD><EC90AC><EFBFBD><EFBFBD> (1.0 to -1.0)
|
|||
|
|
int i;
|
|||
|
|
double w = m_SampleFreq/m_Speed;
|
|||
|
|
double BT = 1.0;
|
|||
|
|
double LN2 = sqrt(2.0/log(2.0));
|
|||
|
|
double LN2P = sqrt(2.0*PI/log(2.0));
|
|||
|
|
double cd = 0;
|
|||
|
|
for( i = 0; i < MODTABLEMAX; i++ ){
|
|||
|
|
// double d = LN2 * PI * BT * double(i)/w;
|
|||
|
|
// d = BT * exp(-(d * d));
|
|||
|
|
// d = 1.0 - d;
|
|||
|
|
double d = LN2 * PI * BT * double(i-w*0.5)/w;
|
|||
|
|
d = LN2P * BT * exp(-(d * d));
|
|||
|
|
cd += (d / w);
|
|||
|
|
// d = 0 to 1
|
|||
|
|
m_Tbl[MOD_Z2P][i] = cd; // 0 to 1
|
|||
|
|
m_Tbl[MOD_Z2M][i] = -cd; // 0 to -1
|
|||
|
|
m_Tbl[MOD_P2M][i] = 1.0 - cd * 2; // 1 to -1
|
|||
|
|
m_Tbl[MOD_M2P][i] = cd * 2 - 1.0; // -1 to 1
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
void __fastcall CMODFSK::CreatePSK(void)
|
|||
|
|
{
|
|||
|
|
// Cos<6F><73><EFBFBD><EFBFBD><EFBFBD>̃e<CC83>[<5B>u<EFBFBD><75><EFBFBD><EFBFBD><EFBFBD>쐬<EFBFBD><EC90AC><EFBFBD><EFBFBD> (1.0 to -1.0)
|
|||
|
|
int i;
|
|||
|
|
if( m_fQPSK ){
|
|||
|
|
double k = PI * m_Speed / m_SampleFreq;
|
|||
|
|
for( i = 0; i < MODTABLEMAX; i++ ){
|
|||
|
|
double cd = cos(double(i)*k) * 0.5 + 0.5;
|
|||
|
|
m_Tbl[MOD_Z2P][i] = -cd; // 0 to 1
|
|||
|
|
m_Tbl[MOD_Z2M][i] = cd; // 0 to -1
|
|||
|
|
m_Tbl[MOD_P2M][i] = cd; // 1 to -1
|
|||
|
|
m_Tbl[MOD_M2P][i] = -cd; // -1 to 1
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
double k = PI * m_Speed / m_SampleFreq;
|
|||
|
|
for( i = 0; i < MODTABLEMAX; i++ ){
|
|||
|
|
double cd = cos(double(i)*k);
|
|||
|
|
if( i >= (m_SampleFreq / m_Speed) ) cd = -1.0;
|
|||
|
|
m_Tbl[MOD_Z2P][i] = -cd; // 0 to 1
|
|||
|
|
m_Tbl[MOD_Z2M][i] = cd; // 0 to -1
|
|||
|
|
m_Tbl[MOD_P2M][i] = cd; // 1 to -1
|
|||
|
|
m_Tbl[MOD_M2P][i] = -cd; // -1 to 1
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
void __fastcall CMODFSK::CreateRTTY(void)
|
|||
|
|
{
|
|||
|
|
#if 0
|
|||
|
|
// Gaussian<61><6E><EFBFBD><EFBFBD><EFBFBD>̃e<CC83>[<5B>u<EFBFBD><75><EFBFBD><EFBFBD><EFBFBD>쐬<EFBFBD><EC90AC><EFBFBD><EFBFBD> (1.0 to -1.0)
|
|||
|
|
int i;
|
|||
|
|
double w = m_SampleFreq/m_Speed;
|
|||
|
|
double BT = 0.5;
|
|||
|
|
double LN2 = sqrt(2.0/log(2.0));
|
|||
|
|
double LN2P = sqrt(2.0*PI/log(2.0));
|
|||
|
|
double cd = 0;
|
|||
|
|
for( i = 0; i < MODTABLEMAX; i++ ){
|
|||
|
|
// double d = LN2 * PI * BT * double(i)/w;
|
|||
|
|
// d = BT * exp(-(d * d));
|
|||
|
|
// d = 1.0 - d;
|
|||
|
|
double d = LN2 * PI * BT * double(i-w*0.5)/w;
|
|||
|
|
d = LN2P * BT * exp(-(d * d));
|
|||
|
|
cd += (d / w);
|
|||
|
|
// d = 0 to 1
|
|||
|
|
m_Tbl[MOD_Z2P][i] = cd; // 0 to 1
|
|||
|
|
m_Tbl[MOD_Z2M][i] = -cd; // 0 to -1
|
|||
|
|
m_Tbl[MOD_P2M][i] = 1.0 - cd * 2; // 1 to -1
|
|||
|
|
m_Tbl[MOD_M2P][i] = cd * 2 - 1.0; // -1 to 1
|
|||
|
|
}
|
|||
|
|
#else
|
|||
|
|
int i;
|
|||
|
|
for( i = 0; i < MODTABLEMAX; i++ ){
|
|||
|
|
m_Tbl[MOD_Z2P][i] = 1; // 0 to 1
|
|||
|
|
m_Tbl[MOD_Z2M][i] = -1; // 0 to -1
|
|||
|
|
m_Tbl[MOD_P2M][i] = -1; // 1 to -1
|
|||
|
|
m_Tbl[MOD_M2P][i] = 1; // -1 to 1
|
|||
|
|
}
|
|||
|
|
#endif
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
void __fastcall CMODFSK::Create(void)
|
|||
|
|
{
|
|||
|
|
m_fMFSK = IsMFSK(m_Type);
|
|||
|
|
m_fQPSK = IsQPSK(m_Type);
|
|||
|
|
m_Encode.SetType(m_Type);
|
|||
|
|
if( m_fMFSK ){
|
|||
|
|
m_Encode.SetMFSKType(m_MFSK_TYPE);
|
|||
|
|
}
|
|||
|
|
m_Sym.r = 1;
|
|||
|
|
m_Sym.j = 0;
|
|||
|
|
m_PrevSym = m_Sym;
|
|||
|
|
m_s = 0;
|
|||
|
|
m_Carrier.SetSampleFreq(m_SampleFreq);
|
|||
|
|
|
|||
|
|
SetCarrierFreq(m_CarrierFreq);
|
|||
|
|
m_Encode.SetSampleFreq(m_SampleFreq);
|
|||
|
|
m_Encode.SetSpeed(m_Speed);
|
|||
|
|
SetCWSpeed(m_CWSpeed);
|
|||
|
|
m_AMPSIG.SetMax(m_SampleFreq/m_Speed);
|
|||
|
|
|
|||
|
|
switch(m_Type){
|
|||
|
|
case MODE_GMSK:
|
|||
|
|
case MODE_FSK:
|
|||
|
|
case MODE_FSKW:
|
|||
|
|
m_Encode.m_fTWO = FALSE;
|
|||
|
|
CreateGMSK();
|
|||
|
|
break;
|
|||
|
|
case MODE_BPSK:
|
|||
|
|
m_Encode.m_fTWO = FALSE;
|
|||
|
|
CreatePSK();
|
|||
|
|
break;
|
|||
|
|
case MODE_N_BPSK:
|
|||
|
|
case MODE_qpsk_L:
|
|||
|
|
case MODE_qpsk_U:
|
|||
|
|
m_Encode.m_fTWO = TRUE;
|
|||
|
|
CreatePSK();
|
|||
|
|
m_fLSB = (m_Type == MODE_qpsk_L);
|
|||
|
|
break;
|
|||
|
|
case MODE_RTTY:
|
|||
|
|
case MODE_U_RTTY:
|
|||
|
|
m_Encode.m_fTWO = FALSE;
|
|||
|
|
if( m_Speed >= m_RTTYShift ){
|
|||
|
|
CreateGMSK();
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
CreateRTTY();
|
|||
|
|
}
|
|||
|
|
break;
|
|||
|
|
case MODE_mfsk_L:
|
|||
|
|
case MODE_mfsk_U:
|
|||
|
|
m_Encode.m_fTWO = TRUE;
|
|||
|
|
CreateRTTY(); // dummy
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
m_pTbl = NULL;
|
|||
|
|
m_d = 0.0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
void __fastcall CMODFSK::SetCWSpeed(int d)
|
|||
|
|
{
|
|||
|
|
m_CWSpeed = d;
|
|||
|
|
int dCW = m_SampleFreq/m_CWSpeed;
|
|||
|
|
if( dCW < 2 ) dCW = 2;
|
|||
|
|
m_AMPCW.SetMax(dCW*0.25);
|
|||
|
|
m_Encode.SetCW(d);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
void __fastcall CMODFSK::SetCarrierFreq(double f)
|
|||
|
|
{
|
|||
|
|
m_CarrierFreq = f;
|
|||
|
|
m_Carrier.SetFreeFreq(m_CarrierFreq);
|
|||
|
|
switch(m_Type){
|
|||
|
|
case MODE_qpsk_L:
|
|||
|
|
case MODE_qpsk_U:
|
|||
|
|
case MODE_BPSK:
|
|||
|
|
case MODE_N_BPSK:
|
|||
|
|
case MODE_GMSK:
|
|||
|
|
m_Carrier.SetGain((m_Speed * 0.5) * 0.5); // fm = 0.5
|
|||
|
|
break;
|
|||
|
|
case MODE_FSK:
|
|||
|
|
m_Carrier.SetGain((m_Speed * 0.5) * 1.0); // fm = 1.0
|
|||
|
|
break;
|
|||
|
|
case MODE_FSKW:
|
|||
|
|
case MODE_RTTY:
|
|||
|
|
case MODE_U_RTTY:
|
|||
|
|
m_Carrier.SetGain(m_RTTYShift * 0.5);
|
|||
|
|
break;
|
|||
|
|
case MODE_mfsk_L:
|
|||
|
|
// m_Carrier.SetGain(-250);
|
|||
|
|
m_Carrier.SetGain(-m_MFSK_SPEED * m_MFSK_TONES);
|
|||
|
|
if( sys.m_MFSK_Center ){
|
|||
|
|
m_Carrier.SetFreeFreq(m_CarrierFreq+m_MFSK_BW*0.5);
|
|||
|
|
}
|
|||
|
|
break;
|
|||
|
|
case MODE_mfsk_U:
|
|||
|
|
// m_Carrier.SetGain(250);
|
|||
|
|
m_Carrier.SetGain(m_MFSK_SPEED * m_MFSK_TONES);
|
|||
|
|
if( sys.m_MFSK_Center ){
|
|||
|
|
m_Carrier.SetFreeFreq(m_CarrierFreq-m_MFSK_BW*0.5);
|
|||
|
|
}
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
double fl, fh;
|
|||
|
|
int fHigh = (m_SampleFreq >= 15000.0);
|
|||
|
|
int type = ffBPF;
|
|||
|
|
double dATT = 60;
|
|||
|
|
if( fHigh ) dATT -= ((m_SampleFreq - 15000.0)/1750);
|
|||
|
|
if( Is170(m_Type) ){
|
|||
|
|
double hw = m_RTTYShift * 0.5;
|
|||
|
|
fl = m_CarrierFreq - hw - (fHigh ? (m_SampleFreq*0.1) : 200);
|
|||
|
|
fh = m_CarrierFreq + hw + (fHigh ? (m_SampleFreq*0.1) : 200);
|
|||
|
|
}
|
|||
|
|
else if( m_fMFSK ){
|
|||
|
|
double hw = m_MFSK_SPEED;
|
|||
|
|
if( m_Type == MODE_mfsk_U ){
|
|||
|
|
fl = m_CarrierFreq - hw - (fHigh ? (m_SampleFreq*0.1) : 200);
|
|||
|
|
fh = m_CarrierFreq + m_MFSK_BW + hw + (fHigh ? (m_SampleFreq*0.1) : 200);
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
fl = m_CarrierFreq - m_MFSK_BW - hw - (fHigh ? (m_SampleFreq*0.1) : 200);
|
|||
|
|
fh = m_CarrierFreq + hw + (fHigh ? (m_SampleFreq*0.1) : 200);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
fl = m_CarrierFreq-m_Speed - (fHigh ? (m_SampleFreq*0.1) : 200);
|
|||
|
|
fh = m_CarrierFreq+m_Speed + (fHigh ? (m_SampleFreq*0.1) : 200);
|
|||
|
|
}
|
|||
|
|
if( fl < (fHigh ? 800 : 200) ){
|
|||
|
|
type = ffLPF;
|
|||
|
|
fl = fh;
|
|||
|
|
}
|
|||
|
|
m_BPF.Create(24, type, m_SampleFreq, fl, fh, dATT, 1.0);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//--------------------------------------------------------
|
|||
|
|
double __fastcall CMODFSK::Do(void)
|
|||
|
|
{
|
|||
|
|
int s = m_Encode.Do();
|
|||
|
|
if( (s == 128)||(s == 129) ){
|
|||
|
|
s -= 128; // s = 0 or 1
|
|||
|
|
return m_BPF.Do(m_Carrier.Do() * m_AMPCW.Do(s));
|
|||
|
|
}
|
|||
|
|
else if( m_fMFSK ){
|
|||
|
|
return m_BPF.Do(m_Carrier.Do(double(s)*m_MFSK_K)*m_AMPSIG.Do(m_OutVol));
|
|||
|
|
}
|
|||
|
|
else if( m_fQPSK ){
|
|||
|
|
if( !m_Encode.m_Cnt ){
|
|||
|
|
s = m_Encode.m_outbit;
|
|||
|
|
m_PrevSym = m_Sym;
|
|||
|
|
if( s == -1 ){
|
|||
|
|
s = 0;
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
m_SHDATA = m_SHDATA << 1;
|
|||
|
|
if( s > 0 ) m_SHDATA |= 1;
|
|||
|
|
|
|||
|
|
s = tQPSK_Viterbi[m_SHDATA & 0x1f];
|
|||
|
|
if(m_fLSB){
|
|||
|
|
switch(s){ // <20><><EFBFBD>]<5D><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>t<EFBFBD>]
|
|||
|
|
case 1:
|
|||
|
|
s = 3;
|
|||
|
|
break;
|
|||
|
|
case 3:
|
|||
|
|
s = 1;
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
switch(s){ // <20><><EFBFBD><EFBFBD><EFBFBD>]
|
|||
|
|
case 0: // 0
|
|||
|
|
m_Sym.r = 1.0;
|
|||
|
|
m_Sym.j = 0.0;
|
|||
|
|
break;
|
|||
|
|
case 1: // 270
|
|||
|
|
m_Sym.r = 0.0;
|
|||
|
|
m_Sym.j = -1.0;
|
|||
|
|
break;
|
|||
|
|
case 2: // 180
|
|||
|
|
m_Sym.r = -1.0;
|
|||
|
|
m_Sym.j = 0.0;
|
|||
|
|
break;
|
|||
|
|
case 3: // 90
|
|||
|
|
m_Sym.r = 0.0;
|
|||
|
|
m_Sym.j = 1.0;
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
m_Sym *= m_PrevSym;
|
|||
|
|
}
|
|||
|
|
double sh = m_Tbl[MOD_Z2M][m_Encode.m_Cnt];
|
|||
|
|
double iv = sh * m_PrevSym.r + (1.0 - sh) * m_Sym.r;
|
|||
|
|
double qv = sh * m_PrevSym.j + (1.0 - sh) * m_Sym.j;
|
|||
|
|
|
|||
|
|
double d = (m_Carrier.Do() * qv + m_Carrier.DoCos() * iv);
|
|||
|
|
return m_BPF.Do(d*m_AMPSIG.Do(m_OutVol));
|
|||
|
|
}
|
|||
|
|
int cnt = m_Encode.m_Cnt;
|
|||
|
|
if( !cnt ){
|
|||
|
|
if( s > 0 ){
|
|||
|
|
if( m_s > 0 ){ // 1 to 1
|
|||
|
|
m_d = 1.0; m_pTbl = NULL;
|
|||
|
|
}
|
|||
|
|
else if( m_s < 0 ){ // -1 to 1
|
|||
|
|
m_pTbl = m_Tbl[MOD_M2P];
|
|||
|
|
}
|
|||
|
|
else { // 0 to 1
|
|||
|
|
m_pTbl = m_Tbl[MOD_Z2P];
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else if( s < 0 ){
|
|||
|
|
if( m_s > 0 ){ // 1 to -1
|
|||
|
|
m_pTbl = m_Tbl[MOD_P2M];
|
|||
|
|
}
|
|||
|
|
else if( m_s < 0 ){ // -1 to -1
|
|||
|
|
m_d = -1; m_pTbl = NULL;
|
|||
|
|
}
|
|||
|
|
else { // 0 to -1
|
|||
|
|
m_pTbl = m_Tbl[MOD_Z2M];
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else { // 0
|
|||
|
|
m_d = 0; m_pTbl = NULL;
|
|||
|
|
}
|
|||
|
|
m_s = s;
|
|||
|
|
}
|
|||
|
|
if( cnt > MODTABLEMAX ) cnt = MODTABLEMAX - 1;
|
|||
|
|
if( m_pTbl ){
|
|||
|
|
m_d = m_pTbl[cnt];
|
|||
|
|
}
|
|||
|
|
double d;
|
|||
|
|
switch(m_Type){
|
|||
|
|
case MODE_GMSK: // <20><><EFBFBD>g<EFBFBD><67><EFBFBD>ϒ<EFBFBD>
|
|||
|
|
case MODE_FSK:
|
|||
|
|
case MODE_FSKW:
|
|||
|
|
case MODE_RTTY:
|
|||
|
|
d = m_Carrier.Do(m_d);
|
|||
|
|
break;
|
|||
|
|
case MODE_BPSK:
|
|||
|
|
case MODE_N_BPSK: // <20><><EFBFBD><EFBFBD><EFBFBD>ϒ<EFBFBD>
|
|||
|
|
d = -m_d;
|
|||
|
|
d = (m_Carrier.Do() * m_d + m_Carrier.DoCos() * d) * PSK_OUTFAC;
|
|||
|
|
break;
|
|||
|
|
case MODE_U_RTTY:
|
|||
|
|
d = m_Carrier.Do(-m_d);
|
|||
|
|
break;
|
|||
|
|
default:
|
|||
|
|
d = 0.0;
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
return m_BPF.Do(d*m_AMPSIG.Do(m_OutVol));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
double __fastcall CMODFSK::DoCarrier(void)
|
|||
|
|
{
|
|||
|
|
return m_BPF.Do(m_Carrier.Do()*m_AMPSIG.Do(m_OutVol));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//--------------------------------------------------------
|
|||
|
|
__fastcall CDECFSK::CDECFSK()
|
|||
|
|
{
|
|||
|
|
m_Tmg = 0;
|
|||
|
|
m_cMode = 0;
|
|||
|
|
m_SampleFreq = SAMPFREQ;
|
|||
|
|
// m_SampleFreq = 11100;
|
|||
|
|
m_Speed = SPEED;
|
|||
|
|
m_Lock = 0;
|
|||
|
|
m_dAdj = 0;
|
|||
|
|
m_dTmg3 = 0;
|
|||
|
|
m_dTmg2 = 0;
|
|||
|
|
m_dTmg = 0;
|
|||
|
|
m_fATC = TRUE;
|
|||
|
|
Create();
|
|||
|
|
m_T = 0;
|
|||
|
|
m_T2 = 0;
|
|||
|
|
m_T3 = 0;
|
|||
|
|
m_cBWave = 15;
|
|||
|
|
m_ATCSpeed = 0;
|
|||
|
|
m_ATCLimit = 25000;
|
|||
|
|
|
|||
|
|
m_ATCCounter = 0;
|
|||
|
|
m_Type = MODE_GMSK;
|
|||
|
|
m_AvgRTTY.Create(48);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#define INI_T2 64
|
|||
|
|
#define LPFA 20
|
|||
|
|
#define LPFB 16
|
|||
|
|
void __fastcall CDECFSK::Create(void)
|
|||
|
|
{
|
|||
|
|
m_dBTW = m_dTW = m_SampleFreq / m_Speed;
|
|||
|
|
SetATCLimit(m_ATCLimit);
|
|||
|
|
SetTmg(m_dAdj);
|
|||
|
|
m_LPF.Create(LPFA*m_SampleFreq/11025);
|
|||
|
|
m_LPFI.Create(LPFB*m_SampleFreq/11025);
|
|||
|
|
m_cMode = 0;
|
|||
|
|
for( int i = 0; i < 16; i++ ){
|
|||
|
|
m_LPF.Do(0);
|
|||
|
|
m_LPFI.Do(0);
|
|||
|
|
}
|
|||
|
|
m_GainA = 60.0 / m_Speed;
|
|||
|
|
SetATCSpeed(m_ATCSpeed);
|
|||
|
|
m_dNow = 0;
|
|||
|
|
m_dNext = m_dTW;
|
|||
|
|
m_dFree = m_dTW;
|
|||
|
|
m_T = 0;
|
|||
|
|
m_T2 = INI_T2;
|
|||
|
|
m_T3 = 0;
|
|||
|
|
m_Threshold = 128.0;
|
|||
|
|
m_A = 0;
|
|||
|
|
if( m_Speed >= 70.0 ) m_Threshold *= 0.7;
|
|||
|
|
m_a = 0;
|
|||
|
|
|
|||
|
|
m_ATCCounter = 0;
|
|||
|
|
m_ATCLimitH = 32 * m_SampleFreq / m_Speed;
|
|||
|
|
m_ATCLimitL = 0.5 * m_SampleFreq / m_Speed;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void __fastcall CDECFSK::SetATCSpeed(int atcspeed)
|
|||
|
|
{
|
|||
|
|
m_ATCSpeed = atcspeed;
|
|||
|
|
// m_GainB = 0.002 * 60.0 / m_Speed;
|
|||
|
|
m_GainB = 0.002 * 60.0 / 31.25;
|
|||
|
|
if( m_ATCSpeed ){
|
|||
|
|
m_GainB *= ((m_ATCSpeed * 0.5) + 1.0);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void __fastcall CDECFSK::SetATCLimit(int atclimit)
|
|||
|
|
{
|
|||
|
|
m_ATCLimit = atclimit;
|
|||
|
|
double d = double(atclimit) * 1.0e-6;
|
|||
|
|
m_dBTWL = m_dBTW * (1.0-d);
|
|||
|
|
m_dBTWH = m_dBTW * (1.0+d);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void __fastcall CDECFSK::ClearLPF(void)
|
|||
|
|
{
|
|||
|
|
for( int i = 0; i < 16; i++ ){
|
|||
|
|
m_LPF.Do(0);
|
|||
|
|
m_LPFI.Do(0);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void __fastcall CDECFSK::Reset(void)
|
|||
|
|
{
|
|||
|
|
m_dTW = m_SampleFreq / m_Speed;
|
|||
|
|
m_dTWH = m_dTW * 0.5;
|
|||
|
|
m_dNow = 0;
|
|||
|
|
m_dNext = m_dTW;
|
|||
|
|
m_dFree = m_dTW;
|
|||
|
|
m_T = 0;
|
|||
|
|
ClearLPF();
|
|||
|
|
m_T2 = INI_T2;
|
|||
|
|
m_T3 = 0;
|
|||
|
|
|
|||
|
|
m_dTmg3 = 0;
|
|||
|
|
m_dTmg2 = 0;
|
|||
|
|
m_dTmg = 0;
|
|||
|
|
|
|||
|
|
m_ATCCounter = 0;
|
|||
|
|
m_ATCLimitH = 32 * m_SampleFreq / m_Speed;
|
|||
|
|
m_ATCLimitL = 0.5 * m_SampleFreq / m_Speed;
|
|||
|
|
|
|||
|
|
m_fSync = FALSE;
|
|||
|
|
m_BAUDOT.ClearRX();
|
|||
|
|
|
|||
|
|
m_fMeasClock = FALSE;
|
|||
|
|
m_MeasError = m_MeasClock = m_MeasCounter = 0;
|
|||
|
|
m_Meas1st = TRUE;
|
|||
|
|
m_AvgRTTY.Reset();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void __fastcall CDECFSK::SetTmg(int ppm)
|
|||
|
|
{
|
|||
|
|
if( (ppm < -50000) || (ppm > 50000) ) return;
|
|||
|
|
|
|||
|
|
m_dAdj = ppm;
|
|||
|
|
m_dTW = m_SampleFreq / m_Speed;
|
|||
|
|
m_dTW += m_dTW * m_dAdj * 1.0e-6;
|
|||
|
|
// m_dBTW = m_dTW;
|
|||
|
|
m_dTWH = m_dTW * 0.5;
|
|||
|
|
m_T2 = INI_T2;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void __fastcall CDECFSK::SetMeasClock(BOOL f)
|
|||
|
|
{
|
|||
|
|
if( IsRTTY(m_Type) ) return;
|
|||
|
|
|
|||
|
|
m_fMeasClock = f;
|
|||
|
|
if( !f ) m_MeasClock = m_MeasCounter = 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
BOOL __fastcall CDECFSK::GetSyncState(void)
|
|||
|
|
{
|
|||
|
|
if( IsRTTY(m_Type) ){
|
|||
|
|
return m_fSync;
|
|||
|
|
}
|
|||
|
|
else if( m_T && (m_T3 > 16) ){
|
|||
|
|
return (fabs(m_dTmg) >= (0.2*60.0/m_Speed)) ? FALSE : TRUE;
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
return FALSE;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
BOOL __fastcall CDECFSK::Do(double d, BOOL sq, BOOL fATC)
|
|||
|
|
{
|
|||
|
|
BOOL r = FALSE;
|
|||
|
|
int s = m_s;
|
|||
|
|
if( ABS(d) > m_Threshold ){
|
|||
|
|
s = (d > 0) ? 1 : 0;
|
|||
|
|
}
|
|||
|
|
if( IsRTTY(m_Type) ){
|
|||
|
|
return DoBAUDOT(s, sq);
|
|||
|
|
}
|
|||
|
|
int u;
|
|||
|
|
m_ATCCounter++;
|
|||
|
|
m_dNow += 1.0;
|
|||
|
|
if( m_dNow >= m_dFree ) m_dFree += m_dTW;
|
|||
|
|
if( s != m_s ){
|
|||
|
|
m_s = s;
|
|||
|
|
if( (m_ATCCounter >= m_ATCLimitL) && (m_ATCCounter < m_ATCLimitH) ){
|
|||
|
|
BOOL f1st = sq && !m_T;
|
|||
|
|
d = m_dFree - m_dNow;
|
|||
|
|
if( d >= m_dTWH ) d -= m_dTW;
|
|||
|
|
d /= m_dBTW;
|
|||
|
|
if( (m_dTmg >= 0.3) && (d < -0.1) ) d += 1.0;
|
|||
|
|
if( (m_dTmg < -0.3) && (d > 0.1) ) d -= 1.0;
|
|||
|
|
if( !sq ) d *= 0.1;
|
|||
|
|
if( sq && !m_T ){ // <20>ŏ<EFBFBD><C58F><EFBFBD>1<EFBFBD><31><EFBFBD><EFBFBD>
|
|||
|
|
m_dFree -= d * m_dBTW;
|
|||
|
|
}
|
|||
|
|
d = m_LPF.Do(d * m_GainA);
|
|||
|
|
m_dTmg3 = d - m_A;
|
|||
|
|
m_A = d;
|
|||
|
|
m_dTmg = d;
|
|||
|
|
if( m_T ){
|
|||
|
|
if( m_T3 < 256 ){
|
|||
|
|
d *= 2.0;
|
|||
|
|
}
|
|||
|
|
else if( !fATC ){
|
|||
|
|
d *= 0.5;
|
|||
|
|
}
|
|||
|
|
// if( !fATC ) d *= (m_T3 > 256) ? 0.25 : 2.0;
|
|||
|
|
m_dFree -= d;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if( sq ){
|
|||
|
|
m_T = m_Speed;
|
|||
|
|
m_T3++;
|
|||
|
|
}
|
|||
|
|
else if( !m_T ){
|
|||
|
|
d = (m_dTW - m_dBTW) * 20.0;
|
|||
|
|
m_T2 = INI_T2;
|
|||
|
|
m_T3 = 0;
|
|||
|
|
m_MeasClock = m_MeasCounter = 0;
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
m_T--;
|
|||
|
|
m_MeasClock = m_MeasCounter = 0;
|
|||
|
|
}
|
|||
|
|
d = m_LPFI.Do(d);
|
|||
|
|
if( (!m_T2 && fATC) || !m_T ){
|
|||
|
|
if( m_fATC ){
|
|||
|
|
m_dTW -= d * m_GainB;
|
|||
|
|
if( m_dTW < m_dBTWL ){ m_dTW = m_dBTWL; }
|
|||
|
|
if( m_dTW > m_dBTWH ){ m_dTW = m_dBTWH; }
|
|||
|
|
m_dTWH = m_dTW * 0.5;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else if( m_T2 ){
|
|||
|
|
m_T2--;
|
|||
|
|
}
|
|||
|
|
m_dTmg2 = ((m_dTW / m_dBTW) - 1.0) * 1e6;
|
|||
|
|
if( GetSyncState() ){
|
|||
|
|
m_dNext = m_dFree - m_dTW*0.5;
|
|||
|
|
if( m_dNext > (m_dNow + m_dTW) ){
|
|||
|
|
m_dNext -= m_dTW;
|
|||
|
|
}
|
|||
|
|
if( m_dNext < m_dNow ) m_dNext += m_dTW;
|
|||
|
|
}
|
|||
|
|
else if( f1st ){
|
|||
|
|
m_dNext = m_dNow + m_dTWH;
|
|||
|
|
m_MeasClock = m_MeasCounter = 0;
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
d = m_dNext - m_dNow;
|
|||
|
|
m_dNext = m_dNow + (d + m_dTWH) * 0.5;
|
|||
|
|
// m_dNext = m_dNow + (d * 0.25 + m_dTWH * 0.75);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
m_ATCCounter = 0;
|
|||
|
|
}
|
|||
|
|
if( m_MeasClock ) m_MeasCounter++;
|
|||
|
|
switch(m_cMode){
|
|||
|
|
case 0:
|
|||
|
|
if( m_dNext <= m_dNow ){
|
|||
|
|
m_MeasClock++;
|
|||
|
|
if( m_MeasClock >= 256 ){
|
|||
|
|
if( sq && fATC && !GetSyncState() && m_fMeasClock ){
|
|||
|
|
d = double(m_MeasCounter) / double(m_MeasClock-1);
|
|||
|
|
m_dTW += (d - m_dTW) * 0.5;
|
|||
|
|
if( m_dTW < m_dBTWL ){ m_dTW = m_dBTWL; }
|
|||
|
|
if( m_dTW > m_dBTWH ){ m_dTW = m_dBTWH; }
|
|||
|
|
m_dTWH = m_dTW * 0.5;
|
|||
|
|
}
|
|||
|
|
m_MeasClock = 1;
|
|||
|
|
m_MeasCounter = 0;
|
|||
|
|
}
|
|||
|
|
m_Tmg = !m_Tmg;
|
|||
|
|
m_dNext += m_dTW;
|
|||
|
|
u = (s != m_a) ? 0 : 1;
|
|||
|
|
m_a = s;
|
|||
|
|
m_cData = m_cData << 1;
|
|||
|
|
if( u && sq ){
|
|||
|
|
if( !m_Lock ) m_Tmg = 1;
|
|||
|
|
m_cData = 1;
|
|||
|
|
m_cBCount = 1;
|
|||
|
|
m_cMode++;
|
|||
|
|
m_Lock = TRUE;
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
if( !m_cBCount ){
|
|||
|
|
m_Lock = TRUE;
|
|||
|
|
}
|
|||
|
|
else if( m_cBCount >= m_cBWave ){
|
|||
|
|
m_cBCount = -1;
|
|||
|
|
m_Lock = FALSE;
|
|||
|
|
}
|
|||
|
|
m_cBCount++;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
break;
|
|||
|
|
case 1:
|
|||
|
|
if( m_dNext <= m_dNow ){
|
|||
|
|
m_MeasClock++;
|
|||
|
|
m_Tmg = !m_Tmg;
|
|||
|
|
m_dNext += m_dTW;
|
|||
|
|
u = (s != m_a) ? 0 : 1;
|
|||
|
|
m_a = s;
|
|||
|
|
m_cData = m_cData << 1;
|
|||
|
|
m_cBCount++;
|
|||
|
|
if( u ){
|
|||
|
|
m_cData |= 1;
|
|||
|
|
}
|
|||
|
|
else if( m_cBCount >= 3){
|
|||
|
|
if( !(m_cData & 3) ){
|
|||
|
|
m_Data = g_VariCode.Decode(m_cData >> 2);
|
|||
|
|
r = TRUE;
|
|||
|
|
m_cMode--;
|
|||
|
|
m_Lock = FALSE;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
break;
|
|||
|
|
default:
|
|||
|
|
m_cMode = 0;
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
if( m_dNow >= 1000.0 ){
|
|||
|
|
m_dNow -= 1000.0;
|
|||
|
|
m_dNext -= 1000.0;
|
|||
|
|
m_dFree -= 1000.0;
|
|||
|
|
}
|
|||
|
|
return r;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
BOOL __fastcall CDECFSK::DoBAUDOT(int s, BOOL sq)
|
|||
|
|
{
|
|||
|
|
if( s != m_s ){
|
|||
|
|
m_s = s;
|
|||
|
|
if( sq ){
|
|||
|
|
if( !m_cMode && !s ){
|
|||
|
|
if( m_MeasClock ){
|
|||
|
|
int tw = m_MeasCounter - m_MeasClock;
|
|||
|
|
int stw = m_SampleFreq * 6.5 / m_Speed;
|
|||
|
|
if( tw < stw ){
|
|||
|
|
m_MeasError++;
|
|||
|
|
if( m_MeasError >= 3 ){
|
|||
|
|
m_MeasError = m_MeasCounter = m_MeasClock = 0;
|
|||
|
|
m_AvgRTTY.Reset();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else if( m_AvgRTTY.IsHalf() ){
|
|||
|
|
int atw = m_AvgRTTY.GetAvg();
|
|||
|
|
if( ABS(atw-tw) >= (m_dTW*0.2) ){
|
|||
|
|
m_MeasError++;
|
|||
|
|
if( m_MeasError >= 3 ){
|
|||
|
|
m_MeasError = m_MeasCounter = m_MeasClock = 0;
|
|||
|
|
m_AvgRTTY.Reset();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
m_AvgRTTY.Do(tw);
|
|||
|
|
m_MeasError = 0;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
m_AvgRTTY.Do(tw);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
if( m_Meas1st ){
|
|||
|
|
m_AvgRTTY.Reset();
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
m_MeasClock = m_MeasCounter = 1;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
m_MeasError = m_MeasCounter = m_MeasClock = 0;
|
|||
|
|
m_Meas1st = TRUE;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
BOOL r = FALSE;
|
|||
|
|
m_MeasCounter++;
|
|||
|
|
m_dNow += 1.0;
|
|||
|
|
switch(m_cMode){
|
|||
|
|
case 0: // Start bits?
|
|||
|
|
if( !s && sq ){
|
|||
|
|
m_Lock = TRUE;
|
|||
|
|
m_Tmg = 0;
|
|||
|
|
m_dNext = m_dNow + m_dTW*0.5;
|
|||
|
|
m_cData = 0;
|
|||
|
|
m_cBCount = 0;
|
|||
|
|
m_cMode++;
|
|||
|
|
}
|
|||
|
|
break;
|
|||
|
|
case 1:
|
|||
|
|
if( m_dNext <= m_dNow ){
|
|||
|
|
m_dNext += m_dTW;
|
|||
|
|
m_Tmg = !m_Tmg;
|
|||
|
|
m_cMode++;
|
|||
|
|
}
|
|||
|
|
break;
|
|||
|
|
case 2:
|
|||
|
|
if( m_dNext <= m_dNow ){
|
|||
|
|
m_dNext += m_dTW;
|
|||
|
|
m_Tmg = !m_Tmg;
|
|||
|
|
m_cData = m_cData << 1;
|
|||
|
|
if( s ) m_cData |= 0x01;
|
|||
|
|
m_cBCount++;
|
|||
|
|
if( m_cBCount >= 5 ){
|
|||
|
|
m_cMode++;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
break;
|
|||
|
|
case 3: // Stop bits
|
|||
|
|
if( m_dNext <= m_dNow ){
|
|||
|
|
m_dNext += m_dTW;
|
|||
|
|
m_Tmg = !m_Tmg;
|
|||
|
|
m_fSync = s;
|
|||
|
|
if( s ){
|
|||
|
|
m_Meas1st = FALSE;
|
|||
|
|
r = TRUE;
|
|||
|
|
m_cMode = 0;
|
|||
|
|
m_Data = m_BAUDOT.ConvAscii(m_cData);
|
|||
|
|
}
|
|||
|
|
else { // <20>t<EFBFBD><74><EFBFBD>[<5B>~<7E><><EFBFBD>O<EFBFBD>G<EFBFBD><47><EFBFBD>[
|
|||
|
|
m_cMode++;
|
|||
|
|
m_MeasClock = 0;
|
|||
|
|
m_Data = m_BAUDOT.ConvAscii(m_cData); // added by JE3HHT on Sep.2010
|
|||
|
|
}
|
|||
|
|
m_Lock = FALSE;
|
|||
|
|
}
|
|||
|
|
break;
|
|||
|
|
case 4:
|
|||
|
|
if( m_dNext <= m_dNow ){
|
|||
|
|
m_dNext += m_dTW;
|
|||
|
|
}
|
|||
|
|
if( s ){
|
|||
|
|
m_cMode = 0;
|
|||
|
|
}
|
|||
|
|
break;
|
|||
|
|
default:
|
|||
|
|
m_cMode = 0;
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
if( m_dNow >= 1000.0 ){
|
|||
|
|
m_dNow -= 1000.0;
|
|||
|
|
m_dNext -= 1000.0;
|
|||
|
|
}
|
|||
|
|
return r;
|
|||
|
|
}
|
|||
|
|
//--------------------------------------------------------------------------
|
|||
|
|
void __fastcall DoAvg(float &av, float in, float factor)
|
|||
|
|
{
|
|||
|
|
av = av * (1.0 - factor) + (in * factor);
|
|||
|
|
}
|
|||
|
|
//--------------------------------------------------------------------------
|
|||
|
|
void __fastcall DoAvg(double &av, double in, double factor)
|
|||
|
|
{
|
|||
|
|
av = av * (1.0 - factor) + (in * factor);
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
__fastcall CFAVG::CFAVG()
|
|||
|
|
{
|
|||
|
|
Create(16);
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
void __fastcall CFAVG::Reset(void)
|
|||
|
|
{
|
|||
|
|
m_Cnt = 0;
|
|||
|
|
m_Sum = 0;
|
|||
|
|
m_Avg = 0;
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
void __fastcall CFAVG::Reset(double d)
|
|||
|
|
{
|
|||
|
|
m_Cnt = m_Max;
|
|||
|
|
m_Sum = d * m_Max;
|
|||
|
|
m_Avg = d;
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
void __fastcall CFAVG::Create(int max)
|
|||
|
|
{
|
|||
|
|
m_Max = max;
|
|||
|
|
m_Mul = 1.0 / m_Max;
|
|||
|
|
Reset();
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
double __fastcall CFAVG::DoZ(double d)
|
|||
|
|
{
|
|||
|
|
m_Sum += d;
|
|||
|
|
if( m_Cnt < m_Max ){
|
|||
|
|
m_Cnt++;
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
m_Sum -= m_Avg;
|
|||
|
|
}
|
|||
|
|
m_Avg = m_Sum * m_Mul;
|
|||
|
|
return m_Avg;
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
double __fastcall CFAVG::Do(double d)
|
|||
|
|
{
|
|||
|
|
m_Sum += d;
|
|||
|
|
if( m_Cnt < m_Max ){
|
|||
|
|
m_Cnt++;
|
|||
|
|
m_Avg = m_Sum / m_Cnt;
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
m_Sum -= m_Avg;
|
|||
|
|
m_Avg = m_Sum * m_Mul;
|
|||
|
|
}
|
|||
|
|
return m_Avg;
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
__fastcall CAVG::CAVG()
|
|||
|
|
{
|
|||
|
|
m_Max = 0;
|
|||
|
|
m_pZ = NULL;
|
|||
|
|
m_Sum = 0.0;
|
|||
|
|
m_Avg = 0;
|
|||
|
|
m_Cnt = m_W = 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
__fastcall CAVG::~CAVG()
|
|||
|
|
{
|
|||
|
|
if( m_pZ ) delete m_pZ;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void __fastcall CAVG::Create(int max)
|
|||
|
|
{
|
|||
|
|
if( max == m_Max ) return;
|
|||
|
|
|
|||
|
|
m_Max = max;
|
|||
|
|
if( m_pZ ) delete m_pZ;
|
|||
|
|
m_pZ = new double[max];
|
|||
|
|
Reset();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void __fastcall CAVG::Reset(void)
|
|||
|
|
{
|
|||
|
|
m_Cnt = m_W = 0;
|
|||
|
|
m_Sum = 0.0;
|
|||
|
|
m_Avg = 0.0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void __fastcall CAVG::Reset(double d)
|
|||
|
|
{
|
|||
|
|
if( !m_pZ ) return;
|
|||
|
|
|
|||
|
|
double *dp = m_pZ;
|
|||
|
|
for( int i = 0; i < m_Max; i++ ){
|
|||
|
|
*dp++ = d;
|
|||
|
|
}
|
|||
|
|
m_Avg = d;
|
|||
|
|
m_Sum = d * m_Max;
|
|||
|
|
m_W = 0;
|
|||
|
|
m_Cnt = m_Max;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
double __fastcall CAVG::Do(double d)
|
|||
|
|
{
|
|||
|
|
if( !m_Max ) return d;
|
|||
|
|
|
|||
|
|
double *dp = &m_pZ[m_W];
|
|||
|
|
if( m_Cnt >= m_Max ){
|
|||
|
|
m_Sum -= *dp;
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
m_Cnt++;
|
|||
|
|
}
|
|||
|
|
m_W++;
|
|||
|
|
if( m_W >= m_Max ) m_W = 0;
|
|||
|
|
*dp = d;
|
|||
|
|
m_Sum += d;
|
|||
|
|
m_Avg = m_Sum / m_Cnt;
|
|||
|
|
return m_Avg;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//--------------------------------------------------------
|
|||
|
|
__fastcall CENCODE::CENCODE()
|
|||
|
|
{
|
|||
|
|
m_MFSK_TYPE = typMFSK16;
|
|||
|
|
m_MFSK_TONES = 16;
|
|||
|
|
m_MFSK_SPEED = 15.625;
|
|||
|
|
m_MFSK_BITS = 4;
|
|||
|
|
m_MFSK_MASK = m_MFSK_TONES - 1;
|
|||
|
|
|
|||
|
|
m_pFunc = NULL;
|
|||
|
|
m_Speed = SPEED;
|
|||
|
|
m_SampleFreq = SAMPFREQ;
|
|||
|
|
m_Code = 0;
|
|||
|
|
Create();
|
|||
|
|
m_RP = m_WP = m_CC = 0;
|
|||
|
|
m_Idle = FALSE;
|
|||
|
|
m_pVCO = NULL;
|
|||
|
|
m_fJA = TRUE;
|
|||
|
|
m_fTWO = FALSE;
|
|||
|
|
m_fCW = FALSE;
|
|||
|
|
m_Type = MODE_GMSK;
|
|||
|
|
m_BAUDOT.Reset();
|
|||
|
|
m_rttyDiddle = diddleLTR;
|
|||
|
|
m_rttyCWait = m_rttyDWait = 0;
|
|||
|
|
m_Mark = FALSE;
|
|||
|
|
|
|||
|
|
m_Viterbi.Init(MFSK_VITERBI_K, MFSK_VITERBI_POLY1, MFSK_VITERBI_POLY2);
|
|||
|
|
m_MFSK_SHDATA = 0;
|
|||
|
|
m_MFSK_SHCount = 0;
|
|||
|
|
}
|
|||
|
|
//--------------------------------------------------------
|
|||
|
|
void __fastcall CENCODE::SetMFSKType(int type)
|
|||
|
|
{
|
|||
|
|
m_MFSK_TYPE = type;
|
|||
|
|
MFSK_SetPara(type, &m_MFSK_TONES, &m_MFSK_SPEED, &m_MFSK_BITS);
|
|||
|
|
m_MFSK_MASK = m_MFSK_TONES - 1;
|
|||
|
|
Create();
|
|||
|
|
}
|
|||
|
|
//--------------------------------------------------------
|
|||
|
|
void __fastcall CENCODE::Create(void)
|
|||
|
|
{
|
|||
|
|
m_Mode = 0;
|
|||
|
|
m_dCW = m_SampleFreq / 20.0;
|
|||
|
|
if( IsMFSK(m_Type) ){
|
|||
|
|
m_dTW = m_SampleFreq / m_MFSK_SPEED;
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
m_dTW = m_SampleFreq / m_Speed;
|
|||
|
|
}
|
|||
|
|
m_out = 0;
|
|||
|
|
m_sync = 0;
|
|||
|
|
m_Idle = FALSE;
|
|||
|
|
m_fCW = FALSE;
|
|||
|
|
memset(m_Z, 0, sizeof(m_Z));
|
|||
|
|
}
|
|||
|
|
void __fastcall CENCODE::SetTmg(double d)
|
|||
|
|
{
|
|||
|
|
if( IsMFSK(m_Type) ){
|
|||
|
|
m_dTW = m_SampleFreq / m_MFSK_SPEED;
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
m_dTW = m_SampleFreq / m_Speed;
|
|||
|
|
}
|
|||
|
|
m_dTW += m_dTW * d / 1e6;
|
|||
|
|
}
|
|||
|
|
void __fastcall CENCODE::Reset(BOOL fCW)
|
|||
|
|
{
|
|||
|
|
m_fCW = fCW;
|
|||
|
|
m_Code = 0;
|
|||
|
|
m_Mode = 0;
|
|||
|
|
m_RP = m_WP = m_CC = 0;
|
|||
|
|
m_Idle = FALSE;
|
|||
|
|
m_Mark = FALSE;
|
|||
|
|
}
|
|||
|
|
void __fastcall CENCODE::SetCW(int f)
|
|||
|
|
{
|
|||
|
|
m_dCW = m_SampleFreq / f;
|
|||
|
|
}
|
|||
|
|
//--------------------------------------------------------
|
|||
|
|
static int __fastcall GetCWCode(int &count, int code)
|
|||
|
|
{
|
|||
|
|
const USHORT _tbl[]={
|
|||
|
|
// 0 1 2 3 4 5 6 7
|
|||
|
|
0x0005, 0x8005, 0xc005, 0xe005, 0xf005, 0xf805, 0x7805, 0x3805, // 0-7
|
|||
|
|
// 8 9 : ; < = > ?
|
|||
|
|
0x1805, 0x0805, 0xe806, 0xA805, 0x0000, 0x7005, 0x0000, 0xcc06, // 8
|
|||
|
|
// @ A B C D E F G
|
|||
|
|
0xb805, 0x8002, 0x7004, 0x5004, 0x6003, 0x8001, 0xd004, 0x2003, // @-G
|
|||
|
|
// H I J K L M N O
|
|||
|
|
0xf004, 0xc002, 0x8004, 0x4003, 0xb004, 0x0002, 0x4002, 0x0003, // H-O
|
|||
|
|
// P Q R S T U V W
|
|||
|
|
0x9004, 0x2004, 0xa003, 0xe003, 0x0001, 0xc003, 0xe004, 0x8003, // P-W
|
|||
|
|
// X Y Z [ \ ]
|
|||
|
|
0x6004, 0x4004, 0x3004, 0x0000, 0x0000, 0x4805, 0x0000, 0x0000, // X-Z
|
|||
|
|
};
|
|||
|
|
if( code == '/' ){
|
|||
|
|
code = 0x6805;
|
|||
|
|
count = 5;
|
|||
|
|
}
|
|||
|
|
else if( (code >= 0x30) && (code <= 0x7f) ){
|
|||
|
|
if( code >= 0x60 ) code -= 0x20;
|
|||
|
|
code -= 0x30;
|
|||
|
|
code = _tbl[code];
|
|||
|
|
count = code & 0x000f;
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
code = 0;
|
|||
|
|
count = 0;
|
|||
|
|
}
|
|||
|
|
return code;
|
|||
|
|
}
|
|||
|
|
//--------------------------------------------------------------------------
|
|||
|
|
void __fastcall CENCODE::MFSKSendBit(BOOL bit)
|
|||
|
|
{
|
|||
|
|
MFSKSendPair(m_Viterbi.Do(bit));
|
|||
|
|
}
|
|||
|
|
//--------------------------------------------------------------------------
|
|||
|
|
void __fastcall CENCODE::MFSKSendPair(BYTE pair)
|
|||
|
|
{
|
|||
|
|
MFSKSendSymBit(pair & 2);
|
|||
|
|
MFSKSendSymBit(pair & 1);
|
|||
|
|
}
|
|||
|
|
//--------------------------------------------------------------------------
|
|||
|
|
//
|
|||
|
|
void __fastcall CENCODE::MFSKSendSymBit(BOOL bit)
|
|||
|
|
{
|
|||
|
|
const BYTE _tGray2Bin[]={ //Encode
|
|||
|
|
0x00,0x01,0x03,0x02,0x07,0x06,0x04,0x05,
|
|||
|
|
0x0F,0x0E,0x0C,0x0D,0x08,0x09,0x0B,0x0A,
|
|||
|
|
0x1F,0x1E,0x1C,0x1D,0x18,0x19,0x1B,0x1A,
|
|||
|
|
0x10,0x11,0x13,0x12,0x17,0x16,0x14,0x15,
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
m_MFSK_SHDATA = m_MFSK_SHDATA << 1;
|
|||
|
|
if( bit ) m_MFSK_SHDATA |= 1;
|
|||
|
|
|
|||
|
|
m_MFSK_SHCount++;
|
|||
|
|
if( m_MFSK_SHCount >= m_MFSK_BITS ){
|
|||
|
|
m_Fifo.PutData(_tGray2Bin[m_InterLeaver.EncodeBits(m_MFSK_SHDATA) & m_MFSK_MASK]);
|
|||
|
|
m_MFSK_SHDATA = 0;
|
|||
|
|
m_MFSK_SHCount = 0;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
//--------------------------------------------------------------------------
|
|||
|
|
void __fastcall CENCODE::MFSKSendChar(int c)
|
|||
|
|
{
|
|||
|
|
int code = g_VariCode.EncodeMFSK(BYTE(c));
|
|||
|
|
int n = (code & 0x0f000) >> 12;
|
|||
|
|
for( n--; n >= 0; n-- ){
|
|||
|
|
MFSKSendBit(_tBitData[n] & code);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
//--------------------------------------------------------------------------
|
|||
|
|
void __fastcall CENCODE::MFSKSendIdle(void)
|
|||
|
|
{
|
|||
|
|
MFSKSendIdle(m_MFSK_TONES);
|
|||
|
|
}
|
|||
|
|
//--------------------------------------------------------------------------
|
|||
|
|
void __fastcall CENCODE::MFSKSendIdle(int n)
|
|||
|
|
{
|
|||
|
|
for(int i = 0; i < n; i++){
|
|||
|
|
MFSKSendBit(0);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
//--------------------------------------------------------------------------
|
|||
|
|
void __fastcall CENCODE::MFSKSendIdleChar(void)
|
|||
|
|
{
|
|||
|
|
MFSKSendChar(0);
|
|||
|
|
MFSKSendIdle();
|
|||
|
|
m_fChar = FALSE;
|
|||
|
|
}
|
|||
|
|
//--------------------------------------------------------------------------
|
|||
|
|
int __fastcall MFSK_GetIdleCount(int type)
|
|||
|
|
{
|
|||
|
|
switch(type){
|
|||
|
|
case typMFSK4:
|
|||
|
|
return (rand() % 2) + 2;
|
|||
|
|
case typMFSK8:
|
|||
|
|
return (rand() % 2) + 3;
|
|||
|
|
case typMFSK31:
|
|||
|
|
case typMFSK32:
|
|||
|
|
return (rand() % 4) + 16;
|
|||
|
|
case typMFSK64:
|
|||
|
|
return (rand() % 8) + 24;
|
|||
|
|
default:
|
|||
|
|
return (rand() % 4) + 8;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
//--------------------------------------------------------
|
|||
|
|
int __fastcall CENCODE::Do(void)
|
|||
|
|
{
|
|||
|
|
m_Cnt++;
|
|||
|
|
m_dNow += 1.0;
|
|||
|
|
switch(m_Mode){
|
|||
|
|
case 0: // <20>G<EFBFBD><47><EFBFBD>R<EFBFBD>[<5B>h<EFBFBD>̊J<CC8A>n
|
|||
|
|
m_fReqRX = FALSE;
|
|||
|
|
m_fChar = FALSE;
|
|||
|
|
if( m_pVCO ) m_pVCO->InitPhase();
|
|||
|
|
if( IsMFSK(m_Type) ){
|
|||
|
|
m_Fifo.Clear();
|
|||
|
|
m_InterLeaver.Init(m_MFSK_BITS);
|
|||
|
|
m_Viterbi.Reset();
|
|||
|
|
m_MFSK_SHDATA = 0;
|
|||
|
|
m_MFSK_SHCount = 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if( m_fCW ){
|
|||
|
|
m_out = 128;
|
|||
|
|
m_Mode = IsMFSK(m_Type) ? 130 : 2;
|
|||
|
|
}
|
|||
|
|
else if( IsRTTY(m_Type) ){
|
|||
|
|
m_Mark = FALSE;
|
|||
|
|
m_BAUDOT.Reset();
|
|||
|
|
m_out = -1;
|
|||
|
|
m_Mode = 64;
|
|||
|
|
}
|
|||
|
|
else if( IsMFSK(m_Type) ){
|
|||
|
|
m_out = 0;
|
|||
|
|
m_Mode = 128;
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
m_out = IsPSK(m_Type) ? 1 : 0;
|
|||
|
|
m_Mode++;
|
|||
|
|
}
|
|||
|
|
m_outbit = m_out;
|
|||
|
|
m_Cnt = 0;
|
|||
|
|
m_dNext = m_dTW * 2;
|
|||
|
|
m_dNow = 0.0;
|
|||
|
|
m_cBCount = 0;
|
|||
|
|
m_Idle = FALSE;
|
|||
|
|
break;
|
|||
|
|
case 1:
|
|||
|
|
if( m_dNext <= m_dNow ){
|
|||
|
|
m_outbit = 0;
|
|||
|
|
m_out = (m_out >= 0) ? -1 : 1;
|
|||
|
|
m_dNext += m_dTW;
|
|||
|
|
m_cBCount++;
|
|||
|
|
if( IsQPSK(m_Type) ){
|
|||
|
|
if( m_cBCount >= (1.0 * m_Speed) ){
|
|||
|
|
m_cBCount = 0;
|
|||
|
|
m_Mode++;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
if( m_cBCount >= (0.64 * m_Speed) ){
|
|||
|
|
m_cBCount = 0;
|
|||
|
|
m_Mode++;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
m_Cnt = 0;
|
|||
|
|
}
|
|||
|
|
break;
|
|||
|
|
case 2:
|
|||
|
|
if( m_dNext <= m_dNow ){
|
|||
|
|
m_dNext += m_dTW;
|
|||
|
|
if( !m_cBCount ){
|
|||
|
|
if( m_CC ){
|
|||
|
|
m_cData = GetChar();
|
|||
|
|
}
|
|||
|
|
else if( m_pFunc ){
|
|||
|
|
m_cData = m_pFunc();
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
m_cData = GetChar();
|
|||
|
|
}
|
|||
|
|
if( (m_cData >= 0x100) && (m_cData < 0x0200) ){
|
|||
|
|
m_Idle = FALSE;
|
|||
|
|
m_cData -= 0x0100;
|
|||
|
|
m_cData = GetCWCode(m_cBCount, m_cData);
|
|||
|
|
m_dNext -= m_dTW;
|
|||
|
|
m_dNext += m_fCW ? m_dCW : m_dCW*3;
|
|||
|
|
m_out = 128;
|
|||
|
|
m_Mode = 16;
|
|||
|
|
m_fCW = TRUE;
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
else if( m_cData == 0x200 ){ // Idle
|
|||
|
|
m_fCW = FALSE;
|
|||
|
|
m_Idle = FALSE;
|
|||
|
|
m_cData = 0;
|
|||
|
|
m_cBCount = 20;
|
|||
|
|
}
|
|||
|
|
else if( m_cData >= 0 ){
|
|||
|
|
m_fCW = FALSE;
|
|||
|
|
m_Idle = FALSE;
|
|||
|
|
if( m_fTWO && (m_cData >= 0x8140) && (m_cData <= 0xfeff) ){
|
|||
|
|
int c1 = (m_cData >> 8) & 0x00ff;
|
|||
|
|
int c2 = m_cData & 0x00ff;
|
|||
|
|
c1 = g_VariCode.Mbcs2Index(c1, FALSE);
|
|||
|
|
c2 = g_VariCode.Mbcs2Index(c2, FALSE);
|
|||
|
|
int b1, b2;
|
|||
|
|
int d1 = g_VariCode.Encode(b1, c1) << 2;
|
|||
|
|
int d2 = g_VariCode.Encode(b2, c2) << 2;
|
|||
|
|
m_cData = (d1 << (b2+2)) | d2;
|
|||
|
|
m_cBCount = b1 + b2 + 4;
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
m_cData = g_VariCode.Mbcs2Index(m_cData, m_fTWO ? FALSE : m_fJA);
|
|||
|
|
if( m_cData >= 0 ){
|
|||
|
|
m_cData = g_VariCode.Encode(m_cBCount, m_cData) << 2;
|
|||
|
|
m_cBCount += 2;
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
m_cData = 0;
|
|||
|
|
m_cBCount = 1;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else if( m_fCW ){
|
|||
|
|
m_out = 128;
|
|||
|
|
m_Idle = TRUE;
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
else if( (m_Mark || m_fReqRX) && sys.m_fSendSingleTone && IsPSK(m_Type) ){
|
|||
|
|
m_outbit = -1;
|
|||
|
|
m_cBCount = 32;
|
|||
|
|
m_Idle = FALSE;
|
|||
|
|
m_Mode++;
|
|||
|
|
m_Cnt = 0;
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
m_Idle = TRUE;
|
|||
|
|
m_cData = 0;
|
|||
|
|
m_cBCount = 1;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
m_cBCount--;
|
|||
|
|
m_outbit = (m_cData & _tBitData[m_cBCount]);
|
|||
|
|
if( !(m_cData & _tBitData[m_cBCount]) ){
|
|||
|
|
m_out = (m_out > 0) ? -1 : 1;
|
|||
|
|
}
|
|||
|
|
m_Cnt = 0;
|
|||
|
|
}
|
|||
|
|
break;
|
|||
|
|
case 3: // output single tone for the ending transmission
|
|||
|
|
if( m_dNext <= m_dNow ){
|
|||
|
|
m_dNext += m_dTW;
|
|||
|
|
m_cBCount--;
|
|||
|
|
if( m_cBCount <= 0 ){
|
|||
|
|
m_Idle = TRUE;
|
|||
|
|
m_cData = 0;
|
|||
|
|
m_cBCount = 1;
|
|||
|
|
}
|
|||
|
|
m_outbit = -1;
|
|||
|
|
m_Cnt = 0;
|
|||
|
|
}
|
|||
|
|
break;
|
|||
|
|
// CW output
|
|||
|
|
case 16:
|
|||
|
|
if( m_dNext <= m_dNow ){
|
|||
|
|
if( m_cBCount ){
|
|||
|
|
m_dNext += m_cData & 0x8000 ? m_dCW : m_dCW*3;
|
|||
|
|
m_out = 129;
|
|||
|
|
m_Mode++;
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
m_out = 128;
|
|||
|
|
m_dNext += m_dCW*6;
|
|||
|
|
m_Mode = IsMFSK(m_Type) ? 130 : 2;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
break;
|
|||
|
|
case 17: // <20>X<EFBFBD>y<EFBFBD>[<5B>X
|
|||
|
|
if( m_dNext <= m_dNow ){
|
|||
|
|
m_dNext += m_dCW;
|
|||
|
|
m_out = 128;
|
|||
|
|
m_cData = m_cData << 1;
|
|||
|
|
m_cBCount--;
|
|||
|
|
if( !m_cBCount ){
|
|||
|
|
m_dNext += m_dCW;
|
|||
|
|
m_Mode = IsMFSK(m_Type) ? 130 : 2;
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
m_Mode--;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
break;
|
|||
|
|
case 64: // BAUDOT
|
|||
|
|
if( m_dNext <= m_dNow ){
|
|||
|
|
m_dNext += m_dTW;
|
|||
|
|
m_cBCount++;
|
|||
|
|
if( m_cBCount >= (0.25 * m_Speed) ){
|
|||
|
|
m_cBCount = 0;
|
|||
|
|
m_Mode++;
|
|||
|
|
}
|
|||
|
|
m_Cnt = 0;
|
|||
|
|
}
|
|||
|
|
break;
|
|||
|
|
case 65: // BAUDOT
|
|||
|
|
if( m_dNext <= m_dNow ){
|
|||
|
|
m_dNext += m_dTW*0.5;
|
|||
|
|
if( !m_cBCount ){
|
|||
|
|
if( m_CC ){
|
|||
|
|
m_cData = GetChar();
|
|||
|
|
}
|
|||
|
|
else if( m_pFunc ){
|
|||
|
|
m_cData = m_pFunc();
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
m_cData = GetChar();
|
|||
|
|
}
|
|||
|
|
if( (m_cData >= 0x100) && (m_cData < 0x0200) ){
|
|||
|
|
m_Idle = FALSE;
|
|||
|
|
m_cData -= 0x0100;
|
|||
|
|
m_cData = GetCWCode(m_cBCount, m_cData);
|
|||
|
|
m_dNext -= m_dTW*0.5;
|
|||
|
|
m_dNext += m_fCW ? m_dCW : m_dCW*3;
|
|||
|
|
m_out = 128;
|
|||
|
|
m_Mode = 16;
|
|||
|
|
m_fCW = TRUE;
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
else if( m_cData == 0x200 ){ // Idle
|
|||
|
|
m_BAUDOT.Reset();
|
|||
|
|
m_fCW = FALSE;
|
|||
|
|
m_Idle = FALSE;
|
|||
|
|
if( m_fChar ){
|
|||
|
|
m_cData = (m_rttyDiddle == diddleLTR) ? 0x7ffc : 0x7000;
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
m_cData = 0xffff;
|
|||
|
|
}
|
|||
|
|
m_cBCount = 15;
|
|||
|
|
}
|
|||
|
|
else if( m_cData >= 0 ){
|
|||
|
|
m_fChar = TRUE;
|
|||
|
|
m_fCW = FALSE;
|
|||
|
|
m_Idle = FALSE;
|
|||
|
|
m_cData = m_BAUDOT.GetCode(m_cBCount, m_cData);
|
|||
|
|
if( m_cData < 0 ){
|
|||
|
|
m_cData = 0x7000; // BLK
|
|||
|
|
m_cBCount = 15;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else if( m_fCW ){
|
|||
|
|
m_BAUDOT.Reset();
|
|||
|
|
m_out = 128;
|
|||
|
|
m_Idle = TRUE;
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
else if( m_Mark || m_fReqRX ){
|
|||
|
|
m_fChar = FALSE;
|
|||
|
|
m_out = -1;
|
|||
|
|
m_Idle = TRUE;
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
else { // Diddle
|
|||
|
|
m_BAUDOT.Reset();
|
|||
|
|
m_Idle = TRUE;
|
|||
|
|
m_cData = (m_rttyDiddle == diddleLTR) ? 0x7ffc : 0x7000;
|
|||
|
|
m_cBCount = 15;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
m_cBCount--;
|
|||
|
|
if( !(m_cData & 0x0001) ){
|
|||
|
|
m_out = 1;
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
m_out = -1;
|
|||
|
|
}
|
|||
|
|
m_cData = m_cData >> 1;
|
|||
|
|
m_Cnt = 0;
|
|||
|
|
if( !m_cBCount || (m_cBCount == 15) ){
|
|||
|
|
if( m_Idle ){
|
|||
|
|
if( m_rttyDWait ) m_Mode++;
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
if( m_rttyCWait ) m_Mode++;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
break;
|
|||
|
|
case 66: // BAUDOT-wait
|
|||
|
|
if( m_dNext <= m_dNow ){
|
|||
|
|
m_dNext += m_dTW * 0.1 * (m_Idle ? m_rttyDWait : m_rttyCWait);
|
|||
|
|
m_Mode = 65;
|
|||
|
|
}
|
|||
|
|
m_Cnt = 0;
|
|||
|
|
break;
|
|||
|
|
|
|||
|
|
// MFSK
|
|||
|
|
case 128:
|
|||
|
|
switch(m_MFSK_TYPE){
|
|||
|
|
case typMFSK4:
|
|||
|
|
m_cBCount = 8;
|
|||
|
|
break;
|
|||
|
|
case typMFSK31:
|
|||
|
|
case typMFSK32:
|
|||
|
|
m_cBCount = 32;
|
|||
|
|
break;
|
|||
|
|
case typMFSK64:
|
|||
|
|
m_cBCount = 64;
|
|||
|
|
break;
|
|||
|
|
case typMFSK22:
|
|||
|
|
m_cBCount = 22;
|
|||
|
|
break;
|
|||
|
|
default:
|
|||
|
|
m_cBCount = 16;
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
m_dNext = m_dNow + m_dTW;
|
|||
|
|
m_Mode++;
|
|||
|
|
case 129:
|
|||
|
|
if( m_dNext <= m_dNow ){
|
|||
|
|
m_dNext += m_dTW;
|
|||
|
|
m_cBCount--;
|
|||
|
|
if( !m_cBCount ){
|
|||
|
|
if( (m_MFSK_TONES == 8)||(m_MFSK_TONES == 32) ){ // <20>Q<EFBFBD>r<EFBFBD>^<5E>r<EFBFBD>̃<EFBFBD><CC83>g<EFBFBD><67><EFBFBD>b<EFBFBD>N<EFBFBD>X<EFBFBD><58><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>̂<EFBFBD><CC82><EFBFBD>
|
|||
|
|
MFSKSendChar(0);
|
|||
|
|
MFSKSendChar(0);
|
|||
|
|
}
|
|||
|
|
m_Mode++;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
break;
|
|||
|
|
case 130:
|
|||
|
|
case 131:
|
|||
|
|
if( m_dNext <= m_dNow ){
|
|||
|
|
m_dNext += m_dTW;
|
|||
|
|
if( !m_Fifo.GetCount() ){
|
|||
|
|
_try:;
|
|||
|
|
if( m_CC ){
|
|||
|
|
m_cData = GetChar();
|
|||
|
|
}
|
|||
|
|
else if( m_pFunc ){
|
|||
|
|
m_cData = m_pFunc();
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
m_cData = GetChar();
|
|||
|
|
}
|
|||
|
|
if( (m_cData >= 0x100) && (m_cData < 0x0200) ){
|
|||
|
|
m_Idle = FALSE;
|
|||
|
|
m_cData -= 0x0100;
|
|||
|
|
m_cData = GetCWCode(m_cBCount, m_cData);
|
|||
|
|
if( m_fCW ){
|
|||
|
|
m_dNext -= m_dTW;
|
|||
|
|
m_dNext += m_fCW ? m_dCW : m_dCW*3;
|
|||
|
|
m_out = 128;
|
|||
|
|
m_Mode = 16;
|
|||
|
|
m_fCW = TRUE;
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
MFSKSendIdleChar();
|
|||
|
|
MFSKSendIdleChar();
|
|||
|
|
MFSKSendIdleChar();
|
|||
|
|
m_Mode = 132;
|
|||
|
|
if( m_Fifo.GetCount() ) m_out = m_Fifo.GetData();
|
|||
|
|
}
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
else if( m_cData == 0x200 ){ // Idle
|
|||
|
|
m_Mode = 130;
|
|||
|
|
m_fCW = FALSE;
|
|||
|
|
m_Idle = FALSE;
|
|||
|
|
// MFSKSendIdleChar();
|
|||
|
|
if( m_fChar ){
|
|||
|
|
MFSKSendIdleChar();
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
MFSKSendIdle();
|
|||
|
|
}
|
|||
|
|
MFSKSendIdle();
|
|||
|
|
}
|
|||
|
|
else if( m_cData >= 0 ){
|
|||
|
|
m_fChar = TRUE;
|
|||
|
|
m_Mode = 130;
|
|||
|
|
m_fCW = FALSE;
|
|||
|
|
m_Idle = FALSE;
|
|||
|
|
if( m_fTWO && (m_cData >= 0x8140) && (m_cData <= 0xfeff) ){
|
|||
|
|
MFSKSendChar((m_cData >> 8) & 0x00ff);
|
|||
|
|
MFSKSendChar(m_cData & 0x00ff);
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
MFSKSendChar(m_cData & 0x00ff);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else if( m_fCW ){
|
|||
|
|
m_out = 128;
|
|||
|
|
m_Idle = TRUE;
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
else if( m_Mode == 130 ){
|
|||
|
|
m_Idle = FALSE;
|
|||
|
|
MFSKSendIdleChar();
|
|||
|
|
m_cBCount = 3;
|
|||
|
|
m_Mode++;
|
|||
|
|
}
|
|||
|
|
else if( m_Idle ){
|
|||
|
|
m_cBCount--;
|
|||
|
|
if( m_cBCount <= 0 ){
|
|||
|
|
m_cBCount = MFSK_GetIdleCount(m_MFSK_TYPE);
|
|||
|
|
MFSKSendIdleChar();
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
MFSKSendIdle();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else if( m_fReqRX ){
|
|||
|
|
if( m_MFSK_TONES == 32 ){
|
|||
|
|
MFSKSendIdle(26);
|
|||
|
|
}
|
|||
|
|
else if( m_MFSK_TONES == 16 ){
|
|||
|
|
MFSKSendIdle(32);
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
MFSKSendIdle(20);
|
|||
|
|
}
|
|||
|
|
m_cBCount--;
|
|||
|
|
if( m_cBCount <= 0 ){
|
|||
|
|
m_Idle = TRUE;
|
|||
|
|
m_cBCount = MFSK_GetIdleCount(m_MFSK_TYPE);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
m_cBCount--;
|
|||
|
|
if( m_cBCount <= 0 ){
|
|||
|
|
m_Idle = TRUE;
|
|||
|
|
m_cBCount = MFSK_GetIdleCount(m_MFSK_TYPE);
|
|||
|
|
if( m_MFSK_TONES == 32 ){
|
|||
|
|
MFSKSendIdleChar();
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
MFSKSendIdle();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
MFSKSendIdle();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
if( m_Fifo.GetCount() ){
|
|||
|
|
m_out = m_Fifo.GetData();
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
goto _try;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
break;
|
|||
|
|
case 132:
|
|||
|
|
if( m_dNext <= m_dNow ){
|
|||
|
|
m_dNext += m_dTW;
|
|||
|
|
if( m_Fifo.GetCount() ){
|
|||
|
|
m_out = m_Fifo.GetData();
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
m_dNext += m_fCW ? m_dCW : m_dCW*3;
|
|||
|
|
m_out = 128;
|
|||
|
|
m_Mode = 16;
|
|||
|
|
m_fCW = TRUE;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
if( m_dNow >= 8192.0 ){
|
|||
|
|
m_dNow -= 8192.0;
|
|||
|
|
m_dNext -= 8192.0;
|
|||
|
|
}
|
|||
|
|
return m_out;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//--------------------------------------------------------
|
|||
|
|
BOOL __fastcall CENCODE::IsBuffFull(void)
|
|||
|
|
{
|
|||
|
|
return m_CC >= AN(m_Buff);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//--------------------------------------------------------
|
|||
|
|
void __fastcall CENCODE::PutChar(int c)
|
|||
|
|
{
|
|||
|
|
if( !IsBuffFull() ){
|
|||
|
|
m_Buff[m_WP] = c;
|
|||
|
|
m_WP++;
|
|||
|
|
if( m_WP >= AN(m_Buff) ){
|
|||
|
|
m_WP = 0;
|
|||
|
|
}
|
|||
|
|
m_CC++;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//--------------------------------------------------------
|
|||
|
|
int __fastcall CENCODE::GetChar(void)
|
|||
|
|
{
|
|||
|
|
if( !m_CC ) return -1;
|
|||
|
|
int c = m_Buff[m_RP];
|
|||
|
|
m_RP++;
|
|||
|
|
if( m_RP >= AN(m_Buff) ){
|
|||
|
|
m_RP = 0;
|
|||
|
|
}
|
|||
|
|
m_CC--;
|
|||
|
|
return c;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//--------------------------------------------------------
|
|||
|
|
__fastcall CCOLLECT::CCOLLECT()
|
|||
|
|
{
|
|||
|
|
m_Max = 0;
|
|||
|
|
m_Cnt = 0;
|
|||
|
|
m_pZ = NULL;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
__fastcall CCOLLECT::~CCOLLECT()
|
|||
|
|
{
|
|||
|
|
if( m_pZ ) delete m_pZ;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void __fastcall CCOLLECT::Create(int max)
|
|||
|
|
{
|
|||
|
|
if( m_Max == max ) return;
|
|||
|
|
|
|||
|
|
m_Max = max;
|
|||
|
|
m_Cnt = 0;
|
|||
|
|
if( m_pZ ) delete m_pZ;
|
|||
|
|
m_pZ = new double[m_Max];
|
|||
|
|
memset(m_pZ, 0, sizeof(m_pZ));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void __fastcall CCOLLECT::Do(double d)
|
|||
|
|
{
|
|||
|
|
if( m_Cnt >= m_Max ) return;
|
|||
|
|
|
|||
|
|
m_pZ[m_Cnt] = d;
|
|||
|
|
m_Cnt++;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
const BYTE _tMbcs2Index[]={ // PSK31 index converter
|
|||
|
|
0x58,0x62,0x66,0x76,0x65,0x71,0x67,0x6B, /*00*/
|
|||
|
|
0x6C,0x30,0x0A,0x74,0x63,0x0B,0x75,0x7A, /*08*/
|
|||
|
|
0x69,0x68,0x7B,0x7C,0x6F,0x72,0x73,0x6E, /*10*/
|
|||
|
|
0x77,0x78,0x7E,0x6D,0x70,0x7F,0x6A,0x79, /*18*/
|
|||
|
|
0x00,0x57,0x3A,0x53,0x4D,0x60,0x5D,0x42, /*20*/
|
|||
|
|
0x33,0x32,0x3D,0x4F,0x1C,0x0F,0x15,0x45, /*28*/
|
|||
|
|
0x25,0x27,0x2F,0x35,0x3F,0x38,0x3B,0x44, /*30*/
|
|||
|
|
0x43,0x47,0x31,0x49,0x51,0x14,0x4C,0x5A, /*38*/
|
|||
|
|
0x5E,0x1F,0x2E,0x22,0x24,0x1D,0x2B,0x34, /*40*/
|
|||
|
|
0x36,0x20,0x56,0x41,0x2A,0x26,0x2C,0x21, /*48*/
|
|||
|
|
0x29,0x4E,0x23,0x1B,0x1A,0x37,0x46,0x39, /*50*/
|
|||
|
|
0x3E,0x40,0x59,0x54,0x52,0x55,0x5F,0x3C, /*58*/
|
|||
|
|
0x64,0x04,0x18,0x0E,0x0D,0x01,0x12,0x16, /*60*/
|
|||
|
|
0x0C,0x05,0x50,0x28,0x09,0x11,0x06,0x03, /*68*/
|
|||
|
|
0x13,0x4A,0x07,0x08,0x02,0x10,0x1E,0x19, /*70*/
|
|||
|
|
0x2D,0x17,0x4B,0x5C,0x48,0x5B,0x61,0x7D,
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
__fastcall CVARICODE::CVARICODE()
|
|||
|
|
{
|
|||
|
|
m_tEncode = NULL;
|
|||
|
|
m_Max = m_TMax = 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
__fastcall CVARICODE::~CVARICODE()
|
|||
|
|
{
|
|||
|
|
if( m_tEncode ) delete m_tEncode;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void __fastcall CVARICODE::Init(void)
|
|||
|
|
{
|
|||
|
|
if( !LoadBin("VariCode.tbl") ){
|
|||
|
|
Create(256+(192*126));
|
|||
|
|
}
|
|||
|
|
for( int i = 0; i < 128; i++ ){
|
|||
|
|
m_tIndex2Mbcs[_tMbcs2Index[i]] = BYTE(i);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void __fastcall CVARICODE::Create(int max)
|
|||
|
|
{
|
|||
|
|
if( m_tEncode ) delete m_tEncode;
|
|||
|
|
m_TMax = max;
|
|||
|
|
DWORD *tEncode = new DWORD[m_TMax];
|
|||
|
|
m_Max = 0;
|
|||
|
|
int i;
|
|||
|
|
int b, db;
|
|||
|
|
tEncode[m_Max++] = 0x01000001;
|
|||
|
|
tEncode[m_Max++] = 0x02000003;
|
|||
|
|
int bmax = 3;
|
|||
|
|
int bm = 2;
|
|||
|
|
int bl = 0;
|
|||
|
|
while(m_Max < m_TMax){
|
|||
|
|
for( b = bl; b < bm; b++ ){
|
|||
|
|
BOOL f = TRUE;
|
|||
|
|
db = b;
|
|||
|
|
for( i = 3; i < bmax; i++ ){
|
|||
|
|
if( !(db & 1) && !(db & 2) ){
|
|||
|
|
f = FALSE;
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
db = db >> 1;
|
|||
|
|
}
|
|||
|
|
if( f ){
|
|||
|
|
db = b << 1;
|
|||
|
|
db |= (1 | (bm<<1));
|
|||
|
|
db = db | (bmax << 24);
|
|||
|
|
tEncode[m_Max++] = db;
|
|||
|
|
if( m_Max >= m_TMax ) break;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
bl = bl << 1;
|
|||
|
|
if( !(bl & 2) ) bl |= 1;
|
|||
|
|
bm = bm << 1;
|
|||
|
|
bmax++;
|
|||
|
|
if( bmax >= 24 ) break;
|
|||
|
|
}
|
|||
|
|
m_tEncode = tEncode;
|
|||
|
|
SaveBin("VariCode.tbl");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static int __fastcall SwapIndex(int index)
|
|||
|
|
{
|
|||
|
|
if( index <= 0x00d3 ){ // $80-$D3
|
|||
|
|
index += 0x21f - 0x0080; // $80-$D3 to Hiragana
|
|||
|
|
}
|
|||
|
|
else if( index <= 0x12a ){ // $D4-$12A
|
|||
|
|
index += 0x280 - 0x00d4; // $D4-$12A to Katakana
|
|||
|
|
}
|
|||
|
|
else if( (index >= 0x021f) && (index <= 0x0272) ){ // Hiragana
|
|||
|
|
index -= 0x21f - 0x0080; // Hiragana to $80-$D3
|
|||
|
|
}
|
|||
|
|
else if( (index >= 0x0280) && (index <= 0x02d6) ){ // Katakana
|
|||
|
|
index -= 0x280 - 0x00d4; // Katakana to $D4-$12A
|
|||
|
|
}
|
|||
|
|
else if( (index >= 0x1840) && (index <= 0x2f7f) ){
|
|||
|
|
index += 0x4840 - 0x1840;
|
|||
|
|
}
|
|||
|
|
else if( (index >= 0x4840) && (index <= 0x5f7f) ){
|
|||
|
|
index -= 0x4840 - 0x1840;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return index;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
UINT __fastcall CVARICODE::Index2Mbcs(int index, BOOL fJA)
|
|||
|
|
{
|
|||
|
|
if( fJA && (index >= 0x4840) ){ // <20>Â<EFBFBD><C382>o<EFBFBD>[<5B>W<EFBFBD><57><EFBFBD><EFBFBD><EFBFBD>Ƃ̌݊<CC8C><DD8A><EFBFBD><EFBFBD>p
|
|||
|
|
index -= 0x4840 - 0x1840;
|
|||
|
|
}
|
|||
|
|
if( index <= 0x007f ){
|
|||
|
|
index = m_tIndex2Mbcs[index];
|
|||
|
|
}
|
|||
|
|
else if( index >= m_Max ){
|
|||
|
|
return 0;
|
|||
|
|
}
|
|||
|
|
else if( fJA ){
|
|||
|
|
index = SwapIndex(index);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
UINT mbcs;
|
|||
|
|
int m, b;
|
|||
|
|
if( index >= 0x0100 ){
|
|||
|
|
index -= 0x0100;
|
|||
|
|
m = index % 192;
|
|||
|
|
b = index / 192;
|
|||
|
|
mbcs = 0x8140 + m + b * 256;
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
mbcs = index;
|
|||
|
|
}
|
|||
|
|
return mbcs;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
int __fastcall CVARICODE::Mbcs2Index(UINT mbcs, BOOL fJA)
|
|||
|
|
{
|
|||
|
|
int index, m, b;
|
|||
|
|
if( mbcs >= 0x8100 ){
|
|||
|
|
if( (mbcs & 0x00ff) >= 0x0040 ){
|
|||
|
|
mbcs -= 0x8100;
|
|||
|
|
m = mbcs % 256;
|
|||
|
|
b = mbcs / 256;
|
|||
|
|
index = 0x100 - 0x40 + m + b * 192;
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
return -1;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
index = mbcs;
|
|||
|
|
}
|
|||
|
|
if( index >= m_Max ){
|
|||
|
|
index = 0;
|
|||
|
|
}
|
|||
|
|
else if( index <= 0x007f ){
|
|||
|
|
index = _tMbcs2Index[index];
|
|||
|
|
}
|
|||
|
|
else if( fJA ){
|
|||
|
|
index = SwapIndex(index);
|
|||
|
|
}
|
|||
|
|
return index;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void __fastcall CVARICODE::SaveTable(LPCSTR pName)
|
|||
|
|
{
|
|||
|
|
CWaitCursor w;
|
|||
|
|
FILE *fp;
|
|||
|
|
if( (fp = fopen(pName, "wt")) != NULL ){
|
|||
|
|
OnWave();
|
|||
|
|
fprintf(fp, "Index ANSI JA HL/BV/BY Bits\tVaricode\n");
|
|||
|
|
int i, j;
|
|||
|
|
for( i = 0; i < m_Max; i++ ){
|
|||
|
|
DWORD b = m_tEncode[i];
|
|||
|
|
int n = b >> 24;
|
|||
|
|
b &= 0x00ffffff;
|
|||
|
|
int m = Index2Mbcs(i, FALSE);
|
|||
|
|
j = Index2Mbcs(i, TRUE);
|
|||
|
|
if( i >= 0x2f80 ){
|
|||
|
|
fprintf(fp, "%04X %04X %-4u\t", i, m, n);
|
|||
|
|
}
|
|||
|
|
else if( i < 0x100 ){
|
|||
|
|
fprintf(fp, "%04X %04X %04X %04X %-4u\t", i, m, j, m, n);
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
fprintf(fp, "%04X %04X %04X %-4u\t", i, j, m, n);
|
|||
|
|
}
|
|||
|
|
DWORD bm = _tBitData[n-1];
|
|||
|
|
for( j = 0; j < n; j++, bm = bm >> 1){
|
|||
|
|
fprintf(fp, "%c", (b & bm) ? '1' : '0');
|
|||
|
|
}
|
|||
|
|
fprintf(fp, "\n");
|
|||
|
|
if( !(i & 0xff) ) OnWave();
|
|||
|
|
}
|
|||
|
|
fclose(fp);
|
|||
|
|
OnWave();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void __fastcall CVARICODE::SaveSource(LPCSTR pName)
|
|||
|
|
{
|
|||
|
|
FILE *fp;
|
|||
|
|
if( (fp = fopen(pName, "wt")) != NULL ){
|
|||
|
|
fprintf(fp, "const DWORD g_tVariCode[%u]={\n", m_TMax);
|
|||
|
|
int i;
|
|||
|
|
for( i = 0; i < m_Max; i++ ){
|
|||
|
|
DWORD b = m_tEncode[i];
|
|||
|
|
if( !(i % 8) ) fprintf(fp, "\n\t");
|
|||
|
|
fprintf(fp, "0x%X,", b);
|
|||
|
|
}
|
|||
|
|
fprintf(fp, "};\n");
|
|||
|
|
fclose(fp);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void __fastcall CVARICODE::SaveBin(LPCSTR pName)
|
|||
|
|
{
|
|||
|
|
CWaitCursor w;
|
|||
|
|
char name[256];
|
|||
|
|
sprintf(name, "%s%s", sys.m_BgnDir, pName);
|
|||
|
|
FILE *fp;
|
|||
|
|
if( (fp = fopen(name, "wb")) != NULL ){
|
|||
|
|
fwrite(m_tEncode, sizeof(DWORD), m_Max, fp);
|
|||
|
|
fclose(fp);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
BOOL __fastcall CVARICODE::LoadBin(LPCSTR pName)
|
|||
|
|
{
|
|||
|
|
BOOL r = FALSE;
|
|||
|
|
char name[256];
|
|||
|
|
sprintf(name, "%s%s", sys.m_BgnDir, pName);
|
|||
|
|
FILE *fp;
|
|||
|
|
if( (fp = fopen(name, "rb")) != NULL ){
|
|||
|
|
int len = 256 + (126*192);
|
|||
|
|
if( m_tEncode ) delete m_tEncode;
|
|||
|
|
m_tEncode = new DWORD[len];
|
|||
|
|
fread(m_tEncode, sizeof(DWORD), len, fp);
|
|||
|
|
fclose(fp);
|
|||
|
|
m_TMax = m_Max = len;
|
|||
|
|
r = TRUE;
|
|||
|
|
}
|
|||
|
|
return r;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
DWORD __fastcall CVARICODE::Encode(int &n, DWORD d)
|
|||
|
|
{
|
|||
|
|
if( d < DWORD(m_Max) ){
|
|||
|
|
d = m_tEncode[d];
|
|||
|
|
n = d >> 24;
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
d = 0;
|
|||
|
|
n = 1;
|
|||
|
|
}
|
|||
|
|
return d;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
int __fastcall CVARICODE::Decode(DWORD d)
|
|||
|
|
{
|
|||
|
|
// VARICODE<44><45><EFBFBD>T<F195AA92><54><EFBFBD>T<EFBFBD>[<5B>`<60>ŃC<C583><43><EFBFBD>f<EFBFBD>b<EFBFBD>N<EFBFBD>X<EFBFBD>ɕϊ<C995>
|
|||
|
|
int l, h, m;
|
|||
|
|
l = 0;
|
|||
|
|
h = m_Max - 1;
|
|||
|
|
while(l <= h){
|
|||
|
|
m = (l + h)/2;
|
|||
|
|
DWORD b = m_tEncode[m] & 0x00ffffff;
|
|||
|
|
if( d < b ){
|
|||
|
|
h = m - 1;
|
|||
|
|
}
|
|||
|
|
else if( d > b ){
|
|||
|
|
l = m + 1;
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
return m;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return -1;
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
const WORD g_tMFSKVariCode[]={ // MFSK VARICODE <20>C<EFBFBD><43><EFBFBD>f<EFBFBD>b<EFBFBD>N<EFBFBD>X<EFBFBD><58>
|
|||
|
|
0x3004,0x4008,0x400C,0x5010,0x5014,0x5018,0x501C,0x6020,0x6028,0x602C,0x6030,0x6034,0x6038,0x603C,0x7040,0x7050, //00
|
|||
|
|
0x7054,0x7058,0x705C,0x7060,0x7068,0x706C,0x7070,0x7074,0x7078,0x707C,0x8080,0x80A0,0x80A8,0x80AC,0x80B0,0x80B4, //10
|
|||
|
|
0x80B8,0x80BC,0x80C0,0x80D0,0x80D4,0x80D8,0x80DC,0x80E0,0x80E8,0x80EC,0x80F0,0x80F4,0x80F8,0x80FC,0x9100,0x9140, //20
|
|||
|
|
0x9150,0x9154,0x9158,0x915C,0x9160,0x9168,0x916C,0x9170,0x9174,0x9178,0x917C,0x9180,0x91A0,0x91A8,0x91AC,0x91B0, //30
|
|||
|
|
0x91B4,0x91B8,0x91BC,0x91C0,0x91D0,0x91D4,0x91D8,0x91DC,0x91E0,0x91E8,0x91EC,0x91F0,0x91F4,0x91F8,0x91FC,0xA200, //40
|
|||
|
|
0xA280,0xA2A0,0xA2A8,0xA2AC,0xA2B0,0xA2B4,0xA2B8,0xA2BC,0xA2C0,0xA2D0,0xA2D4,0xA2D8,0xA2DC,0xA2E0,0xA2E8,0xA2EC, //50
|
|||
|
|
0xA2F0,0xA2F4,0xA2F8,0xA2FC,0xA300,0xA340,0xA350,0xA354,0xA358,0xA35C,0xA360,0xA368,0xA36C,0xA370,0xA374,0xA378, //60
|
|||
|
|
0xA37C,0xA380,0xA3A0,0xA3A8,0xA3AC,0xA3B0,0xA3B4,0xA3B8,0xA3BC,0xA3C0,0xA3D0,0xA3D4,0xA3D8,0xA3DC,0xA3E0,0xA3E8, //70
|
|||
|
|
0xA3EC,0xA3F0,0xA3F4,0xA3F8,0xA3FC,0xB400,0xB500,0xB540,0xB550,0xB554,0xB558,0xB55C,0xB560,0xB568,0xB56C,0xB570, //80
|
|||
|
|
0xB574,0xB578,0xB57C,0xB580,0xB5A0,0xB5A8,0xB5AC,0xB5B0,0xB5B4,0xB5B8,0xB5BC,0xB5C0,0xB5D0,0xB5D4,0xB5D8,0xB5DC, //90
|
|||
|
|
0xB5E0,0xB5E8,0xB5EC,0xB5F0,0xB5F4,0xB5F8,0xB5FC,0xB600,0xB680,0xB6A0,0xB6A8,0xB6AC,0xB6B0,0xB6B4,0xB6B8,0xB6BC, //A0
|
|||
|
|
0xB6C0,0xB6D0,0xB6D4,0xB6D8,0xB6DC,0xB6E0,0xB6E8,0xB6EC,0xB6F0,0xB6F4,0xB6F8,0xB6FC,0xB700,0xB740,0xB750,0xB754, //B0
|
|||
|
|
0xB758,0xB75C,0xB760,0xB768,0xB76C,0xB770,0xB774,0xB778,0xB77C,0xB780,0xB7A0,0xB7A8,0xB7AC,0xB7B0,0xB7B4,0xB7B8, //C0
|
|||
|
|
0xB7BC,0xB7C0,0xB7D0,0xB7D4,0xB7D8,0xB7DC,0xB7E0,0xB7E8,0xB7EC,0xB7F0,0xB7F4,0xB7F8,0xB7FC,0xC800,0xCA00,0xCA80, //D0
|
|||
|
|
0xCAA0,0xCAA8,0xCAAC,0xCAB0,0xCAB4,0xCAB8,0xCABC,0xCAC0,0xCAD0,0xCAD4,0xCAD8,0xCADC,0xCAE0,0xCAE8,0xCAEC,0xCAF0, //E0
|
|||
|
|
0xCAF4,0xCAF8,0xCAFC,0xCB00,0xCB40,0xCB50,0xCB54,0xCB58,0xCB5C,0xCB60,0xCB68,0xCB6C,0xCB70,0xCB74,0xCB78,0xCB7C,
|
|||
|
|
};
|
|||
|
|
const BYTE g_tMFSKIndex2Ascii[]={ // MFSK Index -> Ascii
|
|||
|
|
0x20,0x65,0x74,0x6F,0x61,0x69,0x6E,0x72,0x73,0x6C,0x68,0x64,0x63,0x75,0x6D,0x66, //00
|
|||
|
|
0x70,0x67,0x79,0x62,0x77,0x76,0x6B,0x78,0x71,0x7A,0x6A,0x2C,0x08,0x0D,0x54,0x53, //10
|
|||
|
|
0x45,0x41,0x49,0x4F,0x43,0x52,0x44,0x30,0x4D,0x50,0x31,0x4C,0x46,0x4E,0x42,0x32, //20
|
|||
|
|
0x47,0x33,0x48,0x55,0x35,0x57,0x36,0x58,0x34,0x59,0x4B,0x38,0x37,0x56,0x39,0x51, //30
|
|||
|
|
0x4A,0x5A,0x27,0x21,0x3F,0x2E,0x2D,0x3D,0x2B,0x2F,0x3A,0x29,0x28,0x3B,0x22,0x26, //40
|
|||
|
|
0x40,0x25,0x24,0x60,0x5F,0x2A,0x7C,0x3E,0x3C,0x5C,0x5E,0x23,0x7B,0x7D,0x5B,0x5D, //50
|
|||
|
|
0x7E,0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE, //60
|
|||
|
|
0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE, //70
|
|||
|
|
0xBF,0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE, //80
|
|||
|
|
0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE, //90
|
|||
|
|
0xDF,0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE, //A0
|
|||
|
|
0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE, //B0
|
|||
|
|
0xFF,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x09,0x0A,0x0B,0x0C,0x0E,0x0F,0x10, //C0
|
|||
|
|
0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,0x7F, //D0
|
|||
|
|
0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, //E0
|
|||
|
|
0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,
|
|||
|
|
};
|
|||
|
|
const BYTE g_tMFSKAscii2Index[]={ // MFSK Ascii -> Index
|
|||
|
|
0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0x1C,0xC9,0xCA,0xCB,0xCC,0x1D,0xCD,0xCE, //00
|
|||
|
|
0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE, //10
|
|||
|
|
0x00,0x43,0x4E,0x5B,0x52,0x51,0x4F,0x42,0x4C,0x4B,0x55,0x48,0x1B,0x46,0x45,0x49, //20
|
|||
|
|
0x27,0x2A,0x2F,0x31,0x38,0x34,0x36,0x3C,0x3B,0x3E,0x4A,0x4D,0x58,0x47,0x57,0x44, //30
|
|||
|
|
0x50,0x21,0x2E,0x24,0x26,0x20,0x2C,0x30,0x32,0x22,0x40,0x3A,0x2B,0x28,0x2D,0x23, //40
|
|||
|
|
0x29,0x3F,0x25,0x1F,0x1E,0x33,0x3D,0x35,0x37,0x39,0x41,0x5E,0x59,0x5F,0x5A,0x54, //50
|
|||
|
|
0x53,0x04,0x13,0x0C,0x0B,0x01,0x0F,0x11,0x0A,0x05,0x1A,0x16,0x09,0x0E,0x06,0x03, //60
|
|||
|
|
0x10,0x18,0x07,0x08,0x02,0x0D,0x15,0x14,0x17,0x12,0x19,0x5C,0x56,0x5D,0x60,0xDF, //70
|
|||
|
|
0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, //80
|
|||
|
|
0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF, //90
|
|||
|
|
0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F,0x70, //A0
|
|||
|
|
0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0x7B,0x7C,0x7D,0x7E,0x7F,0x80, //B0
|
|||
|
|
0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90, //C0
|
|||
|
|
0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,0xA0, //D0
|
|||
|
|
0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0, //E0
|
|||
|
|
0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF,0xC0,
|
|||
|
|
};
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
int __fastcall CVARICODE::DecodeMFSK(DWORD d)
|
|||
|
|
{
|
|||
|
|
// VARICODE<44><45><EFBFBD>T<F195AA92><54><EFBFBD>T<EFBFBD>[<5B>`<60>ŃC<C583><43><EFBFBD>f<EFBFBD>b<EFBFBD>N<EFBFBD>X<EFBFBD>ɕϊ<C995>
|
|||
|
|
int l, h, m;
|
|||
|
|
l = 0;
|
|||
|
|
h = 256 - 1;
|
|||
|
|
while(l <= h){
|
|||
|
|
m = (l + h)/2;
|
|||
|
|
DWORD b = g_tMFSKVariCode[m] & 0x00fff;
|
|||
|
|
if( d < b ){
|
|||
|
|
h = m - 1;
|
|||
|
|
}
|
|||
|
|
else if( d > b ){
|
|||
|
|
l = m + 1;
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
return g_tMFSKIndex2Ascii[m];
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return -1;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
int __fastcall CVARICODE::EncodeMFSK(BYTE c)
|
|||
|
|
{
|
|||
|
|
return g_tMFSKVariCode[g_tMFSKAscii2Index[c]];
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
BCODETBL _TTY[]={ // S-BELL
|
|||
|
|
// 0x20 - 0x7f
|
|||
|
|
{0x04, 2}, {0x16, 1}, {0x11, 1}, {0x00, 2}, // !"#
|
|||
|
|
{0x12, 1}, {0x00, 2}, {0x0b, 1}, {0x1a, 1}, // $%&'
|
|||
|
|
{0x1e, 1}, {0x09, 1}, {0x00, 2}, {0x00, 2}, // ()*+
|
|||
|
|
{0x06, 1}, {0x18, 1}, {0x07, 1}, {0x17, 1}, // ,-./
|
|||
|
|
{0x0d, 1}, {0x1d, 1}, {0x19, 1}, {0x10, 1}, // 0123 30-33
|
|||
|
|
{0x0a, 1}, {0x01, 1}, {0x15, 1}, {0x1c, 1}, // 4567 34-37
|
|||
|
|
{0x0c, 1}, {0x03, 1}, {0x0e, 1}, {0x0f, 1}, // 89 38-3b
|
|||
|
|
{0x00, 2}, {0x00, 2}, {0x00, 2}, {0x13, 1}, // <=>? 3c-3f
|
|||
|
|
{0x00, 2}, {0x18, 0}, {0x13, 0}, {0x0e, 0}, // @ABC 40-43
|
|||
|
|
{0x12, 0}, {0x10, 0}, {0x16, 0}, {0x0b, 0}, // DEFG
|
|||
|
|
{0x05, 0}, {0x0c, 0}, {0x1a, 0}, {0x1e, 0}, // HIJK
|
|||
|
|
{0x09, 0}, {0x07, 0}, {0x06, 0}, {0x03, 0}, // LMNO
|
|||
|
|
{0x0d, 0}, {0x1d, 0}, {0x0a, 0}, {0x14, 0}, // PQRS
|
|||
|
|
{0x01, 0}, {0x1c, 0}, {0x0f, 0}, {0x19, 0}, // TUVW
|
|||
|
|
{0x17, 0}, {0x15, 0}, {0x11, 0}, {0x00, 2}, // XYZ[ 58-5b
|
|||
|
|
{0x00, 2}, {0x00, 2}, {0x00, 2}, {0x00, 2}, // \]^_
|
|||
|
|
{0x00, 2}, {0x18, 0}, {0x13, 0}, {0x0e, 0}, // @ABC 60-63
|
|||
|
|
{0x12, 0}, {0x10, 0}, {0x16, 0}, {0x0b, 0}, // DEFG
|
|||
|
|
{0x05, 0}, {0x0c, 0}, {0x1a, 0}, {0x1e, 0}, // HIJK
|
|||
|
|
{0x09, 0}, {0x07, 0}, {0x06, 0}, {0x03, 0}, // LMNO
|
|||
|
|
{0x0d, 0}, {0x1d, 0}, {0x0a, 0}, {0x14, 0}, // PQRS
|
|||
|
|
{0x01, 0}, {0x1c, 0}, {0x0f, 0}, {0x19, 0}, // TUVW
|
|||
|
|
{0x17, 0}, {0x15, 0}, {0x11, 0}, {0x00, 2}, // XYZ[ 78-7b
|
|||
|
|
{0x00, 2}, {0x00, 2}, {0x00, 2}, {0x00, 2}, // |{~
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
__fastcall CBAUDOT::CBAUDOT()
|
|||
|
|
{
|
|||
|
|
Reset();
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
__fastcall CBAUDOT::~CBAUDOT()
|
|||
|
|
{
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
int __fastcall CBAUDOT::GetOneCode(int &fig, int code)
|
|||
|
|
{
|
|||
|
|
int r;
|
|||
|
|
switch(code){
|
|||
|
|
case '\n':
|
|||
|
|
r = 0x08;
|
|||
|
|
fig = 2;
|
|||
|
|
break;
|
|||
|
|
case '\r':
|
|||
|
|
r = 0x02;
|
|||
|
|
fig = 2;
|
|||
|
|
break;
|
|||
|
|
default:
|
|||
|
|
if( (code >= 0x20) && (code <= 0x7f) ){
|
|||
|
|
code -= 0x20;
|
|||
|
|
r = _TTY[code].Code;
|
|||
|
|
fig = _TTY[code].Fig;
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
r = -1;
|
|||
|
|
}
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
return r;
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
// 15bits<74>f<EFBFBD>[<5B>^<5E><><EFBFBD>쐬<EFBFBD><EC90AC><EFBFBD><EFBFBD>
|
|||
|
|
int __fastcall CBAUDOT::DblCode(int code)
|
|||
|
|
{
|
|||
|
|
int d = 7; // Stop bits
|
|||
|
|
int i;
|
|||
|
|
for( i = 0; i < 5; i++, code = code >> 1 ){
|
|||
|
|
d = d << 1;
|
|||
|
|
if( code & 0x0001 ) d |= 1;
|
|||
|
|
d = d << 1;
|
|||
|
|
if( code & 0x0001 ) d |= 1;
|
|||
|
|
}
|
|||
|
|
d = d << 2; // Start bits
|
|||
|
|
return d;
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
int __fastcall CBAUDOT::GetCode(int &count, int code)
|
|||
|
|
{
|
|||
|
|
int fig;
|
|||
|
|
int r = GetOneCode(fig, code);
|
|||
|
|
if( r < 0 ) return r;
|
|||
|
|
//Added by JA7UDE (April 17, 2010)
|
|||
|
|
int ext_r = r;
|
|||
|
|
int ext_f = 0;
|
|||
|
|
//Till here
|
|||
|
|
r = DblCode(r);
|
|||
|
|
if( (m_OutFig < 0) || ((fig != 2)&&(m_OutFig != fig)) || ((m_CodeB4 == ' ')&&(fig==1)) ){
|
|||
|
|
switch(fig){
|
|||
|
|
case 1: // FIG
|
|||
|
|
m_OutFig = 1;
|
|||
|
|
r = r << 15;
|
|||
|
|
r |= DblCode(0x1b);
|
|||
|
|
//Added by JA7UDE (April 17, 2010)
|
|||
|
|
ext_f = 0x1b;
|
|||
|
|
//Till here
|
|||
|
|
break;
|
|||
|
|
default: // LTR
|
|||
|
|
m_OutFig = 0;
|
|||
|
|
r = r << 15;
|
|||
|
|
r |= DblCode(0x1f);
|
|||
|
|
//Added by JA7UDE (April 17, 2010)
|
|||
|
|
ext_f = 0x1f;
|
|||
|
|
//Till here
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
count = 30;
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
count = 15;
|
|||
|
|
}
|
|||
|
|
m_CodeB4 = code;
|
|||
|
|
//Added by JA7UDE on April 5, 2010
|
|||
|
|
if( ext_f ) MainVARI->ExtFskIt(ext_f);
|
|||
|
|
MainVARI->ExtFskIt(ext_r);
|
|||
|
|
//Till here
|
|||
|
|
return r;
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
const char _LTR[32]={
|
|||
|
|
0x00, 'T', 0x0d, 'O', ' ', 'H', 'N', 'M',
|
|||
|
|
0x0a, 'L', 'R', 'G', 'I', 'P', 'C', 'V',
|
|||
|
|
'E', 'Z', 'D', 'B', 'S', 'Y', 'F', 'X',
|
|||
|
|
'A', 'W', 'J', 0x00, 'U', 'Q', 'K', 0x00,
|
|||
|
|
};
|
|||
|
|
const char _FIG[32]={
|
|||
|
|
0x00, '5', 0x0d, '9', ' ', 'h', ',', '.',
|
|||
|
|
0x0a, ')', '4', '&', '8', '0', ':', ';',
|
|||
|
|
'3', '"', '$', '?', 's', '6', '!', '/',
|
|||
|
|
'-', '2', 0x27, 0x00, '7', '1', '(', 0x00,
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
CRTTY::CRTTY()
|
|||
|
|
{
|
|||
|
|
m_outfig = 3;
|
|||
|
|
|
|||
|
|
m_fig = 0;
|
|||
|
|
m_uos = TRUE;
|
|||
|
|
|
|||
|
|
m_txuos = 1;
|
|||
|
|
m_CodeSet = 0; // 0:S-BELL, 1:J-BELL
|
|||
|
|
SetCodeSet();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void CRTTY::SetCodeSet(void)
|
|||
|
|
{
|
|||
|
|
memcpy(m_TBL, _TTY, sizeof(m_TBL));
|
|||
|
|
if( m_CodeSet ){ // J-BELL
|
|||
|
|
m_TBL[7].Code = 0x14;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 11011 FIG
|
|||
|
|
// 11111 LTR
|
|||
|
|
char CRTTY::ConvAscii(int d)
|
|||
|
|
{
|
|||
|
|
char c = 0;
|
|||
|
|
d &= 0x1f;
|
|||
|
|
if( d == 0x1b ){ // FIG
|
|||
|
|
m_fig = 1;
|
|||
|
|
}
|
|||
|
|
else if( d == 0x1f ){ // LTR
|
|||
|
|
m_fig = 0;
|
|||
|
|
}
|
|||
|
|
else if( m_fig ){
|
|||
|
|
c = _FIG[d];
|
|||
|
|
if( m_CodeSet ){
|
|||
|
|
switch(c){
|
|||
|
|
case 's':
|
|||
|
|
c = 0x27;
|
|||
|
|
break;
|
|||
|
|
case 0x27:
|
|||
|
|
c = 'j';
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
if( m_uos ){
|
|||
|
|
switch(c){
|
|||
|
|
case ' ':
|
|||
|
|
// case 0x0d:
|
|||
|
|
// case 0x0a:
|
|||
|
|
m_fig = 0;
|
|||
|
|
break;
|
|||
|
|
default:
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
c = _LTR[d];
|
|||
|
|
}
|
|||
|
|
return c;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
int CRTTY::ConvRTTY(char d)
|
|||
|
|
{
|
|||
|
|
int fig = 2;
|
|||
|
|
int r = 0;
|
|||
|
|
switch(d){
|
|||
|
|
case '_':
|
|||
|
|
r = 0x00ff;
|
|||
|
|
break;
|
|||
|
|
case '~':
|
|||
|
|
r = 0x00fe;
|
|||
|
|
break;
|
|||
|
|
case '[':
|
|||
|
|
r = 0x00fd;
|
|||
|
|
break;
|
|||
|
|
case ']':
|
|||
|
|
r = 0x00fc;
|
|||
|
|
break;
|
|||
|
|
case 0x0a:
|
|||
|
|
r = 0x08;
|
|||
|
|
break;
|
|||
|
|
case 0x0d:
|
|||
|
|
r = 0x02;
|
|||
|
|
break;
|
|||
|
|
case 0x1b:
|
|||
|
|
r = 0x1b;
|
|||
|
|
fig = 1;
|
|||
|
|
break;
|
|||
|
|
case 0x1f:
|
|||
|
|
r = 0x1f;
|
|||
|
|
fig = 0;
|
|||
|
|
break;
|
|||
|
|
default:
|
|||
|
|
if( d >= 0x20 ){
|
|||
|
|
d -= char(0x20);
|
|||
|
|
r = m_TBL[d].Code;
|
|||
|
|
fig = m_TBL[d].Fig;
|
|||
|
|
}
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
if( fig != 2 ){
|
|||
|
|
if( fig != m_outfig ){
|
|||
|
|
r |= (fig ? 0x1b00 : 0x1f00);
|
|||
|
|
m_outfig = fig;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else if( r == 0x04 ){ // <20>X<EFBFBD>y<EFBFBD>[<5B>X<EFBFBD>̎<EFBFBD>
|
|||
|
|
if( m_outfig == 1 ) m_outfig = 2;
|
|||
|
|
}
|
|||
|
|
return r;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
int CRTTY::ConvRTTY(BYTE *t, LPCSTR p)
|
|||
|
|
{
|
|||
|
|
int n;
|
|||
|
|
int d;
|
|||
|
|
for( n = 0;*p; p++ ){
|
|||
|
|
d = ConvRTTY(*p);
|
|||
|
|
if( d & 0x0000ff00 ){
|
|||
|
|
*t++ = BYTE(d >> 8);
|
|||
|
|
n++;
|
|||
|
|
}
|
|||
|
|
*t++ = BYTE(d);
|
|||
|
|
n++;
|
|||
|
|
}
|
|||
|
|
return n;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
int CRTTY::GetShift(char d)
|
|||
|
|
{
|
|||
|
|
int fig = 2;
|
|||
|
|
switch(d){
|
|||
|
|
default:
|
|||
|
|
if( d >= 0x20 ){
|
|||
|
|
d -= char(0x20);
|
|||
|
|
fig = m_TBL[d].Fig;
|
|||
|
|
if( !m_TBL[d].Code ){
|
|||
|
|
fig = 2;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
return fig;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
char CRTTY::InvShift(char c)
|
|||
|
|
{
|
|||
|
|
int fs = GetShift(c);
|
|||
|
|
if( (c == 'h') || (c == 's') || (c == 'j') ) fs = 1;
|
|||
|
|
int d = ConvRTTY(c) & 0x001f;
|
|||
|
|
switch(fs){
|
|||
|
|
case 0:
|
|||
|
|
if( _FIG[d] ){
|
|||
|
|
c = _FIG[d];
|
|||
|
|
if( m_CodeSet ){
|
|||
|
|
switch(c){
|
|||
|
|
case 's':
|
|||
|
|
c = 0x27;
|
|||
|
|
break;
|
|||
|
|
case 0x27:
|
|||
|
|
c = 'j';
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return c;
|
|||
|
|
case 1:
|
|||
|
|
return _LTR[d] ? _LTR[d] : c;
|
|||
|
|
default:
|
|||
|
|
return c;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
__fastcall CClock::CClock()
|
|||
|
|
{
|
|||
|
|
m_pData = NULL;
|
|||
|
|
m_SampleFreq = SAMPFREQ;
|
|||
|
|
m_ToneFreq = 1000.0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
__fastcall CClock::~CClock()
|
|||
|
|
{
|
|||
|
|
if( m_pData ) delete m_pData;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
void __fastcall CClock::Create(int max)
|
|||
|
|
{
|
|||
|
|
m_Width = max;
|
|||
|
|
if( m_pData ) delete m_pData;
|
|||
|
|
m_pData = new int[m_Width];
|
|||
|
|
memset(m_pData, 0, sizeof(int)*m_Width);
|
|||
|
|
m_dNow = 0;
|
|||
|
|
m_BPF.m_Freq = m_ToneFreq;
|
|||
|
|
m_BPF.m_BW = 100.0;
|
|||
|
|
SetSampleFreq(m_SampleFreq);
|
|||
|
|
m_LPF.Create(ffLPF, 100, m_SampleFreq, 3, 0, 0);
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
void __fastcall CClock::SetSampleFreq(double f)
|
|||
|
|
{
|
|||
|
|
m_SampleFreq = f;
|
|||
|
|
m_dAdd = m_Width / m_SampleFreq;
|
|||
|
|
m_BPF.SetSampleFreq(m_SampleFreq);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
void __fastcall CClock::SetToneFreq(double f)
|
|||
|
|
{
|
|||
|
|
m_ToneFreq = f;
|
|||
|
|
m_BPF.m_Freq = m_ToneFreq;
|
|||
|
|
m_BPF.SetSampleFreq(m_SampleFreq);
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
BOOL __fastcall CClock::Do(short ds)
|
|||
|
|
{
|
|||
|
|
BOOL f = FALSE;
|
|||
|
|
double d = m_BPF.Do(ds);
|
|||
|
|
d = m_LPF.Do(ABS(d));
|
|||
|
|
int i = m_dNow;
|
|||
|
|
if( i < 0 ) i = 0;
|
|||
|
|
if( i > m_Width ) i = m_Width;
|
|||
|
|
m_pData[i] = d;
|
|||
|
|
m_dNow += m_dAdd;
|
|||
|
|
if( m_dNow >= m_Width ){
|
|||
|
|
f = TRUE;
|
|||
|
|
m_dNow -= m_Width;
|
|||
|
|
}
|
|||
|
|
if( m_dNow < 0 ) m_dNow += m_Width;
|
|||
|
|
return f;
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
__fastcall CAMPCONT::CAMPCONT()
|
|||
|
|
{
|
|||
|
|
m_Max = g_SinTable.m_Size / 4;
|
|||
|
|
m_iMax = g_SinTable.m_Size / 4;
|
|||
|
|
m_Cnt = m_Max;
|
|||
|
|
m_S = 0;
|
|||
|
|
SetMax(16);
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
void __fastcall CAMPCONT::SetMax(int max)
|
|||
|
|
{
|
|||
|
|
m_ADD = m_Max / double(max);
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
void __fastcall CAMPCONT::Reset(void)
|
|||
|
|
{
|
|||
|
|
m_Cnt = m_Max;
|
|||
|
|
m_S = 0;
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
double __fastcall CAMPCONT::Do(int s)
|
|||
|
|
{
|
|||
|
|
if( s != m_S ){
|
|||
|
|
m_Cnt = 0.0;
|
|||
|
|
m_S = s;
|
|||
|
|
}
|
|||
|
|
int r = m_Cnt;
|
|||
|
|
if( r >= m_Max ) return s;
|
|||
|
|
m_Cnt += m_ADD;
|
|||
|
|
if( s ){
|
|||
|
|
return g_SinTable.m_tSin[r];
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
return g_SinTable.m_tSin[r+m_iMax];
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
__fastcall CBFifo::CBFifo()
|
|||
|
|
{
|
|||
|
|
m_WP = m_RP = m_CNT = m_MAX = 0;
|
|||
|
|
m_pBase = NULL;
|
|||
|
|
m_D = FALSE;
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
__fastcall CBFifo::~CBFifo()
|
|||
|
|
{
|
|||
|
|
if( m_pBase ){
|
|||
|
|
delete m_pBase;
|
|||
|
|
m_pBase = NULL;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
void __fastcall CBFifo::Create(int max)
|
|||
|
|
{
|
|||
|
|
if( m_pBase ) delete m_pBase;
|
|||
|
|
m_pBase = new BOOL[max];
|
|||
|
|
m_WP = m_RP = m_CNT = 0;
|
|||
|
|
m_MAX = max;
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
void __fastcall CBFifo::PutFlag(BOOL f)
|
|||
|
|
{
|
|||
|
|
if( m_CNT < m_MAX ){
|
|||
|
|
m_pBase[m_WP] = f;
|
|||
|
|
m_WP++;
|
|||
|
|
if( m_WP >= m_MAX ) m_WP = 0;
|
|||
|
|
m_CNT++;
|
|||
|
|
if( m_CNT >= m_MAX ) m_CNT = m_MAX;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
BOOL __fastcall CBFifo::GetFlag(void)
|
|||
|
|
{
|
|||
|
|
if( m_CNT ){
|
|||
|
|
m_D = m_pBase[m_RP];
|
|||
|
|
m_RP++;
|
|||
|
|
if( m_RP >= m_MAX ) m_RP = 0;
|
|||
|
|
m_CNT--;
|
|||
|
|
}
|
|||
|
|
return m_D;
|
|||
|
|
}
|
|||
|
|
/*=============================================================================
|
|||
|
|
CPHASE<EFBFBD>N<EFBFBD><EFBFBD><EFBFBD>X
|
|||
|
|
=============================================================================*/
|
|||
|
|
__fastcall CPHASE::CPHASE()
|
|||
|
|
{
|
|||
|
|
m_MFSK_TONES = 16;
|
|||
|
|
m_MFSK_SPEED = 15.625;
|
|||
|
|
m_MFSK_BASEPOINT = int(MFSK_BASEFREQ/15.625);
|
|||
|
|
|
|||
|
|
m_SampleFreq = 11025.0*0.5;
|
|||
|
|
m_CarrierFreq = 1750;
|
|||
|
|
m_MixerFreq = 0;
|
|||
|
|
SetSampleFreq(m_SampleFreq);
|
|||
|
|
}
|
|||
|
|
//--------------------------------------------------------------------------
|
|||
|
|
void __fastcall CPHASE::SetMFSKType(int type)
|
|||
|
|
{
|
|||
|
|
MFSK_SetPara(type, &m_MFSK_TONES, &m_MFSK_SPEED, NULL);
|
|||
|
|
m_MFSK_BASEPOINT = int(MFSK_BASEFREQ/m_MFSK_SPEED);
|
|||
|
|
}
|
|||
|
|
//--------------------------------------------------------------------------
|
|||
|
|
void __fastcall CPHASE::SetSampleFreq(double f)
|
|||
|
|
{
|
|||
|
|
m_SampleFreq = f;
|
|||
|
|
Create();
|
|||
|
|
}
|
|||
|
|
//--------------------------------------------------------------------------
|
|||
|
|
void __fastcall CPHASE::Create(void)
|
|||
|
|
{
|
|||
|
|
m_SymbolLen = m_SampleFreq/m_MFSK_SPEED;
|
|||
|
|
m_MixerFreq = double(m_MFSK_BASEPOINT) * m_SampleFreq / m_SymbolLen;
|
|||
|
|
m_VCO.SetSampleFreq(m_SampleFreq);
|
|||
|
|
m_Hilbert.Create(20, m_SampleFreq, 25.0, m_SampleFreq*0.5 - 25.0);
|
|||
|
|
m_Hilbert.Clear();
|
|||
|
|
SetCarrierFreq(m_CarrierFreq);
|
|||
|
|
m_SlideFFT.Create(int(m_SymbolLen + 0.5), m_MFSK_BASEPOINT, m_MFSK_TONES);
|
|||
|
|
}
|
|||
|
|
//--------------------------------------------------------------------------
|
|||
|
|
void __fastcall CPHASE::SetCarrierFreq(double f)
|
|||
|
|
{
|
|||
|
|
m_CarrierFreq = f;
|
|||
|
|
m_VCO.SetFreeFreq(m_CarrierFreq - m_MixerFreq);
|
|||
|
|
}
|
|||
|
|
//--------------------------------------------------------------------------
|
|||
|
|
CLX* __fastcall CPHASE::Do(double d)
|
|||
|
|
{
|
|||
|
|
m_Hilbert.Do(m_sig, d); // <20><><EFBFBD>f<EFBFBD><66><EFBFBD><EFBFBD>
|
|||
|
|
|
|||
|
|
CLX z;
|
|||
|
|
z.r = m_VCO.Do();
|
|||
|
|
z.j = m_VCO.DoCos();
|
|||
|
|
z *= m_sig; // <20><><EFBFBD>g<EFBFBD><67><EFBFBD>ϊ<EFBFBD>
|
|||
|
|
|
|||
|
|
return m_SlideFFT.Do(z);
|
|||
|
|
}
|
|||
|
|
/*=============================================================================
|
|||
|
|
CDecMFSK<EFBFBD>N<EFBFBD><EFBFBD><EFBFBD>X
|
|||
|
|
=============================================================================*/
|
|||
|
|
__fastcall CDecMFSK::CDecMFSK()
|
|||
|
|
{
|
|||
|
|
m_MFSK_TYPE = typMFSK16;
|
|||
|
|
m_MFSK_TONES = 16;
|
|||
|
|
m_MFSK_SPEED = 15.625;
|
|||
|
|
m_MFSK_BITS = 4;
|
|||
|
|
m_MFSK_BW = m_MFSK_SPEED * (m_MFSK_TONES - 1);
|
|||
|
|
|
|||
|
|
m_InterLeaver.Init(m_MFSK_BITS);
|
|||
|
|
m_AmpStgPtr = 0;
|
|||
|
|
m_SHDATA = 0;
|
|||
|
|
|
|||
|
|
m_Metric1 = m_Metric2 = 0;
|
|||
|
|
m_ViterbiPair[0] = m_ViterbiPair[1] = 0;
|
|||
|
|
m_ViterbiPhase = 0;
|
|||
|
|
m_Viterbi1.Init(MFSK_VITERBI_K, MFSK_VITERBI_POLY1, MFSK_VITERBI_POLY2);
|
|||
|
|
m_Viterbi2.Init(MFSK_VITERBI_K, MFSK_VITERBI_POLY1, MFSK_VITERBI_POLY2);
|
|||
|
|
|
|||
|
|
memset(m_SymStg, 0, sizeof(m_SymStg));
|
|||
|
|
|
|||
|
|
m_AvgMetric = 0;
|
|||
|
|
|
|||
|
|
m_dNow = 0;
|
|||
|
|
|
|||
|
|
m_Tmg = m_SyncState = 0;
|
|||
|
|
|
|||
|
|
m_fLSB = FALSE;
|
|||
|
|
m_RxData.Clear();
|
|||
|
|
|
|||
|
|
m_fSQ = FALSE;
|
|||
|
|
m_fDelaySQ = FALSE;
|
|||
|
|
m_SQDelayCount = 0;
|
|||
|
|
|
|||
|
|
m_AvgClock.Create(8);
|
|||
|
|
m_AvgAFC.Create(8);
|
|||
|
|
m_PrevZ = 0;
|
|||
|
|
m_kAFC = 0;
|
|||
|
|
m_AFCWidth = 0;
|
|||
|
|
SetSampleFreq(11025*0.5);
|
|||
|
|
}
|
|||
|
|
//--------------------------------------------------------------------------
|
|||
|
|
void __fastcall CDecMFSK::SetMFSKType(int type)
|
|||
|
|
{
|
|||
|
|
m_MFSK_TYPE = type;
|
|||
|
|
MFSK_SetPara(type, &m_MFSK_TONES, &m_MFSK_SPEED, &m_MFSK_BITS);
|
|||
|
|
m_MFSK_BW = m_MFSK_SPEED * (m_MFSK_TONES - 1);
|
|||
|
|
m_InterLeaver.Init(m_MFSK_BITS);
|
|||
|
|
SetSampleFreq(m_SampleFreq);
|
|||
|
|
}
|
|||
|
|
//--------------------------------------------------------------------------
|
|||
|
|
void __fastcall CDecMFSK::SetCarrierFreq(double f)
|
|||
|
|
{
|
|||
|
|
if( sys.m_MFSK_Center ){
|
|||
|
|
f -= m_MFSK_BW*0.5;
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
if( m_fLSB ) f -= m_MFSK_BW;
|
|||
|
|
}
|
|||
|
|
m_Phase.SetCarrierFreq(f);
|
|||
|
|
m_AvgAFC.Reset();
|
|||
|
|
}
|
|||
|
|
//--------------------------------------------------------------------------
|
|||
|
|
void __fastcall CDecMFSK::Reset(void)
|
|||
|
|
{
|
|||
|
|
m_SHDATA = 0;
|
|||
|
|
|
|||
|
|
m_dNow = 0;
|
|||
|
|
m_dTW = m_dBTW = m_SampleFreq / m_MFSK_SPEED;
|
|||
|
|
m_dBTWL = m_dBTW * (1.0-(15000.0 * 1.0e-6));
|
|||
|
|
m_dBTWH = m_dBTW * (1.0+(15000.0 * 1.0e-6));
|
|||
|
|
|
|||
|
|
m_AvgMetric = 0;
|
|||
|
|
memset(m_SymStg, 0, sizeof(m_SymStg));
|
|||
|
|
|
|||
|
|
m_AmpStgPtr = 0;
|
|||
|
|
memset(m_AmpStg, 0, sizeof(m_AmpStg));
|
|||
|
|
|
|||
|
|
m_Metric1 = m_Metric2 = 0;
|
|||
|
|
m_ViterbiPair[0] = m_ViterbiPair[1] = 0;
|
|||
|
|
m_ViterbiPhase = 0;
|
|||
|
|
|
|||
|
|
m_Viterbi1.Reset();
|
|||
|
|
m_Viterbi2.Reset();
|
|||
|
|
|
|||
|
|
m_RxData.Clear();
|
|||
|
|
m_InterLeaver.Reset();
|
|||
|
|
|
|||
|
|
m_SyncState = FALSE;
|
|||
|
|
|
|||
|
|
m_fSQ = FALSE;
|
|||
|
|
m_fDelaySQ = FALSE;
|
|||
|
|
m_SQDelayCount = 0;
|
|||
|
|
ResetMeas();
|
|||
|
|
}
|
|||
|
|
//--------------------------------------------------------------------------
|
|||
|
|
void __fastcall CDecMFSK::SetSampleFreq(double f)
|
|||
|
|
{
|
|||
|
|
m_SampleFreq = f;
|
|||
|
|
m_dTW = m_dBTW = m_SampleFreq / m_MFSK_SPEED;
|
|||
|
|
m_kAFC = m_MFSK_SPEED / (2.0*PI);
|
|||
|
|
m_AFCWidth = m_MFSK_SPEED * 0.48;
|
|||
|
|
m_AmpStgMax = int(m_dBTW * 2);
|
|||
|
|
#if DEBUG
|
|||
|
|
if( m_AmpStgMax > AMPSTGMAX ) Application->MainForm->Caption = "Over AmpStgSize of MFSK";
|
|||
|
|
#endif
|
|||
|
|
memset(m_AmpStg, 0, sizeof(m_AmpStg));
|
|||
|
|
// Application->MainForm->Caption = m_MFSK_TONES;
|
|||
|
|
m_Phase.SetMFSKType(m_MFSK_TYPE);
|
|||
|
|
m_Phase.SetSampleFreq(m_SampleFreq);
|
|||
|
|
Reset();
|
|||
|
|
}
|
|||
|
|
//--------------------------------------------------------------------------
|
|||
|
|
void __fastcall CDecMFSK::ResetMeas(void)
|
|||
|
|
{
|
|||
|
|
m_AvgClock.Reset();
|
|||
|
|
m_MeasClock = m_MeasCounter = m_MeasStage = 0;
|
|||
|
|
m_dTW = m_dBTW;
|
|||
|
|
};
|
|||
|
|
//--------------------------------------------------------------------------
|
|||
|
|
double __fastcall CDecMFSK::GetFactor(void)
|
|||
|
|
{
|
|||
|
|
// Application->MainForm->Caption = m_ViterbiPhase;
|
|||
|
|
if( m_ViterbiPhase < 256 ){
|
|||
|
|
return 0.001;
|
|||
|
|
}
|
|||
|
|
else if( m_MFSK_TONES == 8 ){
|
|||
|
|
return 0.01625;
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
return 0.03125;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
//--------------------------------------------------------------------------
|
|||
|
|
// - MFSK8,MFSK31<33>̏ꍇ<CC8F>͊<CD8A>t<EFBFBD>F<EFBFBD>[<5B>Y<EFBFBD>Ƌ<EFBFBD><C68B><EFBFBD><EFBFBD>t<EFBFBD>F<EFBFBD>[<5B>Y<EFBFBD><59><EFBFBD><EFBFBD><EFBFBD>邽<EFBFBD>߁A
|
|||
|
|
// 2<><EFBFBD>Viterbi<62>̂<EFBFBD><CC82><EFBFBD><EFBFBD>ق<EFBFBD><D982><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|||
|
|
// - MFSK16<31><36>2<EFBFBD><32><EFBFBD><EFBFBD>1<EFBFBD><31>Viterbi2<69><32><EFBFBD><EFBFBD><EFBFBD>s<EFBFBD><73><EFBFBD><EFBFBD>
|
|||
|
|
void __fastcall CDecMFSK::StreamSym(BYTE sym)
|
|||
|
|
{
|
|||
|
|
int c, metric;
|
|||
|
|
|
|||
|
|
m_ViterbiPair[0] = m_ViterbiPair[1]; m_ViterbiPair[1] = sym;
|
|||
|
|
m_ViterbiPhase++;
|
|||
|
|
if( m_ViterbiPhase & 1 ){ // MFSK8, MFSK31
|
|||
|
|
if( m_MFSK_TONES == 16 ) return;
|
|||
|
|
if( (c = m_Viterbi1.Decode(&metric, m_ViterbiPair)) == -1 ) return;
|
|||
|
|
DoAvg(m_Metric1, metric, GetFactor());
|
|||
|
|
if( m_Metric1 < m_Metric2 ) return;
|
|||
|
|
m_AvgMetric = m_Metric1;
|
|||
|
|
// Application->MainForm->Caption = "Phase odd";
|
|||
|
|
}
|
|||
|
|
else { // MFSK8, MFSK16, MFSK31
|
|||
|
|
if( (c = m_Viterbi2.Decode(&metric, m_ViterbiPair)) == -1 ) return;
|
|||
|
|
DoAvg(m_Metric2, metric, GetFactor());
|
|||
|
|
if( (m_MFSK_TONES != 16) && (m_Metric2 < m_Metric1) ) return;
|
|||
|
|
m_AvgMetric = m_Metric2;
|
|||
|
|
// Application->MainForm->Caption = "Phase even";
|
|||
|
|
}
|
|||
|
|
// char bf[256];
|
|||
|
|
// sprintf(bf, "%d", m_ViterbiPhase);
|
|||
|
|
// Application->MainForm->Caption = bf;
|
|||
|
|
//
|
|||
|
|
// S/N Metric
|
|||
|
|
// 30dB 240
|
|||
|
|
// 20dB 220
|
|||
|
|
// 10dB 110
|
|||
|
|
// Application->MainForm->Caption = int(m_AvgMetric);
|
|||
|
|
//
|
|||
|
|
m_SHDATA = m_SHDATA << 1;
|
|||
|
|
if( c ) m_SHDATA |= 1;
|
|||
|
|
|
|||
|
|
if( (m_SHDATA & 7) == 1 ){ // 001<30><31><EFBFBD>T<EFBFBD><54>
|
|||
|
|
c = g_VariCode.DecodeMFSK(m_SHDATA >> 1);
|
|||
|
|
if( (c != -1) && (m_fSQ || m_fDelaySQ) ) m_RxData.PutData(c);
|
|||
|
|
m_SHDATA = 1; // <20><><EFBFBD>̕<EFBFBD><CC95><EFBFBD>(1xxx)<29>̐擪
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
//--------------------------------------------------------------------------
|
|||
|
|
BYTE __fastcall Limit256(double x)
|
|||
|
|
{
|
|||
|
|
if( x < 0 ) return 0;
|
|||
|
|
if( x > 255 ) return 255;
|
|||
|
|
return BYTE(x);
|
|||
|
|
}
|
|||
|
|
//--------------------------------------------------------------------------
|
|||
|
|
void __fastcall CDecMFSK::RecSym(const double *pAmp)
|
|||
|
|
{
|
|||
|
|
int i, n;
|
|||
|
|
BYTE tSym[MFSK_MAXBITS];
|
|||
|
|
double tVal[MFSK_MAXBITS];
|
|||
|
|
double *dp;
|
|||
|
|
|
|||
|
|
memset(tVal, 0, sizeof(tVal));
|
|||
|
|
double sum = 1e-10;
|
|||
|
|
for(i = 0; i < m_MFSK_TONES; i++){
|
|||
|
|
if( m_fLSB ){
|
|||
|
|
n = m_MFSK_TONES - i - 1;
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
n = i;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
double v = pAmp[n]; // <20><><EFBFBD><EFBFBD><EFBFBD>U<EFBFBD><55>
|
|||
|
|
int gray = (i >> 1) ^ i; // <20>O<EFBFBD><4F><EFBFBD>[<5B>R<EFBFBD>[<5B>h<EFBFBD>ɕϊ<C995>
|
|||
|
|
int mask = m_MFSK_TONES >> 1;
|
|||
|
|
dp = tVal;
|
|||
|
|
for( n = 0; n < m_MFSK_BITS; n++, mask = mask >> 1, dp++ ){
|
|||
|
|
if( gray & mask ){
|
|||
|
|
*dp += v;
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
*dp -= v;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
sum += v;
|
|||
|
|
}
|
|||
|
|
sum = 128.0 / sum;
|
|||
|
|
dp = tVal;
|
|||
|
|
BYTE *bp = tSym;
|
|||
|
|
for(i = 0; i < m_MFSK_BITS; i++){
|
|||
|
|
*bp++ = Limit256(128.0 + (sum * *dp++));
|
|||
|
|
}
|
|||
|
|
m_InterLeaver.DecodeSyms(tSym);
|
|||
|
|
bp = tSym;
|
|||
|
|
for(i = 0; i < m_MFSK_BITS; i++) StreamSym(*bp++);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//--------------------------------------------------------------------------
|
|||
|
|
BYTE __fastcall CDecMFSK::DecodeSym(CLX *pFFT, double *pAmp)
|
|||
|
|
{
|
|||
|
|
int sym = 0;
|
|||
|
|
double d;
|
|||
|
|
double max = 0.0;
|
|||
|
|
|
|||
|
|
for( int i = 0; i < m_MFSK_TONES; i++ ){
|
|||
|
|
*pAmp++ = d = pFFT[i].vAbs();
|
|||
|
|
if( d > max ){
|
|||
|
|
max = d;
|
|||
|
|
sym = i;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return BYTE(sym);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//--------------------------------------------------------------------------
|
|||
|
|
void __fastcall CDecMFSK::DoSync(void)
|
|||
|
|
{
|
|||
|
|
/*
|
|||
|
|
<EFBFBD>P<EFBFBD>O<EFBFBD>̃V<EFBFBD><EFBFBD><EFBFBD>{<EFBFBD><EFBFBD><EFBFBD>̍ő<EFBFBD><EFBFBD>U<EFBFBD><EFBFBD><EFBFBD>ʒu<EFBFBD><EFBFBD>
|
|||
|
|
|
|||
|
|
m_dBTW = 7, m_AmpStgMax = 14
|
|||
|
|
v = m_AmpStgPtr
|
|||
|
|
22220001111111 = m_AmpStg[]
|
|||
|
|
<--i<--------- i = 0 to 13
|
|||
|
|
3210dcba987654
|
|||
|
|
N
|
|||
|
|
*/
|
|||
|
|
int N = 0;
|
|||
|
|
double max = 0.0;
|
|||
|
|
double *pAmp = &m_AmpStg[m_AmpStgPtr][m_SymStg[1]];
|
|||
|
|
for(int i = 0; i < m_AmpStgMax; i++){
|
|||
|
|
if( pAmp < m_AmpStg[0] ){
|
|||
|
|
pAmp = &m_AmpStg[m_AmpStgMax-1][m_SymStg[1]];
|
|||
|
|
}
|
|||
|
|
if( *pAmp > max){
|
|||
|
|
N = i;
|
|||
|
|
max = *pAmp;
|
|||
|
|
}
|
|||
|
|
pAmp -= MFSK_MAXTONES;
|
|||
|
|
}
|
|||
|
|
// <20>J<EFBFBD>E<EFBFBD><45><EFBFBD>^<5E><><EFBFBD><EFBFBD><E290B3><EFBFBD><EFBFBD>
|
|||
|
|
m_dNow += (N - m_dTW) * 0.125;
|
|||
|
|
|
|||
|
|
// <20>^<5E>C<EFBFBD>~<7E><><EFBFBD>O<EFBFBD>v<EFBFBD><76><EFBFBD>̊J<CC8A>n
|
|||
|
|
if( m_MeasStage < 16 ){
|
|||
|
|
m_MeasStage++;
|
|||
|
|
m_MeasClock = m_MeasCounter = 0;
|
|||
|
|
m_SyncState = FALSE;
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
m_SyncState = (fabs(m_dNow) < (m_dTW * 0.05));
|
|||
|
|
}
|
|||
|
|
// char bf[256];
|
|||
|
|
// sprintf(bf, "%.1lf", m_dNow);
|
|||
|
|
// Application->MainForm->Caption = bf;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//--------------------------------------------------------------------------
|
|||
|
|
void __fastcall CDecMFSK::DoMeas(void)
|
|||
|
|
{
|
|||
|
|
if( m_MeasStage ){
|
|||
|
|
m_MeasClock++;
|
|||
|
|
if( m_MeasClock >= 128 ){
|
|||
|
|
m_AvgClock.Do(double(m_MeasCounter)/double(m_MeasClock));
|
|||
|
|
m_MeasClock = m_MeasCounter = 0;
|
|||
|
|
|
|||
|
|
// ATC<54><43><EFBFBD><EFBFBD>
|
|||
|
|
if( IsMetSQ() ){
|
|||
|
|
DoAvg(m_dTW, m_AvgClock.GetAvg(), (m_AvgMetric >= 200) ? 0.8 : 0.4);
|
|||
|
|
if( m_dTW < m_dBTWL ){ m_dTW = m_dBTWL; }
|
|||
|
|
if( m_dTW > m_dBTWH ){ m_dTW = m_dBTWH; }
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
DoAvg(m_dTW, m_dBTW, 0.25);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
//--------------------------------------------------------------------------
|
|||
|
|
void __fastcall CDecMFSK::DoAFC(CLX *pFFT)
|
|||
|
|
{
|
|||
|
|
// <20>R<EFBFBD>V<EFBFBD><56><EFBFBD>{<7B><><EFBFBD>A<EFBFBD><41><EFBFBD>œ<EFBFBD><C593><EFBFBD><EFBFBD><EFBFBD><EFBFBD>g<EFBFBD><67>
|
|||
|
|
if( (m_SymStg[2] != m_SymStg[1]) || (m_SymStg[2] != m_SymStg[0]) ) return;
|
|||
|
|
// <20>x<EFBFBD>[<5B>X<EFBFBD>g<EFBFBD>[<5B><><EFBFBD>݂̂<CC82><DD82><EFBFBD><EFBFBD>o<EFBFBD><6F><EFBFBD><EFBFBD>
|
|||
|
|
if( m_fLSB ){
|
|||
|
|
if( m_SymStg[2] != (m_MFSK_TONES - 1) ) return;
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
if( m_SymStg[2] != 0 ) return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
int err = GetClockError();
|
|||
|
|
if( ABS(err) >= 2000 ) return; // ATC<54><EFBFBD><E290B3><EFBFBD>傫<EFBFBD><E582AB><EFBFBD><EFBFBD><EFBFBD>͌덷<CD8C><EB8DB7><EFBFBD>傫<EFBFBD><E582AB>
|
|||
|
|
|
|||
|
|
CLX z;
|
|||
|
|
pFFT += m_SymStg[2];
|
|||
|
|
pFFT->PhDiff(z, m_PrevZ); // <20>ʑ<EFBFBD><CA91><EFBFBD><EFBFBD>̂ݕK<DD95>v<EFBFBD>Ȃ̂ŕ<CC82><C595><EFBFBD><EFBFBD>̌v<CC8C>Z<EFBFBD>͕s<CD95>v
|
|||
|
|
double ferr = z.Phase() * m_kAFC; // <20>ʑ<EFBFBD><CA91><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>g<EFBFBD><67><EFBFBD><EFBFBD><CE8D>ɕϊ<C995>
|
|||
|
|
if( (ferr > -m_AFCWidth) && (ferr < m_AFCWidth) ){
|
|||
|
|
m_AvgAFC.DoZ(ferr);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#if 0
|
|||
|
|
double d = pFFT->Phase() - m_PrevZ.Phase();
|
|||
|
|
d += fmod(2*PI*(m_dBTW-m_dTW), 2*PI);
|
|||
|
|
if( d >= PI ){d = d - PI*2;} else if( d <= -PI ){d = d + PI*2;}
|
|||
|
|
d *= m_kAFC;
|
|||
|
|
char bf[256];
|
|||
|
|
sprintf(bf, "%.2lf %.2lf %.2lf", d, ferr, m_dBTW-m_dTW);
|
|||
|
|
Application->MainForm->Caption = bf;
|
|||
|
|
#endif
|
|||
|
|
}
|
|||
|
|
//--------------------------------------------------------------------------
|
|||
|
|
BOOL __fastcall CDecMFSK::GetAFCShift(double &fq)
|
|||
|
|
{
|
|||
|
|
if( m_AvgAFC.IsFull() ){
|
|||
|
|
fq = m_AvgAFC.GetAvg();
|
|||
|
|
m_AvgAFC.Reset();
|
|||
|
|
return TRUE;
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
return FALSE;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
//--------------------------------------------------------------------------
|
|||
|
|
#define DEBUG_MFSK FALSE
|
|||
|
|
#if DEBUG_MFSK
|
|||
|
|
FILE *pMFSKFP = fopen("test.txt", "wt");
|
|||
|
|
#endif
|
|||
|
|
//--------------------------------------------------------------------------
|
|||
|
|
int __fastcall CDecMFSK::Do(CLX *pFFT, BOOL fSQ)
|
|||
|
|
{
|
|||
|
|
BOOL f = FALSE;
|
|||
|
|
|
|||
|
|
if( m_AmpStgPtr >= m_AmpStgMax ) m_AmpStgPtr = 0;
|
|||
|
|
m_SymStg[2] = DecodeSym(pFFT, m_AmpStg[m_AmpStgPtr]);
|
|||
|
|
|
|||
|
|
m_MeasCounter++;
|
|||
|
|
m_dNow += 1.0;
|
|||
|
|
if( m_dNow >= m_dTW ){
|
|||
|
|
m_dNow -= m_dTW;
|
|||
|
|
m_Tmg = !m_Tmg;
|
|||
|
|
if( fSQ ) DoMeas();
|
|||
|
|
|
|||
|
|
#if DEBUG_MFSK
|
|||
|
|
if( fSQ ) fprintf(pMFSKFP, "%02X\n", m_SymStg[2]);
|
|||
|
|
#endif
|
|||
|
|
|
|||
|
|
// <20>x<EFBFBD><78><EFBFBD>X<EFBFBD>P<EFBFBD><50><EFBFBD>`<60><><EFBFBD><EFBFBD>
|
|||
|
|
if( m_fSQ != fSQ ){
|
|||
|
|
m_fSQ = fSQ;
|
|||
|
|
if( !sys.m_MFSK_SQ_Metric ){
|
|||
|
|
m_SQDelayCount = 32;
|
|||
|
|
}
|
|||
|
|
ResetMeas();
|
|||
|
|
}
|
|||
|
|
else if( m_SQDelayCount ){
|
|||
|
|
m_SQDelayCount--;
|
|||
|
|
if( !m_SQDelayCount ){
|
|||
|
|
m_fDelaySQ = m_fSQ;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
RecSym(m_AmpStg[m_AmpStgPtr]);
|
|||
|
|
// <20>V<EFBFBD><56><EFBFBD>{<7B><><EFBFBD><EFBFBD>2<EFBFBD><32><EFBFBD>A<EFBFBD><41><EFBFBD>ŕω<C595><CF89><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ꍇ<EFBFBD>̂ݓ<CC82><DD93><EFBFBD><EFBFBD>ʒu<CA92><75><EFBFBD>v<EFBFBD>Z
|
|||
|
|
if( (m_SymStg[2] != m_SymStg[1]) && (m_SymStg[0] != m_SymStg[1]) ){
|
|||
|
|
DoSync();
|
|||
|
|
}
|
|||
|
|
if( fSQ ) DoAFC(pFFT);
|
|||
|
|
m_PrevZ = pFFT[m_SymStg[2]];
|
|||
|
|
memcpy(m_SymStg, &m_SymStg[1], 2 * sizeof(m_SymStg[0]));
|
|||
|
|
f = TRUE;
|
|||
|
|
}
|
|||
|
|
m_AmpStgPtr++;
|
|||
|
|
return f;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//--------------------------------------------------------------------------
|
|||
|
|
int __fastcall CDecMFSK::GetData(void)
|
|||
|
|
{
|
|||
|
|
if( m_RxData.GetCount() ){
|
|||
|
|
return m_RxData.GetData();
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
return -1;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
//--------------------------------------------------------------------------
|
|||
|
|
int __fastcall CDecMFSK::GetClockError(void)
|
|||
|
|
{
|
|||
|
|
if( m_AvgClock.GetCount() ){
|
|||
|
|
// double tw = (m_MeasStage >= 2) ? m_dTW : m_AvgClock.GetAvg();
|
|||
|
|
return ((m_dTW / m_dBTW) - 1.0) * 1e6;
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
return 0;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
//--------------------------------------------------------------------------
|
|||
|
|
void __fastcall CDecMFSK::SetTmg(int ppm)
|
|||
|
|
{
|
|||
|
|
if( ppm < -15000 ) ppm = -15000;
|
|||
|
|
if( ppm > 15000 ) ppm = 15000;
|
|||
|
|
|
|||
|
|
m_dBTW = m_SampleFreq / m_MFSK_SPEED;
|
|||
|
|
m_dTW = m_dBTW = m_dBTW + (m_dBTW * ppm * 1.0e-6);
|
|||
|
|
}
|
|||
|
|
//--------------------------------------------------------------------------
|
|||
|
|
// 0 to 2048
|
|||
|
|
int __fastcall CDecMFSK::GetMetric(int sw)
|
|||
|
|
{
|
|||
|
|
double d;
|
|||
|
|
switch(sw){
|
|||
|
|
case 1:
|
|||
|
|
d = m_Metric2;
|
|||
|
|
break;
|
|||
|
|
case 2:
|
|||
|
|
d = m_Metric1;
|
|||
|
|
break;
|
|||
|
|
default:
|
|||
|
|
d = m_AvgMetric;
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
if( d < 80.0 ){
|
|||
|
|
d = (d - 80.0) * 2.0 + 80.0;
|
|||
|
|
if( d < 0.0 ) d = 0.0;
|
|||
|
|
}
|
|||
|
|
else if( d >= 200.0 ){
|
|||
|
|
d = 200.0 + (d - 200.0) * ((512.0-200.0) / (256.0-200.0));
|
|||
|
|
}
|
|||
|
|
return int(d*4.0);
|
|||
|
|
}
|
|||
|
|
/*=============================================================================
|
|||
|
|
CPlayBack<EFBFBD>N<EFBFBD><EFBFBD><EFBFBD>X
|
|||
|
|
=============================================================================*/
|
|||
|
|
__fastcall CPlayBack::CPlayBack()
|
|||
|
|
{
|
|||
|
|
m_StgWidth = 0;
|
|||
|
|
m_StgMax = 0;
|
|||
|
|
m_pStg = NULL;
|
|||
|
|
Clear();
|
|||
|
|
}
|
|||
|
|
//--------------------------------------------------------------------------
|
|||
|
|
__fastcall CPlayBack::~CPlayBack()
|
|||
|
|
{
|
|||
|
|
if( m_pStg ) delete m_pStg;
|
|||
|
|
}
|
|||
|
|
//--------------------------------------------------------------------------
|
|||
|
|
void __fastcall CPlayBack::Delete(void)
|
|||
|
|
{
|
|||
|
|
m_StgMax = 0;
|
|||
|
|
m_StgWidth = 0;
|
|||
|
|
if( m_pStg ){
|
|||
|
|
delete m_pStg;
|
|||
|
|
m_pStg = NULL;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
//--------------------------------------------------------------------------
|
|||
|
|
void __fastcall CPlayBack::Init(int wSize, int SampBase)
|
|||
|
|
{
|
|||
|
|
m_StgWidth = wSize;
|
|||
|
|
m_StgMax = (SampBase * 60.0 / wSize) + 0.5;
|
|||
|
|
int wmax = m_StgMax * wSize;
|
|||
|
|
if( m_pStg ) delete m_pStg;
|
|||
|
|
m_pStg = new short[wmax];
|
|||
|
|
Clear();
|
|||
|
|
}
|
|||
|
|
//--------------------------------------------------------------------------
|
|||
|
|
void __fastcall CPlayBack::Clear(void)
|
|||
|
|
{
|
|||
|
|
m_StgCnt = m_StgRCnt = 0;
|
|||
|
|
m_StgW = m_StgR = 0;
|
|||
|
|
m_WTimer = 0;
|
|||
|
|
}
|
|||
|
|
//--------------------------------------------------------------------------
|
|||
|
|
void __fastcall CPlayBack::Write(const short *p)
|
|||
|
|
{
|
|||
|
|
if( m_StgRCnt ) return;
|
|||
|
|
if( m_WTimer ){
|
|||
|
|
m_WTimer--;
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
memcpy(&m_pStg[m_StgW*m_StgWidth], p, sizeof(short)*m_StgWidth);
|
|||
|
|
m_StgW++;
|
|||
|
|
if( m_StgW >= m_StgMax ) m_StgW = 0;
|
|||
|
|
if( m_StgCnt < m_StgMax ) m_StgCnt++;
|
|||
|
|
}
|
|||
|
|
//--------------------------------------------------------------------------
|
|||
|
|
BOOL __fastcall CPlayBack::Read(short *p)
|
|||
|
|
{
|
|||
|
|
if( !m_StgRCnt ) return FALSE;
|
|||
|
|
|
|||
|
|
memcpy(p, &m_pStg[m_StgR*m_StgWidth], sizeof(WORD)*m_StgWidth);
|
|||
|
|
m_StgR++;
|
|||
|
|
if( m_StgR >= m_StgMax ) m_StgR = 0;
|
|||
|
|
m_StgRCnt--;
|
|||
|
|
return TRUE;
|
|||
|
|
}
|
|||
|
|
//--------------------------------------------------------------------------
|
|||
|
|
void __fastcall CPlayBack::StopPlaying(void)
|
|||
|
|
{
|
|||
|
|
m_StgRCnt = 0;
|
|||
|
|
}
|
|||
|
|
//--------------------------------------------------------------------------
|
|||
|
|
BOOL __fastcall CPlayBack::StartPlaying(int s)
|
|||
|
|
{
|
|||
|
|
if( !m_StgCnt ) return FALSE;
|
|||
|
|
|
|||
|
|
m_WTimer = m_StgMax * 3 / 60;
|
|||
|
|
m_StgRCnt = m_StgMax * s / 60;
|
|||
|
|
if( m_StgRCnt > m_StgCnt ) m_StgRCnt = m_StgCnt;
|
|||
|
|
m_StgR = m_StgW - m_StgRCnt;
|
|||
|
|
if(m_StgR < 0) m_StgR += m_StgMax;
|
|||
|
|
return m_StgRCnt;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/*=============================================================================
|
|||
|
|
CDelay<EFBFBD>N<EFBFBD><EFBFBD><EFBFBD>X
|
|||
|
|
=============================================================================*/
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
__fastcall CDelay::CDelay(void)
|
|||
|
|
{
|
|||
|
|
m_pStg = NULL;
|
|||
|
|
m_Delay = 0;
|
|||
|
|
m_CurPnt = 0;
|
|||
|
|
m_Count = 0;
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
__fastcall CDelay::~CDelay()
|
|||
|
|
{
|
|||
|
|
if( m_pStg ) delete m_pStg;
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
void __fastcall CDelay::Create(int delay)
|
|||
|
|
{
|
|||
|
|
if( !m_pStg || (m_Delay != delay) ){
|
|||
|
|
if( m_pStg ) delete m_pStg;
|
|||
|
|
m_pStg = new double[delay];
|
|||
|
|
}
|
|||
|
|
m_Delay = delay;
|
|||
|
|
Reset();
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
void __fastcall CDelay::Reset(void)
|
|||
|
|
{
|
|||
|
|
memset(m_pStg, 0, sizeof(double)*m_Delay);
|
|||
|
|
m_CurPnt = 0;
|
|||
|
|
m_Count = 0;
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
double __fastcall CDelay::Do(const double &d)
|
|||
|
|
{
|
|||
|
|
double *cp = &m_pStg[m_CurPnt];
|
|||
|
|
double r = *cp;
|
|||
|
|
*cp = d;
|
|||
|
|
m_CurPnt = CIRCULATE(m_CurPnt+1, m_Delay);
|
|||
|
|
if( m_Count < m_Delay ) m_Count++;
|
|||
|
|
return r;
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
double __fastcall CDelay::GetData(void)
|
|||
|
|
{
|
|||
|
|
return m_pStg[m_CurPnt];
|
|||
|
|
}
|
|||
|
|
/*=============================================================================
|
|||
|
|
CCIC<EFBFBD>N<EFBFBD><EFBFBD><EFBFBD>X
|
|||
|
|
=============================================================================*/
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
__fastcall CCIC::CCIC(void)
|
|||
|
|
{
|
|||
|
|
m_N = 0;
|
|||
|
|
m_K = 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
void __fastcall CCIC::Create(int n)
|
|||
|
|
{
|
|||
|
|
m_N = n;
|
|||
|
|
m_K = 1.0 / double(n);
|
|||
|
|
|
|||
|
|
m_Com.Create(n);
|
|||
|
|
m_Z = 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
double __fastcall CCIC::Do(double d)
|
|||
|
|
{
|
|||
|
|
d -= m_Com.Do(d);
|
|||
|
|
d += m_Z;
|
|||
|
|
m_Z = d;
|
|||
|
|
return d * m_K;
|
|||
|
|
}
|
|||
|
|
/*=============================================================================
|
|||
|
|
CCICM<EFBFBD>N<EFBFBD><EFBFBD><EFBFBD>X
|
|||
|
|
=============================================================================*/
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
__fastcall CCICM::CCICM(void)
|
|||
|
|
{
|
|||
|
|
m_N = 0;
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
__fastcall CCICM::~CCICM(void)
|
|||
|
|
{
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
void __fastcall CCICM::Create(int stages, int N)
|
|||
|
|
{
|
|||
|
|
m_N = stages;
|
|||
|
|
for( int i = 0; i < stages; i++ ){
|
|||
|
|
m_tCIC[i].Create(N);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
double __fastcall CCICM::Do(double d)
|
|||
|
|
{
|
|||
|
|
CCIC *cp = m_tCIC;
|
|||
|
|
for( int i = 0; i < m_N; i++, cp++ ){
|
|||
|
|
d = cp->Do(d);
|
|||
|
|
}
|
|||
|
|
return d;
|
|||
|
|
}
|
|||
|
|
/*=============================================================================
|
|||
|
|
CNotches<EFBFBD>N<EFBFBD><EFBFBD><EFBFBD>X
|
|||
|
|
=============================================================================*/
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
__fastcall CNotches::CNotches(void)
|
|||
|
|
{
|
|||
|
|
m_nBaseTaps = 128;
|
|||
|
|
m_NotchWidth = 1;
|
|||
|
|
m_Count = m_Max = 0;
|
|||
|
|
m_pBase = NULL;
|
|||
|
|
m_SampleFreq = SAMPFREQ;
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
__fastcall CNotches::~CNotches()
|
|||
|
|
{
|
|||
|
|
Delete();
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
void __fastcall CNotches::Delete(void)
|
|||
|
|
{
|
|||
|
|
if( m_pBase ){
|
|||
|
|
delete m_pBase;
|
|||
|
|
m_pBase = NULL;
|
|||
|
|
}
|
|||
|
|
m_Count = m_Max = 0;
|
|||
|
|
m_FIR.Delete();
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
void __fastcall CNotches::Create(void)
|
|||
|
|
{
|
|||
|
|
if( m_Count ){
|
|||
|
|
if( m_Count == 1 ){ // <20>V<EFBFBD><56><EFBFBD>O<EFBFBD><4F><EFBFBD>m<EFBFBD>b<EFBFBD>`
|
|||
|
|
m_nTaps = m_nBaseTaps * m_SampleFreq / 11025;
|
|||
|
|
m_nTaps = (m_nTaps + 1) & 0x0ffe;
|
|||
|
|
if( m_nTaps < 4 ) m_nTaps = 4;
|
|||
|
|
double fl = m_pBase[0].Freq - m_NotchWidth;
|
|||
|
|
double fh = m_pBase[0].Freq + m_NotchWidth;
|
|||
|
|
int att = m_NotchWidth > 50 ? 60 : 10;
|
|||
|
|
if( fl < 100.0 ){
|
|||
|
|
m_FIR.Create(m_nTaps, ffHPF, m_SampleFreq, fh, fh, 60, 1.0);
|
|||
|
|
}
|
|||
|
|
else if( (fh > sys.m_MaxCarrier) && (m_NotchWidth >= 10) ){
|
|||
|
|
m_FIR.Create(m_nTaps, ffLPF, m_SampleFreq, fl, fl, 60, 1.0);
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
m_FIR.Create(m_nTaps, ffBEF, m_SampleFreq, fl, fh, att, 1.0);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else { // <20>}<7D><><EFBFBD>`<60>m<EFBFBD>b<EFBFBD>`
|
|||
|
|
m_nTaps = m_nBaseTaps * 1.5 * m_SampleFreq / 11025;
|
|||
|
|
m_nTaps = (m_nTaps + 1) & 0x0ffe;
|
|||
|
|
if( m_nTaps < 4 ) m_nTaps = 4;
|
|||
|
|
int e = m_nTaps / 2;
|
|||
|
|
double *pSamp = new double[e];
|
|||
|
|
double w = m_SampleFreq / m_nTaps;
|
|||
|
|
if( w > 30.0 ) w = 30.0;
|
|||
|
|
double bw = m_NotchWidth;
|
|||
|
|
if( bw < w ) bw = w;
|
|||
|
|
for( int i = 0; i < e; i++ ){
|
|||
|
|
double fq = i * m_SampleFreq / m_nTaps;
|
|||
|
|
double gm = 1.0;
|
|||
|
|
for( int j = 0; j < m_Count; j++ ){
|
|||
|
|
double g = fq - m_pBase[j].Freq;
|
|||
|
|
g = fabs(g);
|
|||
|
|
g = g * 0.5 / bw;
|
|||
|
|
g *= g;
|
|||
|
|
if( g < gm ) gm = g;
|
|||
|
|
}
|
|||
|
|
pSamp[i] = gm;
|
|||
|
|
}
|
|||
|
|
m_FIR.CreateSamp(m_nTaps, m_SampleFreq, pSamp);
|
|||
|
|
delete pSamp;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
void __fastcall CNotches::Alloc(int nIndex)
|
|||
|
|
{
|
|||
|
|
if( nIndex >= m_Max ){
|
|||
|
|
int max = m_Max ? m_Max * 2 : 32;
|
|||
|
|
NOTCHCTR *pNew = new NOTCHCTR[max];
|
|||
|
|
if( m_Count ) memcpy(pNew, m_pBase, m_Count * sizeof(NOTCHCTR));
|
|||
|
|
if( m_pBase ) delete m_pBase;
|
|||
|
|
m_pBase = pNew;
|
|||
|
|
m_Max = max;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
int __fastcall CNotches::Find(int Freq)
|
|||
|
|
{
|
|||
|
|
for( int i = 0; i < m_Count; i++ ){
|
|||
|
|
if( m_pBase[i].Freq == Freq ) return i;
|
|||
|
|
}
|
|||
|
|
return -1;
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
void __fastcall CNotches::Add(int Freq)
|
|||
|
|
{
|
|||
|
|
if( Find(Freq) >= 0 ) return;
|
|||
|
|
|
|||
|
|
Alloc(m_Count);
|
|||
|
|
m_pBase[m_Count].Freq = short(Freq);
|
|||
|
|
m_pBase[m_Count].m_MX = 0;
|
|||
|
|
m_pBase[m_Count].m_MY = 0;
|
|||
|
|
m_Count++;
|
|||
|
|
Create();
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
void __fastcall CNotches::SetFreq(int nIndex, int Freq)
|
|||
|
|
{
|
|||
|
|
if( nIndex < m_Count ){
|
|||
|
|
if( m_pBase[nIndex].Freq != Freq ){
|
|||
|
|
m_pBase[nIndex].Freq = Freq;
|
|||
|
|
Create();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
void __fastcall CNotches::Delete(int nIndex)
|
|||
|
|
{
|
|||
|
|
if( (nIndex < 0) || (nIndex >= m_Count) ) return;
|
|||
|
|
|
|||
|
|
NOTCHCTR *np = &m_pBase[nIndex];
|
|||
|
|
int size = sizeof(NOTCHCTR)*(m_Count-nIndex-1);
|
|||
|
|
if( size > 0 ) memcpy(np, np+1, size);
|
|||
|
|
m_Count--;
|
|||
|
|
if( m_Count ){
|
|||
|
|
Create();
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
Delete();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
/*=============================================================================
|
|||
|
|
CPHASEX<EFBFBD>N<EFBFBD><EFBFBD><EFBFBD>X Added by JE3HHT on Sep.2010 for FFT RTTY demodulator
|
|||
|
|
=============================================================================*/
|
|||
|
|
__fastcall CPHASEX::CPHASEX()
|
|||
|
|
{
|
|||
|
|
m_TONES = 4;
|
|||
|
|
m_SHIFT = 170.0;
|
|||
|
|
m_SampleFreq = 11025.0*0.5;
|
|||
|
|
m_CarrierFreq = 1750;
|
|||
|
|
SetSampleFreq(m_SampleFreq);
|
|||
|
|
}
|
|||
|
|
//--------------------------------------------------------------------------
|
|||
|
|
void __fastcall CPHASEX::ShowPara(void)
|
|||
|
|
{
|
|||
|
|
/*
|
|||
|
|
if( Application->MainForm ){
|
|||
|
|
char bf[256];
|
|||
|
|
sprintf(bf, "Car=%.lf, Shift=%.lf, Syms=%.lf, Tones=%d", m_CarrierFreq, m_SHIFT, m_SymbolLen, m_TONES);
|
|||
|
|
Application->MainForm->Caption = bf;
|
|||
|
|
}
|
|||
|
|
*/
|
|||
|
|
}
|
|||
|
|
//--------------------------------------------------------------------------
|
|||
|
|
void __fastcall CPHASEX::SetSampleFreq(double f)
|
|||
|
|
{
|
|||
|
|
m_SampleFreq = f;
|
|||
|
|
Create();
|
|||
|
|
}
|
|||
|
|
//--------------------------------------------------------------------------
|
|||
|
|
void __fastcall CPHASEX::Create(void)
|
|||
|
|
{
|
|||
|
|
// m_fftSHIFT = m_SHIFT * (m_TONES + 1) / m_TONES;
|
|||
|
|
m_fftSHIFT = m_SHIFT * m_TONES / (m_TONES - 1);
|
|||
|
|
m_SymbolLen = m_TONES * m_SampleFreq / m_fftSHIFT;
|
|||
|
|
m_BASEPOINT = int(CPHASEX_BASEFREQ * m_TONES / m_fftSHIFT);
|
|||
|
|
|
|||
|
|
m_MixerFreq = double(m_BASEPOINT) * m_SampleFreq / m_SymbolLen;
|
|||
|
|
m_VCO.SetSampleFreq(m_SampleFreq);
|
|||
|
|
m_Hilbert.Create(20, m_SampleFreq, 25.0, m_SampleFreq*0.5 - 25.0);
|
|||
|
|
m_Hilbert.Clear();
|
|||
|
|
SetCarrierFreq(m_CarrierFreq);
|
|||
|
|
m_SlideFFT.Create(int(m_SymbolLen + 0.5), m_BASEPOINT, m_TONES);
|
|||
|
|
m_AGC.SetSampleFreq(m_SampleFreq);
|
|||
|
|
m_AGC.SetCarrierFreq(m_CarrierFreq);
|
|||
|
|
// CreateFilter();
|
|||
|
|
#if LOGFFT
|
|||
|
|
m_fp = fopen("FFT.txt", "wt");
|
|||
|
|
#endif
|
|||
|
|
// ShowPara();
|
|||
|
|
}
|
|||
|
|
//--------------------------------------------------------------------------
|
|||
|
|
void __fastcall CPHASEX::SetShift(double f)
|
|||
|
|
{
|
|||
|
|
m_SHIFT = f;
|
|||
|
|
Create();
|
|||
|
|
}
|
|||
|
|
//--------------------------------------------------------------------------
|
|||
|
|
void __fastcall CPHASEX::SetCarrierFreq(double f)
|
|||
|
|
{
|
|||
|
|
m_CarrierFreq = f;
|
|||
|
|
m_VCO.SetFreeFreq(m_CarrierFreq - m_MixerFreq);
|
|||
|
|
m_AGC.SetCarrierFreq(m_CarrierFreq);
|
|||
|
|
// ShowPara();
|
|||
|
|
}
|
|||
|
|
//--------------------------------------------------------------------------
|
|||
|
|
CLX* __fastcall CPHASEX::Do(double d)
|
|||
|
|
{
|
|||
|
|
m_Hilbert.Do(m_sig, d); // <20><><EFBFBD>f<EFBFBD><66><EFBFBD><EFBFBD>
|
|||
|
|
|
|||
|
|
CLX z;
|
|||
|
|
z.r = m_VCO.Do();
|
|||
|
|
z.j = m_VCO.DoCos();
|
|||
|
|
z *= m_sig; // <20><><EFBFBD>g<EFBFBD><67><EFBFBD>ϊ<EFBFBD>
|
|||
|
|
|
|||
|
|
// m_LPF.Do(z);
|
|||
|
|
return m_SlideFFT.Do(z);
|
|||
|
|
}
|
|||
|
|
//--------------------------------------------------------------------------
|
|||
|
|
void __fastcall CPHASEX::DoFSK(double d)
|
|||
|
|
{
|
|||
|
|
// d = m_AGC.Do(d);
|
|||
|
|
CLX *pFFT = Do(d);
|
|||
|
|
m_dm = pFFT[0].vAbs() * (1.0 / 32768.0);
|
|||
|
|
m_ds = pFFT[m_TONES-1].vAbs() * (1.0 / 32768.0);
|
|||
|
|
|
|||
|
|
#if LOGFFT
|
|||
|
|
for( int i = 0; i < m_TONES; i++ ){
|
|||
|
|
if( i ) fprintf(m_fp, ",");
|
|||
|
|
fprintf(m_fp, "%.0lf", pFFT[i].vAbs());
|
|||
|
|
}
|
|||
|
|
fprintf(m_fp, "\n");
|
|||
|
|
#endif
|
|||
|
|
}
|
|||
|
|
/*=============================================================================
|
|||
|
|
CViterbiQPSK<EFBFBD>N<EFBFBD><EFBFBD><EFBFBD>X Added by JE3HHT on Sep.2010 for QPSK demodulator
|
|||
|
|
=============================================================================*/
|
|||
|
|
CViterbiQPSK::CViterbiQPSK(void)
|
|||
|
|
{
|
|||
|
|
Reset();
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
void __fastcall CViterbiQPSK::Reset(void)
|
|||
|
|
{
|
|||
|
|
memset(m_tPath, 0, sizeof(m_tPath));
|
|||
|
|
memset(m_tBit, 0, sizeof(m_tBit));
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
BOOL __fastcall CViterbiQPSK::Do(double angle, double *pMetric)
|
|||
|
|
{
|
|||
|
|
double dist[32];
|
|||
|
|
int bits[32];
|
|||
|
|
double min = MAXDOUBLE;
|
|||
|
|
|
|||
|
|
int i;
|
|||
|
|
if( pMetric ){
|
|||
|
|
for(i = 0; i < 32; i++){
|
|||
|
|
dist[i] = m_tPath[i/2] + pMetric[tQPSK_Viterbi[i]];
|
|||
|
|
if(dist[i] < min) min = dist[i];
|
|||
|
|
bits[i] = ((m_tBit[i/2]) << 1) + (i & 1);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
const double tt1[4] = {3.0*PI/2.0, 0.0, PI/2.0, PI};
|
|||
|
|
const double tt2[4] = {3.0*PI/2.0, PI*2.0, PI/2.0, PI};
|
|||
|
|
const double* pTbl = (angle >= PI) ? tt2 : tt1;
|
|||
|
|
for(i = 0; i < 32; i++){
|
|||
|
|
dist[i] = m_tPath[i/2] + fabs(angle - pTbl[tQPSK_Viterbi[i]]);
|
|||
|
|
if( dist[i] < min ) min = dist[i];
|
|||
|
|
bits[i] = ((m_tBit[i/2]) << 1) + (i & 1);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
for(i = 0; i < 16; i++){
|
|||
|
|
if( dist[i] < dist[i + 16]){
|
|||
|
|
m_tPath[i] = dist[i] - min;
|
|||
|
|
m_tBit[i] = bits[i];
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
m_tPath[i] = dist[i + 16] - min;
|
|||
|
|
m_tBit[i] = bits[i + 16];
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
int ones = 0;
|
|||
|
|
for(i = 0; i < 16; i++){
|
|||
|
|
ones += (m_tBit[i] & (1L << 20));
|
|||
|
|
}
|
|||
|
|
if( ones == (8 << 20 ) ){
|
|||
|
|
return rand() & 1;
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
return ones > (8L << 20);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
/*=============================================================================
|
|||
|
|
CDecPSK<EFBFBD>N<EFBFBD><EFBFBD><EFBFBD>X Added by JE3HHT on Sep.2010 for QPSK demodulator
|
|||
|
|
=============================================================================*/
|
|||
|
|
__fastcall CDecPSK::CDecPSK(void)
|
|||
|
|
{
|
|||
|
|
m_fLSB = FALSE;
|
|||
|
|
m_bQPSK = TRUE;
|
|||
|
|
m_bATC = TRUE;
|
|||
|
|
|
|||
|
|
m_CarrierFreq = 1750.0;
|
|||
|
|
m_Angle = 0.0;
|
|||
|
|
m_Speed = 31.25;
|
|||
|
|
m_SHDATA = 0;
|
|||
|
|
|
|||
|
|
m_SN = 0;
|
|||
|
|
m_dNow = 0;
|
|||
|
|
|
|||
|
|
m_Tmg = m_SyncState = 0;
|
|||
|
|
|
|||
|
|
m_RxData.Clear();
|
|||
|
|
|
|||
|
|
m_fSQ = FALSE;
|
|||
|
|
|
|||
|
|
m_AvgClock.Create(8);
|
|||
|
|
SetSampleFreq(11025*0.5);
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
__fastcall CDecPSK::~CDecPSK(void)
|
|||
|
|
{
|
|||
|
|
}
|
|||
|
|
//--------------------------------------------------------------------------
|
|||
|
|
void __fastcall CDecPSK::SetCarrierFreq(double f)
|
|||
|
|
{
|
|||
|
|
m_CarrierFreq = f;
|
|||
|
|
m_NextCarrierFreq = f;
|
|||
|
|
m_VCO.SetFreeFreq(f);
|
|||
|
|
m_dblAvgAFC = 0.0;
|
|||
|
|
}
|
|||
|
|
//--------------------------------------------------------------------------
|
|||
|
|
void __fastcall CDecPSK::Reset(void)
|
|||
|
|
{
|
|||
|
|
m_SHDATA = 0;
|
|||
|
|
m_SN = 0;
|
|||
|
|
|
|||
|
|
m_dNow = 0;
|
|||
|
|
m_dTW = m_dBTW = m_SampleFreq / m_Speed;
|
|||
|
|
m_dBTWL = m_dBTW * (1.0-(15000.0 * 1.0e-6));
|
|||
|
|
m_dBTWH = m_dBTW * (1.0+(15000.0 * 1.0e-6));
|
|||
|
|
m_iW = int(m_dTW / QPSK_SUBFACTOR);
|
|||
|
|
m_iWM = m_iW/2;
|
|||
|
|
|
|||
|
|
memset(m_AmpStg, 0, sizeof(m_AmpStg));
|
|||
|
|
|
|||
|
|
memset(m_StgZ, 0, sizeof(m_StgZ));
|
|||
|
|
m_Viterbi.Reset();
|
|||
|
|
|
|||
|
|
m_RxData.Clear();
|
|||
|
|
|
|||
|
|
m_SyncState = FALSE;
|
|||
|
|
|
|||
|
|
m_fSQ = FALSE;
|
|||
|
|
|
|||
|
|
int taps = int(m_SampleFreq * 64.0 * 2.0 / 11025.0 + 0.5) & 0x7ffe;
|
|||
|
|
m_LPF1.Create(taps, ffLPF, m_SampleFreq, m_Speed*2.0, m_Speed*2.0, 60.0, 1.0);
|
|||
|
|
taps = int(m_SampleFreq * 8 * 160 / (QPSK_SUBFACTOR * 11025) + 0.5) & 0x7ffe;
|
|||
|
|
m_LPF2.Create(taps, ffLPF, m_SampleFreq/double(QPSK_SUBFACTOR), m_Speed*QPSK_LPF2K, m_Speed*QPSK_LPF2K, 60.0, 1.0);
|
|||
|
|
|
|||
|
|
m_dblAvgAFC = 0.0;
|
|||
|
|
m_vAvg = 32768.0;
|
|||
|
|
ResetATC();
|
|||
|
|
}
|
|||
|
|
//--------------------------------------------------------------------------
|
|||
|
|
// <20><><EFBFBD>M<EFBFBD>ɐ<C990><D882>ւ<EFBFBD><D682><EFBFBD><EFBFBD>ۂɌĂ<C482><CE82><EFBFBD>
|
|||
|
|
void __fastcall CDecPSK::ResetRX(void)
|
|||
|
|
{
|
|||
|
|
m_dNow = 0;
|
|||
|
|
memset(m_AmpStg, 0, sizeof(m_AmpStg));
|
|||
|
|
memset(m_StgZ, 0, sizeof(m_StgZ));
|
|||
|
|
m_dblAvgAFC = 0.0;
|
|||
|
|
m_vAvg = 32768.0;
|
|||
|
|
m_SHDATA = 0;
|
|||
|
|
m_Viterbi.Reset();
|
|||
|
|
m_RxData.Clear();
|
|||
|
|
}
|
|||
|
|
//--------------------------------------------------------------------------
|
|||
|
|
void __fastcall CDecPSK::SetSpeed(double d)
|
|||
|
|
{
|
|||
|
|
m_Speed = d;
|
|||
|
|
Reset();
|
|||
|
|
}
|
|||
|
|
//--------------------------------------------------------------------------
|
|||
|
|
void __fastcall CDecPSK::SetSampleFreq(double f)
|
|||
|
|
{
|
|||
|
|
m_SampleFreq = f;
|
|||
|
|
m_dTW = m_dBTW = m_SampleFreq / m_Speed;
|
|||
|
|
m_iW = int(m_dTW / QPSK_SUBFACTOR);
|
|||
|
|
m_iWM = m_iW/2;
|
|||
|
|
memset(m_AmpStg, 0, sizeof(m_AmpStg));
|
|||
|
|
|
|||
|
|
m_VCO.SetSampleFreq(m_SampleFreq);
|
|||
|
|
m_Hilbert.Create(20, m_SampleFreq, 25.0, m_SampleFreq*0.5 - 25.0);
|
|||
|
|
m_Hilbert.Clear();
|
|||
|
|
SetCarrierFreq(m_CarrierFreq);
|
|||
|
|
Reset();
|
|||
|
|
}
|
|||
|
|
//--------------------------------------------------------------------------
|
|||
|
|
void __fastcall CDecPSK::ResetATC(void)
|
|||
|
|
{
|
|||
|
|
m_AvgClock.Reset();
|
|||
|
|
m_MeasClock = m_MeasCounter = m_MeasStage = 0;
|
|||
|
|
m_dTW = m_dBTW;
|
|||
|
|
m_iW = int(m_dTW / QPSK_SUBFACTOR);
|
|||
|
|
m_iWM = m_iW/2;
|
|||
|
|
m_SN = 0;
|
|||
|
|
};
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
void __fastcall CDecPSK::RxBit(int bit)
|
|||
|
|
{
|
|||
|
|
m_SHDATA = m_SHDATA << 1;
|
|||
|
|
if( bit ) m_SHDATA |= 1;
|
|||
|
|
|
|||
|
|
if( !(m_SHDATA & 3) ){
|
|||
|
|
if( m_fSQ ) m_RxData.PutData(g_VariCode.Decode(m_SHDATA >> 2));
|
|||
|
|
m_SHDATA = 0;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
double __fastcall vPWR(const double &c){
|
|||
|
|
return c * c;
|
|||
|
|
}
|
|||
|
|
void __fastcall CDecPSK::DoSym(const CLX &z)
|
|||
|
|
{
|
|||
|
|
m_StgZ[3] = m_StgZ[2];
|
|||
|
|
m_StgZ[2] = m_StgZ[1];
|
|||
|
|
m_StgZ[1] = m_StgZ[0];
|
|||
|
|
m_StgZ[0] = z;
|
|||
|
|
|
|||
|
|
double max, v;
|
|||
|
|
max = vPWR(m_StgZ[3].j - m_StgZ[2].r - m_StgZ[1].r - m_StgZ[0].r) + vPWR(m_StgZ[3].r + m_StgZ[2].j + m_StgZ[1].j + m_StgZ[0].j);
|
|||
|
|
v = vPWR(m_StgZ[3].j + m_StgZ[2].r - m_StgZ[1].r - m_StgZ[0].r) + vPWR(m_StgZ[3].r - m_StgZ[2].j + m_StgZ[1].j + m_StgZ[0].j);
|
|||
|
|
if( v > max ) max = v;
|
|||
|
|
v = vPWR(m_StgZ[3].j - m_StgZ[2].j - m_StgZ[1].r - m_StgZ[0].r) + vPWR(m_StgZ[3].r - m_StgZ[2].r + m_StgZ[1].j + m_StgZ[0].j);
|
|||
|
|
if( v > max ) max = v;
|
|||
|
|
v = vPWR(m_StgZ[3].j + m_StgZ[2].j - m_StgZ[1].r - m_StgZ[0].r) + vPWR(m_StgZ[3].r + m_StgZ[2].r + m_StgZ[1].j + m_StgZ[0].j);
|
|||
|
|
if( v > max ) max = v;
|
|||
|
|
v = vPWR(m_StgZ[3].j - m_StgZ[2].r + m_StgZ[1].r + m_StgZ[0].r) + vPWR(m_StgZ[3].r + m_StgZ[2].j - m_StgZ[1].j - m_StgZ[0].j);
|
|||
|
|
if( v > max ) max = v;
|
|||
|
|
v = vPWR(m_StgZ[3].j + m_StgZ[2].r + m_StgZ[1].r + m_StgZ[0].r) + vPWR(m_StgZ[3].r - m_StgZ[2].j - m_StgZ[1].j - m_StgZ[0].j);
|
|||
|
|
if( v > max ) max = v;
|
|||
|
|
v = vPWR(m_StgZ[3].j - m_StgZ[2].j + m_StgZ[1].r + m_StgZ[0].r) + vPWR(m_StgZ[3].r - m_StgZ[2].r - m_StgZ[1].j - m_StgZ[0].j);
|
|||
|
|
if( v > max ) max = v;
|
|||
|
|
v = vPWR(m_StgZ[3].j + m_StgZ[2].j + m_StgZ[1].r + m_StgZ[0].r) + vPWR(m_StgZ[3].r + m_StgZ[2].r - m_StgZ[1].j - m_StgZ[0].j);
|
|||
|
|
if( v > max ) max = v;
|
|||
|
|
v = vPWR(m_StgZ[3].j - m_StgZ[2].r - m_StgZ[1].j - m_StgZ[0].j) + vPWR(m_StgZ[3].r + m_StgZ[2].j - m_StgZ[1].r - m_StgZ[0].r);
|
|||
|
|
if( v > max ) max = v;
|
|||
|
|
v = vPWR(m_StgZ[3].j + m_StgZ[2].r - m_StgZ[1].j - m_StgZ[0].j) + vPWR(m_StgZ[3].r - m_StgZ[2].j - m_StgZ[1].r - m_StgZ[0].r);
|
|||
|
|
if( v > max ) max = v;
|
|||
|
|
v = vPWR(m_StgZ[3].j - m_StgZ[2].j - m_StgZ[1].j - m_StgZ[0].j) + vPWR(m_StgZ[3].r - m_StgZ[2].r - m_StgZ[1].r - m_StgZ[0].r);
|
|||
|
|
if( v > max ) max = v;
|
|||
|
|
v = vPWR(m_StgZ[3].j + m_StgZ[2].j - m_StgZ[1].j - m_StgZ[0].j) + vPWR(m_StgZ[3].r + m_StgZ[2].r - m_StgZ[1].r - m_StgZ[0].r);
|
|||
|
|
if( v > max ) max = v;
|
|||
|
|
v = vPWR(m_StgZ[3].j - m_StgZ[2].r + m_StgZ[1].j + m_StgZ[0].j) + vPWR(m_StgZ[3].r + m_StgZ[2].j + m_StgZ[1].r + m_StgZ[0].r);
|
|||
|
|
if( v > max ) max = v;
|
|||
|
|
v = vPWR(m_StgZ[3].j + m_StgZ[2].r + m_StgZ[1].j + m_StgZ[0].j) + vPWR(m_StgZ[3].r - m_StgZ[2].j + m_StgZ[1].r + m_StgZ[0].r);
|
|||
|
|
if( v > max ) max = v;
|
|||
|
|
v = vPWR(m_StgZ[3].j - m_StgZ[2].j + m_StgZ[1].j + m_StgZ[0].j) + vPWR(m_StgZ[3].r - m_StgZ[2].r + m_StgZ[1].r + m_StgZ[0].r);
|
|||
|
|
if( v > max ) max = v;
|
|||
|
|
v = vPWR(m_StgZ[3].j + m_StgZ[2].j + m_StgZ[1].j + m_StgZ[0].j) + vPWR(m_StgZ[3].r + m_StgZ[2].r + m_StgZ[1].r + m_StgZ[0].r);
|
|||
|
|
if( v > max ) max = v;
|
|||
|
|
m_Metric[QPSK_ROT_0] = max;
|
|||
|
|
|
|||
|
|
max = vPWR(m_StgZ[3].j - m_StgZ[2].r + m_StgZ[1].r - m_StgZ[0].r) + vPWR(m_StgZ[3].r + m_StgZ[2].j - m_StgZ[1].j + m_StgZ[0].j);
|
|||
|
|
v = vPWR(m_StgZ[3].j + m_StgZ[2].r + m_StgZ[1].r - m_StgZ[0].r) + vPWR(m_StgZ[3].r - m_StgZ[2].j - m_StgZ[1].j + m_StgZ[0].j);
|
|||
|
|
if( v > max ) max = v;
|
|||
|
|
v = vPWR(m_StgZ[3].j - m_StgZ[2].j + m_StgZ[1].r - m_StgZ[0].r) + vPWR(m_StgZ[3].r - m_StgZ[2].r - m_StgZ[1].j + m_StgZ[0].j);
|
|||
|
|
if( v > max ) max = v;
|
|||
|
|
v = vPWR(m_StgZ[3].j + m_StgZ[2].j + m_StgZ[1].r - m_StgZ[0].r) + vPWR(m_StgZ[3].r + m_StgZ[2].r - m_StgZ[1].j + m_StgZ[0].j);
|
|||
|
|
if( v > max ) max = v;
|
|||
|
|
v = vPWR(m_StgZ[3].j - m_StgZ[2].r - m_StgZ[1].r + m_StgZ[0].r) + vPWR(m_StgZ[3].r + m_StgZ[2].j + m_StgZ[1].j - m_StgZ[0].j);
|
|||
|
|
if( v > max ) max = v;
|
|||
|
|
v = vPWR(m_StgZ[3].j + m_StgZ[2].r - m_StgZ[1].r + m_StgZ[0].r) + vPWR(m_StgZ[3].r - m_StgZ[2].j + m_StgZ[1].j - m_StgZ[0].j);
|
|||
|
|
if( v > max ) max = v;
|
|||
|
|
v = vPWR(m_StgZ[3].j - m_StgZ[2].j - m_StgZ[1].r + m_StgZ[0].r) + vPWR(m_StgZ[3].r - m_StgZ[2].r + m_StgZ[1].j - m_StgZ[0].j);
|
|||
|
|
if( v > max ) max = v;
|
|||
|
|
v = vPWR(m_StgZ[3].j + m_StgZ[2].j - m_StgZ[1].r + m_StgZ[0].r) + vPWR(m_StgZ[3].r + m_StgZ[2].r + m_StgZ[1].j - m_StgZ[0].j);
|
|||
|
|
if( v > max ) max = v;
|
|||
|
|
v = vPWR(m_StgZ[3].j - m_StgZ[2].r + m_StgZ[1].j - m_StgZ[0].j) + vPWR(m_StgZ[3].r + m_StgZ[2].j + m_StgZ[1].r - m_StgZ[0].r);
|
|||
|
|
if( v > max ) max = v;
|
|||
|
|
v = vPWR(m_StgZ[3].j + m_StgZ[2].r + m_StgZ[1].j - m_StgZ[0].j) + vPWR(m_StgZ[3].r - m_StgZ[2].j + m_StgZ[1].r - m_StgZ[0].r);
|
|||
|
|
if( v > max ) max = v;
|
|||
|
|
v = vPWR(m_StgZ[3].j - m_StgZ[2].j + m_StgZ[1].j - m_StgZ[0].j) + vPWR(m_StgZ[3].r - m_StgZ[2].r + m_StgZ[1].r - m_StgZ[0].r);
|
|||
|
|
if( v > max ) max = v;
|
|||
|
|
v = vPWR(m_StgZ[3].j + m_StgZ[2].j + m_StgZ[1].j - m_StgZ[0].j) + vPWR(m_StgZ[3].r + m_StgZ[2].r + m_StgZ[1].r - m_StgZ[0].r);
|
|||
|
|
if( v > max ) max = v;
|
|||
|
|
v = vPWR(m_StgZ[3].j - m_StgZ[2].r - m_StgZ[1].j + m_StgZ[0].j) + vPWR(m_StgZ[3].r + m_StgZ[2].j - m_StgZ[1].r + m_StgZ[0].r);
|
|||
|
|
if( v > max ) max = v;
|
|||
|
|
v = vPWR(m_StgZ[3].j + m_StgZ[2].r - m_StgZ[1].j + m_StgZ[0].j) + vPWR(m_StgZ[3].r - m_StgZ[2].j - m_StgZ[1].r + m_StgZ[0].r);
|
|||
|
|
if( v > max ) max = v;
|
|||
|
|
v = vPWR(m_StgZ[3].j - m_StgZ[2].j - m_StgZ[1].j + m_StgZ[0].j) + vPWR(m_StgZ[3].r - m_StgZ[2].r - m_StgZ[1].r + m_StgZ[0].r);
|
|||
|
|
if( v > max ) max = v;
|
|||
|
|
v = vPWR(m_StgZ[3].j + m_StgZ[2].j - m_StgZ[1].j + m_StgZ[0].j) + vPWR(m_StgZ[3].r + m_StgZ[2].r - m_StgZ[1].r + m_StgZ[0].r);
|
|||
|
|
if( v > max ) max = v;
|
|||
|
|
m_Metric[QPSK_ROT_180] = max;
|
|||
|
|
|
|||
|
|
max = vPWR(m_StgZ[3].j - m_StgZ[2].r - m_StgZ[1].j - m_StgZ[0].r) + vPWR(m_StgZ[3].r + m_StgZ[2].j - m_StgZ[1].r + m_StgZ[0].j);
|
|||
|
|
v = vPWR(m_StgZ[3].j + m_StgZ[2].r - m_StgZ[1].j - m_StgZ[0].r) + vPWR(m_StgZ[3].r - m_StgZ[2].j - m_StgZ[1].r + m_StgZ[0].j);
|
|||
|
|
if( v > max ) max = v;
|
|||
|
|
v = vPWR(m_StgZ[3].j - m_StgZ[2].j - m_StgZ[1].j - m_StgZ[0].r) + vPWR(m_StgZ[3].r - m_StgZ[2].r - m_StgZ[1].r + m_StgZ[0].j);
|
|||
|
|
if( v > max ) max = v;
|
|||
|
|
v = vPWR(m_StgZ[3].j + m_StgZ[2].j - m_StgZ[1].j - m_StgZ[0].r) + vPWR(m_StgZ[3].r + m_StgZ[2].r - m_StgZ[1].r + m_StgZ[0].j);
|
|||
|
|
if( v > max ) max = v;
|
|||
|
|
v = vPWR(m_StgZ[3].j - m_StgZ[2].r + m_StgZ[1].j + m_StgZ[0].r) + vPWR(m_StgZ[3].r + m_StgZ[2].j + m_StgZ[1].r - m_StgZ[0].j);
|
|||
|
|
if( v > max ) max = v;
|
|||
|
|
v = vPWR(m_StgZ[3].j + m_StgZ[2].r + m_StgZ[1].j + m_StgZ[0].r) + vPWR(m_StgZ[3].r - m_StgZ[2].j + m_StgZ[1].r - m_StgZ[0].j);
|
|||
|
|
if( v > max ) max = v;
|
|||
|
|
v = vPWR(m_StgZ[3].j - m_StgZ[2].j + m_StgZ[1].j + m_StgZ[0].r) + vPWR(m_StgZ[3].r - m_StgZ[2].r + m_StgZ[1].r - m_StgZ[0].j);
|
|||
|
|
if( v > max ) max = v;
|
|||
|
|
v = vPWR(m_StgZ[3].j + m_StgZ[2].j + m_StgZ[1].j + m_StgZ[0].r) + vPWR(m_StgZ[3].r + m_StgZ[2].r + m_StgZ[1].r - m_StgZ[0].j);
|
|||
|
|
if( v > max ) max = v;
|
|||
|
|
v = vPWR(m_StgZ[3].j - m_StgZ[2].r + m_StgZ[1].r - m_StgZ[0].j) + vPWR(m_StgZ[3].r + m_StgZ[2].j - m_StgZ[1].j - m_StgZ[0].r);
|
|||
|
|
if( v > max ) max = v;
|
|||
|
|
v = vPWR(m_StgZ[3].j + m_StgZ[2].r + m_StgZ[1].r - m_StgZ[0].j) + vPWR(m_StgZ[3].r - m_StgZ[2].j - m_StgZ[1].j - m_StgZ[0].r);
|
|||
|
|
if( v > max ) max = v;
|
|||
|
|
v = vPWR(m_StgZ[3].j - m_StgZ[2].j + m_StgZ[1].r - m_StgZ[0].j) + vPWR(m_StgZ[3].r - m_StgZ[2].r - m_StgZ[1].j - m_StgZ[0].r);
|
|||
|
|
if( v > max ) max = v;
|
|||
|
|
v = vPWR(m_StgZ[3].j + m_StgZ[2].j + m_StgZ[1].r - m_StgZ[0].j) + vPWR(m_StgZ[3].r + m_StgZ[2].r - m_StgZ[1].j - m_StgZ[0].r);
|
|||
|
|
if( v > max ) max = v;
|
|||
|
|
v = vPWR(m_StgZ[3].j - m_StgZ[2].r - m_StgZ[1].r + m_StgZ[0].j) + vPWR(m_StgZ[3].r + m_StgZ[2].j + m_StgZ[1].j + m_StgZ[0].r);
|
|||
|
|
if( v > max ) max = v;
|
|||
|
|
v = vPWR(m_StgZ[3].j + m_StgZ[2].r - m_StgZ[1].r + m_StgZ[0].j) + vPWR(m_StgZ[3].r - m_StgZ[2].j + m_StgZ[1].j + m_StgZ[0].r);
|
|||
|
|
if( v > max ) max = v;
|
|||
|
|
v = vPWR(m_StgZ[3].j - m_StgZ[2].j - m_StgZ[1].r + m_StgZ[0].j) + vPWR(m_StgZ[3].r - m_StgZ[2].r + m_StgZ[1].j + m_StgZ[0].r);
|
|||
|
|
if( v > max ) max = v;
|
|||
|
|
v = vPWR(m_StgZ[3].j + m_StgZ[2].j - m_StgZ[1].r + m_StgZ[0].j) + vPWR(m_StgZ[3].r + m_StgZ[2].r + m_StgZ[1].j + m_StgZ[0].r);
|
|||
|
|
if( v > max ) max = v;
|
|||
|
|
m_Metric[QPSK_ROT_270] = max;
|
|||
|
|
|
|||
|
|
max = vPWR(m_StgZ[3].j - m_StgZ[2].r + m_StgZ[1].j - m_StgZ[0].r) + vPWR(m_StgZ[3].r + m_StgZ[2].j + m_StgZ[1].r + m_StgZ[0].j);
|
|||
|
|
v = vPWR(m_StgZ[3].j + m_StgZ[2].r + m_StgZ[1].j - m_StgZ[0].r) + vPWR(m_StgZ[3].r - m_StgZ[2].j + m_StgZ[1].r + m_StgZ[0].j);
|
|||
|
|
if( v > max ) max = v;
|
|||
|
|
v = vPWR(m_StgZ[3].j - m_StgZ[2].j + m_StgZ[1].j - m_StgZ[0].r) + vPWR(m_StgZ[3].r - m_StgZ[2].r + m_StgZ[1].r + m_StgZ[0].j);
|
|||
|
|
if( v > max ) max = v;
|
|||
|
|
v = vPWR(m_StgZ[3].j + m_StgZ[2].j + m_StgZ[1].j - m_StgZ[0].r) + vPWR(m_StgZ[3].r + m_StgZ[2].r + m_StgZ[1].r + m_StgZ[0].j);
|
|||
|
|
if( v > max ) max = v;
|
|||
|
|
v = vPWR(m_StgZ[3].j - m_StgZ[2].r - m_StgZ[1].j + m_StgZ[0].r) + vPWR(m_StgZ[3].r + m_StgZ[2].j - m_StgZ[1].r - m_StgZ[0].j);
|
|||
|
|
if( v > max ) max = v;
|
|||
|
|
v = vPWR(m_StgZ[3].j + m_StgZ[2].r - m_StgZ[1].j + m_StgZ[0].r) + vPWR(m_StgZ[3].r - m_StgZ[2].j - m_StgZ[1].r - m_StgZ[0].j);
|
|||
|
|
if( v > max ) max = v;
|
|||
|
|
v = vPWR(m_StgZ[3].j - m_StgZ[2].j - m_StgZ[1].j + m_StgZ[0].r) + vPWR(m_StgZ[3].r - m_StgZ[2].r - m_StgZ[1].r - m_StgZ[0].j);
|
|||
|
|
if( v > max ) max = v;
|
|||
|
|
v = vPWR(m_StgZ[3].j + m_StgZ[2].j - m_StgZ[1].j + m_StgZ[0].r) + vPWR(m_StgZ[3].r + m_StgZ[2].r - m_StgZ[1].r - m_StgZ[0].j);
|
|||
|
|
if( v > max ) max = v;
|
|||
|
|
v = vPWR(m_StgZ[3].j - m_StgZ[2].r - m_StgZ[1].r - m_StgZ[0].j) + vPWR(m_StgZ[3].r + m_StgZ[2].j + m_StgZ[1].j - m_StgZ[0].r);
|
|||
|
|
if( v > max ) max = v;
|
|||
|
|
v = vPWR(m_StgZ[3].j + m_StgZ[2].r - m_StgZ[1].r - m_StgZ[0].j) + vPWR(m_StgZ[3].r - m_StgZ[2].j + m_StgZ[1].j - m_StgZ[0].r);
|
|||
|
|
if( v > max ) max = v;
|
|||
|
|
v = vPWR(m_StgZ[3].j - m_StgZ[2].j - m_StgZ[1].r - m_StgZ[0].j) + vPWR(m_StgZ[3].r - m_StgZ[2].r + m_StgZ[1].j - m_StgZ[0].r);
|
|||
|
|
if( v > max ) max = v;
|
|||
|
|
v = vPWR(m_StgZ[3].j + m_StgZ[2].j - m_StgZ[1].r - m_StgZ[0].j) + vPWR(m_StgZ[3].r + m_StgZ[2].r + m_StgZ[1].j - m_StgZ[0].r);
|
|||
|
|
if( v > max ) max = v;
|
|||
|
|
v = vPWR(m_StgZ[3].j - m_StgZ[2].r + m_StgZ[1].r + m_StgZ[0].j) + vPWR(m_StgZ[3].r + m_StgZ[2].j - m_StgZ[1].j + m_StgZ[0].r);
|
|||
|
|
if( v > max ) max = v;
|
|||
|
|
v = vPWR(m_StgZ[3].j + m_StgZ[2].r + m_StgZ[1].r + m_StgZ[0].j) + vPWR(m_StgZ[3].r - m_StgZ[2].j - m_StgZ[1].j + m_StgZ[0].r);
|
|||
|
|
if( v > max ) max = v;
|
|||
|
|
v = vPWR(m_StgZ[3].j - m_StgZ[2].j + m_StgZ[1].r + m_StgZ[0].j) + vPWR(m_StgZ[3].r - m_StgZ[2].r - m_StgZ[1].j + m_StgZ[0].r);
|
|||
|
|
if( v > max ) max = v;
|
|||
|
|
v = vPWR(m_StgZ[3].j + m_StgZ[2].j + m_StgZ[1].r + m_StgZ[0].j) + vPWR(m_StgZ[3].r + m_StgZ[2].r - m_StgZ[1].j + m_StgZ[0].r);
|
|||
|
|
if( v > max ) max = v;
|
|||
|
|
m_Metric[QPSK_ROT_90] = max;
|
|||
|
|
|
|||
|
|
int i;
|
|||
|
|
max = m_Metric[0];
|
|||
|
|
for( i = 0; i < 4; i++ ){
|
|||
|
|
if(m_Metric[i] > max) max = m_Metric[i];
|
|||
|
|
}
|
|||
|
|
if( max > 0.0 ){
|
|||
|
|
for( i = 0; i < 4; i++ ){
|
|||
|
|
m_Metric[i] = -log10(m_Metric[i]/max + 1.0E-100);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if( m_bQPSK && m_fLSB ){ // <20><><EFBFBD>]<5D><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>t<EFBFBD>]
|
|||
|
|
double d = m_Metric[QPSK_ROT_90];
|
|||
|
|
m_Metric[QPSK_ROT_90] = m_Metric[QPSK_ROT_270];
|
|||
|
|
m_Metric[QPSK_ROT_270] = d;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if( m_bQPSK && m_fLSB ){
|
|||
|
|
m_Angle = PI + ATAN2( (m_StgZ[1].j*m_StgZ[0].j + m_StgZ[1].r*m_StgZ[0].r), (m_StgZ[0].j*m_StgZ[1].r - m_StgZ[1].j*m_StgZ[0].r));
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
m_Angle = PI + ATAN2( (m_StgZ[1].j*m_StgZ[0].j + m_StgZ[1].r*m_StgZ[0].r), (m_StgZ[1].j*m_StgZ[0].r - m_StgZ[0].j*m_StgZ[1].r));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
m_Bits = m_Viterbi.Do(m_Angle, m_Metric);
|
|||
|
|
RxBit(m_Bits);
|
|||
|
|
}
|
|||
|
|
//--------------------------------------------------------------------------
|
|||
|
|
void __fastcall CDecPSK::DoAFC(void)
|
|||
|
|
{
|
|||
|
|
// if( m_SN < 1500 ) return;
|
|||
|
|
if( m_SN < 1200 ) return;
|
|||
|
|
|
|||
|
|
double deg = m_Angle;
|
|||
|
|
if( deg < 0.0 ) deg += 2*PI;
|
|||
|
|
|
|||
|
|
double w;
|
|||
|
|
if( deg < (PI/4) ){ // ROT 0
|
|||
|
|
w = deg;
|
|||
|
|
}
|
|||
|
|
else if( deg < (PI/4 + PI/2) ){ // ROT 90
|
|||
|
|
w = deg - PI/2;
|
|||
|
|
}
|
|||
|
|
else if( deg < (PI/4 + PI) ){ // ROT 180
|
|||
|
|
w = deg - PI;
|
|||
|
|
}
|
|||
|
|
else if( deg < (PI/4 + PI + PI/2) ){ // ROT 270
|
|||
|
|
w = deg - PI - PI/2;
|
|||
|
|
}
|
|||
|
|
else { // ROT 0
|
|||
|
|
w = deg - (2*PI);
|
|||
|
|
}
|
|||
|
|
double err = w * m_SampleFreq / (2 * PI * QPSK_SUBFACTOR * m_Speed);
|
|||
|
|
DoAvg(m_dblAvgAFC, err, (m_SN > 2000) ? 0.025 : 0.0125);
|
|||
|
|
if( m_fLSB ){
|
|||
|
|
m_NextCarrierFreq = m_CarrierFreq - m_dblAvgAFC * 0.25;
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
m_NextCarrierFreq = m_CarrierFreq + m_dblAvgAFC * 0.25;
|
|||
|
|
}
|
|||
|
|
/*
|
|||
|
|
char bf[32];
|
|||
|
|
sprintf(bf, "SN=%u, %.03lf", m_SN, m_dblAvgAFC);
|
|||
|
|
Application->MainForm->Caption = bf;
|
|||
|
|
*/
|
|||
|
|
}
|
|||
|
|
//--------------------------------------------------------------------------
|
|||
|
|
void __fastcall CDecPSK::DoATC(BOOL fATC)
|
|||
|
|
{
|
|||
|
|
if( m_MeasStage >= 7 ){
|
|||
|
|
m_SyncState = TRUE;
|
|||
|
|
m_MeasClock++;
|
|||
|
|
if( m_MeasClock >= 64 ){
|
|||
|
|
if( m_MeasStage >= 8 ){
|
|||
|
|
m_AvgClock.Do(double(m_MeasCounter)/double(m_MeasClock));
|
|||
|
|
/*
|
|||
|
|
char bf[256];
|
|||
|
|
sprintf(bf, "%.3lf, %.3lf, %.3lf", m_dBTW, double(m_MeasCounter)/double(m_MeasClock), m_AvgClock.GetAvg());
|
|||
|
|
Application->MainForm->Caption = bf;
|
|||
|
|
*/
|
|||
|
|
// ATC<54><43><EFBFBD><EFBFBD>
|
|||
|
|
if( m_bATC && fATC ){
|
|||
|
|
DoAvg(m_dTW, m_AvgClock.GetAvg(), m_SN > 2000 ? 0.5 : 0.25);
|
|||
|
|
if( m_dTW < m_dBTWL ){ m_dTW = m_dBTWL; }
|
|||
|
|
if( m_dTW > m_dBTWH ){ m_dTW = m_dBTWH; }
|
|||
|
|
m_iW = int(m_dTW / QPSK_SUBFACTOR);
|
|||
|
|
m_iWM = m_iW/2;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
m_MeasStage++;
|
|||
|
|
}
|
|||
|
|
m_MeasClock = m_MeasCounter = 0;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
//--------------------------------------------------------------------------
|
|||
|
|
void __fastcall CDecPSK::DoSync(CLX &z)
|
|||
|
|
{
|
|||
|
|
int N = int(m_dNow / QPSK_SUBFACTOR);
|
|||
|
|
if( N < 0 ) N += m_iW;
|
|||
|
|
if( N >= m_iW ) N -= m_iW;
|
|||
|
|
m_AmpStg[N] = z.vAbs();
|
|||
|
|
|
|||
|
|
float psum = 0.0;
|
|||
|
|
float msum = 0.0;
|
|||
|
|
float *p = m_AmpStg;
|
|||
|
|
float *t = p + m_iWM;
|
|||
|
|
for( N = 0; N < m_iWM; N++, p++, t++ ){
|
|||
|
|
msum += *p - *t;
|
|||
|
|
psum += *p + *t;
|
|||
|
|
}
|
|||
|
|
if( psum > 0.0 ){
|
|||
|
|
msum /= psum;
|
|||
|
|
m_dNow -= msum * QPSK_SUBFACTOR * 0.2;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// <20>^<5E>C<EFBFBD>~<7E><><EFBFBD>O<EFBFBD>v<EFBFBD><76><EFBFBD>̊J<CC8A>n
|
|||
|
|
if( m_MeasStage < 7 ){
|
|||
|
|
m_MeasStage++;
|
|||
|
|
m_SyncState = FALSE;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
//---------------------------------------------------------------------------
|
|||
|
|
int __fastcall CDecPSK::Do(double d, BOOL fSQ, BOOL fATC)
|
|||
|
|
{
|
|||
|
|
m_Hilbert.Do(m_sig, d); // <20><><EFBFBD>f<EFBFBD><66><EFBFBD><EFBFBD>
|
|||
|
|
|
|||
|
|
CLX z;
|
|||
|
|
z.r = m_VCO.Do();
|
|||
|
|
z.j = m_VCO.DoCos();
|
|||
|
|
z *= m_sig; // <20><><EFBFBD>g<EFBFBD><67><EFBFBD>ϊ<EFBFBD>
|
|||
|
|
|
|||
|
|
m_LPF1.Do(z); // <20>f<EFBFBD>V<EFBFBD><56><EFBFBD>[<5B>^
|
|||
|
|
|
|||
|
|
m_MeasCounter++;
|
|||
|
|
m_nSubCounter--;
|
|||
|
|
if( m_nSubCounter <= 0 ){ // <20>T<EFBFBD>u<EFBFBD>T<EFBFBD><54><EFBFBD>v<EFBFBD><76><EFBFBD><EFBFBD><EFBFBD>O
|
|||
|
|
m_nSubCounter = QPSK_SUBFACTOR;
|
|||
|
|
|
|||
|
|
m_LPF2.Do(z);
|
|||
|
|
m_Z = z;
|
|||
|
|
|
|||
|
|
if( fSQ ) DoSync(z);
|
|||
|
|
|
|||
|
|
m_dNow += QPSK_SUBFACTOR;
|
|||
|
|
if( m_dNow >= m_dTW ){
|
|||
|
|
m_dNow -= m_dTW;
|
|||
|
|
m_Tmg = !m_Tmg;
|
|||
|
|
|
|||
|
|
if( m_fSQ != fSQ ){
|
|||
|
|
m_fSQ = fSQ;
|
|||
|
|
m_dblAvgAFC = 0.0;
|
|||
|
|
ResetATC();
|
|||
|
|
}
|
|||
|
|
DoSym(z);
|
|||
|
|
if( fSQ ){
|
|||
|
|
DoATC(fATC);
|
|||
|
|
DoAFC();
|
|||
|
|
}
|
|||
|
|
return TRUE;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return FALSE;
|
|||
|
|
}
|
|||
|
|
//--------------------------------------------------------------------------
|
|||
|
|
int __fastcall CDecPSK::GetData(void)
|
|||
|
|
{
|
|||
|
|
if( m_RxData.GetCount() ){
|
|||
|
|
return m_RxData.GetData();
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
return -1;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
//--------------------------------------------------------------------------
|
|||
|
|
int __fastcall CDecPSK::GetClockError(void)
|
|||
|
|
{
|
|||
|
|
if( m_AvgClock.GetCount() ){
|
|||
|
|
return ((m_dTW / m_dBTW) - 1.0) * 1e6;
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
return 0;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
//--------------------------------------------------------------------------
|
|||
|
|
void __fastcall CDecPSK::SetTmg(int ppm)
|
|||
|
|
{
|
|||
|
|
if( ppm < -15000 ) ppm = -15000;
|
|||
|
|
if( ppm > 15000 ) ppm = 15000;
|
|||
|
|
|
|||
|
|
m_dBTW = m_SampleFreq / m_Speed;
|
|||
|
|
m_dTW = m_dBTW = m_dBTW + (m_dBTW * ppm * 1.0e-6);
|
|||
|
|
m_iW = int(m_dTW / QPSK_SUBFACTOR);
|
|||
|
|
m_iWM = m_iW / 2;
|
|||
|
|
}
|
|||
|
|
//--------------------------------------------------------------------------
|
|||
|
|
int __fastcall CDecPSK::GetD(void)
|
|||
|
|
{
|
|||
|
|
double d = m_Z.vAbs();
|
|||
|
|
DoAvg(m_vAvg, d, 0.001);
|
|||
|
|
if( m_vAvg > 0.0 ){
|
|||
|
|
d /= m_vAvg;
|
|||
|
|
d *= 20000.0;
|
|||
|
|
}
|
|||
|
|
if( d > 40000.0 ) d = 40000.0;
|
|||
|
|
return d - 20000.0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//--------------------------------------------------------------------------
|
|||
|
|
|
|||
|
|
|