mirror of
https://github.com/saitohirga/WSJT-X.git
synced 2024-11-16 17:11:53 -05:00
11b7aa9429
By cascading the full 24-bit crc generator matrix with the (240,74) LDPC code generator, create a (240,50) generator that is used to decode with approximately 1 dB better sensitivity than the (240,64) with 14-bit CRC approach that is normally used. This approach treats the CRC bits as additional parity bits and provides no means for identifying incorrect codewords. All codewords on the list generated by the OSD algorithm have CRCs that match the CRC of the message payload. Codewords are validated by unpacking the message and comparing the unpacked message with the list of stored callsign/grid pairs stored in the fst4w_calls.txt file.
292 lines
8.0 KiB
Fortran
292 lines
8.0 KiB
Fortran
subroutine fastosd240_74(llr,k,apmask,ndeep,message74,cw,nhardmin,dmin)
|
|
!
|
|
! An ordered-statistics decoder for the (240,74) code.
|
|
! Message payload is 50 bits. Any or all of a 24-bit CRC can be
|
|
! used for detecting incorrect codewords. The remaining CRC bits are
|
|
! cascaded with the LDPC code for the purpose of improving the
|
|
! distance spectrum of the code.
|
|
!
|
|
! If p1 (0.le.p1.le.24) is the number of CRC24 bits that are
|
|
! to be used for bad codeword detection, then the argument k should
|
|
! be set to 77+p1.
|
|
!
|
|
! Valid values for k are in the range [50,74].
|
|
!
|
|
character*24 c24
|
|
integer, parameter:: N=240
|
|
integer*1 apmask(N),apmaskr(N)
|
|
integer*1, allocatable, save :: gen(:,:)
|
|
integer*1, allocatable :: genmrb(:,:),g2(:,:)
|
|
integer*1, allocatable :: temp(:),temprow(:),m0(:),me(:),mi(:)
|
|
integer indices(N),indices2(N),nxor(N)
|
|
integer*1 cw(N),ce(N),c0(N),hdec(N)
|
|
integer*1, allocatable :: decoded(:)
|
|
integer*1 message74(74)
|
|
integer*1, allocatable :: sp(:)
|
|
integer indx(N),ksave
|
|
real llr(N),rx(N),absrx(N)
|
|
|
|
logical first
|
|
data first/.true./,ksave/64/
|
|
save first,ksave
|
|
|
|
allocate( genmrb(k,N), g2(N,k) )
|
|
allocate( temp(k), temprow(n), m0(k), me(k), mi(k) )
|
|
allocate( decoded(k) )
|
|
|
|
if( first .or. k.ne.ksave) then ! fill the generator matrix
|
|
!
|
|
! Create generator matrix for partial CRC cascaded with LDPC code.
|
|
!
|
|
! Let p2=74-k and p1+p2=24.
|
|
!
|
|
! The last p2 bits of the CRC24 are cascaded with the LDPC code.
|
|
!
|
|
! The first p1=k-50 CRC24 bits will be used for error detection.
|
|
!
|
|
if( allocated(gen) ) deallocate(gen)
|
|
allocate( gen(k,N) )
|
|
gen=0
|
|
do i=1,k
|
|
message74=0
|
|
message74(i)=1
|
|
if(i.le.50) then
|
|
call get_crc24(message74,74,ncrc24)
|
|
write(c24,'(b24.24)') ncrc24
|
|
read(c24,'(24i1)') message74(51:74)
|
|
message74(51:k)=0
|
|
endif
|
|
call encode240_74(message74,cw)
|
|
gen(i,:)=cw
|
|
enddo
|
|
|
|
first=.false.
|
|
ksave=k
|
|
endif
|
|
|
|
! Use best k elements from the sorted list for the first basis. For the 2nd basis replace
|
|
! the nswap lowest quality symbols with the best nswap elements from the parity symbols.
|
|
nswap=20
|
|
|
|
do ibasis=1,2
|
|
rx=llr
|
|
apmaskr=apmask
|
|
|
|
! Hard decisions on the received word.
|
|
hdec=0
|
|
where(rx .ge. 0) hdec=1
|
|
|
|
! Use magnitude of received symbols as a measure of reliability.
|
|
absrx=abs(llr)
|
|
call indexx(absrx,N,indx)
|
|
|
|
! Re-order the columns of the generator matrix in order of decreasing reliability.
|
|
do i=1,N
|
|
genmrb(1:k,i)=gen(1:k,indx(N+1-i))
|
|
indices(i)=indx(N+1-i)
|
|
enddo
|
|
|
|
if(ibasis.eq.2) then
|
|
do i=k-nswap+1,k
|
|
temp(1:k)=genmrb(1:k,i)
|
|
genmrb(1:k,i)=genmrb(1:k,i+nswap)
|
|
genmrb(1:k,i+nswap)=temp(1:k)
|
|
itmp=indices(i)
|
|
indices(i)=indices(i+nswap)
|
|
indices(i+nswap)=itmp
|
|
enddo
|
|
endif
|
|
|
|
! Do gaussian elimination to create a generator matrix with the most reliable
|
|
! received bits in positions 1:k in order of decreasing reliability (more or less).
|
|
|
|
icol=1
|
|
indices2=0
|
|
nskipped=0
|
|
do id=1,k
|
|
iflag=0
|
|
do while(iflag.eq.0)
|
|
if(genmrb(id,icol).ne.1) then
|
|
do j=id+1,k
|
|
if(genmrb(j,icol).eq.1) then
|
|
temprow=genmrb(id,:)
|
|
genmrb(id,:)=genmrb(j,:)
|
|
genmrb(j,:)=temprow
|
|
iflag=1
|
|
endif
|
|
enddo
|
|
if(iflag.eq.0) then ! skip this column
|
|
nskipped=nskipped+1
|
|
indices2(k+nskipped)=icol ! put icol where skipped columns go
|
|
icol=icol+1 ! look at the next column
|
|
endif
|
|
else
|
|
iflag=1
|
|
endif
|
|
enddo
|
|
indices2(id)=icol
|
|
do j=1,k
|
|
if(id.ne.j .and. genmrb(j,icol).eq.1) then
|
|
genmrb(j,:)=ieor(genmrb(id,:),genmrb(j,:))
|
|
endif
|
|
enddo
|
|
icol=icol+1
|
|
enddo
|
|
do i=k+nskipped+1,240
|
|
indices2(i)=i
|
|
enddo
|
|
genmrb(1:k,:)=genmrb(1:k,indices2)
|
|
indices=indices(indices2)
|
|
|
|
!************************************
|
|
g2=transpose(genmrb)
|
|
|
|
! The hard decisions for the k MRB bits define the order 0 message, m0.
|
|
! Encode m0 using the modified generator matrix to find the "order 0" codeword.
|
|
! Flip various combinations of bits in m0 and re-encode to generate a list of
|
|
! codewords. Return the member of the list that has the smallest Euclidean
|
|
! distance to the received word.
|
|
|
|
hdec=hdec(indices) ! hard decisions from received symbols
|
|
m0=hdec(1:k) ! zero'th order message
|
|
absrx=abs(llr)
|
|
absrx=absrx(indices)
|
|
rx=rx(indices)
|
|
apmaskr=apmaskr(indices)
|
|
|
|
call mrbencode74(m0,c0,g2,N,k)
|
|
nxor=ieor(c0,hdec)
|
|
nhardmin=sum(nxor)
|
|
dmin=sum(nxor*absrx)
|
|
np=32
|
|
if(ibasis.eq.1) allocate(sp(np))
|
|
|
|
cw=c0
|
|
ntotal=0
|
|
nrejected=0
|
|
|
|
if(ndeep.eq.0) goto 998 ! norder=0
|
|
if(ndeep.gt.4) ndeep=4
|
|
if( ndeep.eq. 1) then
|
|
nord=1
|
|
xlambda=0.0
|
|
nsyncmax=np
|
|
elseif(ndeep.eq.2) then
|
|
nord=2
|
|
xlambda=0.0
|
|
nsyncmax=np
|
|
elseif(ndeep.eq.3) then
|
|
nord=3
|
|
xlambda=4.0
|
|
nsyncmax=11
|
|
elseif(ndeep.eq.4) then
|
|
nord=4
|
|
xlambda=3.5
|
|
nsyndmax=11
|
|
endif
|
|
|
|
s1=sum(absrx(1:k))
|
|
s2=sum(absrx(k+1:N))
|
|
rho=s1/(s1+xlambda*s2)
|
|
rhodmin=rho*dmin
|
|
nerr64=-1
|
|
do iorder=1,nord
|
|
!beta=0.0
|
|
!if(iorder.ge.3) beta=0.4
|
|
!spnc_order=sum(absrx(k-iorder+1:k))+beta*(N-k)
|
|
!if(dmin.lt.spnc_order) cycle
|
|
mi(1:k-iorder)=0
|
|
mi(k-iorder+1:k)=1
|
|
iflag=k-iorder+1
|
|
do while(iflag .ge.0)
|
|
ntotal=ntotal+1
|
|
me=ieor(m0,mi)
|
|
d1=sum(mi(1:k)*absrx(1:k))
|
|
if(d1.gt.rhodmin) exit
|
|
call partial_syndrome(me,sp,np,g2,N,K)
|
|
nwhsp=sum(ieor(sp(1:np),hdec(k:k+np-1)))
|
|
if(nwhsp.le.nsyndmax) then
|
|
call mrbencode74(me,ce,g2,N,k)
|
|
nxor=ieor(ce,hdec)
|
|
dd=sum(nxor*absrx(1:N))
|
|
if( dd .lt. dmin ) then
|
|
dmin=dd
|
|
rhodmin=rho*dmin
|
|
cw=ce
|
|
nhardmin=sum(nxor)
|
|
nwhspmin=nwhsp
|
|
nerr64=sum(nxor(1:K))
|
|
endif
|
|
endif
|
|
! Get the next test error pattern, iflag will go negative
|
|
! when the last pattern with weight iorder has been generated.
|
|
call nextpat74(mi,k,iorder,iflag)
|
|
enddo
|
|
enddo
|
|
|
|
998 continue
|
|
! Re-order the codeword to [message bits][parity bits] format.
|
|
cw(indices)=cw
|
|
hdec(indices)=hdec
|
|
message74=cw(1:74)
|
|
call get_crc24(message74,74,nbadcrc)
|
|
if(nbadcrc.eq.0) exit
|
|
nhardmin=-nhardmin
|
|
enddo ! basis loop
|
|
return
|
|
end subroutine fastosd240_74
|
|
|
|
subroutine mrbencode74(me,codeword,g2,N,K)
|
|
integer*1 me(K),codeword(N),g2(N,K)
|
|
! fast encoding for low-weight test patterns
|
|
codeword=0
|
|
do i=1,K
|
|
if( me(i) .eq. 1 ) then
|
|
codeword=ieor(codeword,g2(1:N,i))
|
|
endif
|
|
enddo
|
|
return
|
|
end subroutine mrbencode74
|
|
|
|
subroutine partial_syndrome(me,sp,np,g2,N,K)
|
|
integer*1 me(K),sp(np),g2(N,K)
|
|
! compute partial syndrome
|
|
sp=0
|
|
do i=1,K
|
|
if( me(i) .eq. 1 ) then
|
|
sp=ieor(sp,g2(K:K+np-1,i))
|
|
endif
|
|
enddo
|
|
return
|
|
end subroutine partial_syndrome
|
|
|
|
subroutine nextpat74(mi,k,iorder,iflag)
|
|
integer*1 mi(k),ms(k)
|
|
! generate the next test error pattern
|
|
ind=-1
|
|
do i=1,k-1
|
|
if( mi(i).eq.0 .and. mi(i+1).eq.1) ind=i
|
|
enddo
|
|
if( ind .lt. 0 ) then ! no more patterns of this order
|
|
iflag=ind
|
|
return
|
|
endif
|
|
ms=0
|
|
ms(1:ind-1)=mi(1:ind-1)
|
|
ms(ind)=1
|
|
ms(ind+1)=0
|
|
if( ind+1 .lt. k ) then
|
|
nz=iorder-sum(ms)
|
|
ms(k-nz+1:k)=1
|
|
endif
|
|
mi=ms
|
|
do i=1,k ! iflag will point to the lowest-index 1 in mi
|
|
if(mi(i).eq.1) then
|
|
iflag=i
|
|
exit
|
|
endif
|
|
enddo
|
|
return
|
|
end subroutine nextpat74
|
|
|