Use 4 different Costas arrays to prevent false syncs as received frames move

through the analysis window.

Add a random 77-bit vector to each message so that tone transitions occur
even if the message contains a long string of 0 or 1 (like a CQ).

Add alternative sync calculation as an option (sync2), for testing.

Add basic framework for AP decoding.
This commit is contained in:
Steve Franke 2019-02-05 19:18:50 -06:00
parent 91e3dbdf20
commit 71cb6d9f50
5 changed files with 148 additions and 55 deletions

View File

@ -1,17 +1,19 @@
subroutine ft4_decode(cdatetime0,tbuf,nfa,nfb,nfqso,iwave,ndecodes,mycall, &
subroutine ft4_decode(cdatetime0,tbuf,nfa,nfb,nQSOProgress,nfqso,iwave,ndecodes,mycall, &
hiscall,nrx,line,data_dir)
use packjt77
include 'ft4_params.f90'
parameter (NSS=NSPS/NDOWN)
character message*37
character message*37,msgsent*37
character c77*77
character*61 line,linex(100)
character*37 decodes(100)
character*512 data_dir,fname
character*17 cdatetime0
character*6 mycall,hiscall,hhmmss
character*6 mycall,hiscall
character*6 mycall0,hiscall0
character*6 hhmmss
complex cd2(0:NMAX/NDOWN-1) !Complex waveform
complex cb(0:NMAX/NDOWN-1)
@ -29,31 +31,50 @@ subroutine ft4_decode(cdatetime0,tbuf,nfa,nfb,nfqso,iwave,ndecodes,mycall, &
real savg(NH1),sbase(NH1)
integer nrxx(100)
integer icos4(0:3)
integer icos4a(0:3),icos4b(0:3),icos4c(0:3),icos4d(0:3)
integer*2 iwave(NMAX) !Generated full-length waveform
integer*1 message77(77),apmask(2*ND),cw(2*ND)
integer*1 message77(77),rvec(77),apbits(2*ND),apmask(2*ND),cw(2*ND)
integer*1 hbits(2*NN)
integer graymap(0:3)
integer ip(1)
integer nappasses(0:5) ! # of decoding passes for QSO States 0-5
integer naptypes(0:5,4) ! nQSOProgress, decoding pass
integer mcq(29),mcqru(29),mcqfd(29),mcqtest(29)
integer mrrr(19),m73(19),mrr73(19)
integer mcall(29),hcall(29)
logical unpk77_success
logical one(0:255,0:7) ! 256 4-symbol sequences, 8 bits
logical first
data icos4/0,1,3,2/
data icos4a/0,1,3,2/
data icos4b/1,0,2,3/
data icos4c/2,3,1,0/
data icos4d/3,2,0,1/
data graymap/0,1,3,2/
data first/.true./
save one,first,nrxx,linex
data mcq/0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0/
data mcqru/0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,1,1,1,0,0,1,1,0,0/
data mcqfd/0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,1,0,0,0,1,0/
data mcqtest/0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,1,0,1,0,1,1,1,1,1,1,0,0,1,0/
data mrrr/0,1,1,1,1,1,1,0,1,0,0,1,0,0,1,0,0,0,1/
data m73/0,1,1,1,1,1,1,0,1,0,0,1,0,1,0,0,0,0,1/
data mrr73/0,1,1,1,1,1,1,0,0,1,1,1,0,1,0,1,0,0,1/
data rvec/0,1,0,0,1,0,1,0,0,1,0,1,1,1,1,0,1,0,0,0,1,0,0,1,1,0,1,1,0, &
1,0,0,1,0,1,1,0,0,0,0,1,0,0,0,1,0,1,0,0,1,1,1,1,0,0,1,0,1, &
0,1,0,1,0,1,1,0,1,1,1,1,1,0,0,0,1,0,1/
save fs,dt,tt,txt,twopi,h,one,first,nrxx,linex,apbits,nappasses,naptypes,mycall0,hiscall0
call clockit('ft4_deco',0)
hhmmss=cdatetime0(8:13)
fs=12000.0/NDOWN !Sample rate after downsampling
dt=1/fs !Sample interval after downsample (s)
tt=NSPS*dt !Duration of "itone" symbols (s)
txt=NZ*dt !Transmission length (s) without ramp up/down
twopi=8.0*atan(1.0)
h=1.0
if(first) then
fs=12000.0/NDOWN !Sample rate after downsampling
dt=1/fs !Sample interval after downsample (s)
tt=NSPS*dt !Duration of "itone" symbols (s)
txt=NZ*dt !Transmission length (s) without ramp up/down
twopi=8.0*atan(1.0)
h=1.0
one=.false.
do i=0,255
do j=0,7
@ -63,6 +84,22 @@ subroutine ft4_decode(cdatetime0,tbuf,nfa,nfb,nfqso,iwave,ndecodes,mycall, &
first=.false.
endif
if(mycall.ne.mycall0 .or. hiscall.ne.hiscall0) then
message=trim(mycall)//' '//trim(hiscall)//' '//'RR73'
i3=-1
n3=-1
call pack77(message,i3,n3,c77)
call unpack77(c77,0,msgsent,unpk77_success)
if(message.ne.msgsent) write(*,*) 'ERROR setting AP message'
read(c77,"(77i1)") message77
message77=mod(message77+rvec,2)
call encode174_91(message77,cw)
mcall=cw(1:29)
hcall=cw(30:58)
mycall0=mycall
hiscall0=hiscall
endif
candidate=0.0
ncand=0
syncmin=1.2
@ -87,7 +124,7 @@ subroutine ft4_decode(cdatetime0,tbuf,nfa,nfb,nfqso,iwave,ndecodes,mycall, &
sum2=sum(cd2*conjg(cd2))/(real(NMAX)/real(NDOWN))
if(sum2.gt.0.0) cd2=cd2/sqrt(sum2)
! Sample rate is now 12000/16 = 750 samples/second
do isync=1,2
do isync=1,1
if(isync.eq.1) then
idfmin=-12
idfmax=12
@ -116,7 +153,7 @@ subroutine ft4_decode(cdatetime0,tbuf,nfa,nfb,nfqso,iwave,ndecodes,mycall, &
call clockit('sync4d ',0)
do istart=ibmin,ibmax,ibstp
call sync4d(cd2,istart,ctwk2,1,sync) !Find sync power
call sync4d(cd2,istart,ctwk2,1,sync,sync2) !Find sync power
if(sync.gt.smax) then
smax=sync
ibest=istart
@ -127,8 +164,10 @@ subroutine ft4_decode(cdatetime0,tbuf,nfa,nfb,nfqso,iwave,ndecodes,mycall, &
enddo
enddo
f0=f0+real(idfbest)
!f0=1500
!ibest=219
call clockit('ft4down ',0)
call ft4_downsample(iwave,f0,cb) !Final downsample with corrected f0
call clockit('ft4down ',1)
@ -152,17 +191,17 @@ subroutine ft4_decode(cdatetime0,tbuf,nfa,nfb,nfqso,iwave,ndecodes,mycall, &
is4=0
do k=1,4
ip=maxloc(s4(:,k))
if(icos4(k-1).eq.(ip(1)-1)) is1=is1+1
if(icos4a(k-1).eq.(ip(1)-1)) is1=is1+1
ip=maxloc(s4(:,k+33))
if(icos4(k-1).eq.(ip(1)-1)) is2=is2+1
if(icos4b(k-1).eq.(ip(1)-1)) is2=is2+1
ip=maxloc(s4(:,k+66))
if(icos4(k-1).eq.(ip(1)-1)) is3=is3+1
if(icos4c(k-1).eq.(ip(1)-1)) is3=is3+1
ip=maxloc(s4(:,k+99))
if(icos4(k-1).eq.(ip(1)-1)) is4=is4+1
if(icos4d(k-1).eq.(ip(1)-1)) is4=is4+1
enddo
nsync=is1+is2+is3+is4 !Number of hard sync errors, 0-16
if(smax .lt. 0.9 .or. nsync .lt. 9) cycle
if(smax .lt. 0.7 .or. nsync .lt. 8) cycle
do nseq=1,3 !Try coherent sequences of 1, 2, and 4 symbols
if(nseq.eq.1) nsym=1
if(nseq.eq.2) nsym=2
@ -217,11 +256,10 @@ subroutine ft4_decode(cdatetime0,tbuf,nfa,nfb,nfqso,iwave,ndecodes,mycall, &
hbits=0
where(bmeta.ge.0) hbits=1
ns1=count(hbits( 1: 8).eq.(/0,0,0,1,1,0,1,1/))
ns2=count(hbits( 67: 74).eq.(/0,0,0,1,1,0,1,1/))
ns3=count(hbits(133:140).eq.(/0,0,0,1,1,0,1,1/))
ns4=count(hbits(199:206).eq.(/0,0,0,1,1,0,1,1/))
ns2=count(hbits( 67: 74).eq.(/0,1,0,0,1,1,1,0/))
ns3=count(hbits(133:140).eq.(/1,1,1,0,0,1,0,0/))
ns4=count(hbits(199:206).eq.(/1,0,1,1,0,0,0,1/))
nsync_qual=ns1+ns2+ns3+ns4
if(nsync_qual.lt. 20) cycle
scalefac=2.83
@ -242,7 +280,9 @@ subroutine ft4_decode(cdatetime0,tbuf,nfa,nfb,nfqso,iwave,ndecodes,mycall, &
if(isd.eq.1) llr=llra
if(isd.eq.2) llr=llrb
if(isd.eq.3) llr=llrc
!llr(1:59)=1.5*scalefac*(2*apbits(1:59)-1)
apmask=0
!apmask(1:91)=1
max_iterations=40
do ibias=0,0
llr2=llr
@ -256,6 +296,7 @@ subroutine ft4_decode(cdatetime0,tbuf,nfa,nfb,nfqso,iwave,ndecodes,mycall, &
enddo
if(sum(message77).eq.0) cycle
if( nharderror.ge.0 ) then
message77=mod(message77+rvec,2)
write(c77,'(77i1)') message77(1:77)
call unpack77(c77,1,message,unpk77_success)
idupe=0
@ -310,8 +351,9 @@ subroutine ft4_decode(cdatetime0,tbuf,nfa,nfb,nfqso,iwave,ndecodes,mycall, &
enddo !Sequence estimation
enddo !Candidate list
call clockit('ft4_deco',1)
call clockit2(data_dir)
call clockit('ft4_deco',101)
! clockit data directory does not get set properly on the Mac.
! call clockit2(data_dir)
! call clockit('ft4_deco',101)
return
entry get_ft4msg(idecode,nrx,line)

View File

@ -44,6 +44,7 @@ program ft4d
endif
nfa=200
nfb=3000
nQSOProgress=0
do ifile=iarg,nargs
call getarg(ifile,infile)
@ -55,7 +56,7 @@ program ft4d
cdatetime=' '//datetime
close(10)
call ft4_decode(cdatetime,0.0,nfa,nfb,nfqso,iwave,ndecodes,mycall, &
call ft4_decode(cdatetime,0.0,nfa,nfb,nQSOProgress,nfqso,iwave,ndecodes,mycall, &
hiscall,nrx,line,data_dir)
do idecode=1,ndecodes

View File

@ -23,11 +23,16 @@ subroutine genft4(msg0,ichk,msgsent,i4tone)
character*77 c77
integer*4 i4tone(NN),itmp(ND)
integer*1 codeword(2*ND)
integer*1 msgbits(77)
integer icos4(4)
integer*1 msgbits(77),rvec(77)
integer icos4a(4),icos4b(4),icos4c(4),icos4d(4)
logical unpk77_success
data icos4/0,1,3,2/
data icos4a/0,1,3,2/
data icos4b/1,0,2,3/
data icos4c/2,3,1,0/
data icos4d/3,2,0,1/
data rvec/0,1,0,0,1,0,1,0,0,1,0,1,1,1,1,0,1,0,0,0,1,0,0,1,1,0,1,1,0, &
1,0,0,1,0,1,1,0,0,0,0,1,0,0,0,1,0,1,0,0,1,1,1,1,0,0,1,0,1, &
0,1,0,1,0,1,1,0,1,1,1,1,1,0,0,0,1,0,1/
message=msg0
do i=1, 37
@ -48,6 +53,7 @@ subroutine genft4(msg0,ichk,msgsent,i4tone)
if(ichk.eq.1) go to 999
read(c77,"(77i1)") msgbits
msgbits=mod(msgbits+rvec,2)
call encode174_91(msgbits,codeword)
! Grayscale mapping:
@ -64,13 +70,13 @@ subroutine genft4(msg0,ichk,msgsent,i4tone)
if(is.eq.3) itmp(i)=2
enddo
i4tone(1:4)=icos4
i4tone(1:4)=icos4a
i4tone(5:33)=itmp(1:29)
i4tone(34:37)=icos4
i4tone(34:37)=icos4b
i4tone(38:66)=itmp(30:58)
i4tone(67:70)=icos4
i4tone(67:70)=icos4c
i4tone(71:99)=itmp(59:87)
i4tone(100:103)=icos4
i4tone(100:103)=icos4d
999 return
end subroutine genft4

View File

@ -1,31 +1,47 @@
subroutine sync4d(cd0,i0,ctwk,itwk,sync)
subroutine sync4d(cd0,i0,ctwk,itwk,sync,sync2)
! Compute sync power for a complex, downsampled FT4 signal.
include 'ft4_params.f90'
parameter(NP=NMAX/NDOWN,NSS=NSPS/NDOWN)
complex cd0(0:NP-1)
complex csync(4*NSS)
complex csynca(4*NSS),csyncb(4*NSS),csyncc(4*NSS),csyncd(4*NSS)
complex csync2(4*NSS)
complex ctwk(4*NSS)
complex z1,z2,z3,z4
complex zz1,zz2,zz3,zz4
logical first
integer icos4(0:3)
data icos4/0,1,3,2/
integer icos4a(0:3),icos4b(0:3),icos4c(0:3),icos4d(0:3)
data icos4a/0,1,3,2/
data icos4b/1,0,2,3/
data icos4c/2,3,1,0/
data icos4d/3,2,0,1/
data first/.true./
save first,twopi,csync,fac
save first,twopi,csynca,csyncb,csyncc,csyncd,fac
p(z1)=real(z1*fac)**2 + aimag(z1*fac)**2 !Statement function for power
if( first ) then
twopi=8.0*atan(1.0)
k=1
phi=0.0
phia=0.0
phib=0.0
phic=0.0
phid=0.0
do i=0,3
dphi=twopi*icos4(i)/real(NSS)
dphia=twopi*icos4a(i)/real(NSS)
dphib=twopi*icos4b(i)/real(NSS)
dphic=twopi*icos4c(i)/real(NSS)
dphid=twopi*icos4d(i)/real(NSS)
do j=1,NSS
csync(k)=cmplx(cos(phi),sin(phi))
phi=mod(phi+dphi,twopi)
csynca(k)=cmplx(cos(phia),sin(phia))
csyncb(k)=cmplx(cos(phib),sin(phib))
csyncc(k)=cmplx(cos(phic),sin(phic))
csyncd(k)=cmplx(cos(phid),sin(phid))
phia=mod(phia+dphia,twopi)
phib=mod(phib+dphib,twopi)
phic=mod(phic+dphic,twopi)
phid=mod(phid+dphid,twopi)
k=k+1
enddo
enddo
@ -33,18 +49,45 @@ subroutine sync4d(cd0,i0,ctwk,itwk,sync)
fac=1.0/(4.0*NSS)
endif
sync=0
i1=i0 !four Costas arrays
i2=i0+33*NSS
i3=i0+66*NSS
i4=i0+99*NSS
csync2=csync
if(itwk.eq.1) csync2=ctwk*csync2 !Tweak the frequency
z1=0.
z2=0.
z3=0.
z4=0.
if(itwk.eq.1) csync2=ctwk*csynca !Tweak the frequency
if(i1.ge.0 .and. i1+4*NSS-1.le.NP-1) z1=sum(cd0(i1:i1+4*NSS-1)*conjg(csync2))
if(itwk.eq.1) csync2=ctwk*csyncb !Tweak the frequency
if(i2.ge.0 .and. i2+4*NSS-1.le.NP-1) z2=sum(cd0(i2:i2+4*NSS-1)*conjg(csync2))
if(itwk.eq.1) csync2=ctwk*csyncc !Tweak the frequency
if(i3.ge.0 .and. i3+4*NSS-1.le.NP-1) z3=sum(cd0(i3:i3+4*NSS-1)*conjg(csync2))
if(itwk.eq.1) csync2=ctwk*csyncd !Tweak the frequency
if(i4.ge.0 .and. i4+4*NSS-1.le.NP-1) z4=sum(cd0(i4:i4+4*NSS-1)*conjg(csync2))
sync = sync + p(z1) + p(z2) + p(z3) + p(z4)
sync = p(z1) + p(z2) + p(z3) + p(z4)
sync2=0.0
do i=1,4
i1=i0+(i-1)*33*NSS
if(i.eq.1) csync2=ctwk*csynca
if(i.eq.2) csync2=ctwk*csyncb
if(i.eq.3) csync2=ctwk*csyncc
if(i.eq.4) csync2=ctwk*csyncd
z1=sum(cd0(i1 :i1+ NSS-1)*conjg(csync2( 1: NSS)))
z2=sum(cd0(i1+ NSS:i1+2*NSS-1)*conjg(csync2( NSS+1:2*NSS)))
z3=sum(cd0(i1+2*NSS:i1+3*NSS-1)*conjg(csync2(2*NSS+1:3*NSS)))
z4=sum(cd0(i1+3*NSS:i1+4*NSS-1)*conjg(csync2(3*NSS+1:4*NSS)))
sync2=sync2 + abs(z1)**2+abs(z2)**2+abs(z3)**2+abs(z4)**2+&
2*abs(z1*conjg(z2)+z2*conjg(z3)+z3*conjg(z4))
enddo
sync2=sync2*(fac**2)
return
end subroutine sync4d

View File

@ -163,10 +163,10 @@ extern "C" {
void chkcall_(char* w, char* basc_call, bool cok, int len1, int len2);
void ft4_decode_(char* cdatetime, float* tbuf, int* nfa, int* nfb, int* nfqso,
short int id[], int* ndecodes, char* mycall6, char* hiscall6,
int* nrx, char* line, char* ddir, int len1, int len2, int len3,
int len4, int len5);
void ft4_decode_(char* cdatetime, float* tbuf, int* nfa, int* nfb, int* nQSOProgress,
int* nfqso, short int id[], int* ndecodes, char* mycall6,
char* hiscall6, int* nrx, char* line, char* ddir, int len1, int len2,
int len3, int len4, int len5);
void get_ft4msg_(int* idecode, int* nrx, char* line, int len);
@ -8659,11 +8659,12 @@ void MainWindow::ft4Data(int k)
int nrx=-1;
int nfa=m_wideGraph->nStartFreq();
int nfb=m_wideGraph->Fmax();
int nQSOProgress=m_QSOProgress;
QString dataDir;
dataDir = m_config.writeable_data_dir ().absolutePath ();
char ddir[512];
strncpy(ddir,dataDir.toLatin1(), sizeof (ddir) - 1);
ft4_decode_(cdatetime,&tbuf,&nfa,&nfb,&nfqso,id,&ndecodes,mycall6,hiscall6,
ft4_decode_(cdatetime,&tbuf,&nfa,&nfb,&nQSOProgress,&nfqso,id,&ndecodes,mycall6,hiscall6,
&nrx,&line[0],&ddir[0],17,6,6,61,512);
line[60]=0;
// if(ndecodes>0) {