; ; $Header: E:/HAM/EVM/RCS/psk.asm 1.14 1997/10/23 13:43:08 dbraun Exp $ ; ; $Log: psk.asm $ ; Revision 1.14 1997/10/23 13:43:08 dbraun ; Added blinking of orange LED for received serial port data. ; ; Revision 1.13 1997/10/22 22:28:58 dbraun ; Added spying of DCD, and optional yellow LED for data flow indication ; ; Revision 1.12 1997/02/05 09:11:55 dbraun ; Change to DCD calculation to make it less sensitive when ; spectral asymmetry is not used. ; ; Revision 1.11 1997/01/22 11:01:22 dbraun ; Removed Hilbert Transform filtering of new transmitter output. ; ; Revision 1.10 1997/01/19 23:17:44 dbraun ; Added fudge factor for initialization of TxDigLevel for new xmtr. ; ; Revision 1.9 1997/01/19 20:09:22 dbraun ; Added new transmitter code. ; ; Revision 1.8 1997/01/19 18:02:32 dbraun ; Updated SPY code to more recent spec. ; ; Revision 1.7 1997/01/18 16:52:30 dbraun ; Tweaked some frequencies, etc. for my IC821. ; ; Revision 1.6 1996/12/16 22:27:19 dbraun ; Fixed up spectral asymettry on/off option, and reduced ; mike click rate for IC821. ; ; Revision 1.5 1996/12/08 10:15:23 dbraun ; added support for run-time patching of kiss txtail parameter. ; ; Revision 1.4 1996/12/06 22:12:29 dbraun ; Tweaked levels for IC821 ; ; Revision 1.3 1996/11/25 08:06:47 dbraun ; Added assembly-time option for use of spectral asymmetry for DCD. ; ; Revision 1.2 1996/06/19 12:48:29 dbraun ; Added RCS headers ; ; ;FILE: BPSK1200.ASM, Last edition: 01-JAN-1996 ;1200 bps BPSK modem, primary usage is for satellites like LO-19 ;but can be used in simplex mode for HF or VHF packet. ;(c) 1995,1996 Pawel Jalocha, SP9VRC, ;e-mail: jalocha@chopin.ifj.edu.pl, sp9vrc@gw.sp9kby.ampr.org ; ;This software is not to be used for purposes other than amateur radio ;without a written permision of the author. ;Usage for profit or in commercial/military products is explicitly prohibited. page 132 opt mu nolist include 'leonid' list scsjmp short ;force short jumps for .if/.endi, .while/.endw, etc. title '1200 bps BPSK modem by SP9VRC' ;************************************************************************* ;compile-time constants, modem parameters SampleFreq equ 9600.0 AliasFilterLen equ 64 ;the length of the anti-alias/Hilbert transform filter AliasLowFreq equ 150.0 ;lower and upper edges of the input/output filters AliasUppFreq equ 3050.0 ;here we center the filters at 1600 Hz HilbertDecimate equ 1 ;decimation ratio for the Hilbert transform. ;1 => one Hilbert (complex) sample per each real sample ;2 => bit rate falls by 2 without touching any ; other parameters. Note that we can decimate by 2 ; without risks for any aliasing because we ; process complex samples. ;higher than 2 can be done but you need to think well ;about the anti-alias filters and the carrier freq. SymbolSepar equ 8 ;8 samples between symbols => 9600/8=1200 baud ;SymbolSepar should be an even number ;If you change it, there is one place around line 450 ;to be manually changed. SymbolShapeLen equ 2*SymbolSepar ;Symbol's shape is 16 samples long ;For the current symbol's shape (Tr/RxSymbolShape) ;SymbolShapeLen should be 2*SymbolSepar UseNewTransmitter equ 1 ;Use the new N1OWU transmitter code instead of ;the original PSK-like code. This is only ;for Manchester satellite uplinks. If enabled, ;the TxCarrier and TxCarSync are irrelevant. TxCarrier equ 1200.0 ;[Hz] transmitter carrier frequency. ;For satellite uplink this should be 1200 Hz TxCarSync equ 1 ;Synchronize the carrier to the data rate. ;This we need for the Manchester satellite uplink. ;Enable this option only if the carrier frequency ;is an exact multiply of the symbol rate like for ;1200 bps and 1200 Hz. ;If you try this BPSK modem on shortwave (no need ;for Manchester encoding) I suggest that you set ;TxCarrier around 1500-1700 Hz - then you must turn off ;the TxCarSync. TxContCarrier equ 0 ;1 => keep transmitter's carrier ON all the time. ;0 => the carrier is ON only when the PTT is on. ; Beware of the TxTail being long enough ! ;If this is on, beware leaving the modem turned on ;when working voice!!! DefTxDelay equ 20 ;default value for the txdelay (20 => 200 ms) DefTxTail equ 20 ;default value for the txtail (3 => 30 ms) DefTxDuplex equ 1 ;1 = full duplex mode (for satellite uplink) ;0 = simplex mode (for HF or VHF packet) SciTimerRate equ baud ;interrupt rate of the SCI timer. This we need ;for proper scaling of txdelay and txtail. ;It is 19200 unless you have messed up the LEONID ;or the SCI itself or if the new LEONID version ;has changed the data/timer rate. ;was 10.5 for IC821 1200 baud tx mode TxAttenuate equ 4.5 ;[dB] attenuate the output CODEC's signal. ;Set this between 0.0 and 90.0 ;to accomodate the output level for the ;modulator input of your tranceiver. ;Expect some noise out of the CODEC for high ;attenuation levels thus you better use ;an external resistor divider to achieve ;high attenuation factors. TxSymbAmpl equ 0.250 ;Tx symbol amplitude ;I experimentally set this as high as possible ;before saturation in the output filters ;occur. This parameter is of concern if you ;really need full swing output out of the ;DSP card to provide enough voltage to drive ;directly the FM modulator. ;Otherwise just set it to 0.25. ;Make it twice as big for HilbertDecimate=2 RxCarrier equ 1400.0 ;[Hz] receiver (expected) carrier frequency ;for satellite downlink put this in the middle ;of your receiver's passband ;Originally 1600, but 1400 is better for my IC821 RxCarTrack equ 1 ;enable/disable carrier tracking. ;The demodulator is made such that a mis-tune of up ;to at least 50 Hz is tolerable without the need to ;correct the RxCarrier frequency. ;Enable RxCarTrack if you want the demodulator ;to internally track the RxCarrier and ;optionally to steer the receiver via the UP/DOWN ;keys to correct the frequency error at the receiver ;or the Doppler shift resulting from satellite's motion. RxCarLow equ RxCarrier-200.0 ;[Hz] lower and upper limits where the carrier is allowed RxCarUpp equ RxCarrier+200.0 ;[Hz] to move due to internal tracking RxCarTrackWeight equ 1.0/350.0 ;carrier tracking weight per symbol ;Lower numbers make the tracking ;slower but more resistant to noise. ;Higher numbers speed up the tracking ;but make overshoots and the stability gets worse ;in high noise. RxAutoScan equ 1 ;When you enable RxAutoScan and no carrier is beeing ;detected the demodulator sweeps its carrier frequency ;within the range defined below. RxScanLow equ RxCarrier-200.0 ;As soon as DCD drops the demodulator sweeps the RxScanUpp equ RxCarrier+200.0 ;carrier within these limits until the DCD is on again ;Note that searching takes time thus ;wider range => more time to lock onto a signal. ;In simplex mode a wide scan with short TxDelay may ;result in packets which are lost because the receiver ;wasn't fast enough to equire the carrier. RxScanStep equ 1.5 ;[Hz] scanning step per symbol for auto-scan. ;Larger step => faster search but may overlook ;some signals and make overshoots when locking ;on signals. To observe the carrier catch-up set ;SPY=1, SPY_RxCarFreq=1, set up a loopback test ;and watch the demodulator's frequency with SPY.EXE ;while applying and removing the loopback. RxCtrlUpDown equ 1 ;Control the up/down switches to have the receiver ;follow automatically the frequency drift. ;This feature works only when RxCarTrack=1 UpDownPulseLen equ 50 ;[symbols] Pulse length for the Up/Down corrections ;50/1200 => the key is pushed for 1/24th second UpDownPulseSepar equ 300 ;[symbols] Minimal separation between pulses ;100/1200 = 1/12th second. If your receiver has ;10 Hz tuning step the maximum tracking speed ;is 10*12 = 120 Hz/sec which should be fine ;for 70 cm downlinks of low orbit satellites. ;If your tuning steps are larger you should ;increase the pulse separation otherwise the modem ;may overcontrol the receiver. UpDownCorrThres equ 50.0 ;[Hz] Up/Down corrections will be done only ;if frequency error is larger than this. UpDownReverse equ 0 ;reverse the sense: usefull for LSB operation ;or if UP/DOWN lines have been wired the other way... RxGain equ 9.0 ;[dB] Rx CODEC's input gain ;set this between 0 and 22.5 dB depending on ;the audio level from your tranceiver RxAGC equ 0 ;enable the automatic gain adjustment ;for the CODEC's audio input. ;ideally you should avoid the AGC and set ;RxGain for best audio level match. ;Note, that the AGC may get fooled up by ;for example long periods of total silence, ;thus you should rather keep the quelch (if any) ;open all the time. RxAGC_MSfollow equ 1.0/256.0 ;update weight per sample ;for the audio Mean Square tracking RxAGChold equ 6000 ;AGC peak hold time [symbols] RxAGCfall equ 600 ;AGC falling period/1.5 dB step [symbols] RxAGCminMS equ 0.01 ;min. and max. tolerable audio Mean Square level RxAGCmaxMS equ 0.04 RxCorrelFollow equ 4 ;follow factor for averaging the correlations ;the actuall weight is 1/2^RxCorrelFollow ;per sample. ;Lower number => the demodulator will better ;follow frequency instabilities (phase noise) ;of the receiver and the satellite but Doppler ;tracking and DCD will fluctuate more due ;to noise. ;When you change RxCorrelFollow ;you should scale accordingly RxCarTrackWeight ;and RxScanStep for optimal perfomance. RxProcPipeLen equ 1< Use spectral asymetry as part of DCD ;criterion. RxDCDsensitive equ 0 ;0 => "normal" sensitivity ;1 => more sensitivity (less restrictive ;conditions for the DCD to go on) RxDCDdelay equ 16 ;wait 16 symbols before declaring DCD ON ;to make sure that this is not a momentary ;noise fluctuation RxDCDhold equ 256 ;hold DCD for 256 symbols ;even if there are no signs of carrier TxRightChannel equ 0 ;Use the right CODEC's channel not the left. PTTRightChannel equ 0 ;Use the right PTT line not the left. RxRightChannel equ 0 ;Use the right CODEC's channel not the left. UpDownRightChannel equ 1 ;Use the right CODEC's channel not the left. ListenToRxCarrier equ 0 ;Put out the RX carrier on the other channel. BufLen equ 4*AliasFilterLen ;sample buffer length ;with some safety margin ;The following are the debugging options... ;normally ALL of them should be set to 0 SPY equ 0 ; SPY=0 => KISS mode (_all_ SPY_ sub-options must be set to 0 !) ; SPY=1 => KISS code excluded, selected debug code included SPY_RxAudioInp equ 0 SPY_RxI equ 0 SPY_RxQ equ 0 SPY_RxIQ equ 0 ;I/Q after the Hilbert tranformer + symbol filter SPY_RxPhase equ 0 ;phase of the I/Q pair SPY_RxPhaseDiff equ 0 ;diiferences in phase ( = frequency ) SPY_RxAudioMS equ 0 ;power (mean square) of the incoming audio SPY_RxCorrel equ 0 ;signal power, auto-correl, de-tune, sync. SPY_RxProcPipePtr equ 0 SPY_RxCrossedIQ equ 0 ;demodulator: crossed succesive I/Q vectors SPY_RxFreqCorr equ 0 ;demodulator: frequency-error correction vector SPY_RxCorrIQ equ 0 ;demodulator: vector after frequency correction SPY_RxCarFreq equ 0 ;Rx demodulator carrier frequency SPY_RxSamplePtr equ 0 ;how the symbol sampling point moves around SPY_DCD equ 0 ; DCD score SPY_TxSymbolI equ 0 ;transmitted symbol I-part SPY_TxCarI equ 0 SPY_TxFiltOutI equ 0 SPY_TxOutputI equ 0 ;transmitted I after the filter and the mixer SPY_TxAudioOut equ 0 ;samples just before they are sent to the CODEC TxDrift equ 0 ;enable artificial drift of the transmitter carrier ;works only when SPY=1 and is intended for debugging ;the demodulator in loopback tests. TxDriftStep equ 0.1 ;[Hz] drift step per symbol, 0.1*1200 = 120 Hz/sec TxDriftLow equ 1300.0 ;lower and upper limit for the drift TxDriftUpp equ 2200.0 MonitorRxAGC equ 0 ;monitor the gain changes being done by the AGC ;with the UP and DOWN LEDs ;This option conflicts with RxCtrlUpDown ;when you use the left channel. ;************************************************************************* ;macros if PTTRightChannel PTT macro mode ;PTT line: clr/set/chg b\mode #4,X:$FFE4 endm else PTT macro mode ;PTT line: clr/set/chg b\mode #0,X:$FFE4 endm endif if UpDownRightChannel PushUp macro mode ;Push UP line of the TRX b\mode #5,X:$FFE4 endm else PushUp macro mode b\mode #7,X:$FFE4 endm endif if UpDownRightChannel PushDown macro mode ;Push DOWN line of the TRX b\mode #6,X:$FFE4 endm else PushDown macro mode b\mode #8,X:$FFE4 endm endif UpLED macro mode ;UP line (a red LED connected) b\mode #1,X:$FFE4 endm DownLED macro mode ;DOWN line (a red LED connected) b\mode #2,X:$FFE4 endm YellowLED macro mode ;CAT line (a yellow LED connected) b\mode #3,X:$FFE4 endm OrangeLED macro mode ; (an orange LED connected) b\mode #14,X:$FFE4 endm DCDLed macro mode ; DCD (Green) LED clr/set/chg b\mode #13,X:$FFE4 endm ;************************************************************************* ;The actuall code (internal/external program RAM) LOMEM P:$0000 HIMEM P:$1FFF org p:user_code jmp HilbertDecimate,a ;a = 1 (wait for one new sample) move X: jsr ;then sample the data bit move (r1)-n1 move L:(r1)-n1,x ;get the two vectors to be compared move L:(r1)+n1,y ;from the very end of the pipe mpy x1,y1,a (r1)+n1 mac x0,y0,a mpy x1,y0,b #<2,n4 mac -x0,y1,b (r4)+ jsr jsr ;if DCD condition is satisfied bset #1,X: ;if DCD not yet declared ON cmp x0,a ;check if counter above 1/2 .if ;if so then bset #0,X: ;if DCD is declared ON cmp x0,a ;check if counter below -1/2 .if ;if so then bclr #0,X: ;if so then track the carrier move L: if RxAutoScan ;sweep the carrier within the defined region move X: add b,a #2.0*HilbertDecimate*RxScanUpp/SampleFreq,x0 cmp x0,a .if neg b x0,a move b,X: neg b x0,a move b,X: sub y0,a .if clr a .endi .else add y0,a .if clr a .endi .endi add x1,a move a,X:1,x0 .if ;if pulse timer running sub x0,a ;decrement the timer move a,X: ;if it reached zero PushUp clr ;turn off both UP and DOWN PushDown clr if !MonitorRxAGC UpLED clr DownLED clr endif .endi .endi move X:1,x0 .if ;if hold timer running sub x0,a ;decrement it move a,X: ;if DCD is ON tst a X: ;if hold timer not running move #2.0*HilbertDecimate*RxCarrier/SampleFreq,x0 sub x0,a #2.0*HilbertDecimate*UpDownCorrThres/SampleFreq,x0 cmpm x0,a .if ;if frequency offset larger than desired tst a #>UpDownPulseLen,x0 move x0,X: else .if endif PushUp set if !MonitorRxAGC UpLED set endif .else PushDown set if !MonitorRxAGC DownLED set endif .endi move #>UpDownPulseSepar,x0 move x0,X:RxCorrel,y0 sub y0,a rep #8 asl a jsr move n4,n5 move (r4)+ move (r5)+ move L:(r4)-n4,y move L:(r5)-n5,a sub y,a L:(r4)+n4,y move L:(r5)+n5,b sub y,b cmp a,b .if move (r5)-n5 move (r5)- move r5,X: move (r5)+n5 move (r5)- move r5,X: neg a .endi jsr neg a .endi jsr RxProcPipe,x0 eor x0,a1 #RxCorrel,r4 .if jsr move #<4,n4 move X: bclr #3,x:$ffe4 .else bset #3,x:$ffe4 .endi endif ; Do the same for the Rx data line and the orange LED. btst #0,x:$ffe5 ; Port C data register .if OrangeLED clr .else OrangeLED set .endi jmp 1,x1 sub x1,b ;did it come to a moment to put out a new bit ? .if if RxAGC ; This is being done here because we want to do it ; once per bit, not per sample. jsr SymbolSepar,b ;if so, restart the counter if SPY jsr ;negate the signal level for one-bits. Thus neg a ;for zero-bits the phase is inverted. move a,X:SymbolSepar/2,x1 cmp x1,b ;see if we are at mid-bit .if neg a ;if at mid-bit, invert the signal level move a,X: ;then set I=0 as well clr a .endi endif ; Simply stick the sample in the output buffer... ; The CODEC output filtering (~4.2 kHz cutoff) should be sufficient. ; If HilbertDecimate is > 1, stick it in more than once... move X:1,x1 sub x1,a #<0,b ;did it come to a moment to put out a new bit ? .if ;if not yet, then we put out a zero clr a a,X:SymbolSepar,a ;and put out the new bit move a,X: add b,a #2.0*HilbertDecimate*TxDriftUpp/SampleFreq,x0 cmp x0,a .if neg b x0,a move b,X: neg b x0,a move b,X: clr b #TxSymbAmpl,a .else clr b #-TxSymbAmpl,a .endi else ;in KISS-TNC mode get data from LEONID getbit move X: ;invert the phase for zero-bits neg a .endi clr b a,X: ;then set I=0 as well clr a .endi endif endif .endi if SPY_TxSymbolI jsr 2,x1 add x1,a move a,x1 CheckSampleBlock_1 move r7,a move r2,x0 sub x0,a jpl BufLen*4,x0 add x0,a CheckSample_cmp cmp x1,a rts ;on output: a,x0,x1 are modified ;If carry=0 => we are sure that: ;1. there are at least A new input samples at X:(r2) ; to be read ;2. there are at least A locations at Y:(r2) to ; be written WaitSampleBlock ;wait for a block of samples from the CODEC ;on input: a = how many samples we want ; r2 = where the block starts jsr 1,x0 sub x0,a move a,X:RxAGCfall,x0 ;preset the AGC "timer" to prohibit asl a x0,X:RxAGChold,y0 ;preset the AGC "timer" to prohibit gain increase move #RxAGCmaxMS,x0 ;for the RxAGChold period cmp x0,a y0,X:RxAGChold,x0 ;initialize the AGC hold count-down move a,X:$0F0F00,x0 ;r2/m2 should point to the CODEC's buffer move Y:(r2),a1 ;get the CODEC's input control word and x0,a ;extract the gain bits cmp x0,a #>$010100,x0 ;already maximum ? jeq $F0F000,x0 ;if not, increment the gain by 1 move a1,x1 move Y:(r2),a1 ;and reload all the control words and x0,a n2,x0 ;in the output buffer or x1,a #<4,n2 ;make n2=4 for a moment .loop #BufLen move a1,Y:(r2)+n2 .endl move x0,n2 ;restore n2 andi #$FE,ccr ;clear carry rts ;modifies a,x0,x1 RxGainDown ;decrease the CODEC's input gain (both channels) clr a #>$0F0F00,x0 ;r2/m2 should point to the CODEC's buffer move Y:(r2),a1 ;get the CODEC's input control word and x0,a #>$010100,x0 ;extract the gain bits sub x0,a #>$F0F000,x0 ;attempt to decrease the gain jcs $80,x1 ;shift out 8 most significant bits mpy x0,x1,a #>$FF,x0 move x0,m0 and x0,a #>$100,x0 or x0,a #<$40,n0 move a1,r0 ;put the 8 most significant bits into r0 with offset = $100 move a0,y0 ;save the remaining bits in y0 jclr #23,y0,SinTable_lev2 move (r0)+ SinTable_lev2 move Y:(r0+n0),x0 ;x0 = coarse cosine move Y:(r0),x1 ;x1 = coarse sine mpyr x1,y0,a #PI/256.0,y1 tfr x0,a a,x1 macr -x1,y1,a ;a = fine cosine mpyr x0,y0,b Y:(r0),x1 tfr x1,b b,x1 macr x1,y1,b #PI*PI/2.0/65536.0,y1 ;b = fine sine mpyr y0,y0,a a,x0 move a,y0 mpyr y0,y1,a tfr x0,a a,y1 macr -x0,y1,a b,x1 ;a = super fine cosine macr -x1,y1,b ;b = super fine sine rts ;x,y are modified ;r0,m0,n0 are modified ;maximum error is about 0.7E-6 ;execution time 4+64+4 clock cycles ;including "jsr turn by PI .if neg a #<%10000000,x0 neg b .endi tst a ;if I-part negative => turn by -PI/2 .if bset #22,x0 tfr a,b b,a ;swap I with Q neg b ;negate the new Q .endi add b,a ;add Q to I (what if I+Q >= 1.0 ?) asr a ;I+Q /= 2 in case it is > 1 asr b a,x1 ;Q /= 2 because of the above, x1 = I+Q andi #$FE,ccr ;divive Q by (I+Q) rep #24 div x1,b tfr x0,a b0,x0 ;x0 = Q div (I+Q), a=approx angle tfr x0,b #0.5,x0 ;b = Q/(I+Q) sub x0,b #0.25,x0 ;b = Q/(I+Q) - 1/2 =: X add x0,a b,x1 #0.63361654,y1 ;angle += 0.25, x1 = X mac x1,y1,a x1,x0 ;angle += F1*X, x0 = X mpyr x0,x0,b #-0.73728217,y1 ;b = X*X mpyr x1,y1,b b,x0 ;b = F3*X, x0 = X*X move b,y1 mac x0,y1,a x0,y0 ;angle += F3*X * X*X, y0 = X*X mpyr x0,x0,b #0.85568791,y1 ;b = (X*X)*(X*X) mpyr x1,y1,b b,x0 ;b = F5*X, x0 = X*X*X*X move b,y1 mac x0,y1,a ;angle += F5*X * X*X*X*X mpyr x0,y0,b #-0.17769569,y1 ;b = (X*X*X*X)*(X*X) mpyr x1,y1,b b,x0 ;b = F5*X, x0 = X*X*X*X*X*X move b,y0 macr x0,y0,a ;angle += F5*X * X*X*X*X*X*X rts ;a = the phase (-1.0 => -PI, 1.0 => PI) ;b,x,y are modified ;execution time is about 130 cycles (65 instructions) ;----------------------------------------------------------------------------- Rand48 ;a simple random number generator move L:@cvi(TxDelay*SciTimerRate/100.0),a ;set TxDelay ;;move #>@cvi(TxTail*SciTimerRate/100.0),a ;set TxTail move x:(baud/100),x1 ; time scale parameter mpy x0,x1,a asr a ; integer multiply correction move a0,p:kiss_pars ; product in low order word move x:(baud/100),x1 ; time scale parameter mpy x0,x1,a asr a move a0,p:kiss_pars+3 move x: no spy request move a2,X: spy request ! move x0,Y:'S',a cmp x0,a ori #$01,ccr jne 'P',x0 putc move #>0,x0 ; send a 0 meaning non-complex data putc move #>512,a move a,X:'S',a cmp x0,a jne 'P',x0 putc move #>0,x0 ; send a 0 meaning non-complex data putc move #>512,a Spy_copy move #>1,x0 sub x0,a move a,X:=@cvi(LastY) org L:LastX else org L:LastY endif ;************************************************************************* ;External L/X/Y data RAM if EVM56K LOMEM X:$2000,Y:$2000,L:$2000 HIMEM X:$3FFF,Y:$3FFF,L:$3FFF else LOMEM X:$0200,Y:$0200,L:$0200 HIMEM X:$1FFF,Y:$1FFF,L:$1FFF endif if EVM56K org L:$2000 else org L:$200 endif RxSymbolFilterTap dsm SymbolShapeLen TxSymbolFilterTap dsm SymbolShapeLen RxCorrel dsm SymbolSepar*4 RxCorrel0 dsm SymbolSepar*4 RxProcPipe dsm RxProcPipeLen*SymbolSepar LastL = * org X:LastL org Y:LastL org X: LastX = * org Y: LastY = * if @cvi(LastX)>=@cvi(LastY) org L:LastX else org L:LastY endif Buffer dsm BufLen*4 ;CODEC's input/output buffer ;************************************************************************* ;External Y-only data RAM if EVM56K LOMEM Y:$0200 HIMEM Y:$1FFF else LOMEM Y:$2000 HIMEM Y:$3FFF endif if EVM56K org Y:$200 else org Y:$2000 endif org Y: AliasFilterI dsm AliasFilterLen AliasFilterQ dsm AliasFilterLen org Y: RxSymbolShape dsm SymbolShapeLen TxSymbolShape dsm SymbolShapeLen ;************************************************************************* ;constant tables: FIR and window shapes LowFreq equ AliasLowFreq/SampleFreq UppFreq equ AliasUppFreq/SampleFreq w0 equ 0.35875 ;coeff. for Blackman-Harris 4 term w1 equ 0.48829 ;minimum sidelobe window (copied from Motorola BBS) w2 equ 0.14128 w3 equ 0.01168 org Y:AliasFilterI time = -@cvf(AliasFilterLen/2)+0.5 count set 0 dup AliasFilterLen angle = PI*time/@cvf(AliasFilterLen/2) Window = w0+w1*@cos(angle)+w2*@cos(2.0*angle)+w3*@cos(3.0*angle) Filter = (@sin(2.0*PI*time*UppFreq)-@sin(2.0*PI*time*LowFreq))/(PI*time) time = time+1.0 dc Window*Filter count set count+1 endm org Y:AliasFilterQ time = -@cvf(AliasFilterLen/2)+0.5 count set 0 dup AliasFilterLen angle = PI*time/@cvf(AliasFilterLen/2) Window = w0+w1*@cos(angle)+w2*@cos(2.0*angle)+w3*@cos(3.0*angle) Filter = (-@cos(2.0*PI*time*UppFreq)+@cos(2.0*PI*time*LowFreq))/(PI*time) time = time+1.0 dc Window*Filter count set count+1 endm s0 equ 0.35005138 ;Like Blackman-Harris but for minimal s1 equ 0.50799695 ;crosstalk between symbols. s2 equ 0.14499812 ;The Blackman-Harris is not that bad and s3 equ -0.01294745 ;the transmitted spectrum has no sidelobes. org Y:RxSymbolShape time = -@cvf(SymbolShapeLen/2)+0.5 count set 0 dup SymbolShapeLen angle = PI*time/@cvf(SymbolShapeLen/2) Filter = s0+s1*@cos(angle)+s2*@cos(2.0*angle)+s3*@cos(3.0*angle) ;Filter = 0.75*@cos(PI*time/@cvf(SymbolShapeLen))+0.25*@cos(3*PI*time/@cvf(SymbolShapeLen)) time = time+1.0 dc Filter/(SymbolShapeLen/2) count set count+1 endm org Y:TxSymbolShape time = -@cvf(SymbolShapeLen/2)+1.0 count set 0 dup SymbolShapeLen angle = PI*time/@cvf(SymbolShapeLen/2) ;Filter = 0.5+0.5*@cos(angle) Filter = s0+s1*@cos(angle)+s2*@cos(2.0*angle)+s3*@cos(3.0*angle) ;Filter = 0.75*@cos(PI*time/@cvf(SymbolShapeLen))+0.25*@cos(3*PI*time/@cvf(SymbolShapeLen)) time = time+1.0 dc Filter count set count+1 endm ;************************************************************************* end