From c8e5d8ecd608339085bd24ec7301af5b420a599a Mon Sep 17 00:00:00 2001 From: Steven Franke Date: Wed, 14 Jun 2017 00:45:44 +0000 Subject: [PATCH] More test files. git-svn-id: svn+ssh://svn.code.sf.net/p/wsjt/wsjt/branches/wsjtx@7713 ab8295b8-cf94-4d9e-aec4-7959e3be5d79 --- lib/fsk4hf/bpdecode174.f90 | 402 ++++++++++++++++++++++++++++++ lib/fsk4hf/encode174.f90 | 50 ++++ lib/fsk4hf/ldpc_174_87_params.f90 | 103 ++++++++ lib/fsk4hf/ldpcsim174.f90 | 241 ++++++++++++++++++ lib/fsk4hf/osd174.f90 | 151 +++++++++++ 5 files changed, 947 insertions(+) create mode 100644 lib/fsk4hf/bpdecode174.f90 create mode 100644 lib/fsk4hf/encode174.f90 create mode 100644 lib/fsk4hf/ldpc_174_87_params.f90 create mode 100644 lib/fsk4hf/ldpcsim174.f90 create mode 100644 lib/fsk4hf/osd174.f90 diff --git a/lib/fsk4hf/bpdecode174.f90 b/lib/fsk4hf/bpdecode174.f90 new file mode 100644 index 000000000..334f88f2c --- /dev/null +++ b/lib/fsk4hf/bpdecode174.f90 @@ -0,0 +1,402 @@ +subroutine bpdecode174(llr,apmask,maxiterations,decoded,niterations) +! +! A log-domain belief propagation decoder for the (174,87) code. +! +integer, parameter:: N=174, K=87, M=N-K +integer*1 codeword(N),cw(N),apmask(N) +integer colorder(N) +integer*1 decoded(K) +integer Nm(7,M) ! 5, 6, or 7 bits per check +integer Mn(3,N) ! 3 checks per bit +integer synd(M) +real tov(3,N) +real toc(7,M) +real tanhtoc(7,M) +real zn(N) +real llr(N) +real Tmn +integer nrw(M) + +data colorder/ & + 0, 1, 2, 3, 30, 4, 5, 6, 7, 8, 9, 10, 11, 32, 12, 40, 13, 14, 15, 16,& + 17, 18, 37, 45, 29, 19, 20, 21, 41, 22, 42, 31, 33, 34, 44, 35, 47, 51, 50, 43,& + 36, 52, 63, 46, 25, 55, 27, 24, 23, 53, 39, 49, 59, 38, 48, 61, 60, 57, 28, 62,& + 56, 58, 65, 66, 26, 70, 64, 69, 68, 67, 74, 71, 54, 76, 72, 75, 78, 77, 80, 79,& + 73, 83, 84, 81, 82, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99,& + 100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,& + 120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,& + 140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,& + 160,161,162,163,164,165,166,167,168,169,170,171,172,173/ + +data Mn/ & + 1, 25, 69, & + 2, 5, 73, & + 3, 32, 68, & + 4, 51, 61, & + 6, 63, 70, & + 7, 33, 79, & + 8, 50, 86, & + 9, 37, 43, & + 10, 41, 65, & + 11, 14, 64, & + 12, 75, 77, & + 13, 23, 81, & + 15, 16, 82, & + 17, 56, 66, & + 18, 53, 60, & + 19, 31, 52, & + 20, 67, 84, & + 21, 29, 72, & + 22, 24, 44, & + 26, 35, 76, & + 27, 36, 38, & + 28, 40, 42, & + 30, 54, 55, & + 34, 49, 87, & + 39, 57, 58, & + 45, 74, 83, & + 46, 62, 80, & + 47, 48, 85, & + 59, 71, 78, & + 1, 50, 53, & + 2, 47, 84, & + 3, 25, 79, & + 4, 6, 14, & + 5, 7, 80, & + 8, 34, 55, & + 9, 36, 69, & + 10, 43, 83, & + 11, 23, 74, & + 12, 17, 44, & + 13, 57, 76, & + 15, 27, 56, & + 16, 28, 29, & + 18, 19, 59, & + 20, 40, 63, & + 21, 35, 52, & + 22, 54, 64, & + 24, 62, 78, & + 26, 32, 77, & + 30, 72, 85, & + 31, 65, 87, & + 33, 39, 51, & + 37, 48, 75, & + 38, 70, 71, & + 41, 42, 68, & + 45, 67, 86, & + 46, 81, 82, & + 49, 66, 73, & + 58, 60, 66, & + 61, 65, 85, & + 1, 14, 21, & + 2, 13, 59, & + 3, 67, 82, & + 4, 32, 73, & + 5, 36, 54, & + 6, 43, 46, & + 7, 28, 75, & + 8, 33, 71, & + 9, 49, 76, & + 10, 58, 64, & + 11, 48, 68, & + 12, 19, 45, & + 15, 50, 61, & + 16, 22, 26, & + 17, 72, 80, & + 18, 40, 55, & + 20, 35, 51, & + 23, 25, 34, & + 24, 63, 87, & + 27, 39, 74, & + 29, 78, 83, & + 30, 70, 77, & + 31, 69, 84, & + 22, 37, 86, & + 38, 41, 81, & + 42, 44, 57, & + 47, 53, 62, & + 52, 56, 79, & + 60, 75, 81, & + 1, 39, 77, & + 2, 16, 41, & + 3, 31, 54, & + 4, 36, 78, & + 5, 45, 65, & + 6, 57, 85, & + 7, 14, 49, & + 8, 21, 46, & + 9, 15, 72, & + 10, 20, 62, & + 11, 17, 71, & + 12, 34, 47, & + 13, 68, 86, & + 18, 23, 43, & + 19, 64, 73, & + 24, 48, 79, & + 25, 70, 83, & + 26, 80, 87, & + 27, 32, 40, & + 28, 56, 69, & + 29, 63, 66, & + 30, 42, 50, & + 33, 37, 82, & + 35, 60, 74, & + 38, 55, 84, & + 44, 52, 61, & + 51, 53, 72, & + 58, 59, 67, & + 47, 56, 76, & + 1, 19, 37, & + 2, 61, 75, & + 3, 8, 66, & + 4, 60, 84, & + 5, 34, 39, & + 6, 26, 53, & + 7, 32, 57, & + 9, 52, 67, & + 10, 12, 15, & + 11, 51, 69, & + 13, 14, 65, & + 16, 31, 43, & + 17, 20, 36, & + 18, 80, 86, & + 21, 48, 59, & + 22, 40, 46, & + 23, 33, 62, & + 24, 30, 74, & + 25, 42, 64, & + 27, 49, 85, & + 28, 38, 73, & + 29, 44, 81, & + 35, 68, 70, & + 41, 63, 76, & + 45, 49, 71, & + 50, 58, 87, & + 48, 54, 83, & + 13, 55, 79, & + 77, 78, 82, & + 1, 2, 24, & + 3, 6, 75, & + 4, 56, 87, & + 5, 44, 53, & + 7, 50, 83, & + 8, 10, 28, & + 9, 55, 62, & + 11, 29, 67, & + 12, 33, 40, & + 14, 16, 20, & + 15, 35, 73, & + 17, 31, 39, & + 18, 36, 57, & + 19, 46, 76, & + 21, 42, 84, & + 22, 34, 59, & + 23, 26, 61, & + 25, 60, 65, & + 27, 64, 80, & + 30, 37, 66, & + 32, 45, 72, & + 38, 51, 86, & + 41, 77, 79, & + 43, 56, 68, & + 47, 74, 82, & + 40, 52, 78, & + 54, 61, 71, & + 46, 58, 69/ + +data Nm/ & + 1, 30, 60, 89, 118, 147, 0, & + 2, 31, 61, 90, 119, 147, 0, & + 3, 32, 62, 91, 120, 148, 0, & + 4, 33, 63, 92, 121, 149, 0, & + 2, 34, 64, 93, 122, 150, 0, & + 5, 33, 65, 94, 123, 148, 0, & + 6, 34, 66, 95, 124, 151, 0, & + 7, 35, 67, 96, 120, 152, 0, & + 8, 36, 68, 97, 125, 153, 0, & + 9, 37, 69, 98, 126, 152, 0, & + 10, 38, 70, 99, 127, 154, 0, & + 11, 39, 71, 100, 126, 155, 0, & + 12, 40, 61, 101, 128, 145, 0, & + 10, 33, 60, 95, 128, 156, 0, & + 13, 41, 72, 97, 126, 157, 0, & + 13, 42, 73, 90, 129, 156, 0, & + 14, 39, 74, 99, 130, 158, 0, & + 15, 43, 75, 102, 131, 159, 0, & + 16, 43, 71, 103, 118, 160, 0, & + 17, 44, 76, 98, 130, 156, 0, & + 18, 45, 60, 96, 132, 161, 0, & + 19, 46, 73, 83, 133, 162, 0, & + 12, 38, 77, 102, 134, 163, 0, & + 19, 47, 78, 104, 135, 147, 0, & + 1, 32, 77, 105, 136, 164, 0, & + 20, 48, 73, 106, 123, 163, 0, & + 21, 41, 79, 107, 137, 165, 0, & + 22, 42, 66, 108, 138, 152, 0, & + 18, 42, 80, 109, 139, 154, 0, & + 23, 49, 81, 110, 135, 166, 0, & + 16, 50, 82, 91, 129, 158, 0, & + 3, 48, 63, 107, 124, 167, 0, & + 6, 51, 67, 111, 134, 155, 0, & + 24, 35, 77, 100, 122, 162, 0, & + 20, 45, 76, 112, 140, 157, 0, & + 21, 36, 64, 92, 130, 159, 0, & + 8, 52, 83, 111, 118, 166, 0, & + 21, 53, 84, 113, 138, 168, 0, & + 25, 51, 79, 89, 122, 158, 0, & + 22, 44, 75, 107, 133, 155, 172, & + 9, 54, 84, 90, 141, 169, 0, & + 22, 54, 85, 110, 136, 161, 0, & + 8, 37, 65, 102, 129, 170, 0, & + 19, 39, 85, 114, 139, 150, 0, & + 26, 55, 71, 93, 142, 167, 0, & + 27, 56, 65, 96, 133, 160, 174, & + 28, 31, 86, 100, 117, 171, 0, & + 28, 52, 70, 104, 132, 144, 0, & + 24, 57, 68, 95, 137, 142, 0, & + 7, 30, 72, 110, 143, 151, 0, & + 4, 51, 76, 115, 127, 168, 0, & + 16, 45, 87, 114, 125, 172, 0, & + 15, 30, 86, 115, 123, 150, 0, & + 23, 46, 64, 91, 144, 173, 0, & + 23, 35, 75, 113, 145, 153, 0, & + 14, 41, 87, 108, 117, 149, 170, & + 25, 40, 85, 94, 124, 159, 0, & + 25, 58, 69, 116, 143, 174, 0, & + 29, 43, 61, 116, 132, 162, 0, & + 15, 58, 88, 112, 121, 164, 0, & + 4, 59, 72, 114, 119, 163, 173, & + 27, 47, 86, 98, 134, 153, 0, & + 5, 44, 78, 109, 141, 0, 0, & + 10, 46, 69, 103, 136, 165, 0, & + 9, 50, 59, 93, 128, 164, 0, & + 14, 57, 58, 109, 120, 166, 0, & + 17, 55, 62, 116, 125, 154, 0, & + 3, 54, 70, 101, 140, 170, 0, & + 1, 36, 82, 108, 127, 174, 0, & + 5, 53, 81, 105, 140, 0, 0, & + 29, 53, 67, 99, 142, 173, 0, & + 18, 49, 74, 97, 115, 167, 0, & + 2, 57, 63, 103, 138, 157, 0, & + 26, 38, 79, 112, 135, 171, 0, & + 11, 52, 66, 88, 119, 148, 0, & + 20, 40, 68, 117, 141, 160, 0, & + 11, 48, 81, 89, 146, 169, 0, & + 29, 47, 80, 92, 146, 172, 0, & + 6, 32, 87, 104, 145, 169, 0, & + 27, 34, 74, 106, 131, 165, 0, & + 12, 56, 84, 88, 139, 0, 0, & + 13, 56, 62, 111, 146, 171, 0, & + 26, 37, 80, 105, 144, 151, 0, & + 17, 31, 82, 113, 121, 161, 0, & + 28, 49, 59, 94, 137, 0, 0, & + 7, 55, 83, 101, 131, 168, 0, & + 24, 50, 78, 106, 143, 149, 0/ + +data nrw/ & + 6,6,6,6,6,6,6,6,6,6, & + 6,6,6,6,6,6,6,6,6,6, & + 6,6,6,6,6,6,6,6,6,6, & + 6,6,6,6,6,6,6,6,6,7, & + 6,6,6,6,6,7,6,6,6,6, & + 6,6,6,6,6,7,6,6,6,6, & + 7,6,5,6,6,6,6,6,6,5, & + 6,6,6,6,6,6,6,6,6,6, & + 5,6,6,6,5,6,6/ + +ncw=3 + +toc=0 +tov=0 +tanhtoc=0 +!write(*,*) llr +! initialize messages to checks +do j=1,M + do i=1,nrw(j) + toc(i,j)=llr((Nm(i,j))) + enddo +enddo + +ncnt=0 + +do iter=0,maxiterations + +! Update bit log likelihood ratios (tov=0 in iteration 0). + do i=1,N + if( apmask(i) .ne. 1 ) then + zn(i)=llr(i)+sum(tov(1:ncw,i)) + else + zn(i)=llr(i) + endif + enddo + +! Check to see if we have a codeword (check before we do any iteration). + cw=0 + where( zn .gt. 0. ) cw=1 + ncheck=0 + do i=1,M + synd(i)=sum(cw(Nm(1:nrw(i),i))) + if( mod(synd(i),2) .ne. 0 ) ncheck=ncheck+1 +! if( mod(synd(i),2) .ne. 0 ) write(*,*) 'check ',i,' unsatisfied' + enddo +!write(*,*) 'number of unsatisfied parity checks ',ncheck + if( ncheck .eq. 0 ) then ! we have a codeword - reorder the columns and return it +! niterations=iter + codeword=cw(colorder+1) + decoded=codeword(M+1:N) + nerr=0 + do i=1,N + if( (2*cw(i)-1)*llr(i) .lt. 0.0 ) nerr=nerr+1 + enddo + niterations=nerr + return + endif + + if( iter.gt.0 ) then ! this code block implements an early stopping criterion +! if( iter.gt.10000 ) then ! this code block implements an early stopping criterion + nd=ncheck-nclast + if( nd .lt. 0 ) then ! # of unsatisfied parity checks decreased + ncnt=0 ! reset counter + else + ncnt=ncnt+1 + endif +! write(*,*) iter,ncheck,nd,ncnt + if( ncnt .ge. 5 .and. iter .ge. 10 .and. ncheck .gt. 15) then + niterations=-1 + return + endif + endif + nclast=ncheck + +! Send messages from bits to check nodes + do j=1,M + do i=1,nrw(j) + ibj=Nm(i,j) + toc(i,j)=zn(ibj) + do kk=1,ncw ! subtract off what the bit had received from the check + if( Mn(kk,ibj) .eq. j ) then + toc(i,j)=toc(i,j)-tov(kk,ibj) + endif + enddo + enddo + enddo + +! send messages from check nodes to variable nodes + do i=1,M + tanhtoc(1:7,i)=tanh(-toc(1:7,i)/2) + enddo + + do j=1,N + do i=1,ncw + ichk=Mn(i,j) ! Mn(:,j) are the checks that include bit j + Tmn=product(tanhtoc(1:nrw(ichk),ichk),mask=Nm(1:nrw(ichk),ichk).ne.j) + call platanh(-Tmn,y) +! y=atanh(-Tmn) + tov(i,j)=2*y + enddo + enddo + +enddo +niterations=-1 +return +end subroutine bpdecode174 diff --git a/lib/fsk4hf/encode174.f90 b/lib/fsk4hf/encode174.f90 new file mode 100644 index 000000000..8ef463e89 --- /dev/null +++ b/lib/fsk4hf/encode174.f90 @@ -0,0 +1,50 @@ +subroutine encode174(message,codeword) +! Encode an 101-bit message and return a 174-bit codeword. +! The generator matrix has dimensions (73,101). +! The code is a (174,101) regular ldpc code with column weight 3. +! The code was generated using the PEG algorithm. +! After creating the codeword, the columns are re-ordered according to +! "colorder" to make the codeword compatible with the parity-check matrix +! + +include "ldpc_174_87_params.f90" + +integer*1 codeword(N) +integer*1 gen(M,K) +integer*1 itmp(N) +integer*1 message(K) +integer*1 pchecks(M) +logical first +data first/.true./ + +save first,gen + +if( first ) then ! fill the generator matrix + gen=0 + do i=1,M + do j=1,11 + read(g(i)( (j-1)*2+1:(j-1)*2+2 ),"(Z2)") istr + do jj=1, 8 + icol=(j-1)*8+jj + if( icol .le. 87 ) then + if( btest(istr,8-jj) ) gen(i,icol)=1 + endif + enddo + enddo + enddo +first=.false. +endif + +do i=1,M + nsum=0 + do j=1,K + nsum=nsum+message(j)*gen(i,j) + enddo + pchecks(i)=mod(nsum,2) +enddo +itmp(1:M)=pchecks +itmp(M+1:N)=message(1:K) +codeword(colorder+1)=itmp(1:N) + +return +end subroutine encode174 diff --git a/lib/fsk4hf/ldpc_174_87_params.f90 b/lib/fsk4hf/ldpc_174_87_params.f90 new file mode 100644 index 000000000..08ee971e7 --- /dev/null +++ b/lib/fsk4hf/ldpc_174_87_params.f90 @@ -0,0 +1,103 @@ +integer, parameter:: N=174, K=87, M=N-K +character*22 g(87) +integer colorder(N) +data g/ & !parity generator matrix for (174,87) code +"23bba830e23b6b6f509828", & +"1f8e55da218c5df3309050", & +"ca7b3217cd92bd59a5ae20", & +"56f78313537d0f43829648", & +"29c29dba9c545e267762f8", & +"6be396b5e2e819e3733408", & +"293548a138858328af4210", & +"cb6c6afcdc28bb3f7c6e80", & +"3f2a86f5c5bd225c961150", & +"849dd2d63673481860f628", & +"56cdaec6e7ae14b43feee8", & +"04ef5cfa3766ba778f45a0", & +"c525ae4bd4f627320a3970", & +"fe37802941d66dde02b998", & +"41fd9520b2e4abeb2f9898", & +"40907b01280f03c0323940", & +"7fb36c24085a34d8c1dbc0", & +"40fc3e44bb7d2bb2756e40", & +"d38ab0a1d2e52a8ec3bc70", & +"3d0f929ef3949bd84d4730", & +"45d3814f504064f80549a8", & +"f14dbf263825d0bd04b058", & +"f08a91fb2e1f78290619a8", & +"7a8dec79a51e8ac5388020", & +"ca4186dd44c3121565cf58", & +"db714f8f64e8ac7af1a768", & +"8d0274de71e7c1a8055eb0", & +"51f81573dd4049b082de10", & +"d037db825175d851f3af00", & +"d8f937f31822e57c562370", & +"1bf1490607c54032660ed8", & +"1616d78018d0b4745ca0f0", & +"a9fa8e50bcb032c85e3300", & +"83f640f1a48a8ebc0443e8", & +"eca9afa0f6b01d92305ed8", & +"3776af54ccfbae916afde0", & +"6abb212d9739dfc02580f0", & +"05209a0abb530b9e7e34b0", & +"612f63acc025b6ab476f78", & +"0af7723161ec223080be80", & +"a8fc906976c35669e79ce0", & +"45b7ab6242b77474d9f118", & +"b274db8abd3c6f396ea350", & +"9059dfa2bb20ef7ef73ad0", & +"3d188ea477f6fa41317a48", & +"8d9071b7e7a6a2eed69658", & +"a377253773ea678367c3f0", & +"ecbd7c73b9cd34c3720c88", & +"b6537f417e61d1a7085330", & +"6c280d2a0523d9c4bc5940", & +"d36d662a69ae24b74dcbd8", & +"d747bfc5fd65ef70fbd9b8", & +"a9fa2eefa6f8796a355770", & +"cc9da55fe046d0cb3a7708", & +"f6ad4824b87c80ebfce460", & +"cc6de59755420925f90ed0", & +"164cc861bdd803c547f2a8", & +"c0fc3ec4fb7d2bb2756640", & +"0dbd816fba1543f721dc70", & +"a0c0033a52ab6299802fd0", & +"bf4f56e073271f6ab4bf80", & +"57da6d13cb96a7689b2790", & +"81cfc6f18c35b1e1f17110", & +"481a2a0df8a23583f82d68", & +"1ac4672b549cd6dba79bc8", & +"c87af9a5d5206abca532a8", & +"97d4169cb33e7435718d90", & +"a6573f3dc8b16c9d19f740", & +"2c4142bf42b01e71076ac8", & +"081c29a10d468ccdbcecb0", & +"5b0f7742bca86b80126098", & +"012dee2198eba82b19a1d8", & +"f1627701a2d692fd9449e0", & +"35ad3fb0faeb5f1b0c30d8", & +"b1ca4ea2e3d173bad43798", & +"37d8e0af9258b9e8c5f9b0", & +"cd921fdf59e882683763f0", & +"6114e08483043fd3f38a88", & +"2e547dd7a05f6597aac510", & +"95e45ecd0135aca9d6e6a8", & +"b33ec97be83ce413f9acc8", & +"c8b5dffc335095dcdcaf28", & +"3dd01a59d86310743ec750", & +"14cd0f642fc0c5fe3a65c8", & +"3a0a1dfd7eee29c2e827e0", & +"8abdb889efbe39a510a118", & +"3f231f212055371cf3e2a0"/ + +data colorder/ & + 0, 1, 2, 3, 30, 4, 5, 6, 7, 8, 9, 10, 11, 32, 12, 40, 13, 14, 15, 16,& + 17, 18, 37, 45, 29, 19, 20, 21, 41, 22, 42, 31, 33, 34, 44, 35, 47, 51, 50, 43,& + 36, 52, 63, 46, 25, 55, 27, 24, 23, 53, 39, 49, 59, 38, 48, 61, 60, 57, 28, 62,& + 56, 58, 65, 66, 26, 70, 64, 69, 68, 67, 74, 71, 54, 76, 72, 75, 78, 77, 80, 79,& + 73, 83, 84, 81, 82, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99,& + 100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,& + 120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,& + 140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,& + 160,161,162,163,164,165,166,167,168,169,170,171,172,173/ + diff --git a/lib/fsk4hf/ldpcsim174.f90 b/lib/fsk4hf/ldpcsim174.f90 new file mode 100644 index 000000000..57486eb77 --- /dev/null +++ b/lib/fsk4hf/ldpcsim174.f90 @@ -0,0 +1,241 @@ +program ldpcsim174 +! End to end test of the (174,75)/crc12 encoder and decoder. +use crc +use packjt + +parameter(NRECENT=10) +character*12 recent_calls(NRECENT) +character*22 msg,msgsent,msgreceived +character*8 arg +integer*1, allocatable :: codeword(:), decoded(:), message(:) +integer*1, target:: i1Msg8BitBytes(11) +integer*1 msgbits(87) +integer*1 apmask(174), cw(174) +integer*2 checksum +integer*4 i4Msg6BitWords(13) +integer colorder(174) +integer nerrtot(174),nerrdec(174),nmpcbad(87) +logical checksumok,fsk,bpsk +real*8, allocatable :: rxdata(:) +real, allocatable :: llr(:) + +data colorder/ & + 0, 1, 2, 3, 30, 4, 5, 6, 7, 8, 9, 10, 11, 32, 12, 40, 13, 14, 15, 16,& + 17, 18, 37, 45, 29, 19, 20, 21, 41, 22, 42, 31, 33, 34, 44, 35, 47, 51, 50, 43,& + 36, 52, 63, 46, 25, 55, 27, 24, 23, 53, 39, 49, 59, 38, 48, 61, 60, 57, 28, 62,& + 56, 58, 65, 66, 26, 70, 64, 69, 68, 67, 74, 71, 54, 76, 72, 75, 78, 77, 80, 79,& + 73, 83, 84, 81, 82, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99,& + 100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,& + 120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,& + 140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,& + 160,161,162,163,164,165,166,167,168,169,170,171,172,173/ + +do i=1,NRECENT + recent_calls(i)=' ' +enddo +nerrtot=0 +nerrdec=0 +nmpcbad=0 ! Used to collect the number of errors in the message+crc part of the codeword + +nargs=iargc() +if(nargs.ne.4) then + print*,'Usage: ldpcsim niter norder #trials s ' + print*,'eg: ldpcsim 10 2 1000 0.84' + print*,'belief propagation iterations: niter, ordered-statistics order: norder' + print*,'If s is negative, then value is ignored and sigma is calculated from SNR.' + return +endif +call getarg(1,arg) +read(arg,*) max_iterations +call getarg(2,arg) +read(arg,*) norder +call getarg(3,arg) +read(arg,*) ntrials +call getarg(4,arg) +read(arg,*) s + +fsk=.false. +bpsk=.true. + +! don't count crc bits as data bits +N=174 +K=87 +! scale Eb/No for a (174,87) code +rate=real(87)/real(N) + +write(*,*) "rate: ",rate +write(*,*) "niter= ",max_iterations," s= ",s + +allocate ( codeword(N), decoded(K), message(K) ) +allocate ( rxdata(N), llr(N) ) + +! msg="K1JT K9AN EN50" + msg="G4WJS K9AN EN50" + call packmsg(msg,i4Msg6BitWords,itype) !Pack into 12 6-bit bytes + call unpackmsg(i4Msg6BitWords,msgsent) !Unpack to get msgsent + write(*,*) "message sent ",msgsent + + i4=0 + ik=0 + im=0 + do i=1,12 + nn=i4Msg6BitWords(i) + do j=1, 6 + ik=ik+1 + i4=i4+i4+iand(1,ishft(nn,j-6)) + i4=iand(i4,255) + if(ik.eq.8) then + im=im+1 +! if(i4.gt.127) i4=i4-256 + i1Msg8BitBytes(im)=i4 + ik=0 + endif + enddo + enddo + + i1Msg8BitBytes(10:11)=0 + checksum = crc12 (c_loc (i1Msg8BitBytes), 11) +! For reference, the next 3 lines show how to check the CRC + i1Msg8BitBytes(10)=checksum/256 + i1Msg8BitBytes(11)=iand (checksum,255) + checksumok = crc12_check(c_loc (i1Msg8BitBytes), 11) + if( checksumok ) write(*,*) 'Good checksum' + +! K=87, For now: +! msgbits(1:72) JT message bits +! msgbits(73:75) 3 free message bits (set to 0) +! msgbits(76:87) CRC12 + mbit=0 + do i=1, 9 + i1=i1Msg8BitBytes(i) + do ibit=1,8 + mbit=mbit+1 + msgbits(mbit)=iand(1,ishft(i1,ibit-8)) + enddo + enddo + msgbits(73:75)=0 ! the three extra message bits go here + i1=i1Msg8BitBytes(10) ! First 4 bits of crc12 are LSB of this byte + do ibit=1,4 + msgbits(75+ibit)=iand(1,ishft(i1,ibit-4)) + enddo + i1=i1Msg8BitBytes(11) ! Now shift in last 8 bits of the CRC + do ibit=1,8 + msgbits(79+ibit)=iand(1,ishft(i1,ibit-8)) + enddo + + write(*,*) 'message' + write(*,'(11(8i1,1x))') msgbits + + call encode174(msgbits,codeword) + call init_random_seed() + call sgran() + + write(*,*) 'codeword' + write(*,'(22(8i1,1x))') codeword + +write(*,*) "Es/N0 SNR2500 ngood nundetected nbadcrc sigma" +do idb = 14,-6,-1 + db=idb/2.0-1.0 + sigma=1/sqrt( 2*(10**(db/10.0)) ) + ngood=0 + nue=0 + nbadcrc=0 + nberr=0 + do itrial=1, ntrials +! Create a realization of a noisy received word + do i=1,N + if( bpsk ) then + rxdata(i) = 2.0*codeword(i)-1.0 + sigma*gran() + elseif( fsk ) then + if( codeword(i) .eq. 1 ) then + r1=(1.0 + sigma*gran())**2 + (sigma*gran())**2 + r2=(sigma*gran())**2 + (sigma*gran())**2 + elseif( codeword(i) .eq. 0 ) then + r2=(1.0 + sigma*gran())**2 + (sigma*gran())**2 + r1=(sigma*gran())**2 + (sigma*gran())**2 + endif + rxdata(i)=0.35*(sqrt(r1)-sqrt(r2)) +! rxdata(i)=0.35*(exp(r1)-exp(r2)) +! rxdata(i)=0.12*(log(r1)-log(r2)) + endif + enddo + nerr=0 + do i=1,N + if( rxdata(i)*(2*codeword(i)-1.0) .lt. 0 ) nerr=nerr+1 + enddo + nerrtot(nerr)=nerrtot(nerr)+1 + nberr=nberr+nerr + +! Correct signal normalization is important for this decoder. +! rxav=sum(rxdata)/N +! rx2av=sum(rxdata*rxdata)/N +! rxsig=sqrt(rx2av-rxav*rxav) +! rxdata=rxdata/rxsig +! To match the metric to the channel, s should be set to the noise standard deviation. +! For now, set s to the value that optimizes decode probability near threshold. +! The s parameter can be tuned to trade a few tenth's dB of threshold for an order of +! magnitude in UER + if( s .lt. 0 ) then + ss=sigma + else + ss=s + endif + + llr=2.0*rxdata/(ss*ss) + nap=0 ! number of AP bits + llr(colorder(174-87+1:174-87+nap)+1)=5*(2.0*msgbits(1:nap)-1.0) + apmask=0 + apmask(colorder(174-87+1:174-87+nap)+1)=1 + +! max_iterations is max number of belief propagation iterations + call bpdecode174(llr, apmask, max_iterations, decoded, niterations) +ni1=niterations + if( norder .ge. 0 .and. niterations .lt. 0 ) call osd174(llr, norder, decoded, niterations, cw) +ni2=niterations +! If the decoder finds a valid codeword, niterations will be .ge. 0. + if( niterations .ge. 0 ) then + call extractmessage174(decoded,msgreceived,ncrcflag,recent_calls,nrecent) + if( ncrcflag .ne. 1 ) then + nbadcrc=nbadcrc+1 + endif + + nueflag=0 + nerrmpc=0 + do i=1,K ! find number of errors in message+crc part of codeword + if( msgbits(i) .ne. decoded(i) ) then + nueflag=1 + nerrmpc=nerrmpc+1 + endif + enddo + nmpcbad(nerrmpc)=nmpcbad(nerrmpc)+1 + + if( ncrcflag .eq. 1 ) then + if( nueflag .eq. 0 ) then + ngood=ngood+1 + nerrdec(nerr)=nerrdec(nerr)+1 + else if( nueflag .eq. 1 ) then + nue=nue+1; + endif + endif + endif + enddo + snr2500=db+10*log10(6.08/2500.0) + pberr=real(nberr)/(real(ntrials*N)) + write(*,"(f4.1,4x,f5.1,1x,i8,1x,i8,1x,i8,8x,f5.2,8x,e10.3)") db,snr2500,ngood,nue,nbadcrc,ss,pberr + +enddo + +open(unit=23,file='nerrhisto.dat',status='unknown') +do i=1,174 + write(23,'(i4,2x,i10,i10,f10.2)') i,nerrdec(i),nerrtot(i),real(nerrdec(i))/real(nerrtot(i)+1e-10) +enddo +close(23) +open(unit=25,file='nmpcbad.dat',status='unknown') +do i=1,87 + write(25,'(i4,2x,i10)') i,nmpcbad(i) +enddo +close(25) + + + +end program ldpcsim174 diff --git a/lib/fsk4hf/osd174.f90 b/lib/fsk4hf/osd174.f90 new file mode 100644 index 000000000..6fcee3c61 --- /dev/null +++ b/lib/fsk4hf/osd174.f90 @@ -0,0 +1,151 @@ +subroutine osd174(llr,norder,decoded,niterations,cw) +! +! An ordered-statistics decoder based on ideas from: +! "Soft-decision decoding of linear block codes based on ordered statistics," +! by Marc P. C. Fossorier and Shu Lin, +! IEEE Trans Inf Theory, Vol 41, No 5, Sep 1995 +! + +include "ldpc_174_87_params.f90" + +integer*1 gen(K,N) +integer*1 genmrb(K,N) +integer*1 temp(K),m0(K),me(K) +integer indices(N) +integer*1 codeword(N),cw(N),hdec(N) +integer*1 decoded(K) +integer indx(N) +real llr(N),rx(N),absrx(N) +logical first +data first/.true./ + +save first,gen + +if( first ) then ! fill the generator matrix + gen=0 + do i=1,M + do j=1,21 + read(g(i)(j:j),"(Z1)") istr + do jj=1, 4 + irow=(j-1)*4+jj + if( irow .le. K ) then + if( btest(istr,4-jj) ) gen(irow,i)=1 + endif + enddo + enddo + enddo + do irow=1,K + gen(irow,M+irow)=1 + enddo +first=.false. +endif + +! re-order received vector to place systematic msg bits at the end +rx=llr(colorder+1) + +! hard decode the received word +hdec=0 +where(rx .ge. 0) hdec=1 + +! use magnitude of received symbols as a measure of reliability. +absrx=abs(rx) +call indexx(absrx,N,indx) +! re-order the columns of the generator matrix in order of increasing reliability. +do i=1,N + genmrb(1:K,N+1-i)=gen(1:K,indx(N+1-i)) +enddo + +! do gaussian elimination to create a generator matrix with the most reliable +! received bits as the systematic bits. if it happens that the K most reliable +! bits are not independent, then we dip into the bits just below the K best bits +! to find K independent most reliable bits. the "indices" array tracks column +! permutations caused by reliability sorting and gaussian elimination. +do i=1,N + indices(i)=indx(i) +enddo +do id=1,K ! diagonal element indices + do ic=id,K+20 ! The 20 is ad hoc - beware + icol=N-K+ic + if( icol .gt. N ) icol=M+1-(icol-N) + iflag=0 + if( genmrb(id,icol) .eq. 1 ) then + iflag=1 + if( icol-M .ne. id ) then ! reorder column + temp(1:K)=genmrb(1:K,M+id) + genmrb(1:K,M+id)=genmrb(1:K,icol) + genmrb(1:K,icol)=temp(1:K) + itmp=indices(M+id) + indices(M+id)=indices(icol) + indices(icol)=itmp + endif + do ii=1,K + if( ii .ne. id .and. genmrb(ii,N-K+id) .eq. 1 ) then + genmrb(ii,1:N)=mod(genmrb(ii,1:N)+genmrb(id,1:N),2) + endif + enddo + exit + endif + enddo +enddo + +! use the hard decisions for the K MRB bits to define the order 0 +! message, m0. Encode m0 using the modified generator matrix to +! find the order 0 codeword. Flip all combinations of N bits in m0 +! and re-encode to find the list of order N codewords. Test all such +! codewords against the received word to decide which codeword is +! most likely to be correct. +m0=0 +where (rx(indices(M+1:N)).ge.0.0) m0=1 + +nhardmin=N +corrmax=-1.0e32 +j0=0 +j1=0 +j2=0 +j3=0 +if( norder.ge.4 ) j0=K +if( norder.ge.3 ) j1=K +if( norder.ge.2 ) j2=K +if( norder.ge.1 ) j3=K +nt=0 +do i1=0,j0 + do i2=i1,j1 + do i3=i2,j2 + do i4=i3,j3 +nt=nt+1 + me=m0 + if( i1 .ne. 0 ) me(i1)=1-me(i1) + if( i2 .ne. 0 ) me(i2)=1-me(i2) + if( i3 .ne. 0 ) me(i3)=1-me(i3) + if( i4 .ne. 0 ) me(i4)=1-me(i4) + +! me is the m0 + error pattern. encode this message using genmrb to +! produce a codeword. test the codeword against the received vector +! and save it if it's the best that we've seen so far. + do i=1,N + nsum=sum(iand(me,genmrb(1:K,i))) + codeword(i)=mod(nsum,2) + enddo +! undo the bit re-ordering to put the "real" message bits at the end + codeword(indices)=codeword + nhard=count(codeword .ne. hdec) +! corr=sum(codeword*rx) ! to save time use nhard to pick best codeword + if( nhard .lt. nhardmin ) then +! if( corr .gt. corrmax ) then + cw=codeword + nhardmin=nhard +! corrmax=corr + i1min=i1 + i2min=i2 + i3min=i3 + i4min=i4 + if( nhardmin .le. 5 ) goto 200 ! early exit - tune for each code + endif + enddo + enddo + enddo +enddo +200 decoded=cw(M+1:N) +niterations=nhardmin +return +end subroutine osd174