; AMSAT/TAPR DSP BEL-202 modem. Filter splitter design
; Sample rate should be set to 9600 samples/sec.
; code by Bob McGwier N4HY
org 0
b go
org 16
sine: equ 0 ; will store sine values from tone
one: equ 1 ; guess what goes here duhhhhh!
energy: equ 2
thresh: equ 3
maskl: equ 4 ; mask for fine or low order bits of phase
mask: equ 5 ; mask for doing modulo 16384 arithmetic with phase
sinx: equ 6 ; used to store coarse sine value (high order bits)
cosx: equ 7 ; as above for cosine
mone: equ 8 ; minus one stored here
wkph: equ 9 ; different phases (PLL, remodulator tone etc) are stored hr
; for frequency synthesis
masko: equ 10 ; mask for converting on board PCM to DAC format
mps: equ 11 ; multiplier for quadrant determination for sine
mpc: equ 12 ; multiplier for quadrant determination for cosine
siny: equ 13 ; fine correction value for use in SIN(X+Y) = sinx*cosy+
cosy: equ 14 ; cosx*siny
cosine: equ 15 ; cosine is also needed for Q arm in Costas loop
coph: equ 16 ; working number holder
modem: equ 17 ; Used to choose between complex tone for arms and real tone
; in the modulator as explained below
xn0: equ 18
xn1: equ 19
xn2: equ 20
xn3: equ 21
xn4: equ 22
xn5: equ 23
xn6: equ 24
xn7: equ 25
xn8: equ 26
xn9: equ 27
xn10: equ 28
xn11: equ 29
xn12: equ 30
xn13: equ 31
xn14: equ 32
xn15: equ 33
xn16: equ 34
xn17: equ 35
xn18: equ 36
xn19: equ 37
xn20: equ 38
xn21: equ 39
xn22: equ 40
xn23: equ 41
xn24: equ 42
xn25: equ 43
xn26: equ 44
xn27: equ 45
xn28: equ 46
xn29: equ 47
xn30: equ 48
xn31: equ 49
xn32: equ 50
b0: equ 51
b1: equ 52
b2: equ 53
b3: equ 54
b4: equ 55
b5: equ 56
b6: equ 57
b7: equ 58
b8: equ 59
b9: equ 60
b10: equ 61
b11: equ 62
b12: equ 63
b13: equ 64
b14: equ 65
b15: equ 66
b16: equ 67
b17: equ 68
b18: equ 69
b19: equ 70
b20: equ 71
freql: equ 72 ; low tone for remodulator stored here
freqh: equ 73 ; high tone remod.
freqo: equ 74 ; freqo is assigned one of the values above for remod
phaseo: equ 75 ; phaseo is the phase of the remodulator output. phase is
hl12: equ 76
hl13: equ 77
hl15: equ 78
hl16: equ 79
hu13: equ 80
hu14: equ 81
hu16: equ 82
hb8: equ 83
hb9: equ 84
hb10: equ 85
tester: equ 86
suml: equ 87
sumh: equ 88
clockp: equ 89
clockf: equ 90
clocke: equ 91
clocka: equ 92
sintbl:
dw 0 ; coarse sine table in steps of PI/64 radians to PI/2
dw 804
dw 1607
dw 2410
dw 3211
dw 4011
dw 4807
dw 5601
dw 6392
dw 7179
dw 7961
dw 8739
dw 9511
dw 10278
dw 11038
dw 11792
dw 12539
dw 13278
dw 14009
dw 14732
dw 15446
dw 16150
dw 16845
dw 17530
dw 18204
dw 18867
dw 19519
dw 20159
dw 20787
dw 21402
dw 22004
dw 22594
dw 23169
dw 23731
dw 24278
dw 24811
dw 25329
dw 25831
dw 26318
dw 26789
dw 27244
dw 27683
dw 28105
dw 28510
dw 28897
dw 29268
dw 29621
dw 29955
dw 30272
dw 30571
dw 30851
dw 31113
dw 31356
dw 31580
dw 31785
dw 31970
dw 32137
dw 32284
dw 32412
dw 32520
dw 32609
dw 32678
dw 32727
dw 32757
dw 32767 ; PI/2
fines: dw 0 ; fine sine table in steps of PI/(64*64) radians to PI/64
dw 12
dw 25
dw 37
dw 50
dw 62
dw 75
dw 87
dw 100
dw 113
dw 125
dw 138
dw 150
dw 163
dw 175
dw 188
dw 201
dw 213
dw 226
dw 238
dw 251
dw 263
dw 276
dw 289
dw 301
dw 314
dw 326
dw 339
dw 351
dw 364
dw 376
dw 389
dw 402
dw 414
dw 427
dw 439
dw 452
dw 464
dw 477
dw 490
dw 502
dw 515
dw 527
dw 540
dw 552
dw 565
dw 578
dw 590
dw 603
dw 615
dw 628
dw 640
dw 653
dw 665
dw 678
dw 691
dw 703
dw 716
dw 728
dw 741
dw 753
dw 766
dw 779
dw 791
finec: dw 32767 ;ditto to above for fine sine
dw 32766
dw 32766
dw 32766
dw 32766
dw 32766
dw 32766
dw 32766
dw 32766
dw 32766
dw 32766
dw 32766
dw 32766
dw 32766
dw 32766
dw 32766
dw 32766
dw 32766
dw 32766
dw 32766
dw 32766
dw 32765
dw 32765
dw 32765
dw 32765
dw 32765
dw 32765
dw 32765
dw 32765
dw 32764
dw 32764
dw 32764
dw 32764
dw 32764
dw 32764
dw 32764
dw 32763
dw 32763
dw 32763
dw 32763
dw 32763
dw 32762
dw 32762
dw 32762
dw 32762
dw 32762
dw 32761
dw 32761
dw 32761
dw 32761
dw 32760
dw 32760
dw 32760
dw 32760
dw 32759
dw 32759
dw 32759
dw 32759
dw 32758
dw 32758
dw 32758
dw 32758
dw 32757
dw 32757
filtd:
dw -4178
dw -5415
dw 4323
dw 7299
dw -4545
dw -5167
dw 6951
dw 4513
dw 8819
dw 10635
go: ldpk 0 ; make sure that we are pointing to 0 data page
lack one ; make and store one
sacl one
lac one,11
sacl clockf
lack filtd ; store address of the too large coefficients
tblr hl12
add one
tblr hl13
add one
tblr hl15
add one
tblr hl16
add one
tblr hu13
add one
tblr hu14
add one
tblr hu16
add one
tblr hb8
add one
tblr hb9
add one
tblr hb10
sacl masko
lt one
mpyk 3755
pac
sacl freqh
lac one,4
sacl thresh
lt one
mpyk 2048
pac
sacl freql
zac
sacl clockp
sub one
sacl mone ; make and store minus one
sacl modem
lac one,14
sub one
sacl mask ; make and store mask for modulo 16384 phase arithmetic
lac one,6
sub one
sacl maskl ; make and store fine part of address mask;
lac one,8 ; make and store frequency address in memory
sub one
; Okay the BS is over lets get to work !
wait: bioz fire ; is it time for a new sample
b wait ; nope go wait in the corner
fire: in xn0,pa3 ; get a new sample here
lac xn0,4
sub one,15 ; Change ADC format to two's complement
sacl xn0
; remodulator output
lac thresh
sub energy
bgz noout
lac sine,6
addh masko
sach b0
out b0,pa4 ; send it to the TNC here
; as the following routines have a variable length
; end output
noout: lack one ;
sacl mps ; Restore sine and cosine quadrant multipliers
sacl mpc ;
;
; FINITE IMPULSE RESPONSE (FIR)
; LINEAR PHASE DIGITAL FILTER DESIGN
; REMEZ EXCHANGE ALGORITHM
; BANDPASS FILTER
; FILTER LENGTH = 33
;
; BAND 1 BAND 2 BAND 3
; LOWER BAND EDGE .0000000 .1150000 .2290000
; UPPER BAND EDGE .0550000 .1770000 .5000000
; DESIRED VALUE .0000000 1.0000000 .0000000
; WEIGHTING 1.0000000 1.0000000 1.0000000
; DEVIATION .0158519 .0158519 .0158519
; DEVIATION IN DB -35.9983500 .1366083 -35.9983500
; EXTREMAL FREQUENCIES--MAXIMA OF THE ERROR CURVE
; .0000000 .0404412 .0550000 .1150000 .1241912
; .1462500 .1664706 .1770000 .2290000 .2381912
; .2620883 .2896618 .3190736 .3503236 .3834119
; .4146619 .4514267 .5000000
;
; FILTER for low side with the filter given above
;
zac ; Zero the accumulator as we will be summing as we multiply
lt xn32
mpyk 270
lta xn31
mpyk -212
lta xn30
mpyk -670
lta xn29
mpyk -680
lta xn28
mpyk -25
lta xn27
mpyk 610
lta xn26
mpyk 479
lta xn25
mpyk -19
lta xn24
mpyk 317
lta xn23
mpyk 1577
lta xn22
mpyk 1907
lta xn21
mpyk -447
lta xn20
mpy hl12
lta xn19
mpy hl13
lta xn18
mpyk -1748
lta xn17
mpy hl15
lta xn16
mpy hl16
lta xn15
mpy hl15
lta xn14
mpyk -1748
lta xn13
mpy hl13
lta xn12
mpy hl12
lta xn11
mpyk -447
lta xn10
mpyk 1907
lta xn9
mpyk 1507
lta xn8
mpyk 317
lta xn7
mpyk -19
lta xn6
mpyk 479
lta xn5
mpyk 610
lta xn4
mpyk -25
lta xn3
mpyk -680
lta xn2
mpyk -670
lta xn1
mpyk -212
lta xn0
mpyk 270
apac
sach suml ; suml is the low side filter output
bgez posl
zac
sub suml
sacl suml
posl:
;
;
; FINITE IMPULSE RESPONSE (FIR)
; LINEAR PHASE DIGITAL FILTER DESIGN
; REMEZ EXCHANGE ALGORITHM
; BANDPASS FILTER
; FILTER LENGTH = 33
; BAND 1 BAND 2 BAND 3
; LOWER BAND EDGE .0000000 .1770000 .2900000
; UPPER BAND EDGE .1200000 .2290000 .5000000
; DESIRED VALUE .0000000 1.0000000 .0000000
; WEIGHTING 1.0000000 1.0000000 1.0000000
; DEVIATION .0114788 .0114788 .0114788
; DEVIATION IN DB -38.8020300 .0991361 -38.8020300
;
; FILTER for high side with the filter given above
;
zac ; Zero the accumulator as we will be summing as we multiply
lt xn32
mpyk -43
ltd xn31
mpyk -642
ltd xn30
mpyk -196
ltd xn29
mpyk 612
ltd xn28
mpyk 600
ltd xn27
mpyk -201
ltd xn26
mpyk -275
ltd xn25
mpyk 115
ltd xn24
mpyk -726
ltd xn23
mpyk -1492
ltd xn22
mpyk 785
ltd xn21
mpyk 3790
ltd xn20
mpyk 1545
ltd xn19
mpy hu13
ltd xn18
mpy hu14
ltd xn17
mpyk 2078
ltd xn16
mpy hu16
ltd xn15
mpyk 2078
ltd xn14
mpy hu14
ltd xn13
mpy hu13
ltd xn12
mpyk 1545
ltd xn11
mpyk 3790
ltd xn10
mpyk 785
ltd xn9
mpyk -1492
ltd xn8
mpyk -726
ltd xn7
mpyk 115
ltd xn6
mpyk -275
ltd xn5
mpyk -201
ltd xn4
mpyk 600
ltd xn3
mpyk 612
ltd xn2
mpyk -196
ltd xn1
mpyk -642
ltd xn0
mpyk -43
apac
sach sumh ; sumh is the high side filter output
bgez posh
zac
sub sumh
sacl sumh
posh:
; load the high filter value subtract the low filter value
; send this through the LPF.
lac sumh
sub suml
sacl b0
; See if there is energy in the filters and use this as a data
; squelch. In other words, you must use the squelch on your radio
; to turn the data squelch on and off
lac sumh,15
add suml,15
add energy,15
sach energy
; FINITE IMPULSE RESPONSE (FIR)
; LINEAR PHASE DIGITAL FILTER DESIGN
; REMEZ EXCHANGE ALGORITHM
; BANDPASS FILTER
; FILTER LENGTH = 21
; BAND 1 BAND 2
; LOWER BAND EDGE .0000000 .1750000
; UPPER BAND EDGE .1250000 .5000000
; DESIRED VALUE 1.0000000 .0000000
; WEIGHTING 1.0000000 1.0000000
; DEVIATION .0687429 .0687429
; DEVIATION IN DB .5774649 -23.2554400
;
; LPF the splitter output and this is the bits
;
;
; If the bit is positive output 2200 else output 1200
;
zac
lt b20
mpyk -431
ltd b19
mpyk 323
ltd b18
mpyk 821
ltd b17
mpyk 801
ltd b16
mpyk -185
ltd b15
mpyk -1568
ltd b14
mpyk -1844
ltd b13
mpyk 269
ltd b12
mpy hb8
ltd b11
mpy hb9
ltd b10
mpy hb10
ltd b9
mpy hb9
ltd b8
mpy hb8
ltd b7
mpyk 269
ltd b6
mpyk -1844
ltd b5
mpyk -1568
ltd b4
mpyk -185
ltd b3
mpyk 801
ltd b2
mpyk 821
ltd b1
mpyk 323
ltd b0
mpyk -431
apac
sach b0
; b0 contains the bandlimited noisy bit value. Recover the clock
; so that we may choose point of maximum eye opening for the bit
; decision.
;
; The clock recovery nonlinearity begins with absolute value
lac b0
bgez addc
zac
sub b0
addc: sacl clocke
; Keep a IIR LPF version of this so that the DC may be subtracted
; and get a clock tone at the data rate.
; Simplest IIR, 0.5*old value + 0.5 * new value
;
lac clocka,15
add clocke,15
sach clocka
; Subtract off DC
lac clocke
sub clocka
sacl clocke
; get sine from tones that runs at the clock rate
lac clockp
call tones
zac
; mix (multiply) with the clock signal from above
lt sine
mpy clocke
spac
; taking the negative of this (spac from a zero'd accumulator)
sach clocke
; using a gain of 1/8 add correction into the old clock phase plus
; the phase increment (frequency)
lac clocke,13
sach clocke
lac clockf
add clockp
add clocke
sacl clockp
; After storing the new clock phase test to see if we have passed
; two pi at which time we will take the value of b0 for the bit value
; Since this is the point of maximal eye opening. If the phase has
; been corrected negative put back between 0 and 2pi.
bgez gpi
add one,14
sacl clockp
b outt
gpi: lac one,14
sub clockp
blz nfrq
b outt
nfrq: lac clockp
and mask
sacl clockp
lac b0
; bit positive?
bgez posb
; No load low frequency for this bit period
lac freql
b newf
; Yes load high frequency for this bit period
posb: lac freqh
newf: sacl freqo
; freqo is the output frequency for the remodulator
outt: lack one
sacl mpc
sacl mps
lac freqo
add phaseo
and mask
sacl phaseo
call tones
b wait
; complex tone generator if modem>0 if modem<0 sine wave generator
tones: sacl wkph ; store a working copy
lac wkph,4
subh one
blz getem ; is it in a quadrant bigger than first?
subh one
bgez thfr; is it in a quadrant greater than two?
lac 1,13 ; nope so load pi
sub wkph ; subtract phase so that it maps back into 1st quad
sacl wkph ; store
lac mone ; load -1
sacl mpc ; store it in the cosine multiplier
b getem ; go read tables
thfr: lac mone ; multiplier for bottom half
sacl mps ; store
lac wkph ;
sub one,13 ; map angle back to upper half and go do it again
b tones
getem: lac wkph,10 ; take 1st quadrant phase equiv for sine and pick
; off coarse part of phase address
sach coph ; store it
lack sintbl ; load sine table offset into accumulator
add coph ; add coarse address off set
tblr sinx ; read the coarse sine value
lac one,6 ; load pi/2
sub coph ; subtract the coarse phase to get cosines offset
sacl coph
lack sintbl
add coph ; do same as above for coarse cosine
tblr cosx
lac wkph ; load working phase
and maskl ; mask off fine addres
sacl coph ; store it
lack fines ; locate fine table offset
add coph ; add for offset into fine table
tblr siny ; read table
lack finec
add coph
tblr cosy
zac
lt sinx ; load sinx
mpy cosy ; multiply by cosy
lta siny ; load t reg with fine sin and accumulate previous prod.
mpy cosx ; multiply by coarse cosx to use sin(X+Y)
apac ; add the result to coarse sine
sach sine ; store it.
lac modem
blz mult
lac 1,12 ; load full address pi/2
sub wkph ; subtract the working phase to get cosine
sacl wkph
lac wkph,10 ; from here to the later MARK it is identical to above
sach coph
lack sintbl
add coph
tblr sinx
lac one,6
sub coph
sacl coph
lack sintbl
add coph
tblr cosx
lac wkph
and maskl
sacl coph
lack fines
add coph
tblr siny
lack finec
add coph
tblr cosy
zac
lt cosy
mpy sinx
lta siny
mpy cosx
apac ; MARK
sach cosine ; store it in the cosine
mult: lt mps; now we need to do a few multiplies by sign changes due to
mpy sine ; to quadrant part of phase address
pac; multiply sine by sine sign (:-) and
sacl sine ; store the result
lac modem
bgz cosm
ret
cosm: mpy cosine; now multiply cosine by the same
pac
sacl cosine ; store it
lt mpc; load cosine differentiator from sine sign (:-)
mpy cosine; multiply
pac
sacl cosine ; store
ret
end
; Ebbly Ebbly Ebbly thats all folks
�