mirror of
https://github.com/saitohirga/WSJT-X.git
synced 2025-05-28 20:32:28 -04:00
Moving from JT8 to JT9, and working toward program jt9sim.
git-svn-id: svn+ssh://svn.code.sf.net/p/wsjt/wsjt/branches/wsjtx@2602 ab8295b8-cf94-4d9e-aec4-7959e3be5d79
This commit is contained in:
parent
4caf2ddec0
commit
32171f3696
65
jt9.txt
Normal file
65
jt9.txt
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
JT9 is a mode designed for amateur QSOs and beacon-like transmissions
|
||||||
|
at MF and LF. The mode uses the same 72-bit user messages as JT65,
|
||||||
|
augmented by a 12-bit cyclic redundancy check (CRC). Error-control
|
||||||
|
coding uses a convolutional code with constraint length K=16, rate
|
||||||
|
r=1/2, and a zero tail, leading to an encoded message length of
|
||||||
|
(72+12+15)*2 = 198 bits. Modulation is 9-FSK -- 8 tones for data, and
|
||||||
|
one for a synchronization vector. With 15 symbol intervals used for
|
||||||
|
synchronization, a transmission requires a total of 198/3 + 15 = 81
|
||||||
|
channel symbols. Tone spacing df of the 9-FSK modulation is equal to
|
||||||
|
the keying rate; symbol duration tsym = 1/df, and the total occupied
|
||||||
|
bandwidth is 9*df. Transmission length is slightly less than the T/R
|
||||||
|
sequence time, to allow for message decoding at time Tdec, a time
|
||||||
|
Tfree seconds before the next transmission starts.
|
||||||
|
|
||||||
|
Parameters of the five JT9 sub-modes are summarized in the following
|
||||||
|
table, along with S/N thresholds measured by simulation on an AWGN
|
||||||
|
(additive white Gaussian noise) channel. Parameter nsps1 is the number
|
||||||
|
of samples per symbol at sample rate 12000 Hz; nsps is the same
|
||||||
|
quantity at 750 Hz.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
Mode nsps1 nsps df tsym BW S/N* Tdec Tfree Factors
|
||||||
|
12000 750 (Hz) (s) (Hz) (dB) (s) (s) of nsps
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
JT9-1 7168 448 1.674 0.60 15.1 -26.9 51.9 8.1 2^10 7
|
||||||
|
JT9-2 16000 1000 0.750 1.33 6.8 -30.2 111.5 8.5 2^7 5^3
|
||||||
|
JT9-5 42336 2646 0.283 3.53 2.5 -34.4 289.4 10.6 2^5 3^3 7^2
|
||||||
|
JT9-10 86400 5400 0.139 7.20 1.3 -37.5 586.7 13.3 2^7 3^3 5^2
|
||||||
|
JT9-30 262144 16384 0.046 21.85 0.4 -42.3 1773.4 26.6 2^18
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
* Noise power measured in a 2500 Hz bandwidth.
|
||||||
|
|
||||||
|
|
||||||
|
Transmitting
|
||||||
|
------------
|
||||||
|
1. Source encode the structured message to 72 bits
|
||||||
|
2. Add 12-bit CRC
|
||||||
|
3. Convolutionally encode (K=16, r=1/2) to (72+12+15)*2 = 198 bits
|
||||||
|
4. Interleave to scramble the bit order
|
||||||
|
5. Assemble 3-bit groups to make 198/3 = 66 symbols
|
||||||
|
6. Apply Gray code to the symbol values
|
||||||
|
7. Insert 15 sync symbols ==> 66+15=81 channel symbols with values 0-8
|
||||||
|
|
||||||
|
|
||||||
|
Receiving
|
||||||
|
---------
|
||||||
|
1. Apply noise blanking with the timf2 method
|
||||||
|
2. Filter to 500 Hz bandwidth, downsample (1/16) to 750 Hz complex
|
||||||
|
using FIR filter with 61 taps. Data in array c0(1800*750) (1.35M)
|
||||||
|
3. Compute symbol-length spectra at half-symbol steps. Use for
|
||||||
|
waterfalls s(16384) and save in ss(180,16384), savg(16384)
|
||||||
|
4. At time Tdec, look for sync vectors in ss() to get estimates of DF, DT
|
||||||
|
5. Do full-length FFTs of length NFFT1=96*nsps
|
||||||
|
6. For each candidate JT9 signal, do inverse FFT of length 1536. This
|
||||||
|
gives 16 complex samples per symbol, sync tone should be close to f=0.
|
||||||
|
7. Use afc65b method to get improved values of DF, DT.
|
||||||
|
8. Tweak freq and time offset to 0.
|
||||||
|
9. Compute 8-bin spectra of 66 data symbols: s2(8,66). Re-order the
|
||||||
|
bins by removing Gray code.
|
||||||
|
10. Compute soft symbols for 198 bits
|
||||||
|
11. Re-order the bits by removing interleaving.
|
||||||
|
12. Pack bits into bytes, send to Viterbi decoder ==> 72-bit message,
|
||||||
|
12-bit CRC, and metric.
|
||||||
|
13. Declare erasure if CRC check fails
|
||||||
|
14. If CRC is good, remove source encoding and display user message.
|
@ -3,7 +3,7 @@ CC = gcc
|
|||||||
FC = g95
|
FC = g95
|
||||||
|
|
||||||
FFLAGS = -O2 -fbounds-check -Wall -Wno-precision-loss -fno-second-underscore
|
FFLAGS = -O2 -fbounds-check -Wall -Wno-precision-loss -fno-second-underscore
|
||||||
CFLAGS = -I. -fbounds-check
|
CFLAGS = -I. -fbounds-check -mno-stack-arg-probe
|
||||||
|
|
||||||
# Default rules
|
# Default rules
|
||||||
%.o: %.c
|
%.o: %.c
|
||||||
@ -17,7 +17,7 @@ CFLAGS = -I. -fbounds-check
|
|||||||
%.o: %.F90
|
%.o: %.F90
|
||||||
${FC} ${FFLAGS} -c $<
|
${FC} ${FFLAGS} -c $<
|
||||||
|
|
||||||
all: libm65.a msk.exe
|
all: libm65.a jt9sim.exe
|
||||||
|
|
||||||
OBJS1 = trimlist.o display.o getdphi.o pctile.o ccf65.o \
|
OBJS1 = trimlist.o display.o getdphi.o pctile.o ccf65.o \
|
||||||
decode1a.o sort.o filbig.o fil6521.o afc65b.o \
|
decode1a.o sort.o filbig.o fil6521.o afc65b.o \
|
||||||
@ -30,19 +30,20 @@ OBJS1 = trimlist.o display.o getdphi.o pctile.o ccf65.o \
|
|||||||
four2a.o rfile3a.o grid2deg.o pfxdump.o dpol.o \
|
four2a.o rfile3a.o grid2deg.o pfxdump.o dpol.o \
|
||||||
astro.o tm2.o sun.o moondop.o coord.o tmoonsub.o \
|
astro.o tm2.o sun.o moondop.o coord.o tmoonsub.o \
|
||||||
geocentric.o moon2.o toxyz.o dot.o dcoord.o f77_wisdom.o \
|
geocentric.o moon2.o toxyz.o dot.o dcoord.o f77_wisdom.o \
|
||||||
gen65.o chkmsg.o ptt.o astrosub.o astro0.o recvpkt.o symspec.o \
|
gen65.o chkmsg.o ptt.o astrosub.o astro0.o recvpkt.o symspecx.o \
|
||||||
iqcal.o iqfix.o timf2.o s3avg.o genjtms3.o analytic.o \
|
iqcal.o iqfix.o timf2.o s3avg.o genjtms3.o analytic.o \
|
||||||
db.o specjtms.o genmsk.o mskdf.o tweak1.o syncmsk.o \
|
db.o specjtms.o genmsk.o mskdf.o tweak1.o syncmsk.o \
|
||||||
lenmsk.o decodemsk.o ping.o makepings.o alignmsg.o match.o \
|
lenmsk.o decodemsk.o ping.o makepings.o alignmsg.o match.o \
|
||||||
rtping.o jtmsk.o hipass.o setupmsk.o foldmsk.o
|
rtping.o jtmsk.o hipass.o setupmsk.o foldmsk.o genjt9.o \
|
||||||
|
packbits.o unpackbits.o vit216.o tab.o
|
||||||
|
|
||||||
libm65.a: $(OBJS1)
|
libm65.a: $(OBJS1)
|
||||||
ar cr libm65.a $(OBJS1)
|
ar cr libm65.a $(OBJS1)
|
||||||
ranlib libm65.a
|
ranlib libm65.a
|
||||||
|
|
||||||
OBJS3 = msk.o
|
OBJS3 = jt9sim.o noisegen.o gran.o tab.o
|
||||||
msk.exe: $(OBJS3) libm65.a
|
jt9sim.exe: $(OBJS3) libm65.a
|
||||||
$(FC) -o msk.exe $(OBJS3) libm65.a ../libfftw3f_win.a
|
$(FC) -o jt9sim.exe $(OBJS3) libm65.a
|
||||||
|
|
||||||
OBJS2 = JT65code.o
|
OBJS2 = JT65code.o
|
||||||
JT65code.exe: $(OBJS2) libm65.a
|
JT65code.exe: $(OBJS2) libm65.a
|
||||||
|
87
libm65/genjt9.f90
Normal file
87
libm65/genjt9.f90
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
subroutine genjt9(message,minutes,lwave,msgsent,d7,iwave,nwave)
|
||||||
|
|
||||||
|
! Encodes a "JT9-minutes" message and returns array d7(81) of tone
|
||||||
|
! values in the range 0-8. If lwave is true, also returns a generated
|
||||||
|
! waveform in iwave(nwave), at 12000 samples per second.
|
||||||
|
|
||||||
|
parameter (NMAX=1800*12000) !Max length of wave file
|
||||||
|
character*22 message !Message to be generated
|
||||||
|
character*22 msgsent !Message as it will be received
|
||||||
|
character*3 cok
|
||||||
|
real*8 dt,phi,f,f0,dfgen,dphi,twopi
|
||||||
|
integer*2 iwave(NMAX) !Generated wave file
|
||||||
|
integer d0(14) !72-bit message + 12-bit CRC, as 6-bit bytes
|
||||||
|
integer*1 d1(84) !72+12 = 84 single bits
|
||||||
|
integer d2(11) !72+12 bits, as 8-bit words
|
||||||
|
integer*1 d3(11) !72+12 bits, as 8-bit bytes
|
||||||
|
integer*1 d4(198) !Encoded information-carrying bits
|
||||||
|
integer*1 d5(198) !Bits from d4, after interleaving
|
||||||
|
integer*1 d6(66) !Symbols from d5, values 0-7
|
||||||
|
integer*1 d7(66) !Gray-coded symbols, values 0-7
|
||||||
|
integer*1 d8(81) !Channel symbols including sync, values 0-8
|
||||||
|
|
||||||
|
logical lwave
|
||||||
|
integer isync(15)
|
||||||
|
data isync/1,6,11,16,21,26,31,39,45,51,57,63,69,75,81/
|
||||||
|
data twopi/6.283185307179586476d0/
|
||||||
|
save
|
||||||
|
|
||||||
|
call chkmsg(message,cok,nspecial,flip)
|
||||||
|
call packmsg(message,d0) !Pack message into 12 6-bit bytes
|
||||||
|
d0(11)=0 !### Temporary CRC=0 ###
|
||||||
|
d0(12)=0
|
||||||
|
call unpackbits(d0,14,6,d1) !Unpack into 84 bits
|
||||||
|
nbits=84
|
||||||
|
call packbits(d1,nbits,8,d2) !Pack into 11 8-bit words
|
||||||
|
nbytes=(nbits+7)/8
|
||||||
|
do i=1,nbytes
|
||||||
|
if(d2(i).lt.128) d3(i)=d2(i)
|
||||||
|
if(d2(i).ge.128) d3(i)=d2(i)-256
|
||||||
|
enddo
|
||||||
|
|
||||||
|
call enc216(d3,nbits,d4,nsym2,16,2) !Convolutional code, K=16, r=1/2
|
||||||
|
! NB: Should give nsym2 = (72+12+15)*2 = 198
|
||||||
|
|
||||||
|
! call interleavejt9(d4,1,d5)
|
||||||
|
d5=d4 !### TEMP ###
|
||||||
|
|
||||||
|
call packbits(d5,nsym2,3,d6)
|
||||||
|
! call graycode(d6,nsym2,1,d7)
|
||||||
|
|
||||||
|
! Now insert sync symbols and add 1 to the tone numbers.
|
||||||
|
|
||||||
|
nwave=0
|
||||||
|
|
||||||
|
if(lwave) then
|
||||||
|
nsps1=0
|
||||||
|
if(minutes.eq.1) nsps1=7168
|
||||||
|
if(minutes.eq.2) nsps1=16000
|
||||||
|
if(minutes.eq.5) nsps1=42336
|
||||||
|
if(minutes.eq.10) nsps1=86400
|
||||||
|
if(minutes.eq.30) nsps1=262144
|
||||||
|
if(nsps1.eq.0) stop 'Bad value for minutes in genjt9.'
|
||||||
|
|
||||||
|
! Set up necessary constants
|
||||||
|
dt=1.d0/12000.d0
|
||||||
|
f0=1500.d0
|
||||||
|
dfgen=12000.d0/nsps1
|
||||||
|
phi=0.d0
|
||||||
|
i=0
|
||||||
|
k=0
|
||||||
|
do j=1,81
|
||||||
|
f=f0 +d7(j)*dfgen
|
||||||
|
dphi=twopi*dt*f
|
||||||
|
do i=1,nsps1
|
||||||
|
phi=phi+dphi
|
||||||
|
if(phi.gt.twopi) phi=phi-twopi
|
||||||
|
xphi=phi
|
||||||
|
k=k+1
|
||||||
|
iwave(k)=32767.0*sin(xphi)
|
||||||
|
enddo
|
||||||
|
enddo
|
||||||
|
nwave=81*nsps1
|
||||||
|
endif
|
||||||
|
call unpackmsg(dgen,msgsent)
|
||||||
|
|
||||||
|
return
|
||||||
|
end subroutine genjt9
|
28
libm65/gran.c
Normal file
28
libm65/gran.c
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
#include <stdlib.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
/* Generate gaussian random float with mean=0 and std_dev=1 */
|
||||||
|
float gran_()
|
||||||
|
{
|
||||||
|
float fac,rsq,v1,v2;
|
||||||
|
static float gset;
|
||||||
|
static int iset;
|
||||||
|
|
||||||
|
if(iset){
|
||||||
|
/* Already got one */
|
||||||
|
iset = 0;
|
||||||
|
return gset;
|
||||||
|
}
|
||||||
|
/* Generate two evenly distributed numbers between -1 and +1
|
||||||
|
* that are inside the unit circle
|
||||||
|
*/
|
||||||
|
do {
|
||||||
|
v1 = 2.0 * (float)rand() / RAND_MAX - 1;
|
||||||
|
v2 = 2.0 * (float)rand() / RAND_MAX - 1;
|
||||||
|
rsq = v1*v1 + v2*v2;
|
||||||
|
} while(rsq >= 1.0 || rsq == 0.0);
|
||||||
|
fac = sqrt(-2.0*log(rsq)/rsq);
|
||||||
|
gset = v1*fac;
|
||||||
|
iset++;
|
||||||
|
return v2*fac;
|
||||||
|
}
|
117
libm65/jt9sim.f90
Normal file
117
libm65/jt9sim.f90
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
program jt9sim
|
||||||
|
|
||||||
|
! Generate simulated data for testing of MAP65
|
||||||
|
|
||||||
|
parameter (NMAX=1800*12000)
|
||||||
|
real*4 d4(NMAX) !Floating-point data
|
||||||
|
integer ihdr(11)
|
||||||
|
integer*2 id2(NMAX) !i*2 data
|
||||||
|
integer*2 iwave(NMAX) !Generated waveform (no noise)
|
||||||
|
real*8 f0,f,dt,twopi,phi,dphi,baud
|
||||||
|
character msg0*22,message*22,msgsent*22,arg*8,fname*11
|
||||||
|
logical lwave
|
||||||
|
integer*1 d7(81)
|
||||||
|
|
||||||
|
nargs=iargc()
|
||||||
|
if(nargs.ne.9) then
|
||||||
|
print*,'Usage: jt9sim "message" fspan nsigs minutes SNR nfiles'
|
||||||
|
print*,'Example: "CQ K1ABC FN42" 200 20 2 -28 1'
|
||||||
|
print*,' '
|
||||||
|
print*,'Enter message = "" to use entries in msgs.txt.'
|
||||||
|
print*,'Enter SNR = 0 to generate a range of SNRs.'
|
||||||
|
go to 999
|
||||||
|
endif
|
||||||
|
|
||||||
|
call getarg(1,msg0)
|
||||||
|
message=msg0 !Transmitted message
|
||||||
|
call getarg(2,arg)
|
||||||
|
read(arg,*) fspan !Total freq range (Hz)
|
||||||
|
call getarg(3,arg)
|
||||||
|
read(arg,*) nsigs !Number of signals in each file
|
||||||
|
call getarg(4,arg)
|
||||||
|
read(arg,*) minutes !Length of file (1 2 5 10 30 minutes)
|
||||||
|
call getarg(5,arg)
|
||||||
|
read(arg,*) snrdb !S/N in dB (2500 hz reference BW)
|
||||||
|
call getarg(6,arg)
|
||||||
|
read(arg,*) nfiles !Number of files
|
||||||
|
|
||||||
|
rmsdb=25.
|
||||||
|
rms=10.0**(0.05*rmsdb)
|
||||||
|
f0=1500.d0 !Center frequency (MHz)
|
||||||
|
fsample=12000.d0 !Sample rate (Hz)
|
||||||
|
dt=1.d0/fsample !Sample interval (s)
|
||||||
|
twopi=8.d0*atan(1.d0)
|
||||||
|
rad=360.0/twopi
|
||||||
|
npts=12000*(60*minutes-6)
|
||||||
|
lwave=.false.
|
||||||
|
nsps1=0
|
||||||
|
if(minutes.eq.1) nsps1=7168
|
||||||
|
if(minutes.eq.2) nsps1=16000
|
||||||
|
if(minutes.eq.5) nsps1=42336
|
||||||
|
if(minutes.eq.10) nsps1=86400
|
||||||
|
if(minutes.eq.30) nsps1=262144
|
||||||
|
if(nsps1.eq.0) stop 'Bad value for minutes.'
|
||||||
|
|
||||||
|
open(12,file='msgs.txt',status='old')
|
||||||
|
|
||||||
|
write(*,1000)
|
||||||
|
1000 format('File N freq S/N Message'/ &
|
||||||
|
'---------------------------------------------------')
|
||||||
|
|
||||||
|
do ifile=1,nfiles
|
||||||
|
nmin=(ifile-1)*minutes
|
||||||
|
ihr=nmin/60
|
||||||
|
imin=mod(nmin,60)
|
||||||
|
write(fname,1002) ihr,imin !Create the output filenames
|
||||||
|
1002 format('000000_',2i2.2)
|
||||||
|
open(10,file=fname//'.wav',access='stream',status='unknown')
|
||||||
|
|
||||||
|
call noisegen(d4,npts) !Generate Gaussian noise
|
||||||
|
|
||||||
|
if(msg0.ne.' ') then
|
||||||
|
call genjt9(message,minutes,lwave,msgsent,d7,iwave,nwave)
|
||||||
|
endif
|
||||||
|
|
||||||
|
rewind 12
|
||||||
|
do isig=1,nsigs
|
||||||
|
|
||||||
|
if(msg0.eq.' ') then
|
||||||
|
read(12,1004) message
|
||||||
|
1004 format(a22)
|
||||||
|
call genjt9(message,minutes,lwave,msgsent,d7,iwave,nwave)
|
||||||
|
endif
|
||||||
|
|
||||||
|
f=1500.d0
|
||||||
|
if(nsigs.gt.1) f=1500.0 - 0.5* fspan + fspan*(isig-1.0)/(nsigs-1.0)
|
||||||
|
snrdbx=snrdb
|
||||||
|
if(snrdb.ge.-1.0) snrdbx=-15.0 - 15.0*(isig-1.0)/nsigs
|
||||||
|
sig=sqrt(2.2*2500.0/96000.0) * 10.0**(0.05*snrdbx)
|
||||||
|
write(*,1020) ifile,isig,0.001*f,snrdbx,msgsent
|
||||||
|
1020 format(i3,i4,f8.3,f7.1,2x,a22)
|
||||||
|
|
||||||
|
phi=0.
|
||||||
|
baud=12000.0/nsps1
|
||||||
|
k=12000 !Start at t = 1 s
|
||||||
|
do isym=1,81
|
||||||
|
freq=f + d7(isym)*baud
|
||||||
|
dphi=twopi*freq*dt + 0.5*twopi
|
||||||
|
do i=1,nsps1
|
||||||
|
phi=phi + dphi
|
||||||
|
if(phi.lt.-twopi) phi=phi+twopi
|
||||||
|
if(phi.gt.twopi) phi=phi-twopi
|
||||||
|
xphi=phi
|
||||||
|
k=k+1
|
||||||
|
d4(k)=d4(k) + sin(phi)
|
||||||
|
enddo
|
||||||
|
enddo
|
||||||
|
enddo
|
||||||
|
|
||||||
|
do i=1,npts
|
||||||
|
id2(i)=nint(rms*d4(i))
|
||||||
|
enddo
|
||||||
|
|
||||||
|
write(10) ihdr,id2(1:npts)
|
||||||
|
close(10)
|
||||||
|
enddo
|
||||||
|
|
||||||
|
999 end program jt9sim
|
13
libm65/noisegen.f90
Normal file
13
libm65/noisegen.f90
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
subroutine noisegen(d4,nmax)
|
||||||
|
|
||||||
|
real*4 d4(4,nmax)
|
||||||
|
|
||||||
|
do i=1,nmax
|
||||||
|
d4(1,i)=gran()
|
||||||
|
d4(2,i)=gran()
|
||||||
|
d4(3,i)=gran()
|
||||||
|
d4(4,i)=gran()
|
||||||
|
enddo
|
||||||
|
|
||||||
|
return
|
||||||
|
end subroutine noisegen
|
21
libm65/packbits.f90
Normal file
21
libm65/packbits.f90
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
subroutine packbits(dbits,nsymd,m0,sym)
|
||||||
|
|
||||||
|
! Pack 0s and 1s from dbits() into sym() with m0 bits per word.
|
||||||
|
! NB: nsymd is the number of packed output words.
|
||||||
|
|
||||||
|
integer sym(nsymd)
|
||||||
|
integer*1 dbits(*)
|
||||||
|
|
||||||
|
k=0
|
||||||
|
do i=1,nsymd
|
||||||
|
n=0
|
||||||
|
do j=1,m0
|
||||||
|
k=k+1
|
||||||
|
m=dbits(k)
|
||||||
|
n=ior(ishft(n,1),m)
|
||||||
|
enddo
|
||||||
|
sym(i)=n
|
||||||
|
enddo
|
||||||
|
|
||||||
|
return
|
||||||
|
end subroutine packbits
|
1
libm65/ss.bat
Normal file
1
libm65/ss.bat
Normal file
@ -0,0 +1 @@
|
|||||||
|
svn status | grep -v '?'
|
36
libm65/tab.c
Normal file
36
libm65/tab.c
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
/* 8-bit parity lookup table, generated by partab.c */
|
||||||
|
unsigned char Partab[] = {
|
||||||
|
0, 1, 1, 0, 1, 0, 0, 1,
|
||||||
|
1, 0, 0, 1, 0, 1, 1, 0,
|
||||||
|
1, 0, 0, 1, 0, 1, 1, 0,
|
||||||
|
0, 1, 1, 0, 1, 0, 0, 1,
|
||||||
|
1, 0, 0, 1, 0, 1, 1, 0,
|
||||||
|
0, 1, 1, 0, 1, 0, 0, 1,
|
||||||
|
0, 1, 1, 0, 1, 0, 0, 1,
|
||||||
|
1, 0, 0, 1, 0, 1, 1, 0,
|
||||||
|
1, 0, 0, 1, 0, 1, 1, 0,
|
||||||
|
0, 1, 1, 0, 1, 0, 0, 1,
|
||||||
|
0, 1, 1, 0, 1, 0, 0, 1,
|
||||||
|
1, 0, 0, 1, 0, 1, 1, 0,
|
||||||
|
0, 1, 1, 0, 1, 0, 0, 1,
|
||||||
|
1, 0, 0, 1, 0, 1, 1, 0,
|
||||||
|
1, 0, 0, 1, 0, 1, 1, 0,
|
||||||
|
0, 1, 1, 0, 1, 0, 0, 1,
|
||||||
|
1, 0, 0, 1, 0, 1, 1, 0,
|
||||||
|
0, 1, 1, 0, 1, 0, 0, 1,
|
||||||
|
0, 1, 1, 0, 1, 0, 0, 1,
|
||||||
|
1, 0, 0, 1, 0, 1, 1, 0,
|
||||||
|
0, 1, 1, 0, 1, 0, 0, 1,
|
||||||
|
1, 0, 0, 1, 0, 1, 1, 0,
|
||||||
|
1, 0, 0, 1, 0, 1, 1, 0,
|
||||||
|
0, 1, 1, 0, 1, 0, 0, 1,
|
||||||
|
0, 1, 1, 0, 1, 0, 0, 1,
|
||||||
|
1, 0, 0, 1, 0, 1, 1, 0,
|
||||||
|
1, 0, 0, 1, 0, 1, 1, 0,
|
||||||
|
0, 1, 1, 0, 1, 0, 0, 1,
|
||||||
|
1, 0, 0, 1, 0, 1, 1, 0,
|
||||||
|
0, 1, 1, 0, 1, 0, 0, 1,
|
||||||
|
0, 1, 1, 0, 1, 0, 0, 1,
|
||||||
|
1, 0, 0, 1, 0, 1, 1, 0,
|
||||||
|
};
|
||||||
|
|
24
libm65/unpackbits.f90
Normal file
24
libm65/unpackbits.f90
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
subroutine unpackbits(sym,nsymd,m0,dbits)
|
||||||
|
|
||||||
|
! Unpack bits from sym() into dbits(), one bit per byte.
|
||||||
|
! NB: nsymd is the number of input words, and m0 their length.
|
||||||
|
! there will be m0*nsymd output bytes, each 0 or 1.
|
||||||
|
|
||||||
|
integer sym(nsymd)
|
||||||
|
integer*1 dbits(*)
|
||||||
|
integer*1 n1
|
||||||
|
equivalence (n,n1)
|
||||||
|
|
||||||
|
k=0
|
||||||
|
do i=1,nsymd
|
||||||
|
mask=ishft(1,m0-1)
|
||||||
|
do j=1,m0
|
||||||
|
k=k+1
|
||||||
|
dbits(k)=0
|
||||||
|
if(iand(mask,sym(i)).ne.0) dbits(k)=1
|
||||||
|
mask=ishft(mask,-1)
|
||||||
|
enddo
|
||||||
|
enddo
|
||||||
|
|
||||||
|
return
|
||||||
|
end subroutine unpackbits
|
219
libm65/vit216.c
Normal file
219
libm65/vit216.c
Normal file
@ -0,0 +1,219 @@
|
|||||||
|
/* Viterbi decoder for arbitrary convolutional code
|
||||||
|
* viterbi27 and viterbi37 for the r=1/2 and r=1/3 K=7 codes are faster
|
||||||
|
* Copyright 1999 Phil Karn, KA9Q
|
||||||
|
* May be used under the terms of the GNU Public License
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Select code here */
|
||||||
|
|
||||||
|
#define V216
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef V216
|
||||||
|
#define K 16 /* Constraint length */
|
||||||
|
#define N 2 /* Number of symbols per data bit */
|
||||||
|
#define Polys Poly216 /* Select polynomials here */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Rate 1/2 codes */
|
||||||
|
unsigned int Poly216[] = {0126723, 0152711}; /* k = 16 */
|
||||||
|
|
||||||
|
#include <memory.h>
|
||||||
|
#define NULL ((void *)0)
|
||||||
|
|
||||||
|
#define LONGBITS 32
|
||||||
|
#define LOGLONGBITS 5
|
||||||
|
|
||||||
|
#undef max
|
||||||
|
#define max(x,y) ((x) > (y) ? (x) : (y))
|
||||||
|
#define D (1 << max(0,K-LOGLONGBITS-1))
|
||||||
|
#define MAXNBITS 200 /* Maximum frame size (user bits) */
|
||||||
|
|
||||||
|
extern unsigned char Partab[]; /* Parity lookup table */
|
||||||
|
|
||||||
|
int Syms[1 << K];
|
||||||
|
int VDInit = 0;
|
||||||
|
|
||||||
|
int parity(int x)
|
||||||
|
{
|
||||||
|
x ^= (x >> 16);
|
||||||
|
x ^= (x >> 8);
|
||||||
|
return Partab[x & 0xff];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wrapper for calling "encode" from Fortran:
|
||||||
|
//void __stdcall ENCODE(
|
||||||
|
void enc216_(
|
||||||
|
unsigned char data[], // User data, 8 bits per byte
|
||||||
|
int *nbits, // Number of user bits
|
||||||
|
unsigned char symbols[], // Encoded one-bit symbols, 8 per byte
|
||||||
|
int *nsymbols, // Number of symbols
|
||||||
|
int *kk, // K
|
||||||
|
int *nn) // N
|
||||||
|
{
|
||||||
|
int nbytes;
|
||||||
|
nbytes=(*nbits+7)/8; // Always encode multiple of 8 information bits
|
||||||
|
enc216(symbols,data,nbytes,0,0); // Do the encoding
|
||||||
|
*nsymbols=(*nbits+K-1)*N; // Return number of encoded symbols
|
||||||
|
*kk=K;
|
||||||
|
*nn=N;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Convolutionally encode data into binary symbols */
|
||||||
|
enc216(unsigned char symbols[], unsigned char data[],
|
||||||
|
unsigned int nbytes, unsigned int startstate,
|
||||||
|
unsigned int endstate)
|
||||||
|
{
|
||||||
|
int i,j,k,n=-1;
|
||||||
|
unsigned int encstate = startstate;
|
||||||
|
|
||||||
|
for(k=0; k<nbytes; k++) {
|
||||||
|
for(i=7;i>=0;i--){
|
||||||
|
encstate = (encstate + encstate) + ((data[k] >> i) & 1);
|
||||||
|
for(j=0;j<N;j++) {
|
||||||
|
n=n+1;
|
||||||
|
symbols[n] = parity(encstate & Polys[j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Flush out with zero tail. (No need, if tail-biting code.)
|
||||||
|
for(i=0; i<K-1;i++){
|
||||||
|
encstate = (encstate << 1) | ((endstate >> i) & 1);
|
||||||
|
for(j=0;j<N;j++) {
|
||||||
|
n=n+1;
|
||||||
|
symbols[n] = parity(encstate & Polys[j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wrapper for calling "viterbi" from Fortran:
|
||||||
|
//void __stdcall VITERBI(
|
||||||
|
void vit216_(
|
||||||
|
unsigned char symbols[], /* Raw deinterleaved input symbols */
|
||||||
|
unsigned int *Nbits, /* Number of decoded information bits */
|
||||||
|
int mettab[2][256], /* Metric table, [sent sym][rx symbol] */
|
||||||
|
unsigned char ddec[], /* Decoded output data */
|
||||||
|
long *Metric /* Final path metric (bigger is better) */
|
||||||
|
){
|
||||||
|
long metric;
|
||||||
|
vit216(&metric,ddec,symbols,*Nbits,mettab,0,0);
|
||||||
|
*Metric=metric;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Viterbi decoder */
|
||||||
|
int vit216(
|
||||||
|
long *metric, /* Final path metric (returned value) */
|
||||||
|
unsigned char *data, /* Decoded output data */
|
||||||
|
unsigned char *symbols, /* Raw deinterleaved input symbols */
|
||||||
|
unsigned int nbits, /* Number of output bits */
|
||||||
|
int mettab[2][256], /* Metric table, [sent sym][rx symbol] */
|
||||||
|
unsigned int startstate, /* Encoder starting state */
|
||||||
|
unsigned int endstate /* Encoder ending state */
|
||||||
|
){
|
||||||
|
int bitcnt = -(K-1);
|
||||||
|
long m0,m1;
|
||||||
|
int i,j,sym,ipp;
|
||||||
|
int mets[1 << N];
|
||||||
|
unsigned long paths[(MAXNBITS+K-1)*D];
|
||||||
|
unsigned long *pp,mask;
|
||||||
|
long cmetric[1 << (K-1)],nmetric[1 << (K-1)];
|
||||||
|
|
||||||
|
memset(paths,0,sizeof(paths));
|
||||||
|
|
||||||
|
// Initialize on first time through:
|
||||||
|
if(!VDInit){
|
||||||
|
for(i=0;i<(1<<K);i++){
|
||||||
|
sym = 0;
|
||||||
|
for(j=0;j<N;j++)
|
||||||
|
sym = (sym << 1) + parity(i & Polys[j]);
|
||||||
|
Syms[i] = sym;
|
||||||
|
}
|
||||||
|
VDInit++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Keep only lower K-1 bits of specified startstate and endstate
|
||||||
|
startstate &= ~((1<<(K-1)) - 1);
|
||||||
|
endstate &= ~((1<<(K-1)) - 1);
|
||||||
|
|
||||||
|
/* Initialize starting metrics */
|
||||||
|
for(i=0;i< 1<<(K-1);i++)
|
||||||
|
cmetric[i] = -999999;
|
||||||
|
cmetric[startstate] = 0;
|
||||||
|
|
||||||
|
pp = paths;
|
||||||
|
ipp=0;
|
||||||
|
for(;;){ /* For each data bit */
|
||||||
|
/* Read input symbols and compute branch metrics */
|
||||||
|
for(i=0;i< 1<<N;i++){
|
||||||
|
mets[i] = 0;
|
||||||
|
for(j=0;j<N;j++){
|
||||||
|
mets[i] += mettab[(i >> (N-j-1)) & 1][symbols[j]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
symbols += N;
|
||||||
|
/* Run the add-compare-select operations */
|
||||||
|
mask = 1;
|
||||||
|
for(i=0;i< 1 << (K-1);i+=2){
|
||||||
|
int b1,b2;
|
||||||
|
|
||||||
|
b1 = mets[Syms[i]];
|
||||||
|
nmetric[i] = m0 = cmetric[i/2] + b1;
|
||||||
|
b2 = mets[Syms[i+1]];
|
||||||
|
b1 -= b2;
|
||||||
|
m1 = cmetric[(i/2) + (1<<(K-2))] + b2;
|
||||||
|
|
||||||
|
if(m1 > m0){
|
||||||
|
nmetric[i] = m1;
|
||||||
|
*pp |= mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
m0 -= b1;
|
||||||
|
nmetric[i+1] = m0;
|
||||||
|
m1 += b1;
|
||||||
|
|
||||||
|
if(m1 > m0){
|
||||||
|
nmetric[i+1] = m1;
|
||||||
|
*pp |= mask << 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
mask <<= 2;
|
||||||
|
if(mask == 0){
|
||||||
|
mask = 1;
|
||||||
|
pp++;
|
||||||
|
ipp++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(mask != 1){
|
||||||
|
pp++;
|
||||||
|
ipp++;
|
||||||
|
}
|
||||||
|
if(++bitcnt == nbits){
|
||||||
|
*metric = nmetric[endstate];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
memcpy(cmetric,nmetric,sizeof(cmetric));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Chain back from terminal state to produce decoded data */
|
||||||
|
if(data == NULL)
|
||||||
|
return 0;/* Discard output */
|
||||||
|
memset(data,0,(nbits+7)/8); /* round up in case nbits % 8 != 0 */
|
||||||
|
|
||||||
|
for(i=nbits-1;i >= 0;i--){
|
||||||
|
// int a0,a1;
|
||||||
|
pp -= D;
|
||||||
|
ipp -= D;
|
||||||
|
m0=endstate >> LOGLONGBITS;
|
||||||
|
m1=1L << (endstate & (LONGBITS-1));
|
||||||
|
if(pp[m0] & m1) {
|
||||||
|
// a0=nmetric[endstate];
|
||||||
|
endstate |= (1 << (K-1));
|
||||||
|
// a1=nmetric[endstate];
|
||||||
|
data[i>>3] |= 0x80 >> (i&7);
|
||||||
|
// printf("B %d %d %d %d\n",*metric,i,a0,a1);
|
||||||
|
}
|
||||||
|
endstate >>= 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user