Tuesday, January 31, 2012

Randomizing WSPR TX Percent

My propeller WSPR beacon so far has implemented TX Percent as a constant.  For example if you set TXPercent to 20% (0.20) then it will transmit every 10 minutes.  Joe Taylor's WSPR specification states that in reality, it should transmit randomly within that interval in order to minimize collisions with other stations transmitting with the same TX Percent value.  So rather than transmitting exactly every 10 minutes with this TX Percent value, I have implemented a routine to pick a random 2 minute period up to the value specified by TX Percent.  So, TX Percent now effectively specifies the maximum amount of time to wait between transmissions.

I created a variable to hold the current random number and initialized it with a constant.  The value of the constant is not important.  Pick your birthday or whatever.  It becomes the starting seed for the random number generator.

VAR
    LONG Rnd


PUB doInitialize
  Rnd  := 22041956                     ' Initialize random number seed

I then created a new procedure to calculate how long to wait before the next transmission based on TX Percent.  TX Percent is declared as a constant.  For me it is set to 20%

CON
  TXPercent =  0.20     ' Transmit 20% of the time or about every 10 minutes

PUB nextSync : s
  s := ROUND(1.0 / TXPercent * 2.0)    ' Calculate when next xmit occurs in minutes
  s := (||?Rnd // s)                   ' Randomize the result
  s += (s // 2)                        ' Send on a 2 minute boundary
  s *= 60                              ' Convert minutes to seconds


Right.  Now, in the main loop, we calculate how long to wait with each go by calling nextSync and setting the new value of Sync to the returned value.

PUB Main
  doInitialize
  repeat
    'Send symbol set for KO7M CN87 7
    sendCode(@mySyms)
    noTone
    Sync := nextSync
    repeat while SecondCnt // Sync
      delay(100)


This seems to do the job nicely.  While it is not always the case that you may want to have the transmission start time randomized, this brings the beacon code closer to that of the WSPR 2.x specification.  If you wish to have constant transmission periods, just change the Sync := nextSync line to set Sync to a constant number of seconds between transmissions.  Remember to make sure this equates to an even number of minutes between transmissions.

As you can see, my transmissions are now being nicely randomized up to 10 minutes.






For those interested, here is the entire updated beacon code:

CON
  _CLKMODE = XTAL1 + PLL16X
  _XINFREQ = 5_000_000
  WMin         =        381        'WAITCNT-expression-overhead Minimum
  RFPin        =         27        ' I use pin 27 for RF output

  ' WSPR standard frequencies

  ' Shown are the dial frequencies plus 1500 hz to put in the middle of
  ' the 200 hz WSPR band
  WSPR500KHz   =     502_400 + 1_500    ' 500 KHz
  WSPR160M     =   1_836_600 + 1_500    ' 160 metres
  WSPR80M      =   3_592_600 + 1_500    '  80 metres
  WSPR60M      =   5_287_200 + 1_500    '  60 metres
  WSPR40M      =   7_038_600 + 1_500    '  40 metres
  WSPR30M      =  10_138_700 + 1_500    '  30 metres
  WSPR20M      =  14_095_600 + 1_500    '  20 metres
  WSPR17M      =  18_104_600 + 1_500    '  17 metres
  WSPR15M      =  21_094_600 + 1_500    '  15 metres
  WSPR12M      =  24_924_600 + 1_500    '  12 metres
  WSPR10M      =  28_124_600 + 1_500    '  10 metres
  WSPR6M       =  50_293_000 + 1_500    '   6 metres
  WSPR4M       =  70_028_600 + 1_500    '   4 metres
  WSPR2M       = 144_489_000 + 1_500    '   2 metres
                     
  Frequency    =     WSPR30M     ' Set to 30 metres
  ErrorOffset  =          20     ' Specific to my propeller board - change this
  symbolLength =         683     ' 8192 / 12000 * 1000 = milliseconds
  TXPercent    =        0.20     ' Transmit 20% or about every 10 minutes

OBJ
  Freq : "Synth"
  'WSPR : "ko7mWSPREncode"
  'T    : "PSM_tv_text"
 
VAR
    LONG SecondCnt, Stack[16]
    LONG Sync
    LONG Rnd

DAT
    ' Symbol set for KO7M CN87 7
    mySyms BYTE "33020202322033300230030333100222201023012020023033"
           BYTE "22132320011212000112303210300300303300031212302010"
           BYTE "22021203023312132013030201132002230302330002020310"
           BYTE "303320231002", 0
              
PUB Main
  doInitialize
  repeat
    'Send symbol set for KO7M CN87 7
    sendCode(@mySyms)
    noTone
    Sync := nextSync
    repeat while SecondCnt // Sync
      delay(100)  

PUB doInitialize
  Rnd  := 22041956                    ' Initialize random seed           
  cognew(Clock, @Stack)               ' Start the clock COG
 
PUB sendCode(stringptr)
  if TXPercent > 0      ' If zero, not transmitting             
    repeat strsize(stringptr)
      sendSymbol(byte[stringptr++])

PUB sendSymbol(char)
  case char
   "0", 0:
    sendTone(-3)
    delay(symbolLength)
   "1", 1:
    sendTone(-1)
    delay(symbolLength)
   "2", 2:
    sendTone(1)
    delay(symbolLength)
   "3", 3:
    sendTone(3)
    delay(SymbolLength)
  
PUB sendTone(tone)
  Freq.Synth("A",RFPin, Frequency + tone + ErrorOffset)

PUB noTone
  Freq.Synth("A",RFPin, 0)

PUB delay(Duration)
  waitcnt(((clkfreq / 1_000 * Duration - 3932) #> WMin) + cnt)

PUB Clock              ' Runs In its own COG
  repeat
    delay(1000)        ' Update second counter every 1000 ms
    SecondCnt++        ' Should be good for 2^32 seconds or about 136 years

PUB nextSync : s
  s := ROUND(1.0 / TXPercent * 2.0)    ' Calculate when next TX occurs in minutes
  s := (||?Rnd // s)                   ' Randomize the result
  s += (s // 2)                        ' Always send on a 2 minute boundary
  s *= 60                              ' Convert minutes to seconds
 

No comments:

Post a Comment