; 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 ÿ