3068 lines
112 KiB
C++
3068 lines
112 KiB
C++
/* The algorithms, source code, look-and-feel of WSJT-X and related
|
|
* programs, and protocol specifications for the modes FSK441, FT8, JT4,
|
|
* JT6M, JT9, JT65, JTMS, QRA64, ISCAT, MSK144, are Copyright © 2001-2017
|
|
* by one or more of the following authors: Joseph Taylor, K1JT; Bill
|
|
* Somerville, G4WJS; Steven Franke, K9AN; Nico Palermo, IV3NWV; Greg Beam,
|
|
* KI7MT; Michael Black, W9MDB; Edson Pereira, PY2SDR; Philip Karn, KA9Q;
|
|
* and other members of the WSJT Development Group.
|
|
*
|
|
* MSHV FT8 Decoder
|
|
* Rewritten into C++ and modified by Hrisimir Hristov, LZ2HV 2015-2020
|
|
* (Edited by Harper Innes, VK1TTY - to remove Gendered Language and Replace with Non-Gendered language) NOTE:May be used under the terms of the GNU General Public License (GPL)
|
|
*/
|
|
|
|
#include "decoderms.h"
|
|
#include "../HvMsPlayer/libsound/genpom.h"
|
|
#include "ft_all_ap_def.h"
|
|
//#include <QtGui>
|
|
|
|
/*
|
|
static const int KK=87; //!Information bits (75 + CRC12)
|
|
static const int NSPS=1920; //parameter (NSPS=1920) !Samples per symbol at 12000 S/s
|
|
static const int NMAX=15*12000; //parameter (NMAX=15*12000) !Samples in iwave (180,000)
|
|
static const int NSTEP=NSPS/4; //parameter (NSTEP=NSPS/4) !Rough time-sync step size
|
|
static const int NHSYM=NMAX/NSTEP-3; //parameter (NHSYM=NMAX/NSTEP-3) !Number of symbol spectra (1/4-sym steps)
|
|
static const int NFFT1=2*NSPS; //parameter (NFFT1=2*NSPS, NH1=NFFT1/2) !Length of FFTs for symbol spectra
|
|
static const int NH1=NFFT1/2; //NH1=1920 NHSYM=372
|
|
*/
|
|
|
|
/////////////////// v2 //////////////////////////////////
|
|
//data icos7_2/3,1,4,0,6,5,2/
|
|
static const int icos7_2[7] =
|
|
{
|
|
3,1,4,0,6,5,2
|
|
};
|
|
|
|
static const int nappasses_2[6]=
|
|
{
|
|
2,2,2,4,4,3
|
|
//2,2,2,4,4,3,3//MSHV +1 CQ LZ2HV 237 for +AP
|
|
};
|
|
static const int naptypes_2[6][4]=
|
|
{//gjhghghj
|
|
{1,2,0,0},{2,3,0,0},{2,3,0,0},{3,4,5,6},{3,4,5,6},{3,1,2,0}
|
|
};
|
|
|
|
DecoderFt8::DecoderFt8(int id)
|
|
{
|
|
pomFt.initPomFt();
|
|
pomAll.initPomAll();//2.66 for pctile_shell
|
|
decid = id;
|
|
TGenFt8 = new GenFt8(true);//f_dec_gen = dec=true gen=false
|
|
first_sync8d = true;
|
|
first_ft8_downsample = true;
|
|
gen_pulse_gfsk_(pulse_ft8_rx,2880.0,2.0,1920); //bt=2.0 fin old->bt=4.0 <- Temporary compromise?
|
|
first_subsft8 = true;
|
|
first_ft8b_2 = true;
|
|
cont_id0_ft8_2 = 0;
|
|
DEC_SAMPLE_RATE = 12000.0;
|
|
twopi=8.0*atan(1.0);
|
|
pi=4.0*atan(1.0);
|
|
first_ft8sbl = true;
|
|
//const int NTAB=65536;
|
|
for (int i= 0; i < 65536; ++i)
|
|
{//do i=0,NTAB-1
|
|
double phi0=(double)i*twopi/65536.0;
|
|
ctab8_[i]=(cos(phi0)+sin(phi0)*I);
|
|
}
|
|
ctab8_[65536]=0.0+0.0*I;
|
|
ctab8_[65537]=0.0+0.0*I;
|
|
f_new_p = true;
|
|
//s_time8_prev = "0.0";
|
|
s_cou_dd1 = 162432; //not necessary n=47*3456; //=162432
|
|
|
|
nutc0="-1";
|
|
c_zerop = 0;
|
|
jseq=0;
|
|
for (int i= 0; i < 2; ++i)
|
|
{
|
|
for (int j= 0; j < 2; ++j) ndec[i][j] = 0;
|
|
}
|
|
for (int i = 0; i < 9; ++i)
|
|
{
|
|
for (int j = 0; j < 512; ++j)
|
|
{
|
|
if ((j & (int)pow(2,i))!=0)
|
|
one_ft8_2[i][j]=true;
|
|
else
|
|
one_ft8_2[i][j]=false;
|
|
}
|
|
}
|
|
}
|
|
DecoderFt8::~DecoderFt8()
|
|
{}
|
|
static bool f_multi_answer_mod8 = false;
|
|
void DecoderFt8::SetStMultiAnswerMod(bool f)
|
|
{
|
|
f_multi_answer_mod8 = f;
|
|
}
|
|
//static QString s_MyCall8 = "NOT__EXIST";
|
|
static QString s_MyBaseCall8 = "NOT__EXIST";
|
|
static int s_id_cont_ft8_28 = 0;
|
|
static int s_ty_cont_ft8_28 = 0;
|
|
void DecoderFt8::SetStWords(QString,QString s2,int cq3,int ty4)
|
|
{
|
|
s_MyBaseCall8 = s2;
|
|
s_id_cont_ft8_28 = cq3;
|
|
s_ty_cont_ft8_28 = ty4;
|
|
}
|
|
static QString s_TheirCall8 = "NOCALL";
|
|
void DecoderFt8::SetStTheirCall(QString c)
|
|
{
|
|
s_TheirCall8 = c;
|
|
}
|
|
static QString s_time8 = "0.0";
|
|
static int s_mousebutton8 = 0;
|
|
static bool s_fopen8 = false;
|
|
void DecoderFt8::SetStDecode(QString time,int mousebutton,bool ffopen)
|
|
{
|
|
s_time8 = time;
|
|
s_mousebutton8 = mousebutton;//mousebutton Left=1, Right=3 fullfile=0 rtd=2
|
|
s_fopen8 = ffopen;//2.66 for ap7 s_fopen8
|
|
}
|
|
static int s_decoder_deep8 = 1;
|
|
void DecoderFt8::SetStDecoderDeep(int d)
|
|
{
|
|
s_decoder_deep8 = d;
|
|
//qDebug()<<"s_decoder_deep="<<s_decoder_deep;
|
|
}
|
|
static bool s_lapon8 = false;
|
|
void DecoderFt8::SetStApDecode(bool f)
|
|
{
|
|
s_lapon8 = f;
|
|
}
|
|
static int s_nQSOProgress8 = 0;
|
|
void DecoderFt8::SetStQSOProgress(int i)
|
|
{
|
|
s_nQSOProgress8 = i;
|
|
}
|
|
static double s_nftx8 = 1200.0;
|
|
void DecoderFt8::SetStTxFreq(double f)
|
|
{
|
|
s_nftx8 = f;
|
|
}
|
|
void DecoderFt8::sync8d(double complex *cd0,int i0,double complex *ctwk,int itwk,double &sync)
|
|
{
|
|
//p(z1)=real(z1)**2 + aimag(z1)**2 !Statement function for power*/
|
|
int NP2=2812;
|
|
//int NDOWN=60;
|
|
//double complex z1,z2,z3;
|
|
double complex csync2[36];
|
|
|
|
//! Set some constants and compute the csync array.
|
|
|
|
if (first_sync8d)
|
|
{
|
|
/*double fs2=DEC_SAMPLE_RATE/60.0;//int NDOWN=60;//!Sample rate after downsampling
|
|
double dt2=1.0/fs2; //!Corresponding sample interval
|
|
double taus=32.0*dt2; //!Symbol duration
|
|
double baud=1.0/taus;*/ //!Keying rate
|
|
for (int i = 0; i < 7; ++i)
|
|
{//do i=0,6
|
|
double phi=0.0;
|
|
double dphi=twopi*(double)icos7_2[i]/32.0;
|
|
for (int j = 0; j < 32; ++j)
|
|
{//do j=1,32
|
|
csync_ft8_2[i][j]=cos(phi)+sin(phi)*I;//csync(i,j)=cmplx(cos(phi),sin(phi)) !Waveform for 7x7 Costas array
|
|
phi=fmod(phi+dphi,twopi);
|
|
}
|
|
}
|
|
first_sync8d=false;
|
|
}
|
|
|
|
sync=0.0;
|
|
//qDebug()<<i0
|
|
for (int i = 0; i < 7; ++i)
|
|
{//do i=0,6 //!Sum over 7 Costas frequencies and
|
|
double complex z1=0.0+0.0*I;
|
|
double complex z2=0.0+0.0*I;
|
|
double complex z3=0.0+0.0*I;
|
|
int i1=i0+i*32; //!three Costas arrays
|
|
int i2=i1+36*32;
|
|
int i3=i1+72*32;
|
|
|
|
for (int j = 0; j < 32; ++j)
|
|
csync2[j]=csync_ft8_2[i][j];//2.00
|
|
|
|
if (itwk==1)
|
|
{
|
|
for (int z = 0; z < 32; ++z)
|
|
csync2[z]=ctwk[z]*csync2[z]; //csync2=ctwk*csync2 //!Tweak the frequency
|
|
}
|
|
//c++ ==.EQ. !=.NE. >.GT. <.LT. >=.GE. <=.LE.
|
|
if (i1>=0 && i1+32<NP2) //if(i1>=1 && i1+31<=NP2)
|
|
z1=pomAll.sum_dca_mplay_conj_dca(cd0,i1,i1+32,csync2);//if(i1.ge.1 .and. i1+31.le.NP2) z1=sum(cd0(i1:i1+31)*conjg(csync2))
|
|
if (i2>=0 && i2+32<NP2) //if(i2>=1 && i2+31<=NP2)
|
|
z2=pomAll.sum_dca_mplay_conj_dca(cd0,i2,i2+32,csync2);//if(i2.ge.1 .and. i2+31.le.NP2) z2=sum(cd0(i2:i2+31)*conjg(csync2))
|
|
if (i3>=0 && i3+32<NP2) //if(i3>=1 && i3+31<=NP2)
|
|
z3=pomAll.sum_dca_mplay_conj_dca(cd0,i3,i3+32,csync2);//if(i3.ge.1 .and. i3+31.le.NP2) z3=sum(cd0(i3:i3+31)*conjg(csync2))
|
|
|
|
z1 *= 0.01;//2.00=0.01 1.76=0.1
|
|
z2 *= 0.01;//2.00=0.01 1.76=0.1
|
|
z3 *= 0.01;//2.00=0.01 1.76=0.1
|
|
sync += (pomAll.ps_hv(z1) + pomAll.ps_hv(z2) + pomAll.ps_hv(z3));//sync = sync + p(z1) + p(z2) + p(z3)
|
|
//sync = sync + ps_hv(z1)*0.01 + ps_hv(z2)*0.01 + ps_hv(z3)*0.01;
|
|
}
|
|
//qDebug()<<"sync=========================="<<sync;
|
|
}
|
|
//#define F0_DB 8.3*6.25 //2.68 8.3*baud double baud=DEC_SAMPLE_RATE/(double)NSPS;
|
|
//#define F1_DB 1.05*6.25 //2.68 1.05*baud;
|
|
//#define F0_DB 8.4*6.25
|
|
//#define F1_DB 0.85*6.25
|
|
#define F0_DB 8.4*6.25 //2.69
|
|
#define F1_DB 1.0*6.25 //2.69
|
|
//#define F0_DB 8.5*6.25
|
|
//#define F1_DB 1.5*6.25
|
|
|
|
#define K_SUB 1.9842 //2.68
|
|
//#define K_SUB 1.9840 //2.66
|
|
//#define K_SUB 1.9600 //old 1.96
|
|
//#define K_SUB 1.9998
|
|
void DecoderFt8::ft8_downsample(double *dd,bool &newdat,double f0,double complex *c1)
|
|
{
|
|
//const int NSPS=1920;
|
|
const int NFFT2=3200;
|
|
const int c_c1=NFFT2;//1.44 tuk be6e problema be6e->(NFFT2-1) triabva da e->(NFFT2-0)
|
|
const int NMAX=15*DEC_SAMPLE_RATE; //=180000 !192000/60 = 3200
|
|
const int NFFT1=192000;
|
|
//double x[NFFT1+100];
|
|
|
|
if (first_ft8_downsample)
|
|
{
|
|
for (int i = 0; i < 101; ++i)// do i=0,100
|
|
taper_ft8_ds[i]=0.5*(1.0+cos((double)i*pi/100.0));//0.25 taper(i)=0.5*(1.0+cos(i*pi/100))
|
|
first_ft8_downsample=false;
|
|
}
|
|
if (newdat)
|
|
{
|
|
double x[NFFT1+100];
|
|
//! Data in dd have changed, recompute the long FFT
|
|
/*for (int i = 0; i < NMAX; ++i)
|
|
x[i]=dd[i]*0.01; //hv correction x(1:NMAX)=dd hv correction
|
|
for (int i = NMAX; i < NFFT1; ++i)
|
|
x[i]=0.0; */ //!Zero-pad the x array
|
|
for (int i = 0; i < NFFT1; ++i)
|
|
{
|
|
if (i < NMAX) x[i]=dd[i]*0.01;
|
|
else x[i]=0.0;
|
|
}
|
|
f2a.four2a_d2c(cx_ft8,x,NFFT1,-1,0,decid);//call four2a(cx,NFFT1,1,-1,0) //!r2c FFT to freq domain
|
|
newdat=false;
|
|
}
|
|
|
|
double df=DEC_SAMPLE_RATE/(double)NFFT1;
|
|
//double baud=DEC_SAMPLE_RATE/(double)NSPS;
|
|
int i0=int(f0/df); //qDebug()<<"baud="<<baud;
|
|
//double ft=f0+8.4*baud; //2.39 (tap 9.0) (no tap 8.5) <-tested ft=f0+8.5*baud
|
|
//double fb=f0-1.06*baud;//2.39 (tap 2.0) (no tap 1.0) <-tested fb=f0-1.5*baud
|
|
//double ft=f0+8.3*baud; //2.39 (tap 9.0) (no tap 8.5) <-tested ft=f0+8.5*baud
|
|
//double fb=f0-1.05*baud; //2.39 (tap 2.0) (no tap 1.0) <-tested fb=f0-1.5*baud
|
|
//double ft=f0+8.2*baud; //2.38 good 8.2 <-tested ft=f0+8.5*baud
|
|
//double fb=f0-1.08*baud;//2.38 1.08 <-tested fb=f0-1.5*baud
|
|
//double ft=f0+8.5*baud;//good 8.5 <-tested ft=f0+8.5*baud 3/1
|
|
//double fb=f0-1.5*baud;//good 1.7 <-tested fb=f0-1.5*baud 3/1
|
|
double ft=f0+F0_DB; //2.39 (tap 9.0) (no tap 8.5) <-tested ft=f0+8.5*baud
|
|
double fb=f0-F1_DB; //2.39 (tap 2.0) (no tap 1.0) <-tested fb=f0-1.5*baud
|
|
int it=fmin(int(ft/df),NFFT1/2);
|
|
int ib=fmax(0,int(fb/df));
|
|
int k=0;
|
|
//qDebug()<<"fdown="<<fb<<"f0="<<f0<<"fup="<<ft;
|
|
//QString my_call = "LZ2HV";
|
|
//qDebug()<<QString("%1").arg(my_call, -12);
|
|
//c1=0.0; in ft8b zero
|
|
for (int i = ib; i < it; ++i)
|
|
{//do i=ib,it
|
|
c1[k]=cx_ft8[i];//c1(k)=cx(i)
|
|
k++;
|
|
}//qDebug()<<"3200 > k="<<k;
|
|
|
|
int to_tap = 101;
|
|
int ctrp = to_tap - 1; //qDebug()<<k; k=900
|
|
for (int i = 0; i < to_tap; ++i)
|
|
{
|
|
//c1[i]=taper_ft8_ds[ctrp]*conj(c1[i]);
|
|
c1[i]*=taper_ft8_ds[ctrp];//c1(0:100)=c1(0:100)*taper(100:0:-1)
|
|
ctrp--;
|
|
}//qDebug()<<ctrp;
|
|
for (int i = 0; i < to_tap; ++i)// k=900
|
|
//c1[i+k-to_tap]=taper_ft8_ds[i]*conj(c1[i+k-to_tap]);
|
|
c1[i+k-to_tap]*=taper_ft8_ds[i];//c1(k-1-100:k-1)=c1(k-1-100:k-1)*taper
|
|
|
|
pomAll.cshift1(c1,c_c1,i0-ib);//c1=cshift(c1,i0-ib)
|
|
f2a.four2a_c2c(c1,NFFT2,1,1,decid); //call four2a(c1,NFFT2,1,1,1) //!c2c FFT back to time domain
|
|
/*
|
|
int ctrp = 100; //qDebug()<<k; k=900
|
|
int to_tap = 101;
|
|
for (int i = 0; i < to_tap; ++i)
|
|
{
|
|
//c1[i]=taper_ft8_ds[ctrp]*conj(c1[i]);
|
|
c1[i]*=taper_ft8_ds[ctrp];//c1(0:100)=c1(0:100)*taper(100:0:-1)
|
|
ctrp--;
|
|
}//qDebug()<<ctrp;
|
|
for (int i = 0; i < to_tap; ++i)// k=900
|
|
//c1[i+k-to_tap]=taper_ft8_ds[i]*conj(c1[i+k-to_tap]);
|
|
c1[i+k-to_tap]*=taper_ft8_ds[i];//c1(k-1-100:k-1)=c1(k-1-100:k-1)*taper
|
|
*/
|
|
double fac=1.0/sqrt((double)NFFT1*(double)NFFT2);
|
|
for (int i = 0; i < c_c1; ++i)
|
|
c1[i]*=fac;
|
|
//c1[i]=fac*c1[i]*0.001;
|
|
/*for (int i = 2783; i < c_c1; ++i)
|
|
{
|
|
c1[i]=0.0;
|
|
}*/
|
|
}
|
|
void DecoderFt8::gen_ft8cwaveRx(int *i4tone,double f_tx,double complex *cwave)
|
|
{
|
|
//////////////////////// GFSK MODULATOR ///////////////////////////////////////////
|
|
//const int NTAB=65536;
|
|
int nsym=79;
|
|
int nsps=1920; //for 12000=1920 for=48000->4*1920;
|
|
int nwave=nsym*nsps;//max rx=151680
|
|
//static double dphi[155570];
|
|
double hmod=1.0;
|
|
double dt=1.0/12000.0;// for RX=12000 for tx=48000
|
|
|
|
//! Compute the smoothed frequency waveform.
|
|
//! Length = (nsym+2)*nsps samples, zero-padded (nsym+2)*nsps TX=215040 RX=53760
|
|
double dphi_peak=twopi*hmod/(double)nsps;
|
|
double *dphi = new double[155620]; //max rx=155520 dphi=79*1920=151680 + 1920*2=155520
|
|
|
|
for (int i= 0; i < 155540; ++i) dphi[i]=0.0;
|
|
|
|
for (int j= 0; j < nsym; ++j)
|
|
{
|
|
int ib=j*nsps;
|
|
for (int i= 0; i < 3*nsps; ++i)//5760
|
|
dphi[i+ib] += dphi_peak*pulse_ft8_rx[i]*(double)i4tone[j];
|
|
}
|
|
|
|
int bgn =nsym*nsps;//=151680
|
|
for (int i= 0; i < 2*nsps; ++i)//=3840
|
|
{
|
|
dphi[i]+=dphi_peak*i4tone[0]*pulse_ft8_rx[i+nsps];
|
|
dphi[i+bgn]+=dphi_peak*i4tone[nsym-1]*pulse_ft8_rx[i];
|
|
}
|
|
|
|
double ofs = twopi*f_tx*dt;
|
|
double phi=0.0;
|
|
for (int j=0; j < nwave; ++j)//=151680
|
|
{
|
|
//2.39 old cwave[j]=(cos(phi)+sin(phi)*I);
|
|
int i=(int)(phi*65536.0/twopi);
|
|
//if (i<0 || i>65535) qDebug()<<i;
|
|
if (i<0) i=0;
|
|
if (i>65535) i=65535;
|
|
cwave[j]=ctab8_[i];
|
|
phi=fmod(phi+dphi[j+nsps]+ofs,twopi);
|
|
}
|
|
|
|
int nramp=(int)((double)nsps/8.0);
|
|
for (int i = 0; i < nramp; ++i)
|
|
cwave[i]*=(1.0-cos(twopi*(double)i/(2.0*nramp)))/2.0;
|
|
int k2=nsym*nsps-nramp+1; //k1=nsym*nsps-nramp+1 //k2=(nsym+1)*nsps+1;
|
|
for (int i = 0; i < nramp; ++i)
|
|
cwave[i+k2]*=(1.0+cos(twopi*(double)i/(2.0*nramp)))/2.0;//i+k1-nsps
|
|
//qDebug()<<"nsamp="<<k2+nramp-1;
|
|
delete [] dphi;
|
|
}
|
|
double DecoderFt8::BestIdtft8(double *dd,double f0,double dt,double idt,double complex *cref,
|
|
double complex *cfilt,double complex *cw_subs,double *endcorr,
|
|
double *xdd,double complex *cx)
|
|
{
|
|
double sqq=0.0;
|
|
const int NFRAME=1920*79;//=151680
|
|
const int NMAX=180000;
|
|
const int NFFT=180000;
|
|
const int NFILT=4000;
|
|
int nstart=dt*DEC_SAMPLE_RATE+1.0+idt;//0 +1.0 -1920
|
|
|
|
//for (int i = 0; i < NMAX; ++i) xdd[i]=0.0;
|
|
for (int i = 0; i < NFRAME; ++i)
|
|
{
|
|
int id=nstart+i-1;//0 -1
|
|
if (id>=0 && id<NMAX)
|
|
{
|
|
xdd[id]=dd[id];//no problem to be here
|
|
cfilt[i]=xdd[id]*conj(cref[i]);//camp[i];//cfilt(1:nframe)=camp(1:nframe)
|
|
}
|
|
}
|
|
|
|
for (int i = NFRAME; i < 180010; ++i)
|
|
cfilt[i]=0.0;//cfilt(nframe+1:)=0.0
|
|
|
|
f2a.four2a_c2c(cfilt,NFFT,-1,1,decid);//call four2a(cfilt,nfft,1,-1,1)
|
|
for (int i = 0; i < NFFT; ++i)
|
|
cfilt[i]*=cw_subs[i];//cfilt(1:nfft)=cfilt(1:nfft)*cw(1:nfft)
|
|
f2a.four2a_c2c(cfilt,NFFT,1,1,decid);//;//call four2a(cfilt,nfft,1,1,1)
|
|
|
|
for (int i = 0; i < NFILT/4; ++i)//hv NFILT/2+1
|
|
cfilt[i]*=endcorr[i];//cfilt(1:NFILT/2+1)=cfilt(1:NFILT/2+1)*endcorrection
|
|
int revv = NFRAME-1;
|
|
for (int i = 0; i < NFILT/4; ++i)//hv NFILT/2+1 //NFRAME=151680 NFILT=4000;
|
|
{
|
|
cfilt[revv]*=endcorr[i];//cfilt(nframe:nframe-NFILT/2:-1)=cfilt(nframe:nframe-NFILT/2:-1)*endcorrection
|
|
revv--;
|
|
}
|
|
|
|
double t_dd[180200];
|
|
//for (int i = 0; i < NMAX; ++i) t_dd[i]=0.0;
|
|
|
|
int c_beg = nstart-1;
|
|
if (c_beg<0) c_beg = abs(c_beg);
|
|
else c_beg = 0;
|
|
if (c_beg>NMAX) c_beg=NMAX;
|
|
for (int i = 0; i < c_beg; ++i) t_dd[i]=0.0;
|
|
for (int i = NFRAME-2; i < NMAX; ++i) t_dd[i]=0.0;
|
|
//qDebug()<<c_beg<<NFRAME-2;
|
|
|
|
//bool fff = true;
|
|
//int start_i = 0;
|
|
//int stop_i = 0;
|
|
for (int i = 0; i < NFRAME; ++i)
|
|
{
|
|
int j=nstart+i-1;//0 -1
|
|
if (j>=0 && j<NMAX)
|
|
{
|
|
double complex cfr = cfilt[i]*cref[i];
|
|
//xdd[j]-=1.96*creal(cfr);//2.41=1.96 2.39=1.97 2.35=1.94 2.26 1.93 no->2.0 //2.07 1.92<-tested 1.5,1.6 ,1.7ok,
|
|
xdd[j]-=K_SUB*creal(cfr);
|
|
t_dd[i]=xdd[j];
|
|
/*if(fff)
|
|
{
|
|
fff=false;
|
|
start_i = i;
|
|
}
|
|
stop_i = i;*/
|
|
}
|
|
}
|
|
for (int i = 0; i < NMAX; ++i) xdd[i]=t_dd[i];
|
|
//qDebug()<<"real="<<start_i<<stop_i;
|
|
|
|
/*int c_end = nstart-1; //qDebug()<<c_end<<j;
|
|
if (c_end>NMAX) c_end=NMAX;//2.40 protection
|
|
for (int i = 0; i < c_end; ++i) xdd[i]=0.0;
|
|
if (j<0) j=0;//2.40 protection
|
|
for (int i = j; i < NMAX; ++i) xdd[i]=0.0;*/
|
|
|
|
f2a.four2a_d2c(cx,xdd,NFFT,-1,0,decid); //!Forward FFT, r2c
|
|
double df=12000.0/(double)NFFT;
|
|
|
|
//int ia=((f0-1.05*6.25)/df);//ia=(f0-1.5*6.25)/df
|
|
//int ib=((f0+8.3*6.25)/df);//ib=(f0+8.5*6.25)/df
|
|
int ia=((f0-F1_DB)/df);//ia=(f0-1.5*6.25)/df
|
|
int ib=((f0+F0_DB)/df);//ib=(f0+8.5*6.25)/df
|
|
//if (ia<5000 || ib>NFFT/2-100) qDebug()<<f0<<ia<<ib;
|
|
if (ia<0) ia = 0;//2.40 protection
|
|
if (ib>(NFFT/2)) ib = (NFFT/2);//2.40 protection
|
|
|
|
for (int i = ia; i < ib; ++i)
|
|
{
|
|
sqq+=(creal(cx[i])*creal(cx[i]) + cimag(cx[i])*cimag(cx[i]));//sqq=sqq + real(cx(i))*real(cx(i)) + aimag(cx(i))*aimag(cx(i))
|
|
}
|
|
//qDebug()<<sqq;
|
|
return sqq;
|
|
}
|
|
void DecoderFt8::subtractft8(double *dd,int *itone,double f0,double dt,bool lrefinedt)
|
|
{
|
|
const int NFRAME=1920*79;//new=151680
|
|
const int NMAX=180000;//15*DEC_SAMPLE_RATE;//=180000
|
|
const int NFFT=180000;//NMAX; need to be number if no crash 180000
|
|
const int NFILT=4000;//3700;//old NFILT=1400; 4000
|
|
int offset_w = NFILT/2+25;
|
|
//int nstart=dt*DEC_SAMPLE_RATE+1.0;//0 +1.0 -1920
|
|
|
|
double complex *cref = new double complex[153681];//151681+ramp double complex cref[NFRAME+100];
|
|
double complex *cfilt= new double complex[180200];//NMAX+100
|
|
//double dd66[180192]= {0.0};// __attribute__((aligned(16))) = {0.0}; //32 =190,192,182,206,174
|
|
//pomAll.zero_double_beg_end(dd66,0,180005);
|
|
//double *dd66 = new double[180100]; // <- slow w10
|
|
|
|
pomAll.zero_double_comp_beg_end(cfilt,0,(NMAX+25));
|
|
//pomAll.zero_double_comp_beg_end(cref,0,NFRAME+25);
|
|
|
|
gen_ft8cwaveRx(itone,f0,cref);
|
|
|
|
if (first_subsft8) //then //c++ ==.EQ. !=.NE. >.GT. <.LT. >=.GE. <=.LE.
|
|
{
|
|
//! Create and normalize the filter
|
|
double window[NFILT+200] __attribute__((aligned(16)));
|
|
double fac=1.0/double(NFFT);
|
|
double sumw=0.0;
|
|
for (int j = -NFILT/2; j < NFILT/2; ++j)
|
|
{//do j=-NFILT/2,NFILT/2
|
|
window[j+offset_w]=cos(pi*(double)j/(double)NFILT)*cos(pi*(double)j/(double)NFILT);
|
|
sumw+=window[j+offset_w];
|
|
}
|
|
pomAll.zero_double_comp_beg_end(cw_subsft8,0,NMAX+25);
|
|
|
|
if (sumw<=0.0) // no devide by zero
|
|
sumw=0.01;
|
|
for (int i = 0; i < NFILT+1; ++i)
|
|
cw_subsft8[i]=window[i+offset_w-NFILT/2]/sumw;//cw(1:NFILT+1)=window/sum
|
|
|
|
pomAll.cshift1(cw_subsft8,NMAX,(NFILT/2+1)); //cw=cshift(cw,NFILT/2+1);
|
|
|
|
f2a.four2a_c2c(cw_subsft8,NFFT,-1,1,decid);//four2a(cw,nfft,1,-1,1)
|
|
|
|
for (int i = 0; i < NMAX; ++i)
|
|
cw_subsft8[i]*=fac;
|
|
|
|
for (int j = 0; j < NFILT/2+1; ++j)
|
|
{// do j=1,NFILT/2+1
|
|
// endcorrection(j)=1.0/(1.0-sum(window(j-1:NFILT/2))/sumw)
|
|
double dell;
|
|
double summ = 0.0;
|
|
for (int z = j; z < NFILT/2; ++z)
|
|
summ+=window[z+offset_w];//hv error offset_w
|
|
dell = 1.0-summ/sumw;
|
|
if (dell<=0.0) dell = 0.0001;
|
|
endcorrectionft8[j]=1.0/dell;
|
|
}
|
|
first_subsft8=false;
|
|
//qDebug()<<endcorrectionft8[0]<<endcorrectionft8[20]<<endcorrectionft8[40]<<endcorrectionft8[60];
|
|
}
|
|
|
|
int idt = 0;
|
|
bool f_du_sub = true;
|
|
if (lrefinedt)//c++ ==.EQ. !=.NE. >.GT. <.LT. >=.GE. <=.LE.
|
|
{
|
|
double *xdd = new double[180200];//NFFT=180200
|
|
double complex *cx = new double complex[90400];//NFFT/2=90000
|
|
double sqa = BestIdtft8(dd,f0,dt,-90,cref,cfilt,cw_subsft8,endcorrectionft8,xdd,cx);
|
|
double sqb = BestIdtft8(dd,f0,dt,+90,cref,cfilt,cw_subsft8,endcorrectionft8,xdd,cx);
|
|
double sq0 = BestIdtft8(dd,f0,dt, 0,cref,cfilt,cw_subsft8,endcorrectionft8,xdd,cx);
|
|
double dx = pomAll.peakup(sqa,sq0,sqb);
|
|
if (fabs(dx)>1.0) f_du_sub = false; //no subtract
|
|
else idt=(int)(90.0*dx);//subtract
|
|
delete [] xdd;
|
|
delete [] cx;
|
|
//if (!f_du_sub) qDebug()<<"idt="<<fabs(dx);
|
|
}
|
|
|
|
if (f_du_sub)
|
|
{
|
|
int nstart=dt*DEC_SAMPLE_RATE+1.0+idt;//0 +1.0 -1920
|
|
for (int i = 0; i < NFRAME; ++i)
|
|
{
|
|
int id=nstart+i-1;//0 -1
|
|
if (id>=0 && id<NMAX)
|
|
{
|
|
cfilt[i]=dd[id]*conj(cref[i]);//camp[i];//cfilt(1:nframe)=camp(1:nframe)
|
|
}
|
|
}
|
|
//2.39
|
|
for (int i = NFRAME; i < 180010; ++i)
|
|
cfilt[i]=0.0;//cfilt(nframe+1:)=0.0
|
|
|
|
f2a.four2a_c2c(cfilt,NFFT,-1,1,decid);//call four2a(cfilt,nfft,1,-1,1)
|
|
for (int i = 0; i < NFFT; ++i)
|
|
cfilt[i]*=cw_subsft8[i];//cfilt(1:nfft)=cfilt(1:nfft)*cw(1:nfft)
|
|
f2a.four2a_c2c(cfilt,NFFT,1,1,decid);//;//call four2a(cfilt,nfft,1,1,1)
|
|
|
|
for (int i = 0; i < NFILT/4; ++i)//hv NFILT/2+1
|
|
cfilt[i]*=endcorrectionft8[i];//cfilt(1:NFILT/2+1)=cfilt(1:NFILT/2+1)*endcorrection
|
|
int revv = NFRAME-1;
|
|
for (int i = 0; i < NFILT/4; ++i)//hv NFILT/2+1 //NFRAME=151680 NFILT=4000;
|
|
{
|
|
cfilt[revv]*=endcorrectionft8[i];//cfilt(nframe:nframe-NFILT/2:-1)=cfilt(nframe:nframe-NFILT/2:-1)*endcorrection
|
|
revv--;
|
|
}
|
|
|
|
for (int i = 0; i < NFRAME; ++i)//if(j.ge.1 .and. j.le.NMAX) dd(j)=dd(j)-2*REAL(cfilt(i)*cref(i))
|
|
{//do i=1,nframe
|
|
int j=nstart+i-1;//0 -1
|
|
if (j>=0 && j<NMAX)
|
|
{
|
|
double complex cfr = cfilt[i]*cref[i];
|
|
//dd[j]-=1.96*creal(cfr);//2.41=1.96 2.39=1.97 2.35=1.94 2.26 1.93 no->2.0 //2.07 1.92<-tested 1.5,1.6 ,1.7ok,
|
|
dd[j]-=K_SUB*creal(cfr);
|
|
}
|
|
}
|
|
}
|
|
delete [] cref;
|
|
delete [] cfilt;
|
|
}
|
|
bool DecoderFt8::ft8_downs_sync_bmet(double *dd,bool ap7,bool &newdat,double &f1,double &xdt,int &nbadcrc,
|
|
int &nsync,double s8_[79][8],double *bmeta,double *bmetb,double *bmetc,double *bmetd)
|
|
{
|
|
double complex cd0[3350]; //3200+100 __attribute__((aligned(32)))
|
|
double complex ctwk[32+5];
|
|
double a[5];
|
|
const int NP2=2812;
|
|
//const int ND=58;// !Data symbols
|
|
const int NS=21;// !Sync symbols (3 @ Costas 7x7)
|
|
const int NN=NS+58;// !Total channel symbols (79)
|
|
double complex csymb[40];//32+8
|
|
//double s8_[NN][8]; //real s1(0:7,ND),s2(0:7,NN)
|
|
double complex cs_[NN][8]; //complex cs(0:7,NN)
|
|
double s2[512];
|
|
const int graymap[8] =
|
|
{
|
|
0,1,3,2,5,6,4,7
|
|
};
|
|
|
|
pomAll.zero_double_comp_beg_end(cd0,0,3300);//3200+100
|
|
//int NDOWN=60;
|
|
double fs2=DEC_SAMPLE_RATE/60.0;
|
|
double dt2=1.0/fs2;
|
|
double delfbest=0.0;
|
|
int ibest=0;
|
|
nbadcrc=1;
|
|
|
|
ft8_downsample(dd,newdat,f1,cd0); //!Mix f1 to baseband and downsample
|
|
|
|
//qDebug()<<"ft8b="<<creal(cd0[100])<<cimag(cd0[100]);
|
|
int i0=int((xdt+0.5)*fs2); //0.5 //!Initial guess for start of signal
|
|
//int i0=int((xdt+0.54)*fs2); 2.34
|
|
double smax=0.0;
|
|
double sync=0.0;
|
|
//pomAll.zero_double_comp_beg_end(ctwk,0,33);//no needed 2.37
|
|
for (int idt = i0-10; idt <= i0+10; ++idt)//2.39 ????
|
|
{//2.39 do idt=i0-10,i0+10 do idt=i0-8,i0+8 //!Search over +/- one quarter symbol
|
|
sync8d(cd0,idt,ctwk,0,sync); //c++ ==.EQ. !=.NE. >.GT. <.LT. >=.GE. <=.LE.
|
|
if (sync>smax)
|
|
{
|
|
smax=sync; //qDebug()<<idt<<sync;
|
|
ibest=idt;
|
|
}
|
|
}
|
|
//2.39 double xdt2=(double)ibest*dt2; //!Improved estimate for DT
|
|
|
|
//! Now peak up in frequency
|
|
//i0=int(xdt2*fs2);
|
|
smax=0.0;//0.0;
|
|
for (int ifr = -10; ifr <= 10; ++ifr)
|
|
//for (int ifr = -5; ifr <= 5; ifr++)
|
|
{//do ifr=-5,5 !Search over +/- 2.5 Hz
|
|
double delf=(double)ifr*0.25;
|
|
//double delf=(double)ifr*0.5;
|
|
double dphi=twopi*delf*dt2;
|
|
double phi=0.0; //qDebug()<<"2-ft8b delfbest="<<delf;
|
|
for (int i = 0; i < 32; ++i)
|
|
{//do i=1,32
|
|
ctwk[i]=cos(phi)+sin(phi)*I;
|
|
phi=fmod(phi+dphi,twopi);
|
|
}
|
|
sync8d(cd0,ibest,ctwk,1,sync);//sync8d(cd0,i0,ctwk,1,sync);
|
|
if (sync>smax)
|
|
{
|
|
smax=sync; //qDebug()<<"2-ft8b delfbest="<<sync;
|
|
delfbest=delf;
|
|
}
|
|
}
|
|
//qDebug()<<"2-ft8b delfbest="<<"delfbest"<<delfbest<<"sync"<<sync<<xdt2;
|
|
for (int i = 0; i < 5; ++i) a[i]=0.0;//-delfbest;//0.0;
|
|
a[0]=-delfbest;
|
|
pomFt.twkfreq1(cd0,NP2,fs2,a,cd0);
|
|
//2.39 old xdt=xdt2;
|
|
f1=f1+delfbest; //!Improved estimate of DF
|
|
|
|
bool fnewdat = false;
|
|
ft8_downsample(dd,fnewdat,f1,cd0); //!Mix f1 to baseband and downsample
|
|
smax=0.0;
|
|
double ss[12];// ss(9)
|
|
for (int idt = -4; idt < 5; ++idt)
|
|
{ //do idt=-4,4 !Search over +/- one quarter symbol
|
|
sync8d(cd0,ibest+idt,ctwk,0,sync);
|
|
ss[idt+4]=sync; //ss(idt+5)=sync
|
|
}
|
|
smax=pomAll.maxval_da_beg_to_end(ss,0,9); //smax=maxval(ss)
|
|
int iloc=pomAll.maxloc_da_end_to_beg(ss,0,9); //iloc=maxloc(ss)
|
|
ibest=iloc-4+ibest;//ibest=iloc(1)-5+ibest
|
|
|
|
if (ap7) xdt=(double)ibest*dt2 - 0.5;
|
|
else xdt=(double)ibest*dt2;//hv tested no-1 (double)(ibest-1)*dt2; xdt=(ibest-1)*dt2
|
|
|
|
sync=smax;
|
|
|
|
//QString sss;
|
|
for (int k = 0; k < NN; ++k)
|
|
{
|
|
int i1=ibest+k*32;//i1=ibest+(k-1)*32
|
|
pomAll.zero_double_comp_beg_end(csymb,0,34);
|
|
if ( i1>=0 && (i1+32) < NP2 )
|
|
{
|
|
for (int z = 0; z < 32; ++z)
|
|
csymb[z]=cd0[i1+z];
|
|
}
|
|
f2a.four2a_c2c(csymb,32,-1,1,decid);
|
|
for (int z = 0; z < 8; ++z)
|
|
{
|
|
cs_[k][z]=csymb[z]*0.001;//1000.0;//cs(0:7,k)=csymb(1:8)/1e3
|
|
s8_[k][z]=cabs(csymb[z]);//s8(0:7,k)=abs(csymb(1:8))
|
|
//sss.append(QString("%1 ").arg(cabs(csymb[z]),0,'f',1));
|
|
}//sss.append("\n");
|
|
}
|
|
|
|
if (!ap7)
|
|
{
|
|
//! sync quality check
|
|
int is1=0;
|
|
int is2=0;
|
|
int is3=0;
|
|
for (int k = 0; k < 7; ++k)
|
|
{
|
|
int ip=pomAll.maxloc_da_beg_to_end(s8_[k],0,8); //ip=maxloc(s2(:,k))
|
|
if (icos7_2[k]==(ip)) is1++; //if(icos7(k-1).eq.(ip(1)-1)) is1=is1+1
|
|
ip=pomAll.maxloc_da_beg_to_end(s8_[k+36],0,8);//ip=maxloc(s2(:,k+36))
|
|
if (icos7_2[k]==(ip)) is2++;//if(icos7(k-1).eq.(ip(1)-1)) is2=is2+1;
|
|
ip=pomAll.maxloc_da_beg_to_end(s8_[k+72],0,8);//ip=maxloc(s2(:,k+72))
|
|
if (icos7_2[k]==(ip)) is3++;//if(icos7(k-1).eq.(ip(1)-1)) is3=is3+1;
|
|
}
|
|
//! hard sync sum - max is 21
|
|
nsync=is1+is2+is3;
|
|
if (nsync <= 6) //! bail out if(nsync .le. 6) then ! bail out
|
|
{
|
|
nbadcrc=1; //qDebug()<<"ft8b NONONO";
|
|
return false;
|
|
}
|
|
}
|
|
/*for (int i = 0; i < 174; ++i)//no needed
|
|
{
|
|
bmeta[i] = 0.001;
|
|
bmetb[i] = 0.001;
|
|
bmetc[i] = 0.001;
|
|
bmetd[i] = 0.001;
|
|
}*/
|
|
for (int nsym = 1; nsym <= 3; ++nsym)
|
|
{//do nsym=1,3
|
|
int nt=pow(2,(3*nsym));//nt=2**(3*nsym);
|
|
//qDebug()<<"ft8b nsync<=6<-"<<nt; 8,64,512
|
|
for (int ihalf = 1; ihalf <= 2; ++ihalf)
|
|
{//do ihalf=1,2
|
|
for (int k = 1; k <= 29; k+=nsym)
|
|
{//do k=1,29,nsym
|
|
int ks=0;
|
|
if (ihalf==1) ks=k+7;
|
|
if (ihalf==2) ks=k+43;
|
|
//if(ks<=2 || ks>=76)
|
|
//qDebug()<<"ft8b ks"<<ks;
|
|
for (int i = 0; i < nt; ++i)
|
|
{//do i=0,nt-1
|
|
int i1=i/64;
|
|
int i2=(i & 63)/8;
|
|
int i3=(i & 7);
|
|
if (nsym==1) //complex cs_[NN][8]; //complex cs(0:7,NN)
|
|
s2[i]=cabs(cs_[ks-1][graymap[i3]]);//s2(i)=abs(cs(graymap(i3),ks))
|
|
else if (nsym==2)
|
|
s2[i]=cabs(cs_[ks-1][graymap[i2]]+cs_[ks][graymap[i3]]); //s2(i)=abs(cs(graymap(i2),ks)+cs(graymap(i3),ks+1))
|
|
else if (nsym==3)
|
|
s2[i]=cabs(cs_[ks-1][graymap[i1]]+cs_[ks][graymap[i2]]+cs_[ks+1][graymap[i3]]);//s2(i)=abs(cs(graymap(i1),ks)+cs(graymap(i2),ks+1)+cs(graymap(i3),ks+2))
|
|
//else
|
|
//qDebug()<<"Error - nsym must be 1, 2, or 3.";
|
|
}
|
|
//for (int i = 0; i < nt; ++i)
|
|
//s2l[i]=log(s2[i]+1e-32);//??? s2l(0:nt-1)=log(s2(0:nt-1)+1e-32)
|
|
int i32=(k-1)*3+(ihalf-1)*87; //??? i32=1+(k-1)*3+(ihalf-1)*87
|
|
int ibmax=0;
|
|
if (nsym==1) ibmax=2;
|
|
if (nsym==2) ibmax=5;
|
|
if (nsym==3) ibmax=8;
|
|
for (int ib = 0; ib <= ibmax; ++ib)
|
|
{//do ib=0,ibmax
|
|
//bm=maxval(s2(0:nt-1),one(0:nt-1,ibmax-ib)) - maxval(s2(0:nt-1),.not.one(0:nt-1,ibmax-ib))
|
|
double max1v=0.0;
|
|
for (int zz = 0; zz < nt; ++zz)
|
|
{
|
|
if (one_ft8_2[ibmax-ib][zz]==true)
|
|
{
|
|
double tmax1v=s2[zz];
|
|
if (tmax1v>max1v)
|
|
max1v=tmax1v;
|
|
}
|
|
}
|
|
double max2v=0.0;
|
|
for (int zz = 0; zz < nt; ++zz)
|
|
{
|
|
if (one_ft8_2[ibmax-ib][zz]==false)
|
|
{
|
|
double tmax2v=s2[zz];
|
|
if (tmax2v>max2v)
|
|
max2v=tmax2v;
|
|
}
|
|
}
|
|
double bm=max1v-max2v; //c++ ==.EQ. !=.NE. >.GT. <.LT. >=.GE. <=.LE.
|
|
//if (max1v==0.0 || max2v==0.0) qDebug()<<max1v<<max2v;
|
|
if (i32+ib>173) continue;//cycle //if(i32+ib .gt.174) cycle
|
|
|
|
if (nsym==1)
|
|
{
|
|
bmeta[i32+ib]=bm; //qDebug()<<"0-173"<<i32+ib;
|
|
//den=max(maxval(s2(0:nt-1),one(0:nt-1,ibmax-ib)), maxval(s2(0:nt-1),.not.one(0:nt-1,ibmax-ib)))
|
|
double den = max1v;
|
|
if (max2v > max1v) den = max2v;
|
|
|
|
double cm = 0.0;
|
|
if (den>0.0) //if(den.gt.0.0) then
|
|
cm=bm/den;
|
|
else
|
|
cm=0.0; //! erase it
|
|
bmetd[i32+ib]=cm;
|
|
}
|
|
else if (nsym==2)
|
|
bmetb[i32+ib]=bm;//bmetb(i32+ib)=bm
|
|
else if (nsym==3)
|
|
bmetc[i32+ib]=bm;//bmetc(i32+ib)=bm
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/*for (int i = 0; i < 174; ++i)
|
|
{
|
|
if (bmeta[i] == 0.001) qDebug()<<"a";
|
|
if (bmetb[i] == 0.001) qDebug()<<"b";
|
|
if (bmetc[i] == 0.001) qDebug()<<"c";
|
|
if (bmetd[i] == 0.001) qDebug()<<"d";
|
|
}*/
|
|
pomFt.normalizebmet(bmeta,174);
|
|
pomFt.normalizebmet(bmetb,174);
|
|
pomFt.normalizebmet(bmetc,174);
|
|
pomFt.normalizebmet(bmetd,174);
|
|
return true;
|
|
}
|
|
void DecoderFt8::ft8b(double *dd,bool &newdat,int nQSOProgress,double nfqso,double nftx,int ndepth,bool n4pas3int,bool lapon,
|
|
double napwid,bool lsubtract,bool nagain,int cont_id,int cont_type,int &iaptype,double &f1,double &xdt,
|
|
double xbase,int *apsym,int &nharderrors,double &dmin,int &nbadcrc,QString &message,
|
|
double &xsnr,QString theircall12,int *i4tone)//QString mygrid6,bool bcontest,
|
|
{
|
|
//int NDOWN=60;//parameter (NDOWN=60) !Downsample factor
|
|
//int NP2=2812;
|
|
//const int ND=58;// !Data symbols
|
|
const int NS=21;// !Sync symbols (3 @ Costas 7x7)
|
|
const int NN=NS+58;// !Total channel symbols (79)
|
|
//const int KK=87;// !Information bits (75 + CRC12)
|
|
|
|
//double complex ctwk[32+5];
|
|
//double a[5];
|
|
//double complex csymb[40];//32+8
|
|
double s8_[NN][8]; //real s1(0:7,ND),s2(0:7,NN)
|
|
//double complex cs_[NN][8]; //complex cs(0:7,NN)
|
|
//double s2[512];
|
|
|
|
double bmeta[174];
|
|
double bmetb[174];
|
|
double bmetc[174];
|
|
double bmetd[174];
|
|
|
|
double llra[174];
|
|
double llrb[174];
|
|
double llrc[174];//llr1(3*ND)
|
|
double llrd[174];
|
|
double llrz[174];
|
|
|
|
bool apmask[174];
|
|
bool cw[194];//174
|
|
bool message91[140];
|
|
|
|
//double complex cd0[3350];//3200+100 __attribute__((aligned(32)))
|
|
//pomAll.zero_double_comp_beg_end(cd0,0,3300);//3200+100
|
|
|
|
/*int graymap[8] =
|
|
{
|
|
0,1,3,2,5,6,4,7
|
|
};*/
|
|
|
|
if (first_ft8b_2 || (cont_id!=cont_id0_ft8_2))
|
|
{
|
|
for (int i = 0; i < 29; ++i)
|
|
{
|
|
/*if (cont_id== 0) mcq_ft8_2[i]=2*mcq_ft[i]-1;
|
|
else if (cont_id== 2) mcq_ft8_2[i]=2*mcqtest_ft[i]-1;
|
|
else if (cont_id== 3) mcq_ft8_2[i]=2*mcqtest_ft[i]-1;
|
|
else if (cont_id== 4) mcq_ft8_2[i]=2*mcqfd_ft[i]-1;
|
|
else if (cont_id== 5) mcq_ft8_2[i]=2*mcqtest_ft[i]-1;//mcq_ft8_2[i]=2*mcqru_ft[i]-1;
|
|
else if (cont_id== 6) mcq_ft8_2[i]=2*mcqww_ft[i]-1;
|
|
else if (cont_id== 7) mcq_ft8_2[i]=2*mcqww_ft[i]-1; //mcq_ft8_2[i]=2*mcqru_ft[i]-1;
|
|
else if (cont_id== 8) mcq_ft8_2[i]=2*mcqww_ft[i]-1; //mcq_ft8_2[i]=2*mcqru_ft[i]-1;
|
|
else if (cont_id== 9) mcq_ft8_2[i]=2*mcqru_ft[i]-1;
|
|
else if (cont_id==10) mcq_ft8_2[i]=2*mcqbu_ft[i]-1;
|
|
else if (cont_id==11) mcq_ft8_2[i]=2*mcqft_ft[i]-1;
|
|
else if (cont_id==12) mcq_ft8_2[i]=2*mcqpdc_ft[i]-1;
|
|
else if (cont_id==13) mcq_ft8_2[i]=2*mcqtest_ft[i]-1;*/
|
|
mcq_ft8_2[i]=2*mcq_ft[cont_id][i]-1;
|
|
if (i<19)
|
|
{
|
|
mrrr_ft8_2[i]=2*mrrr_ft[i]-1;
|
|
m73_ft8_2[i]=2*m73_ft[i]-1;
|
|
mrr73_ft8_2[i]=2*mrr73_ft[i]-1;
|
|
}
|
|
}
|
|
/*! iaptype
|
|
!------------------------
|
|
! 1 CQ ??? ???
|
|
! 2 MyCall ??? ???
|
|
! 3 MyCall DxCall ???
|
|
! 4 MyCall DxCall RRR
|
|
! 5 MyCall DxCall 73
|
|
! 6 MyCall DxCall RR73
|
|
! 7 ??? DxCall ???*/
|
|
//one=.false.
|
|
/*for (int i = 0; i < 9; ++i)
|
|
{//do i=0,511 one_ft8_2[9][512];//(0:511,0:8);
|
|
for (int j = 0; j < 512; ++j)
|
|
{
|
|
//if(iand(i,2**j).ne.0) one(i,j)=.true.
|
|
if ((j & (int)pow(2,i))!=0)
|
|
one_ft8_2[i][j]=true;
|
|
else
|
|
one_ft8_2[i][j]=false;
|
|
}
|
|
}*/
|
|
theircall12_0_ft8_2="";
|
|
cont_id0_ft8_2 = cont_id;
|
|
first_ft8b_2=false;
|
|
}
|
|
|
|
if (theircall12!=theircall12_0_ft8_2)
|
|
{
|
|
QString c13=theircall12+" ";
|
|
int n10 = 0;
|
|
int n12 = 0;
|
|
int n22 = 0;
|
|
TGenFt8->save_hash_call_from_dec(c13,n10,n12,n22);
|
|
theircall12_0_ft8_2=theircall12;
|
|
}
|
|
|
|
//int max_iterations=30;//2.39 30
|
|
nbadcrc=1; //! this is used upstream to flag good decodes.
|
|
nharderrors=-1;
|
|
int nsync=0;
|
|
if (!ft8_downs_sync_bmet(dd,false,newdat,f1,xdt,nbadcrc,nsync,s8_,bmeta,bmetb,bmetc,bmetd)) return;
|
|
|
|
double scalefac = 2.83;//scalefac=2.83 double ss=0.85;//hv tested->85-86 0.84;//0.84
|
|
double maxval_llra_abs = 0.0;
|
|
//double maxval_llrb_abs = 0.0;
|
|
for (int z = 0; z < 174; ++z)
|
|
{
|
|
llra[z]=scalefac*bmeta[z];
|
|
llrb[z]=scalefac*bmetb[z];
|
|
llrc[z]=scalefac*bmetc[z];// ! llr's for use with ap
|
|
llrd[z]=scalefac*bmetd[z];
|
|
|
|
double llra_abs = fabs(llra[z]);
|
|
if (llra_abs>maxval_llra_abs)
|
|
maxval_llra_abs=llra_abs;
|
|
/*double llrb_abs = fabs(llrb[z]);
|
|
if (llrb_abs>maxval_llrb_abs)
|
|
maxval_llrb_abs=llrb_abs;*/
|
|
}
|
|
//double apmag = scalefac*(maxval_llra_abs*1.01);//old 2.39
|
|
double apmag = maxval_llra_abs*1.01; //qDebug()<<"apmag="<<apmag;
|
|
|
|
//! pass #
|
|
//!------------------------------
|
|
//! 1 regular decoding, nsym=1
|
|
//! 2 regular decoding, nsym=2
|
|
//! 3 regular decoding, nsym=3
|
|
//! 4 ap pass 1, nsym=1 (for now?)
|
|
//! 5 ap pass 2
|
|
//! 6 ap pass 3
|
|
//! 7 ap pass 4*/
|
|
int npasses = 0;
|
|
|
|
bool lapcqonly = false;//lapcqonly<-no used fom me. if no TX more then 10min use only AP1
|
|
//if(lapon.or.ncontest.eq.7) then !Hounds always use AP
|
|
if (lapon)//no MSHV Hounds
|
|
{
|
|
if (!lapcqonly)
|
|
npasses=4+nappasses_2[nQSOProgress];//?? old v1 hv 4 // 2,2,2,4,4,3
|
|
else
|
|
npasses=5;//2.29=5 from=4 ?? old v1 hv 5
|
|
}
|
|
else
|
|
npasses=4;//2.29=4 from=3 ?? old v1 hv 4
|
|
|
|
//2.39 nzhsym=??? if(nzhsym<50) npasses=4;
|
|
if (n4pas3int) npasses=4;//2.40
|
|
//qDebug()<<"npasses="<<npasses;
|
|
|
|
for (int ipass = 1; ipass <= npasses; ++ipass)
|
|
{//do ipass=1,npasses //c++ ==.EQ. !=.NE. >.GT. <.LT. >=.GE. <=.LE.
|
|
//qDebug()<<"ft8b ipass======== Start"<<ipass;
|
|
//qDebug()<<"1 Unpack==================77="<<nbadcrc<<ipass;
|
|
for (int z = 0; z < 174; ++z)
|
|
{
|
|
if (ipass==1)
|
|
llrz[z]=llra[z];
|
|
else if (ipass==2)
|
|
llrz[z]=llrb[z];
|
|
else if (ipass==3)
|
|
llrz[z]=llrc[z];
|
|
else if (ipass==4)
|
|
llrz[z]=llrd[z];
|
|
|
|
// if (ipass > 4) dolu go pokriva
|
|
}
|
|
if (ipass<=4) //4new if(ipass.le.4)
|
|
{
|
|
for (int z = 0; z < 174; ++z)
|
|
apmask[z]=0;
|
|
iaptype=0;
|
|
}
|
|
if (ipass > 4) //4new if(ipass .gt. 4) old if(ipass .gt. 3) //c++ ==.EQ. !=.NE. >.GT. <.LT. >=.GE. <=.LE.
|
|
{
|
|
//naptypes_{1,2,0,0},{2,3,0,0},{2,3,0,0},{3,4,5,6},{3,4,5,6},{3,1,2,0}
|
|
for (int z = 0; z < 174; ++z)
|
|
llrz[z]=llra[z];
|
|
if (!lapcqonly)
|
|
iaptype=naptypes_2[nQSOProgress][ipass-(4+1)];//4new v1 4+1
|
|
else
|
|
iaptype=1;
|
|
|
|
// 0 : NONE ncontest=0 CQ
|
|
// 1 : NA_VHF TEST
|
|
// 2 : EU_VHF TEST
|
|
// 3 : FIELD DAY FD
|
|
// 4 : RTTY RU
|
|
// 5 : WW MSHV= WW
|
|
// 6 : FOX MSHV= BU
|
|
// 7 : HOUND NONE
|
|
|
|
// Activity Type id type dec-id dec-type dec-cq
|
|
//"Standard" 0 0 0 = CQ 0 0
|
|
//"EU RSQ And Serial Number" 1 NONE 1 NONE NONE NONE
|
|
//"NA VHF Contest" 2 2 2 CQ TEST 1 3 = CQ TEST
|
|
//"EU VHF Contest" 3 3 3 CQ TEST 2 3 = CQ TEST
|
|
//"ARRL Field Day" 4 4 4 CQ FD 3 2 = CQ FD
|
|
//"ARRL Inter. Digital Contest" 5 2 5 CQ TEST 1 3 = CQ TEST
|
|
//"WW Digi DX Contest" 6 2 6 CQ WW 1 4 = CQ WW
|
|
//"FT4 DX Contest" 7 2 7 CQ WW 1 4 = CQ WW
|
|
//"FT8 DX Contest" 8 2 8 CQ WW 1 4 = CQ WW
|
|
//"FT Roundup Contest" 9 5 9 CQ RU 4 1 = CQ RU
|
|
//"Bucuresti Digital Contest" 10 5 10 CQ BU 4 5 = CQ BU
|
|
//"FT4 SPRINT Fast Training" 11 5 11 CQ FT 4 6 = CQ FT
|
|
//"PRO DIGI Contest" 12 5 12 CQ PDC 4 7 = CQ PDC
|
|
//"CQ WW VHF Contest" 13 2 13 CQ TEST 1 3 = CQ TEST
|
|
|
|
//qDebug()<<"type1"<<iaptype<<ncontest;
|
|
//if(f1>2098 && f1<2110) qDebug()<<"f1-nfqso="<<f1<<fabs(f1-nfqso)<<"f1-nftx="<<fabs(f1-nftx);
|
|
//if(ncontest.le.5 .and. iaptype.ge.3 .and. (abs(f1-nfqso).gt.napwid .and. abs(f1-nftx).gt.napwid) ) cycle
|
|
//HV new=4
|
|
if (cont_type<=4 && iaptype>=3 && (fabs(f1-nfqso)>napwid && fabs(f1-nftx)>napwid) ) continue;
|
|
//if(ncontest.eq.6) cycle ! No AP for Foxes MSHV MAM have AP
|
|
//if(ncontest.eq.7.and.f1.gt.950.0) cycle ! Hounds use AP only for signals below 950 Hz MSHV no Hounds
|
|
if (iaptype>=2 && apsym[0]>1) continue; //! No, or nonstandard, mycall if(iaptype>=2 && apsym(1).gt.1) cycle
|
|
//if(ncontest.eq.7 .and. iaptype.ge.2 .and. aph10(1).gt.1) cycle
|
|
if (iaptype>=3 && apsym[29]>1) continue; //! No, or nonstandard, dxcall if(iaptype>=3 && apsym(30).gt.1) cycle
|
|
//qDebug()<<"type2"<<iaptype<<ncontest;
|
|
for (int z = 0; z < 58; ++z)//apsym[58+5]
|
|
apsym[z]=2*apsym[z]-1; // apsym=2*apsym-1 //! Change from [0,1] to antipodal
|
|
if (iaptype==1) //! CQ or CQ RU or CQ TEST or CQ FD
|
|
{
|
|
for (int z = 0; z < 174; ++z)//3*ND 174
|
|
{
|
|
apmask[z]=0;
|
|
if (z<29)
|
|
{
|
|
apmask[z]=1;
|
|
llrz[z]=apmag*(double)mcq_ft8_2[z];
|
|
//no in MSHV if(ncontest.eq.7) llrz(1:29)=apmag*mcq(1:29)
|
|
}
|
|
}
|
|
apmask[74]=1; //apmask(75:77)=1
|
|
apmask[75]=1;
|
|
apmask[76]=1;
|
|
llrz[74]=apmag*(-1.0);//llrd(75:76)=apmag*(-1)
|
|
llrz[75]=apmag*(-1.0);//llrd(75:76)=apmag*(-1)
|
|
llrz[76]=apmag*(+1.0);//llrd(77)=apmag*(+1)
|
|
}
|
|
if (iaptype==2) //then //! MyCall,???,???
|
|
{
|
|
for (int z = 0; z < 174; ++z)
|
|
apmask[z]=0;
|
|
if (cont_type==0 || cont_type==1)//hv new || cont_type==5
|
|
{
|
|
for (int z = 0; z < 29; ++z)
|
|
{
|
|
apmask[z]=1;//apmask(1:29)=1
|
|
llrz[z]=apmag*(double)apsym[z];//llrd(1:29)=apmag*apsym(1:29)
|
|
}
|
|
apmask[74]=1; //apmask(75:77)=1
|
|
apmask[75]=1;
|
|
apmask[76]=1;
|
|
llrz[74]=apmag*(-1.0);//llrd(75:76)=apmag*(-1)
|
|
llrz[75]=apmag*(-1.0);//llrd(75:76)=apmag*(-1)
|
|
llrz[76]=apmag*(+1.0);//llrd(77)=apmag*(+1)
|
|
}
|
|
else if (cont_type==2) //then
|
|
{
|
|
for (int z = 0; z < 28; ++z)
|
|
{
|
|
apmask[z]=1;//apmask(1:28)=1
|
|
llrz[z]=apmag*(double)apsym[z];//llrd(1:28)=apmag*apsym(1:28)
|
|
}
|
|
apmask[71]=1;//apmask(72:74)=1
|
|
apmask[72]=1;
|
|
apmask[73]=1;
|
|
llrz[71]=apmag*(-1.0);//llrd(72)=apmag*(-1)
|
|
llrz[72]=apmag*(+1.0);//llrd(73)=apmag*(+1)
|
|
llrz[73]=apmag*(-1.0);//llrd(74)=apmag*(-1)
|
|
apmask[74]=1;//apmask(75:77)=1
|
|
apmask[75]=1;
|
|
apmask[76]=1;
|
|
llrz[74]=apmag*(-1.0);//llrd(75:77)=apmag*(-1)
|
|
llrz[75]=apmag*(-1.0);
|
|
llrz[76]=apmag*(-1.0);
|
|
}
|
|
else if (cont_type==3)
|
|
{
|
|
for (int z = 0; z < 28; ++z)
|
|
{
|
|
apmask[z]=1; //apmask(1:28)=1
|
|
llrz[z]=apmag*(double)apsym[z];//llrd(1:28)=apmag*apsym(1:28)
|
|
}
|
|
apmask[74]=1; //apmask(75:77)=1
|
|
apmask[75]=1;
|
|
apmask[76]=1;
|
|
llrz[74]=apmag*(-1.0);//llrd(75:77)=apmag*(-1)
|
|
llrz[75]=apmag*(-1.0);
|
|
llrz[76]=apmag*(-1.0);
|
|
}
|
|
else if (cont_type==4)// || ncontest==6 RTTY RU HV new
|
|
{
|
|
for (int z = 1; z < 29; ++z)
|
|
{
|
|
apmask[z]=1;//apmask(2:29)=1
|
|
llrz[z]=apmag*(double)apsym[z-1];//llrd(2:29)=apmag*apsym(1:28)
|
|
}
|
|
apmask[74]=1;//apmask(75:77)=1
|
|
apmask[75]=1;
|
|
apmask[76]=1;
|
|
llrz[74]=apmag*(-1.0);//llrd(75)=apmag*(-1)
|
|
llrz[75]=apmag*(+1.0);//llrd(76:77)=apmag*(+1)
|
|
llrz[76]=apmag*(+1.0);
|
|
}
|
|
// HOUND = MSHV no
|
|
/*else if(ncontest.eq.7) then ! ??? RR73; MyCall <Fox Call hash10> ???
|
|
apmask(29:56)=1
|
|
llrz(29:56)=apmag*apsym(1:28)
|
|
apmask(57:66)=1
|
|
llrz(57:66)=apmag*aph10(1:10)
|
|
apmask(72:77)=1
|
|
llrz(72:73)=apmag*(-1)
|
|
llrz(74)=apmag*(+1)
|
|
llrz(75:77)=apmag*(-1)
|
|
endif*/
|
|
}
|
|
if (iaptype==3) // ! MyCall,DxCall,???
|
|
{
|
|
for (int z = 0; z < 174; ++z)
|
|
apmask[z]=0;//apmask=0
|
|
//if(ncontest.eq.0.or.ncontest.eq.1.or.ncontest.eq.2.or.ncontest.eq.5.or.ncontest.eq.7) then
|
|
if (cont_type==0 || cont_type==1 || cont_type==2)//||ncontest==7 || ncontest==5
|
|
{
|
|
for (int z = 0; z < 58; ++z)
|
|
{
|
|
apmask[z]=1;//apmask(1:58)=1
|
|
llrz[z]=apmag*(double)apsym[z];//llrd(1:58)=apmag*apsym
|
|
}
|
|
apmask[74]=1;//apmask(75:77)=1
|
|
apmask[75]=1;
|
|
apmask[76]=1;
|
|
llrz[74]=apmag*(-1.0);//llrd(75:76)=apmag*(-1)
|
|
llrz[75]=apmag*(-1.0);
|
|
llrz[76]=apmag*(+1.0);//llrd(77)=apmag*(+1)
|
|
}
|
|
else if (cont_type==3) //then ! Field Day
|
|
{
|
|
for (int z = 0; z < 57; ++z)
|
|
{
|
|
if (z<56)
|
|
apmask[z]=1;//apmask(1:56)=1
|
|
if (z<28)
|
|
llrz[z]=apmag*(double)apsym[z];//llrd(1:28)=apmag*apsym(1:28)
|
|
if (z>28)
|
|
llrz[z-1]=apmag*(double)apsym[z];//llrd(29:56)=apmag*apsym(30:57)
|
|
}
|
|
apmask[71]=1;//apmask(72:74)=1
|
|
apmask[72]=1;
|
|
apmask[73]=1;
|
|
apmask[74]=1;//apmask(75:77)=1
|
|
apmask[75]=1;
|
|
apmask[76]=1;
|
|
llrz[74]=apmag*(-1.0);//llrd(75:77)=apmag*(-1)
|
|
llrz[75]=apmag*(-1.0);
|
|
llrz[76]=apmag*(-1.0);
|
|
}
|
|
else if (cont_type==4)//RTTY RU HV new || ncontest==6
|
|
{
|
|
for (int z = 0; z < 57; ++z)
|
|
{
|
|
if (z>0)
|
|
apmask[z]=1;//apmask(2:57)=1
|
|
if (z<28)
|
|
llrz[z+1]=apmag*(double)apsym[z];//llrd(2:29)=apmag*apsym(1:28)
|
|
if (z>28)
|
|
llrz[z]=apmag*(double)apsym[z];//llrd(30:57)=apmag*apsym(30:57)
|
|
}
|
|
apmask[74]=1;//apmask(75:77)=1
|
|
apmask[75]=1;
|
|
apmask[76]=1;
|
|
llrz[74]=apmag*(-1.0);//llrd(75)=apmag*(-1)
|
|
llrz[75]=apmag*(+1.0);//llrd(76:77)=apmag*(+1)
|
|
llrz[76]=apmag*(+1.0);
|
|
}
|
|
}
|
|
//if(iaptype==5 && ncontest==7) continue;//cycle !Hound
|
|
if (iaptype==4 || iaptype==5 || iaptype==6)
|
|
{
|
|
for (int z = 0; z < 174; ++z)
|
|
apmask[z]=0;//apmask=0
|
|
//if(ncontest.le.5 || (ncontest.eq.7.and.iaptype.eq.6)) then
|
|
if (cont_type<=4)//HV new=4
|
|
{
|
|
for (int z = 0; z < 77; ++z)
|
|
{
|
|
apmask[z]=1;//apmask(1:77)=1 //! mycall, theircall, RRR|73|RR73
|
|
if (z<58)
|
|
llrz[z]=apmag*(double)apsym[z];//llrd(1:58)=apmag*apsym
|
|
}
|
|
for (int z = 0; z < 19; ++z)
|
|
{
|
|
if (iaptype==4)
|
|
llrz[z+58]=apmag*(double)mrrr_ft8_2[z]; //llrd(59:77)=apmag*mrrr
|
|
if (iaptype==5)
|
|
llrz[z+58]=apmag*(double)m73_ft8_2[z]; //llrd(59:77)=apmag*m73
|
|
if (iaptype==6)
|
|
llrz[z+58]=apmag*(double)mrr73_ft8_2[z];//llrd(59:77)=apmag*mrr73
|
|
}
|
|
}
|
|
//HOUND = MSHV no
|
|
/*else if(ncontest.eq.7.and.iaptype.eq.4) then ! Hound listens for MyCall RR73;...
|
|
apmask(1:28)=1
|
|
llrz(1:28)=apmag*apsym(1:28)
|
|
apmask(57:66)=1
|
|
llrz(57:66)=apmag*aph10(1:10)
|
|
apmask(72:77)=1
|
|
llrz(72:73)=apmag*(-1)
|
|
llrz(74)=apmag*(1)
|
|
llrz(75:77)=apmag*(-1)
|
|
endif*/
|
|
}
|
|
}
|
|
|
|
for (int z = 0; z < 174; ++z)
|
|
{
|
|
cw[z]=0;
|
|
if (z<120) message91[z]=0;
|
|
}
|
|
|
|
dmin=0.0;
|
|
int norder=2;
|
|
int maxosd=2; //c++ ==.EQ. !=.NE. >.GT. <.LT. >=.GE. <=.LE.
|
|
//if (ndepth<3) maxosd=1;//old if(ndepth.lt.3) maxosd=1
|
|
if (ndepth==1) maxosd=-1; //2.42 ! BP only
|
|
if (ndepth==2) maxosd=0; //2.42 ! uncoupled BP+OSD
|
|
//if(ndepth.eq.3 .and. (abs(nfqso-f1).le.napwid .or. abs(nftx-f1).le.napwid .or. ncontest.eq.7))
|
|
if (ndepth==3 && (fabs(nfqso-f1)<=napwid || fabs(nftx-f1)<=napwid /*|| ncontest==7*/))//2.42
|
|
maxosd=2;
|
|
if (nagain)//222 removed
|
|
{
|
|
norder=3;
|
|
maxosd=1;
|
|
}
|
|
//all =int Keff=91;
|
|
pomFt.decode174_91(llrz,maxosd,norder,apmask,message91,cw,nharderrors,dmin);//ntype, Keff,
|
|
//if(f1>2098 && f1<2110) qDebug()<<"f1-nfqso="<<f1<<xdt<<nharderrors;
|
|
/*if (nharderrors>=0)
|
|
{
|
|
for (int z = 0; z < 77; ++z)//message77=message91(1:77)
|
|
message77[z]=message91[z];
|
|
}*/
|
|
|
|
|
|
message="";
|
|
xsnr=-99.0;
|
|
nbadcrc=1;//2.42 222=?
|
|
if (nharderrors<0 || nharderrors>36) continue;//cycle
|
|
int c_cw = 0;
|
|
for (int z = 0; z < 174; z++)//c++ ==.EQ. !=.NE. >.GT. <.LT. >=.GE. <=.LE.
|
|
{
|
|
if (cw[z]==0)// 3*ND=174
|
|
c_cw++;
|
|
}
|
|
if (c_cw==174) continue;
|
|
|
|
int i3,n3;
|
|
n3=4*message91[71] + 2*message91[72] + message91[73];//??? check need
|
|
i3=4*message91[74] + 2*message91[75] + message91[76];//??? check need
|
|
// old if (i3>4 || (i3==0 && n3>5)) continue; //cycle
|
|
if (i3>5 || (i3==0 && n3>6)) continue; //2.39 EU VHF Contest
|
|
if (i3==0 && n3==2) continue; //2.42 222 ignore old EU VHF Contest
|
|
bool unpk77_success = false;
|
|
message = TGenFt8->unpack77(message91,unpk77_success); //qDebug()<<message<<unpk77_success;
|
|
//qDebug()<<"100 Unpack=77--->"<<message<<i3<<n3<<unpk77_success<<f1;
|
|
if (!unpk77_success) continue; //cycle
|
|
//if (nharderrors==21) qDebug()<<"100 Unpack=77="<<nbadcrc<<message<<unpk77_success;
|
|
|
|
nbadcrc=0; //! If we get this far: valid codeword, valid (i3,n3), nonquirky message.
|
|
|
|
//int i4tone[120];
|
|
TGenFt8->make_c77_i4tone(message91,i4tone);
|
|
|
|
|
|
if (lsubtract)
|
|
subtractft8(dd,i4tone,f1,xdt,false);//qDebug()<<"subtractft8"<<message<<xdt2<<f1<<ipass;
|
|
|
|
double xsig=0.0;
|
|
for (int i = 0; i < NN; ++i)//NN=79 c++ ==.EQ. !=.NE. >.GT. <.LT. >=.GE. <=.LE.
|
|
{//do i=1,79
|
|
//old variant v1 xsig=xsig+s2_[i][i4tone[i]]*s2_[i][i4tone[i]];
|
|
//s8_/1000.0 = s2_ HV from v1.
|
|
double s88 = s8_[i][i4tone[i]]*0.001;//1000.0;
|
|
xsig=xsig+s88*s88; //double s2_[NN][8]; xsig=xsig+s2(itone(i),i)**2
|
|
//int ios=fmod(i4tone[i]+4,7);//ios=mod(itone(i)+4,7)
|
|
//xnoi=xnoi+s2_[i][ios]*s2_[i][ios]; //xnoi=xnoi+s2(ios,i)**2
|
|
}
|
|
|
|
if (xbase<=0.0) //no devide by zero
|
|
xbase=0.001;
|
|
xsnr=pomAll.db(xsig/xbase - 1.0) - 32.0 - 4.0;
|
|
|
|
|
|
if (nsync<=10 && xsnr<-24.0) //220rc2 !bail out, likely false decode
|
|
{
|
|
nbadcrc=1;
|
|
return;
|
|
}
|
|
|
|
if (xsnr < -25.0) xsnr=-25.0;
|
|
if (xsnr > 49.0) xsnr=49.0; //2.31
|
|
|
|
/*xsig=0.0 //rc3
|
|
xnoi=0.0
|
|
do i=1,79
|
|
xsig=xsig+s8(itone(i),i)**2
|
|
ios=mod(itone(i)+4,7)
|
|
xnoi=xnoi+s8(ios,i)**2
|
|
enddo
|
|
xsnr=0.001
|
|
xsnr2=0.001
|
|
arg=xsig/xnoi-1.0
|
|
if(arg.gt.0.1) xsnr=arg
|
|
arg=xsig/xbase/2.6e6-1.0
|
|
if(arg.gt.0.1) xsnr2=arg
|
|
xsnr=10.0*log10(xsnr)-27.0
|
|
xsnr2=10.0*log10(xsnr2)-27.0
|
|
if(.not.nagain) then
|
|
xsnr=xsnr2
|
|
endif
|
|
if(xsnr .lt. -24.0) xsnr=-24.0*/
|
|
|
|
return;
|
|
}
|
|
}
|
|
void DecoderFt8::baseline(double *s,int nfa,int nfb,double *sbase)
|
|
{
|
|
/*! Fit baseline to spectrum (for FT8)
|
|
! Input: s(npts) Linear scale in power
|
|
! Output: sbase(npts) Baseline
|
|
*/
|
|
double df=DEC_SAMPLE_RATE/3840.0; //!3.125 Hz
|
|
int ia=fmax(0,int(nfa/df));
|
|
int ib=int(nfb/df);
|
|
int nseg = 10;
|
|
int npct = 10;
|
|
double t_s[1970];
|
|
//double *t_s = new double[1920+20];
|
|
double x[1010];
|
|
double y[1010];
|
|
double a[8];
|
|
//qDebug()<<ia<<ib;
|
|
for (int i = ia; i<ib; ++i)
|
|
{//do i=ia,ib
|
|
if (s[i]<0.000001) s[i]=0.000001;
|
|
s[i]=10.0*log10(s[i]); //!Convert to dB scale
|
|
}
|
|
|
|
int nterms=5;
|
|
int nlen=(ib-ia+0)/nseg; //!Length of test segment
|
|
int i0=(ib-ia+0)/2; //!Midpoint
|
|
int k=0;//???
|
|
|
|
for (int n = 0; n<nseg; ++n)
|
|
{//do n=1,nseg //!Loop over all segments
|
|
int ja=ia + (n-0)*nlen;
|
|
int jb=ja+nlen-0;
|
|
|
|
for (int z = 0; z<1920-ja; ++z)
|
|
t_s[z] = s[z+ja];
|
|
//qDebug()<<"ja jb"<<ja<<jb<<nlen<<1920-ja;
|
|
double base = pomAll.pctile_shell(t_s,nlen,npct);//pctile(s(ja),nlen,npct,base); //!Find lowest npct of points
|
|
//qDebug()<<"base"<<base;
|
|
for (int i = ja; i<jb; ++i)
|
|
{//do i=ja,jb
|
|
if (s[i]<=base)// then //c++ ==.EQ. !=.NE. >.GT. <.LT. >=.GE. <=.LE.
|
|
{
|
|
//if (k<1000) k++; //!Save all "lower envelope" points
|
|
x[k]=i-i0;
|
|
y[k]=s[i];
|
|
if (k<999)
|
|
k++;
|
|
}
|
|
}
|
|
}
|
|
|
|
int kz=k;
|
|
//if(kz<32) kz=32;
|
|
|
|
pomAll.zero_double_beg_end(a,0,6);//a=0.
|
|
//call polyfit(x,y,y,kz,nterms,0,a,chisqr) //!Fit a low-order polynomial
|
|
double chisqr = 0.0;
|
|
pomAll.polyfit(x,y,y,kz,nterms,0,a,chisqr);
|
|
//qDebug()<<"a"<<a[0]<<a[1]<<a[2]<<a[3]<<a[4]<<i0;
|
|
for (int i = 0; i<1920; ++i)
|
|
sbase[i]=0.0;
|
|
for (int i = ia; i<ib; ++i)
|
|
{//do i=ia,ib
|
|
double t=i-i0;
|
|
sbase[i]=a[0]+t*(a[1]+t*(a[2]+t*(a[3]+t*(a[4])))) + 0.65;
|
|
//! write(51,3051) i*df,s(i),sbase(i)
|
|
//!3051 format(3f12.3)
|
|
}
|
|
//int hhh=int(1200.0/3.125);
|
|
//qDebug()<<"xbase=="<<sbase[hhh-2]<<sbase[hhh-1]<<sbase[hhh]<<sbase[hhh+1]<<sbase[hhh+2];
|
|
}
|
|
void DecoderFt8::get_spectrum_baseline(double *dd,int nfa,int nfb,double *sbase)
|
|
{
|
|
const int NSPS=1920;
|
|
const int NFFT1=2*NSPS; //=3840
|
|
const int NH1=NFFT1/2;//1920
|
|
const int NF=93;
|
|
const int NST=NFFT1/2;//=960
|
|
const int NMAX=180000;//NMAX=15*12000
|
|
double savg[NH1+50];
|
|
double x[NFFT1+50];
|
|
double complex cx[NH1+100];
|
|
//double ss_[NF+10][NH1+50];//hv no needed (NH1,NF)
|
|
|
|
if (first_ft8sbl)
|
|
{
|
|
first_ft8sbl=false;
|
|
for (int i = 0; i<NFFT1; ++i)
|
|
window_ft8sbl[i]=0.0;
|
|
pomFt.nuttal_window(window_ft8sbl,NFFT1);
|
|
//qDebug()<<window_ft8sbl[10]<<window_ft8sbl[1000]<<window_ft8sbl[2000]<<window_ft8sbl[3000];
|
|
double summ = 0.0;
|
|
for (int i = 0; i<NFFT1; ++i)
|
|
summ+=window_ft8sbl[i];
|
|
summ = summ*(double)NSPS*2.0/300.0;
|
|
//qDebug()<<summ;
|
|
for (int i = 0; i<NFFT1; ++i)
|
|
window_ft8sbl[i]/=summ;//window=window/sum(window)*NSPS*2/300.0
|
|
//qDebug()<<window_ft8sbl[10]<<window_ft8sbl[100]<<window_ft8sbl[200]<<window_ft8sbl[300];
|
|
}
|
|
|
|
//! Compute symbol spectra, stepping by NSTEP steps.
|
|
for (int i = 0; i<NH1+2; ++i)
|
|
savg[i]=0.0;
|
|
//double df=12000.0/(double)NFFT1;
|
|
for (int j = 0; j<NF; ++j)
|
|
{//do j=1,NF
|
|
int ia=j*NST;//(j-1)*NST + 1
|
|
int ib=ia+NFFT1-1;//ib=ia+NFFT1-1
|
|
//if (ia+NFFT1-1>178000) qDebug()<<ia+NFFT1-1;
|
|
if (ib>NMAX-1) break;// if(ib.gt.NMAX) exit //c++ ==.EQ. !=.NE. >.GT. <.LT. >=.GE. <=.LE.
|
|
for (int z = 0; z < NFFT1; ++z)
|
|
x[z]=dd[ia+z]*window_ft8sbl[z]; //x=dd(ia:ib)*window
|
|
//if (ia+NFFT1-1>178000) qDebug()<<ia+NFFT1-1;
|
|
//qDebug()<<x[10]<<x[1000]<<x[2000]<<x[3000];
|
|
f2a.four2a_d2c(cx,x,NFFT1,-1,0,decid); //call four2a(x,NFFT1,1,-1,0) //!r2c FFT
|
|
for (int i = 0; i < NH1; ++i)
|
|
{//do i=1,NH1
|
|
//ss_[j][i]=cabs(cx[i])*cabs(cx[i]);//fin s(1:NH1,j)=abs(cx(1:NH1))**2
|
|
//savg[i]+=ss_[j][i];//savg=savg + s(1:NH1,j) //!Average spectrum
|
|
savg[i]+=cabs(cx[i])*cabs(cx[i]);
|
|
|
|
}
|
|
}
|
|
/*qDebug()<<"-------------------------------------";
|
|
QString sss;
|
|
for (int i = 0; i<NH1; ++i)
|
|
sss.append(QString("%1 ").arg(savg[i],0,'f',1));
|
|
qDebug()<<sss;*/
|
|
|
|
if (nfa<100) nfa=100;
|
|
if (nfb>4910) nfb=4910;
|
|
baseline(savg,nfa,nfb,sbase);
|
|
}
|
|
/*void DecoderFt8::sync8(double *dd,double nfa,double nfb,double syncmin,double nfqso,
|
|
double s_[402][1970],double candidate[2][620],int &ncand,double *sbase)
|
|
{
|
|
const int NSPS=1920;
|
|
int NSTEP=NSPS/4;//=480
|
|
const int NFFT1=2*NSPS;
|
|
int NMAX=15*DEC_SAMPLE_RATE;
|
|
int NHSYM=NMAX/NSTEP-3;//372
|
|
const int NH1=NFFT1/2; //NH1=1920
|
|
const int max_c0 = 400;//305;//2.2.0=500
|
|
//! Search over +/- 1.5s relative to 0.5s TX start time.
|
|
//parameter (JZ=38)
|
|
//old 72/2 int JZ=38;
|
|
//! Search over +/- 2.5s relative to 0.5s TX start time.
|
|
//parameter (JZ=62) new
|
|
int JZ=62;//62;
|
|
|
|
//! Compute symbol spectra, stepping by NSTEP steps.
|
|
//double savg=0.0;
|
|
double tstep=(double)NSTEP/DEC_SAMPLE_RATE;
|
|
double df=DEC_SAMPLE_RATE/(double)NFFT1; //!3.125 Hz
|
|
double fac=1.0/300.0;
|
|
|
|
double x[NFFT1+20];//=3840 //real x(NFFT1)
|
|
//double *x = new double[NFFT1+20];
|
|
double complex cx[NFFT1+20]; //2.09 error-> cx[NH1+20]; //complex cx(0:NH1)
|
|
|
|
// old 76 double sync2d[1920+50][76+20]; //real sync2d(NH1,-JZ:JZ) -JZ=-38 JZ=+38 = 76
|
|
// old 76 double (*sync2d)[76+20]=new double[1920+50][76+20];
|
|
// old 76 int offset_sync2d = JZ+10;
|
|
//static double sync2d[1920+50][124+20]; //real sync2d(NH1,-JZ:JZ) -JZ=-62 JZ=+62 = 124
|
|
//double (*sync2d)[124+20]=new double[1920+50][124+20]; // largest 2d array need create hv
|
|
double (*sync2d)[144] = new double[1970][144];
|
|
int offset_sync2d = JZ+10;
|
|
//double sync2d_[1920+50][124+20];
|
|
|
|
double red[NH1+10];
|
|
int jpeak[NH1+10];
|
|
int indx[NH1+10];
|
|
double candidate0[3][max_c0+10];//2.00 HV no inaf ->200+5 need 300
|
|
//double savg[NH1+10];
|
|
//pomAll.zero_double_beg_end(savg,0,NH1+2);
|
|
|
|
int ia =0;
|
|
for (int j = 0; j < NHSYM; ++j)
|
|
{//do j=1,NHSYM
|
|
ia=(j)*NSTEP; //ia=(j-1)*NSTEP + 1
|
|
//ib=ia+NSPS; //ib=ia+NSPS-1
|
|
for (int z = 0; z < NSPS; ++z)
|
|
x[z]=fac*dd[ia+z]*0.01;//hv double coeficient //x(1:NSPS)=fac*dd(ia:ib)
|
|
//if (((NHSYM-1)*NSTEP+NSPS-1)>180000) qDebug()<<(NHSYM-1)*NSTEP+NSPS-1;
|
|
for (int z = NSPS; z < NFFT1+1; ++z)
|
|
x[z]=0.0; //x(NSPS+1:)=0.
|
|
f2a.four2a_d2c(cx,x,NFFT1,-1,0,decid); //call four2a(x,NFFT1,1,-1,0) //!r2c FFT
|
|
for (int i = 0; i < NH1; ++i)
|
|
{//do i=1,NH1
|
|
s_[j][i]=pomAll.ps_hv(cx[i]); //s(i,j)=real(cx(i))**2 + aimag(cx(i))**2
|
|
}
|
|
//qDebug()<<"sync_abc<<sync_bc"<<s_[j][100];
|
|
}
|
|
|
|
int nfa1 = (int)nfa;
|
|
int nfb1 = (int)nfb;
|
|
if ((nfb-nfa)<2000.0) //2000 HV correction
|
|
{
|
|
double ftmp = nfa + ((nfb-nfa)/2.0);
|
|
nfa1 = (int)(ftmp - 1000.0);
|
|
nfb1 = (int)(ftmp + 1000.0);
|
|
if (nfa1<100)
|
|
{
|
|
nfa1 = 100;
|
|
nfb1 = 100 + 2000;
|
|
}
|
|
if (nfb1>5000)
|
|
{
|
|
nfb1 = 5000;
|
|
nfa1 = 5000 - 2000;
|
|
}
|
|
}
|
|
//qDebug()<<"1="<<nfa<<nfb<<nfb-nfa<<nfa1<<nfb1<<nfb1-nfa1;
|
|
get_spectrum_baseline(dd,nfa1,nfb1,sbase);
|
|
|
|
ia=fmax(0,int(nfa/df));
|
|
int ib=int(nfb/df);
|
|
int nssy=NSPS/NSTEP; //! # steps per symbol =4
|
|
int nfos=NFFT1/NSPS; //! # frequency bin oversampling factor =2
|
|
int jstrt=0.5/tstep;
|
|
//qDebug()<<"00000sync8 nfos=ggggggggggggggggggggg"<<ia<<ib;
|
|
|
|
int k = 0;
|
|
for (int i = 0; i < 3; ++i)
|
|
{
|
|
for (int j = 0; j < max_c0; ++j)
|
|
candidate0[i][j]=0.0;
|
|
}
|
|
|
|
for (int i = ia; i < ib; ++i)
|
|
{//do i=ia,ib
|
|
for (int j = -JZ; j < JZ+1; ++j)
|
|
{//do j=-JZ,+JZ
|
|
double ta=0.0;
|
|
double tb=0.0;
|
|
double tc=0.0;
|
|
double t0a=0.0;
|
|
double t0b=0.0;
|
|
double t0c=0.0;
|
|
for (int n = 0; n < 7; ++n)
|
|
{//do n=0,6
|
|
int m=j+jstrt+nssy*n; //k=j+jstrt+nssy*n //c++ ==.EQ. !=.NE. >.GT. <.LT. >=.GE. <=.LE.
|
|
if (m>=0 && m<NHSYM) //if(k.ge.1.and.k.le.NHSYM) then
|
|
{
|
|
ta+=s_[m][i+nfos*icos7_2[n]]; //ta=ta + s(i+nfos*icos7(n),k)
|
|
for (int z = i; z < i+nfos*6+1; z+=nfos)
|
|
t0a+=s_[m][z]; //???? t0a=t0a + sum(s(i:i+nfos*6:nfos,k))
|
|
}
|
|
tb+=s_[m+nssy*36][i+nfos*icos7_2[n]]; // tb=tb + s(i+nfos*icos7(n),k+nssy*36)
|
|
for (int z = i; z < i+nfos*6+1; z+=nfos)
|
|
t0b+=s_[m+nssy*36][z]; //??? t0b=t0b + sum(s(i:i+nfos*6:nfos,k+nssy*36))
|
|
|
|
if (m+nssy*72<NHSYM) //if(k+nssy*72.le.NHSYM) then
|
|
{
|
|
tc+=s_[m+nssy*72][i+nfos*icos7_2[n]]; //tc=tc + s(i+nfos*icos7(n),k+nssy*72)
|
|
for (int z = i; z < i+nfos*6+1; z+=nfos)
|
|
t0c+=s_[m+nssy*72][z];//??? t0c=t0c + sum(s(i:i+nfos*6:nfos,k+nssy*72))
|
|
}
|
|
}
|
|
double t=ta+tb+tc;
|
|
double t0=t0a+t0b+t0c;
|
|
t0=(t0-t)/6.0;
|
|
double sync_abc; //stop devide by 0 HV double sync_abc=t/t0;
|
|
if (t0==0.0)
|
|
sync_abc=0.0;
|
|
else
|
|
sync_abc=t/t0;
|
|
|
|
t=tb+tc;
|
|
t0=t0b+t0c;
|
|
t0=(t0-t)/6.0;
|
|
double sync_bc; //stop devide by 0 HV double sync_bc=t/t0;
|
|
if (t0==0.0)
|
|
sync_bc=0.0;
|
|
else
|
|
sync_bc=t/t0;
|
|
|
|
sync2d[i][j+offset_sync2d]=fmax(sync_abc,sync_bc); //sync2d(i,j)=fmax(sync_abc,sync_bc);
|
|
//qDebug()<<sync_abc<<sync_bc<<fmax(sync_abc,sync_bc);
|
|
}
|
|
}
|
|
|
|
for (int z = 0; z < NH1; ++z)
|
|
red[z]=0.0;
|
|
for (int i = ia; i < ib; ++i)
|
|
{//do i=ia,ib int maxloc_da_beg_to_end(double*a,int a_beg,int a_end);
|
|
// old 76 int j0=(maxloc_da_beg_to_end(sync2d[i],10,76+10)-offset_sync2d);// - 1 - JZ;//ii=maxloc(sync2d(i,-JZ:JZ)) - 1 - JZ
|
|
int j0=(pomAll.maxloc_da_beg_to_end(sync2d[i],10,124+10)-offset_sync2d);
|
|
jpeak[i]=j0;
|
|
red[i]=sync2d[i][j0+offset_sync2d]; // red[i]=sync2d(i,j0)
|
|
}
|
|
|
|
//qDebug()<<"sync8- 22222"<<ib-ia;
|
|
int iz=ib-ia; //iz=ib-ia+1
|
|
if (iz>1920) iz=1920; //NH1=1920
|
|
double t_red[2048];//2.12 (10Hz to 6000Hz = 1917)
|
|
//qDebug()<<"FULL==="<<iz<<ia<<ia+(iz-1);
|
|
for (int i = 0; i < iz; ++i)
|
|
{
|
|
t_red[i] = red[i+ia];
|
|
indx[i]=0;
|
|
}
|
|
indx[iz] =0;
|
|
indx[iz+1]=0;
|
|
|
|
if (iz>0) pomAll.indexx_msk(t_red,iz-1,indx); //call indexx(red(ia:ib),iz,indx)
|
|
|
|
int npctile=(int)(0.40*(double)(iz));
|
|
if (npctile<0) // something is wrong; bail out
|
|
{
|
|
ncand=0;
|
|
return;
|
|
}
|
|
|
|
int ibase=indx[npctile] + ia; //hv 1.48 0 mybe -1 tested ibase=indx(nint(0.40*iz)) - 1 + ia
|
|
|
|
if (ibase<0) ibase=0;//2.12
|
|
if (ibase>NH1-1) ibase=NH1-1;//2.12
|
|
double base=red[ibase];
|
|
if (base<=0.001) base=0.001;//no devide by 0
|
|
|
|
for (int i = 0; i < NH1; ++i)
|
|
{
|
|
red[i]=red[i]/base; //no devide by 0
|
|
}
|
|
|
|
int to_iz = iz;
|
|
if (to_iz > max_c0) to_iz = max_c0;
|
|
//qDebug()<<"FULL==="<<max_c0<<"iz="<<iz<<indx[(iz-1)];
|
|
for (int i = 0; i < to_iz; ++i)//2.00
|
|
{
|
|
int n=ia + indx[(iz-1)-i]; //tested -1 ->1.69 n=ia + indx(iz+1-i) - 1
|
|
if (red[n]<syncmin) break; //exit if(red(n).lt.syncmin.or.isnan(red(n)).or.k.eq.MAXPRECAND) exit
|
|
candidate0[0][k]=(double)n*df;
|
|
candidate0[1][k]=(double)jpeak[n]*tstep;//(jpeak(n)-0.5) 2.34 tested jpeak[n]-1 to jpeak[n] ///candidate0(2,k)=(jpeak(n)-1)*tstep
|
|
candidate0[2][k]=red[n]; //if (n>1500) qDebug()<<"n="<<n;
|
|
k++;
|
|
}
|
|
ncand=k;
|
|
//qDebug()<<"1 CANDDD="<<k;
|
|
|
|
//! Save only the best of near-dupe freqs.
|
|
for (int i = 0; i < ncand; ++i)//c++ ==.EQ. !=.NE. >.GT. <.LT. >=.GE. <=.LE.
|
|
{//do i=1,ncand
|
|
if (i>=1) //if(i.ge.2) then
|
|
{
|
|
for (int j = 0; j < i; ++j)
|
|
{//do j=1,i-1
|
|
double fdiff=fabs(candidate0[0][i])-fabs(candidate0[0][j]);//fdiff=abs(candidate0(1,i))-abs(candidate0(1,j))
|
|
if (fabs(fdiff)<4.0)//if(abs(fdiff).lt.4.0) then
|
|
{
|
|
if (candidate0[2][i]>=candidate0[2][j]) candidate0[2][j]=0.0; //if(candidate0(3,i).ge.candidate0(3,j)) candidate0(3,j)=0.
|
|
if (candidate0[2][i]<candidate0[2][j]) candidate0[2][i]=0.0; //if(candidate0(3,i).lt.candidate0(3,j)) candidate0(3,i)=0.
|
|
}
|
|
}
|
|
}
|
|
}
|
|
double maxval_s = s_[0][0];
|
|
for (int i = 0; i < 372; ++i)//maxval -> s_[372+20][1920+20]
|
|
{
|
|
for (int j = 0; j < 1920; ++j)//maxval(s)
|
|
{
|
|
if (s_[i][j]>maxval_s)
|
|
maxval_s = s_[i][j];
|
|
}
|
|
}
|
|
if (maxval_s<=0.001)//2.68 0.001, 2.66 0.01 no devide by zero
|
|
maxval_s = 0.001;//2.68 0.001, 2.66 0.01 max 2000.0 factor
|
|
|
|
fac=20.0/maxval_s;
|
|
for (int i = 0; i < 372; ++i)//maxval -> s_[372+20][1920+20]
|
|
{
|
|
for (int j = 0; j < 1920; ++j)
|
|
s_[i][j]=fac*s_[i][j];
|
|
}
|
|
|
|
//! Sort by sync
|
|
//! call indexx(candidate0(3,1:ncand),ncand,indx)
|
|
//! Sort by frequency
|
|
for (int i = 0; i < ncand+2; ++i) //2.37 NH1=1920
|
|
indx[i] = 0;
|
|
if (ncand>0)// Sort by sync
|
|
pomAll.indexx_msk(candidate0[2],ncand-1,indx);//call indexx(candidate0(3,1:ncand),ncand,indx)
|
|
|
|
k=0;
|
|
//! Place candidates within 10 Hz of nfqso at the top of the list
|
|
int end_limit = 249;//2.56 max 254
|
|
for (int i = 0; i < ncand; ++i)
|
|
{//do i=1,ncand
|
|
if (fabs(candidate0[0][i]-nfqso)<=10.0 && candidate0[2][i]>=syncmin && candidate0[1][i]>=-2.5) //if( fabs( candidate0(1,i)-nfqso ).le.10.0 .and. candidate0(3,i).ge.syncmin ) then
|
|
{
|
|
candidate[0][k]=candidate0[0][i];//candidate(1:3,k)=candidate0(1:3,i) && candidate0[1][i]>=-2.5
|
|
candidate[1][k]=candidate0[1][i];
|
|
//candidate[2][k]=candidate0[2][i];
|
|
candidate0[2][i]=0.0; //hv null for next loop candidate0(3,i)=0.0
|
|
if (k<end_limit)
|
|
k++;
|
|
else
|
|
break;
|
|
}
|
|
}
|
|
for (int i = ncand-1; i>= 0; --i)
|
|
{//do i=ncand,1,-1
|
|
int j=indx[i]; //if (j>max_c0/2-2) qDebug()<<j;
|
|
if (candidate0[2][j] >= syncmin && candidate0[1][i]>=-2.5) //if( candidate0(3,j) .ge. syncmin ) then
|
|
{
|
|
candidate[1][k]=candidate0[1][j];//candidate(2:3,k)=candidate0(2:3,j) && candidate0[1][j]>=-2.5
|
|
//candidate[2][k]=candidate0[2][j];
|
|
candidate[0][k]=fabs(candidate0[0][j]);//candidate(1,k)=abs(candidate0(1,j))
|
|
if (k<end_limit)
|
|
k++;
|
|
else
|
|
break;
|
|
}
|
|
}
|
|
ncand=k;
|
|
//qDebug()<<"Out sync8 ncand=="<<ncand;
|
|
delete [] sync2d;
|
|
}*/
|
|
void DecoderFt8::sync8(double *dd,double nfa,double nfb,double syncmin,double nfqso,
|
|
double s_[402][1970],double candidate[2][620],int &ncand,double *sbase)
|
|
{
|
|
const int NSPS=1920;
|
|
int NSTEP=NSPS/4;//=480
|
|
const int NFFT1=2*NSPS;
|
|
int NMAX=15*DEC_SAMPLE_RATE;
|
|
int NHSYM=NMAX/NSTEP-3;//372
|
|
const int NH1=NFFT1/2; //NH1=1920
|
|
const int max_c0 = 800;//2.69 old=400;//2.2.0=500 260r5=1000
|
|
const int max_c_ = 600;//2.69 old=249 max 254 260r5=600
|
|
//! Search over +/- 1.5s relative to 0.5s TX start time.
|
|
//parameter (JZ=38)
|
|
//old 72/2 int JZ=38;
|
|
//! Search over +/- 2.5s relative to 0.5s TX start time.
|
|
//parameter (JZ=62) new
|
|
int JZ=62;//62;
|
|
|
|
//! Compute symbol spectra, stepping by NSTEP steps.
|
|
//double savg=0.0;
|
|
double tstep=(double)NSTEP/DEC_SAMPLE_RATE;
|
|
double df=DEC_SAMPLE_RATE/(double)NFFT1; //!3.125 Hz
|
|
double fac=1.0/300.0;
|
|
|
|
double x[NFFT1+20];//=3840 //real x(NFFT1)
|
|
//double *x = new double[NFFT1+20];
|
|
double complex cx[NFFT1+20]; //2.09 error-> cx[NH1+20]; //complex cx(0:NH1)
|
|
|
|
// old 76 double sync2d[1920+50][76+20]; //real sync2d(NH1,-JZ:JZ) -JZ=-38 JZ=+38 = 76
|
|
// old 76 double (*sync2d)[76+20]=new double[1920+50][76+20];
|
|
// old 76 int offset_sync2d = JZ+10;
|
|
//static double sync2d[1920+50][124+20]; //real sync2d(NH1,-JZ:JZ) -JZ=-62 JZ=+62 = 124
|
|
//double (*sync2d)[124+20]=new double[1920+50][124+20]; // largest 2d array need create hv
|
|
double (*sync2d)[144] = new double[1970][144];
|
|
int offset_sync2d = JZ+10;
|
|
//double sync2d_[1920+50][124+20];
|
|
|
|
double red[NH1+10];
|
|
double red2[NH1+10];//2.69
|
|
int jpeak[NH1+10];
|
|
int jpeak2[NH1+10];//2.69
|
|
int indx[NH1+10];
|
|
int indx2[NH1+10];//2.69
|
|
double candidate0[3][max_c0+10];//2.00 HV no inaf ->200+5 need 300
|
|
//double savg[NH1+10];
|
|
//pomAll.zero_double_beg_end(savg,0,NH1+2);
|
|
|
|
int ia =0;
|
|
//int ib =0;
|
|
//qDebug()<<"sync8- 0"<<dd[5000]<<dd[6000]<<dd[8000]<<dd[9000]<<dd[10000]<<dd[20000]<<dd[30000];
|
|
for (int j = 0; j < NHSYM; ++j)
|
|
{//do j=1,NHSYM
|
|
ia=(j)*NSTEP; //ia=(j-1)*NSTEP + 1
|
|
//ib=ia+NSPS; //ib=ia+NSPS-1
|
|
for (int z = 0; z < NSPS; ++z)
|
|
x[z]=fac*dd[ia+z]*0.01;//hv double coeficient //x(1:NSPS)=fac*dd(ia:ib)
|
|
//if (((NHSYM-1)*NSTEP+NSPS-1)>180000) qDebug()<<(NHSYM-1)*NSTEP+NSPS-1;
|
|
for (int z = NSPS; z < NFFT1+1; ++z)
|
|
x[z]=0.0; //x(NSPS+1:)=0.
|
|
f2a.four2a_d2c(cx,x,NFFT1,-1,0,decid); //call four2a(x,NFFT1,1,-1,0) //!r2c FFT
|
|
for (int i = 0; i < NH1; ++i)
|
|
{//do i=1,NH1
|
|
s_[j][i]=pomAll.ps_hv(cx[i]); //s(i,j)=real(cx(i))**2 + aimag(cx(i))**2
|
|
//if(j==150)
|
|
//qDebug()<<"sync8 t="<<s_[j][i];
|
|
//if(j==0)//1.76 here zero_double
|
|
//savg[i]=0.0;
|
|
//savg[i]+=s_[j][i];//!Average spectrum
|
|
}
|
|
//qDebug()<<"sync_abc<<sync_bc"<<s_[j][100];
|
|
}
|
|
|
|
int nfa1 = (int)nfa;
|
|
int nfb1 = (int)nfb;
|
|
if ((nfb-nfa)<2000.0) //2000 HV correction
|
|
{
|
|
double ftmp = nfa + ((nfb-nfa)/2.0);
|
|
nfa1 = (int)(ftmp - 1000.0);
|
|
nfb1 = (int)(ftmp + 1000.0);
|
|
if (nfa1<100)
|
|
{
|
|
nfa1 = 100;
|
|
nfb1 = 100 + 2000;
|
|
}
|
|
if (nfb1>5000)
|
|
{
|
|
nfb1 = 5000;
|
|
nfa1 = 5000 - 2000;
|
|
}
|
|
}
|
|
//qDebug()<<"1="<<nfa<<nfb<<nfb-nfa<<nfa1<<nfb1<<nfb1-nfa1;
|
|
//qDebug()<<"1="<<nfa<<nfb<<nfa1<<nfb1;
|
|
//baseline(savg,nfa,nfb,sbase);
|
|
// lasttt -> baseline(savg,nfa1,nfb1,sbase);//hv 1.45 all base line off standart trancivers
|
|
//baseline(savg,100.0,3000.0,sbase);
|
|
get_spectrum_baseline(dd,nfa1,nfb1,sbase);
|
|
|
|
//qDebug()<<"sync8="<<50.0/df;//50hz=16;
|
|
//double corrt=0.0; //corr for threads
|
|
//if (decid>0) corrt=50.0;
|
|
//ia=fmax(0,int((nfa-corrt)/df)); //max(1,nint(nfa/df))
|
|
ia=fmax(0,int(nfa/df));
|
|
int ib=int(nfb/df);
|
|
int nssy=NSPS/NSTEP; //! # steps per symbol =4
|
|
int nfos=NFFT1/NSPS; //! # frequency bin oversampling factor =2
|
|
int jstrt=0.5/tstep;
|
|
|
|
int k = 0;
|
|
for (int i = 0; i < 3; ++i)
|
|
{
|
|
for (int j = 0; j < max_c0; ++j) candidate0[i][j]=0.0;
|
|
}
|
|
|
|
for (int i = ia; i < ib; ++i)
|
|
{//do i=ia,ib
|
|
for (int j = -JZ; j < JZ+1; ++j)
|
|
{//do j=-JZ,+JZ
|
|
double ta=0.0;
|
|
double tb=0.0;
|
|
double tc=0.0;
|
|
double t0a=0.0;
|
|
double t0b=0.0;
|
|
double t0c=0.0;
|
|
for (int n = 0; n < 7; ++n)
|
|
{//do n=0,6
|
|
int m=j+jstrt+nssy*n; //k=j+jstrt+nssy*n //c++ ==.EQ. !=.NE. >.GT. <.LT. >=.GE. <=.LE.
|
|
if (m>=0 && m<NHSYM) //if(k.ge.1.and.k.le.NHSYM) then
|
|
{
|
|
ta+=s_[m][i+nfos*icos7_2[n]]; //ta=ta + s(i+nfos*icos7(n),k)
|
|
for (int z = i; z < i+nfos*6+1; z+=nfos)
|
|
t0a+=s_[m][z]; //???? t0a=t0a + sum(s(i:i+nfos*6:nfos,k))
|
|
}
|
|
tb+=s_[m+nssy*36][i+nfos*icos7_2[n]]; // tb=tb + s(i+nfos*icos7(n),k+nssy*36)
|
|
for (int z = i; z < i+nfos*6+1; z+=nfos)
|
|
t0b+=s_[m+nssy*36][z]; //??? t0b=t0b + sum(s(i:i+nfos*6:nfos,k+nssy*36))
|
|
|
|
if (m+nssy*72<NHSYM) //if(k+nssy*72.le.NHSYM) then
|
|
{
|
|
tc+=s_[m+nssy*72][i+nfos*icos7_2[n]]; //tc=tc + s(i+nfos*icos7(n),k+nssy*72)
|
|
for (int z = i; z < i+nfos*6+1; z+=nfos)
|
|
t0c+=s_[m+nssy*72][z];//??? t0c=t0c + sum(s(i:i+nfos*6:nfos,k+nssy*72))
|
|
}
|
|
}
|
|
double t=ta+tb+tc;
|
|
double t0=t0a+t0b+t0c;
|
|
t0=(t0-t)/6.0;
|
|
double sync_abc; //stop devide by 0 HV double sync_abc=t/t0;
|
|
if (t0==0.0) sync_abc=0.0;
|
|
else sync_abc=t/t0;
|
|
|
|
t=tb+tc;
|
|
t0=t0b+t0c;
|
|
t0=(t0-t)/6.0;
|
|
double sync_bc; //stop devide by 0 HV double sync_bc=t/t0;
|
|
if (t0==0.0) sync_bc=0.0;
|
|
else sync_bc=t/t0;
|
|
|
|
sync2d[i][j+offset_sync2d]=fmax(sync_abc,sync_bc); //sync2d(i,j)=fmax(sync_abc,sync_bc);
|
|
//qDebug()<<sync_abc<<sync_bc<<fmax(sync_abc,sync_bc);
|
|
}
|
|
}
|
|
|
|
for (int z = 0; z < NH1; ++z)
|
|
{
|
|
red[z] =0.0;
|
|
red2[z]=0.0; //2.69
|
|
} //qDebug()<<"symbol="<<((2.5/0.16)*4)<<((0.65/0.16)*4);
|
|
for (int i = ia; i < ib; ++i)//2.69
|
|
{
|
|
int j0=(pomAll.maxloc_da_beg_to_end(sync2d[i],10,32+10)-offset_sync2d);//hv=Search over +/-0.6s = +-16 //260r5= +-10
|
|
jpeak[i]=j0;
|
|
red[i]=sync2d[i][j0+offset_sync2d];
|
|
j0=(pomAll.maxloc_da_beg_to_end(sync2d[i],10,124+10)-offset_sync2d);//Search over +/-2.5s = +-62
|
|
jpeak2[i]=j0;
|
|
red2[i]=sync2d[i][j0+offset_sync2d];
|
|
}
|
|
|
|
int iz=ib-ia; //iz=ib-ia+1
|
|
if (iz>1920) iz=1920; //NH1=1920
|
|
|
|
double t_red[2048];//2.12 (10Hz to 6000Hz = 1917)
|
|
double t_red2[2048];
|
|
for (int i = 0; i < iz; ++i)
|
|
{
|
|
t_red[i] = red[i+ia];
|
|
t_red2[i] = red2[i+ia];
|
|
indx[i] =0;
|
|
indx2[i]=0;
|
|
}
|
|
indx[iz] =0;
|
|
indx[iz+1] =0;
|
|
indx2[iz] =0;
|
|
indx2[iz+1]=0;
|
|
if (iz>0)
|
|
{
|
|
pomAll.indexx_msk(t_red, iz-1,indx);
|
|
pomAll.indexx_msk(t_red2,iz-1,indx2);
|
|
}
|
|
int npctile=(int)(0.40*(double)(iz));
|
|
if (npctile<0) // something is wrong; bail out
|
|
{
|
|
ncand=0;
|
|
return;
|
|
}
|
|
int ibase =indx[npctile] + ia; //hv 1.48 0 mybe -1 tested ibase=indx(nint(0.40*iz)) - 1 + ia
|
|
int ibase2=indx2[npctile] + ia;
|
|
if (ibase<0) ibase=0;//2.12
|
|
if (ibase>NH1-1) ibase=NH1-1;//2.12
|
|
if (ibase2<0) ibase2=0;//2.69
|
|
if (ibase2>NH1-1) ibase2=NH1-1;//2.69
|
|
|
|
double base=red[ibase];
|
|
double base2=red2[ibase2];
|
|
if (base <=0.001) base=0.001;//no devide by 0
|
|
if (base2<=0.001) base2=0.001;
|
|
|
|
for (int i = 0; i < NH1; ++i)
|
|
{
|
|
red[i] =red[i] /base; //no devide by 0
|
|
red2[i]=red2[i]/base2;
|
|
}
|
|
|
|
//int to_iz = iz;
|
|
//if (to_iz > max_c0) to_iz = max_c0;//max_c0;
|
|
//qDebug()<<"FULL==="<<max_c0<<"iz="<<iz<<indx[(iz-1)];
|
|
//for (int i = 0; i < to_iz; ++i)//2.00
|
|
for (int i = 0; i < iz; ++i)//2.69
|
|
{
|
|
int n=ia + indx[(iz-1)-i]; //indx[1920] tested -1 ->1.69 n=ia + indx(iz+1-i) - 1
|
|
if (red[n]>=syncmin)
|
|
{
|
|
candidate0[0][k]=(double)n*df;
|
|
candidate0[1][k]=(double)jpeak[n]*tstep;//(jpeak(n)-0.5) 2.34 tested jpeak[n]-1 to jpeak[n] ///candidate0(2,k)=(jpeak(n)-1)*tstep
|
|
candidate0[2][k]=red[n]; //if (n>1500) qDebug()<<"n="<<n;
|
|
k++;
|
|
}
|
|
if (k>=max_c0) break;
|
|
if(abs(jpeak2[n]-jpeak[n])==0) continue;//if(abs(jpeak2(n)-jpeak(n)).eq.0) cycle
|
|
//n=ia + indx2[(iz-1)-i];
|
|
if (red2[n]>=syncmin) //exit if(red(n).lt.syncmin.or.isnan(red(n)).or.k.eq.MAXPRECAND) exit
|
|
{
|
|
candidate0[0][k]=(double)n*df;
|
|
candidate0[1][k]=(double)jpeak2[n]*tstep;//(jpeak(n)-0.5) 2.34 tested jpeak[n]-1 to jpeak[n] ///candidate0(2,k)=(jpeak(n)-1)*tstep
|
|
candidate0[2][k]=red2[n]; //if (n>1500) qDebug()<<"n="<<n;
|
|
k++;
|
|
}
|
|
if (k>=max_c0) break;
|
|
}
|
|
ncand=k;
|
|
//if (k>400) qDebug()<<"1FULL="<<max_c0<<">"<<k;
|
|
|
|
//! Save only the best of near-dupe freqs.
|
|
for (int i = 0; i < ncand; ++i)//c++ ==.EQ. !=.NE. >.GT. <.LT. >=.GE. <=.LE.
|
|
{//do i=1,ncand
|
|
if (i>=1) //if(i.ge.2) then
|
|
{
|
|
for (int j = 0; j < i; ++j)
|
|
{//do j=1,i-1
|
|
double fdiff=fabs(candidate0[0][i])-fabs(candidate0[0][j]);//fdiff=abs(candidate0(1,i))-abs(candidate0(1,j))
|
|
double tdiff=fabs(candidate0[1][i]-candidate0[1][j]);
|
|
if (fabs(fdiff)<4.0 && tdiff<0.08)//one step=0.04 if(abs(fdiff).lt.4.0.and.tdiff.lt.0.04) then
|
|
{
|
|
if (candidate0[2][i]>=candidate0[2][j]) candidate0[2][j]=0.0; //if(candidate0(3,i).ge.candidate0(3,j)) candidate0(3,j)=0.
|
|
if (candidate0[2][i]<candidate0[2][j]) candidate0[2][i]=0.0; //if(candidate0(3,i).lt.candidate0(3,j)) candidate0(3,i)=0.
|
|
} //if (tdiff>0.04) qDebug()<<tdiff;
|
|
}
|
|
}
|
|
}
|
|
double maxval_s = s_[0][0];
|
|
for (int i = 0; i < 372; ++i)//maxval -> s_[372+20][1920+20]
|
|
{
|
|
for (int j = 0; j < 1920; ++j)//maxval(s)
|
|
{
|
|
if (s_[i][j]>maxval_s)
|
|
maxval_s = s_[i][j];
|
|
}
|
|
}
|
|
if (maxval_s<=0.001)//2.68 0.001, 2.66 0.01 no devide by zero
|
|
maxval_s = 0.001;//2.68 0.001, 2.66 0.01 max 2000.0 factor
|
|
|
|
fac=20.0/maxval_s;
|
|
for (int i = 0; i < 372; ++i)//maxval -> s_[372+20][1920+20]
|
|
{
|
|
for (int j = 0; j < 1920; ++j)
|
|
s_[i][j]=fac*s_[i][j];
|
|
}
|
|
|
|
//! Sort by sync
|
|
//! call indexx(candidate0(3,1:ncand),ncand,indx)
|
|
//! Sort by frequency
|
|
for (int i = 0; i < ncand+2; ++i) indx[i] = 0;//2.37 NH1=1920
|
|
if (ncand>0) pomAll.indexx_msk(candidate0[2],ncand-1,indx); // Sort by sync //call indexx(candidate0(3,1:ncand),ncand,indx)
|
|
//freq pomAll.indexx_msk(candidate0[0],ncand-1,indx);//call indexx(candidate0(1,1:ncand),ncand,indx)
|
|
|
|
k=0;
|
|
//! Place candidates within 10 Hz of nfqso at the top of the list
|
|
for (int i = 0; i < ncand; ++i)
|
|
{//do i=1,ncand
|
|
if (fabs(candidate0[0][i]-nfqso)<=10.0 && candidate0[2][i]>=syncmin && candidate0[1][i]>=-2.8) //if( fabs( candidate0(1,i)-nfqso ).le.10.0 .and. candidate0(3,i).ge.syncmin ) then
|
|
{
|
|
candidate[0][k]=candidate0[0][i];//candidate(1:3,k)=candidate0(1:3,i) && candidate0[1][i]>=-2.5
|
|
candidate[1][k]=candidate0[1][i];
|
|
//candidate[2][k]=candidate0[2][i];
|
|
candidate0[2][i]=0.0; //hv null for next loop candidate0(3,i)=0.0
|
|
//k=k+1
|
|
if (k<max_c_) k++;
|
|
else break;
|
|
}
|
|
}
|
|
for (int i = ncand-1; i>= 0; --i)
|
|
{//do i=ncand,1,-1
|
|
int j=indx[i]; //if (j>max_c0/2-2) qDebug()<<j;
|
|
if (candidate0[2][j] >= syncmin && candidate0[1][i]>=-2.8) //if( candidate0(3,j) .ge. syncmin ) then
|
|
{
|
|
candidate[1][k]=candidate0[1][j];//candidate(2:3,k)=candidate0(2:3,j) && candidate0[1][j]>=-2.5
|
|
//candidate[2][k]=candidate0[2][j];
|
|
candidate[0][k]=fabs(candidate0[0][j]);//candidate(1,k)=abs(candidate0(1,j))
|
|
//k=k+1
|
|
//if(k.gt.maxcand) exit
|
|
if (k<max_c_) k++;
|
|
else break;
|
|
}
|
|
}
|
|
ncand=k;
|
|
//if (k>300) qDebug()<<"2FULL==="<<max_c_<<">"<<ncand;
|
|
delete [] sync2d;
|
|
}
|
|
void DecoderFt8::ft8apset(QString mycall12,QString theircall12,int *apsym2)
|
|
{
|
|
int i3=0;
|
|
int n3=0;
|
|
bool c77[100];
|
|
for (int i = 0; i < 78; ++i) c77[i]=0;
|
|
|
|
if (mycall12.isEmpty())
|
|
{
|
|
for (int i = 0; i < 58; ++i) // apsym2[58+5]
|
|
apsym2[i]=0;
|
|
apsym2[0]=99;
|
|
apsym2[29]=99;
|
|
return;
|
|
}
|
|
bool notheircall=false;
|
|
//theircall=theircall12;
|
|
if (theircall12.isEmpty())//if(len(trim(theircall)).eq.0) then
|
|
{
|
|
theircall12="LZ2ABC";//"K9ABC";
|
|
notheircall=true;
|
|
}
|
|
/*if needed for HOUND MSHV no HOUND Activity
|
|
call save_hash_call(hc13,n10,n12,n22)
|
|
write(c10,'(b10.10)') iand(n10,Z'3FF')
|
|
read(c10,'(10i1.1)',err=1) aph10 <-- int n10 = BinToInt32(aph10,0,10);
|
|
aph10=2*aph10-1*/
|
|
|
|
//! Encode a dummy standard message: i3=1, 28 1 28 1 1 15
|
|
//!
|
|
QString msgs2;
|
|
if (pomAll.isStandardCall(mycall12.trimmed())) msgs2.append(mycall12.trimmed()); //2.61
|
|
else msgs2.append("<"+mycall12.trimmed()+">"); //2.61
|
|
|
|
msgs2.append(" ");
|
|
msgs2.append(theircall12.trimmed());
|
|
msgs2.append(" ");
|
|
msgs2.append("RRR"); //qDebug()<<"msg"<<msgs2;
|
|
|
|
TGenFt8->pack77(msgs2,i3,n3,c77); //call pack77(msg,i3,n3,c77)
|
|
|
|
// ??? no need this
|
|
/*bool unpk77_success;
|
|
QString msgchk = TGenFt8->unpack77(c77,unpk77_success); //call unpack77(c77,1,msgchk,unpk77_success)
|
|
if(i3!=1 || (msgs2!=msgchk) || !unpk77_success) return;*/
|
|
|
|
if (i3!=1)
|
|
{
|
|
for (int i = 0; i < 58; ++i) // apsym2[58+5]
|
|
apsym2[i]=0;
|
|
apsym2[0]=99;
|
|
apsym2[29]=99;
|
|
return;
|
|
}
|
|
|
|
//read(c77,'(58i1)',err=1) apsym(1:58)
|
|
for (int i = 0; i < 58; ++i)
|
|
apsym2[i] = c77[i];
|
|
if (notheircall) apsym2[29]=99;
|
|
return;
|
|
//c1:
|
|
//??????????????????????
|
|
for (int i = 0; i < 58; ++i) // apsym2[58+5]
|
|
apsym2[i]=0;
|
|
apsym2[0]=99;
|
|
apsym2[29]=99;
|
|
return;
|
|
}
|
|
/*void DecoderFt8::SetResetPrevT(QString ptime)
|
|
{
|
|
s_time8_prev = ptime;
|
|
}*/
|
|
void DecoderFt8::SetNewP(bool f)
|
|
{
|
|
f_new_p = f;
|
|
}
|
|
static bool s_3intFt8_d_ = true;//2.51 default
|
|
void DecoderFt8::Decode3intFt(bool f)//2.39 remm
|
|
{
|
|
s_3intFt8_d_ = f;
|
|
//qDebug()<<"DecoderFt8 s_3intFt_d_="<<s_3intFt_d_;
|
|
}
|
|
bool DecoderFt8::isgrid4(QString s)
|
|
{
|
|
bool res = false;
|
|
if (s.count()>3)
|
|
{
|
|
int c1 = (int)s.at(0).toLatin1();
|
|
int c2 = (int)s.at(1).toLatin1();
|
|
int c3 = (int)s.at(2).toLatin1();
|
|
int c4 = (int)s.at(3).toLatin1();
|
|
if (c1>=(int)'A' && c1<=(int)'R' && c2>=(int)'A' && c2<=(int)'R' &&
|
|
c3>=(int)'0' && c3<=(int)'9' && c4>=(int)'0' && c4<=(int)'9')// && s.mid(0,4)!="RR73"
|
|
res = true;
|
|
}
|
|
return res;
|
|
}
|
|
int DecoderFt8::ft8_even_odd(QString s)//res=0 (even first), or res=1 (odd second)
|
|
{
|
|
bool res = 0;
|
|
int time_ss = s.midRef(4,2).toInt();//get seconds 120023
|
|
int time_mm = s.midRef(2,2).toInt();//get min 120023
|
|
int time_p = (time_mm*60)+time_ss;
|
|
//int ntrperiod = 15;
|
|
time_p = time_p % (15*2); //j=mod(nutc/5,2)
|
|
if (time_p<15) res = 0;
|
|
else res = 1;
|
|
return res;
|
|
}
|
|
void DecoderFt8::ft8_a7_save(QString nutc,double dt,double f,QString msg)
|
|
{
|
|
int nwords = 0;
|
|
QString w[19+5];
|
|
|
|
if (msg.indexOf("/")>-1 || msg.indexOf("<")>-1) return;
|
|
|
|
msg.append(" ");//for any case for label->c5
|
|
for (int z = 0; z<19; ++z) w[z]=" ";//13 blinks char
|
|
TGenFt8->split77(msg,nwords,w);
|
|
if (nwords<1) return;
|
|
if (w[0].mid(0,3)=="CQ_") return;//???
|
|
|
|
int j=ft8_even_odd(nutc);
|
|
jseq=j;
|
|
|
|
//Add this decode to current table for this sequence
|
|
//Number of decodes in this sequence
|
|
int i=ndec[1][j];
|
|
dt0[1][j][i]=dt;
|
|
f0[1][j][i]=f;
|
|
msg0[1][j][i]=w[0].trimmed()+" "+w[1].trimmed();
|
|
|
|
QString s = w[1].trimmed();
|
|
if (w[0].mid(0,3)=="CQ " && s.count()<=2)
|
|
{
|
|
msg0[1][j][i]="CQ "+w[1].trimmed()+" "+w[2].trimmed();//Save "CQ DX Call_2" ???
|
|
}
|
|
//QString msg1=msg0[1][j][i];//msg1=msg0(i,j,1)
|
|
//nn=len(trim(msg1))
|
|
//Include grid as part of message
|
|
if (isgrid4(w[nwords-1])) msg0[1][j][i]=msg0[1][j][i]+" "+w[nwords-1].trimmed();
|
|
|
|
//If a transmission at this frequency with message fragment "call_1 call_2"
|
|
//was decoded in the previous sequence, flag it as "DO NOT USE" because
|
|
//we have already decoded and subtracted that station's next transmission.
|
|
s = msg0[1][j][i]+" ";//for any case for label->c5
|
|
for (int z = 0; z<19; ++z) w[z]=" ";//13 blinks char
|
|
TGenFt8->split77(s,nwords,w);
|
|
for (int z = 0; z<ndec[0][j]; ++z)
|
|
{
|
|
//hv protect from dupe decode in same period
|
|
if (f0[0][j][z]<=-98.0) continue;
|
|
int i2=msg0[0][j][z].indexOf(" "+w[1].trimmed());
|
|
if (fabs(f-f0[0][j][z])<=3.0 && i2>=2) f0[0][j][z]=-98.0;//Flag as "do not use" for a potential a7 decode
|
|
}
|
|
if (i>MAXDEC-2) return;
|
|
ndec[1][j]++; //qDebug()<<"Save="<<j<<msg<<ndec[1][j];
|
|
}
|
|
void DecoderFt8::ft8_a7d(double *dd0,bool &newdat,QString call_1,QString call_2,QString grid4,double &xdt,
|
|
double &f1,double xbase,int &nharderrors,double &dmin,QString &message,double &xsnr)
|
|
{
|
|
//const int MAXMSG=206;//= -50 to +49
|
|
const int MAXMSG=158;//= -26 to +49
|
|
//const int MAXMSG=140;//= -26 to +40
|
|
//const int MAXMSG=120;//= -26 to +30
|
|
//const int MAXMSG=110;//= -26 to +25
|
|
//const int MAXMSG=100;//= -26 to +20
|
|
|
|
bool std_1,std_2;
|
|
//int NDOWN=60;
|
|
//double complex cd0[3350];//3200+100 __attribute__((aligned(32)))
|
|
//pomAll.zero_double_comp_beg_end(cd0,0,3300);//3200+100
|
|
const int NS=21;//
|
|
const int NN=NS+58;//
|
|
//double complex ctwk[32+5];
|
|
//double a[5];
|
|
//int NP2=2812;
|
|
//double complex csymb[40];//32+8
|
|
double s8_[NN][8]; //real s1(0:7,ND),s2(0:7,NN)
|
|
//double complex cs_[NN][8]; //complex cs(0:7,NN)
|
|
//double s2[512];
|
|
double bmeta[174];
|
|
double bmetb[174];
|
|
double bmetc[174];
|
|
double bmetd[174];
|
|
double llra[174];
|
|
double llrb[174];
|
|
double llrc[174];
|
|
double llrd[174];
|
|
//double rcw[174];
|
|
int itone[105];//NN
|
|
bool hdec[178];
|
|
bool nxor[178];
|
|
double dmm[MAXMSG+20];
|
|
QString msgbest = "";
|
|
QString msgsent = "";
|
|
double pbest;
|
|
|
|
//call_1="CQ"; call_2="LZ444HV"; grid4=" ";
|
|
std_1 = pomAll.isStandardCall(call_1.trimmed());
|
|
if (call_1=="CQ") std_1=true;
|
|
std_2 = pomAll.isStandardCall(call_2.trimmed());
|
|
//qDebug()<<" IN================="<<call_1<<call_2<<grid4<<"std"<<std_1<<std_2;
|
|
|
|
int nbadcrc = 1;
|
|
nharderrors=-1;
|
|
int nsync = 0;
|
|
ft8_downs_sync_bmet(dd0,true,newdat,f1,xdt,nbadcrc,nsync,s8_,bmeta,bmetb,bmetc,bmetd);
|
|
/*if (!ft8_downs_sync_bmet(dd0,true,newdat,f1,xdt,nbadcrc,nsync,s8_,bmeta,bmetb,bmetc,bmetd))
|
|
{
|
|
if (nsync<2) return;
|
|
}*/
|
|
|
|
double scalefac = 2.83;//scalefac=2.83 double ss=0.85;//hv tested->85-86 0.84;//0.84
|
|
for (int z = 0; z < 174; ++z)
|
|
{
|
|
llra[z]=scalefac*bmeta[z];
|
|
llrb[z]=scalefac*bmetb[z];
|
|
llrc[z]=scalefac*bmetc[z];
|
|
llrd[z]=scalefac*bmetd[z];
|
|
}
|
|
|
|
bool c77[140];
|
|
bool cw[180];
|
|
pbest=0.0;
|
|
dmin=1.e30;
|
|
int count_msg = MAXMSG;
|
|
for (int i = 0; i < MAXMSG; ++i)
|
|
{
|
|
//QString msg = msg0;
|
|
QString msg = call_1+" "+call_2;
|
|
if (call_1=="CQ" && i!=4) msg = "QU1RK "+call_2;
|
|
if (!std_1)
|
|
{
|
|
if (i==0 || i>=5) msg = "<"+call_1+"> "+call_2;
|
|
if (i>=1 && i<=3) msg = call_1+" <"+call_2+">";
|
|
}
|
|
else if (!std_2)
|
|
{
|
|
if (call_1=="CQ" && i!=4) msg = "QU1RK "+call_2;//HV add
|
|
else
|
|
{
|
|
if (i<=3 || i==5) msg = "<"+call_1+"> "+call_2;
|
|
if (i>=6) msg = call_1+" <"+call_2+">"; //if (i==5) msg = "TNX 73 GL";
|
|
}
|
|
}
|
|
//else if (i==0) msg = msg0.trimmed();
|
|
if (i==1) msg.append(" RRR");
|
|
if (i==2) msg.append(" RR73");
|
|
if (i==3) msg.append(" 73");
|
|
if (i==4)
|
|
{
|
|
if (std_2)
|
|
{
|
|
msg = "CQ "+call_2;//+" "+theirgrid.mid(0,4);//KN23SF
|
|
if (call_1.mid(2,1)=="_") msg = call_1+" "+call_2;
|
|
if (grid4!="RR73") msg = msg.trimmed()+" "+grid4;
|
|
}
|
|
if (!std_2) msg = "CQ "+call_2;//KN23SF
|
|
}
|
|
if (i==5 && std_2) msg.append(" "+grid4.mid(0,4));
|
|
if (i>=6 && i<MAXMSG)
|
|
{
|
|
if (i>12 && msg.startsWith("QU1RK "))
|
|
{
|
|
//not possyble "CQ <TM22KPW> -26"
|
|
//not possyble "CQ LZ2HV R-26"
|
|
//qDebug()<<"BREAK--->"<<msg<<"msgbest="<<msgbest;
|
|
count_msg = i;
|
|
break;
|
|
}
|
|
|
|
//int isnr = -50 + (i-6)/2;// -50 to +49
|
|
int isnr = -26 + (i-6)/2; // -26 to +49
|
|
if (((i+1) & 1)==1)
|
|
{
|
|
if (isnr>-1) msg.append(" +"+QString("%1").arg(abs(isnr),2,10,QChar('0')));
|
|
else msg.append(" -"+QString("%1").arg(abs(isnr),2,10,QChar('0')));
|
|
}
|
|
else
|
|
{
|
|
if (isnr>-1) msg.append(" R+"+QString("%1").arg(abs(isnr),2,10,QChar('0')));
|
|
else msg.append(" R-"+QString("%1").arg(abs(isnr),2,10,QChar('0')));
|
|
}
|
|
}
|
|
/*if (!std_2)
|
|
{
|
|
qDebug()<<i<<msg<<"----Call_2="<<call_2;
|
|
if (i==MAXMSG-1) qDebug()<<"------------------------------";
|
|
}*/
|
|
|
|
int i3=0;
|
|
int n3=0;
|
|
for (int z= 0; z < 176; ++z)
|
|
{
|
|
if (z<100) c77[z]=0;
|
|
cw[z] = 0;
|
|
}
|
|
|
|
TGenFt8->pack77(msg,i3,n3,c77);
|
|
TGenFt8->make_c77_i4tone_codeword(c77,itone,cw);
|
|
|
|
if (msg.startsWith("QU1RK "))
|
|
{
|
|
msgsent = msg;
|
|
}
|
|
else
|
|
{
|
|
bool unpk77_success = false;
|
|
msgsent = "";
|
|
msgsent = TGenFt8->unpack77(c77,unpk77_success);
|
|
}
|
|
//if (msgsent!=msg.trimmed()) qDebug()<<"---------------"<<i<<msg<<msgsent; //no-std-call problem "CQ <TM22KPW> R-26"
|
|
//if (msgsent.isEmpty()) msgsent = "QU1RK ";
|
|
|
|
//for (int z= 0; z < 176; ++z) rcw[]=2*cw-1 //rcw=2*cw-1
|
|
/*double pow0=0.0;
|
|
for (int z= 0; z < 79; ++z)//double s8_[NN][8];
|
|
{
|
|
pow0+=s8_[z][itone[z]]*s8_[z][itone[z]]; //pow=pow+s8_(itone[i],i)**2
|
|
}*/
|
|
double pow0=0.0;
|
|
for (int z = 0; z < 79; ++z)
|
|
{
|
|
double s88 = s8_[z][itone[z]]*0.001;//1000.0; //s8_/1000.0 = s2_ HV from v1.
|
|
pow0=pow0+s88*s88;
|
|
}
|
|
|
|
double da = 0.0;
|
|
double dbb= 0.0;
|
|
double dc = 0.0;
|
|
double dd = 0.0;
|
|
for (int z= 0; z < 174; ++z)
|
|
{
|
|
hdec[z] = 0;
|
|
if (llra[z]>=0.0) hdec[z] = 1;
|
|
nxor[z]=hdec[z] ^ cw[z];
|
|
da+=(double)nxor[z]*fabs(llra[z]);
|
|
hdec[z] = 0;
|
|
if (llrb[z]>=0.0) hdec[z] = 1;
|
|
nxor[z]=hdec[z] ^ cw[z];
|
|
dbb+=(double)nxor[z]*fabs(llrb[z]);
|
|
hdec[z] = 0;
|
|
if (llrc[z]>=0.0) hdec[z] = 1;
|
|
nxor[z]=hdec[z] ^ cw[z];
|
|
dc+=(double)nxor[z]*fabs(llrc[z]);
|
|
hdec[z] = 0;
|
|
if (llrd[z]>=0.0) hdec[z] = 1;
|
|
nxor[z]=hdec[z] ^ cw[z];
|
|
dd+=(double)nxor[z]*fabs(llrd[z]);
|
|
}
|
|
|
|
double dm = da;
|
|
if (dbb<dm) dm=dbb;
|
|
if (dc<dm) dm=dc;
|
|
if (dd<dm) dm=dd;
|
|
dmm[i]=dm;
|
|
if (dm<dmin)
|
|
{
|
|
dmin=dm;
|
|
msgbest=msgsent;
|
|
pbest=pow0;
|
|
nharderrors = -1;
|
|
if (dm==da)
|
|
{
|
|
for (int z= 0; z < 174; ++z)
|
|
{
|
|
if ((double)(2*cw[z]-1)*llra[z]<0.0) nharderrors++;
|
|
}
|
|
}
|
|
else if (dm==dbb)
|
|
{
|
|
for (int z= 0; z < 174; ++z)
|
|
{
|
|
if ((double)(2*cw[z]-1)*llrb[z]<0.0) nharderrors++;
|
|
}
|
|
}
|
|
else if (dm==dc)
|
|
{
|
|
for (int z= 0; z < 174; ++z)
|
|
{
|
|
if ((double)(2*cw[z]-1)*llrc[z]<0.0) nharderrors++;
|
|
}
|
|
}
|
|
else if (dm==dd)
|
|
{
|
|
for (int z= 0; z < 174; ++z)
|
|
{
|
|
if ((double)(2*cw[z]-1)*llrd[z]<0.0) nharderrors++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
int pos = 0;
|
|
double min = dmm[0];
|
|
for (int z= 1; z < count_msg; ++z)//MAXMSG
|
|
{
|
|
if (dmm[z]<min)
|
|
{
|
|
min=dmm[z];
|
|
pos = z;
|
|
}
|
|
}
|
|