I grabbed a copy of Joe Taylors wsprcode.exe application to determine the set of channel symbols that will make up my beacon message of "KO7M CN87 20". Here is that code:
C:\bin>wsprcode "KO7M CN87 20"
Message: KO7M CN87 20
Message: KO7M CN87 20
Source-encoded message (50 bits, hex): 8B CC 46 9D 56 B5 00
Data symbols:
1 1 0 0 0 0 0 1 1 1 1 0 1 0 1 0 0 1 1 0 0 1 0 1 1 0 0 0 0 1
1 1 1 0 0 1 1 1 0 0 1 1 1 1 0 0 1 1 1 0 1 0 0 0 1 0 1 0 0 0
0 0 0 0 0 0 0 1 0 0 1 1 1 1 0 1 1 1 0 1 0 0 1 1 1 0 0 0 0 1
0 0 0 1 1 0 1 0 0 1 1 1 0 1 0 0 0 1 0 0 1 1 0 0 0 0 1 0 0 1
0 1 0 1 0 0 0 0 1 0 0 0 1 1 0 1 0 0 1 0 0 1 0 0 0 1 0 1 0 0
1 0 1 1 1 1 1 0 0 0 0 1
1 1 0 0 0 0 0 1 1 1 1 0 1 0 1 0 0 1 1 0 0 1 0 1 1 0 0 0 0 1
1 1 1 0 0 1 1 1 0 0 1 1 1 1 0 0 1 1 1 0 1 0 0 0 1 0 1 0 0 0
0 0 0 0 0 0 0 1 0 0 1 1 1 1 0 1 1 1 0 1 0 0 1 1 1 0 0 0 0 1
0 0 0 1 1 0 1 0 0 1 1 1 0 1 0 0 0 1 0 0 1 1 0 0 0 0 1 0 0 1
0 1 0 1 0 0 0 0 1 0 0 0 1 1 0 1 0 0 1 0 0 1 0 0 0 1 0 1 0 0
1 0 1 1 1 1 1 0 0 0 0 1
Sync symbols:
1 1 0 0 0 0 0 0 1 0 0 0 1 1 1 0 0 0 1 0 0 1 0 1 1 1 1 0 0 0
0 0 0 0 1 0 0 1 0 1 0 0 0 0 0 0 1 0 1 1 0 0 1 1 0 1 0 0 0 1
1 0 1 0 0 0 0 1 1 0 1 0 1 0 1 0 1 0 0 1 0 0 1 0 1 1 0 0 0 1
1 0 1 0 1 0 0 0 1 0 0 0 0 0 1 0 0 1 0 0 1 1 1 0 1 1 0 0 1 1
0 1 0 0 0 1 1 1 0 0 0 0 0 1 0 1 0 0 1 1 0 0 0 0 0 0 0 1 1 0
1 0 1 1 0 0 0 1 1 0 0 0
1 1 0 0 0 0 0 0 1 0 0 0 1 1 1 0 0 0 1 0 0 1 0 1 1 1 1 0 0 0
0 0 0 0 1 0 0 1 0 1 0 0 0 0 0 0 1 0 1 1 0 0 1 1 0 1 0 0 0 1
1 0 1 0 0 0 0 1 1 0 1 0 1 0 1 0 1 0 0 1 0 0 1 0 1 1 0 0 0 1
1 0 1 0 1 0 0 0 1 0 0 0 0 0 1 0 0 1 0 0 1 1 1 0 1 1 0 0 1 1
0 1 0 0 0 1 1 1 0 0 0 0 0 1 0 1 0 0 1 1 0 0 0 0 0 0 0 1 1 0
1 0 1 1 0 0 0 1 1 0 0 0
Channel symbols:
3 3 0 0 0 0 0 2 3 2 2 0 3 1 3 0 0 2 3 0 0 3 0 3 3 1 1 0 0 2
2 2 2 0 1 2 2 3 0 1 2 2 2 2 0 0 3 2 3 1 2 0 1 1 2 1 2 0 0 1
1 0 1 0 0 0 0 3 1 0 3 2 3 2 1 2 3 2 0 3 0 0 3 2 3 1 0 0 0 3
1 0 1 2 3 0 2 0 1 2 2 2 0 2 1 0 0 3 0 0 3 3 1 0 1 1 2 0 1 3
0 3 0 2 0 1 1 1 2 0 0 0 2 3 0 3 0 0 3 1 0 2 0 0 0 2 0 3 1 0
3 0 3 3 2 2 2 1 1 0 0 2
2 2 2 0 1 2 2 3 0 1 2 2 2 2 0 0 3 2 3 1 2 0 1 1 2 1 2 0 0 1
1 0 1 0 0 0 0 3 1 0 3 2 3 2 1 2 3 2 0 3 0 0 3 2 3 1 0 0 0 3
1 0 1 2 3 0 2 0 1 2 2 2 0 2 1 0 0 3 0 0 3 3 1 0 1 1 2 0 1 3
0 3 0 2 0 1 1 1 2 0 0 0 2 3 0 3 0 0 3 1 0 2 0 0 0 2 0 3 1 0
3 0 3 3 2 2 2 1 1 0 0 2
Decoded message: KO7M CN87 20 ntype: 20
I then created a propeller procedure that sends this set of channel symbols based on code stolen from Eldon for his Opera beacon:
PUB Main
repeat
' Send symbol set for KO7M CN87 20
sendCode(string("330000023220313002300303311002222012230122220032312011212001101000031032321232030032310003101230201222021003003310112013030201112000230300310200020310303322211002"))
delay(120000)
For the moment I am ignoring all the timing code that requires WSPR transmissions to start on an even minute boundary. I just want to see if I can manually start this thing at the correct time and have Joe Taylor's WSPR application decode it.
So as I did in my Arduino WSPR beacon, I am setting the transmit frequency to be the middle of the four symbol set. On typical SSB transmitters a USB frequency setting for 30 metre band of 10.138.700 is used and a tone of 1500 Hz would yield a "transmit frequency" of 10.1402 at the middle of the 200 Hz WSPR band. There is no clear definition from any WSPR documentation what is meant by this "transmit frequency", so...
In the absence of clarity from Joe Taylor's documentation, I have chosen to define the transmit frequency like this:
Each symbol is 1.4648 Hz apart and the transmit frequency is mid-way between symbols 1 and 2. Band edge operations need to take this into account if you wish to stay within the defined WSPR frequency range with the entire 6 Hz spectrum occupied by the complete WSPR signal.
However, my stolen code has the ability to set the frequency with a 1 Hz resolution, so I have used 2 Hz rather than 1.4648 Hz symbol separation just for grins. Therefore, symbol offsets from the transmit frequency are as follows:
Symbol 0 -3 Hz
Symbol 1 -1 Hz
Symbol 2 +1 Hz
Symbol 3 +3 Hz
Here is the (stolen) sendCode function:
PUB sendCode(stringptr)
repeat strsize(stringptr)
sendSymbol(byte[stringptr++])
sendSymbol offsets the frequency from the transmit frequency as appropriate for the symbol being sent (the first bit of code I have actually written):
PUB sendSymbol(char)
case char
"0":
sendTone(-3)
delay(symbolLength)
"1":
sendTone(-1)
delay(symbolLength)
"2":
sendTone(1)
delay(symbolLength)
"3":
sendTone(3)
delay(symbolLength)
symbolLength is 8192 / 12000 seconds or about 683 milliseconds.
CON
symbolLength = 683
sendTone and noTone do the work of setting the frequency (dutifully stolen from the work of others). The Freq object can be found in the Parallax object library at their web page.
PUB sendTone(tone)
Freq.Synth("A",RFPin, Frequency + tone)
PUB noTone
Freq.Synth("A",RFPin, 0)
So with all this in place, I fired up Joe Taylor's WSPR application, tuned it to my propeller beacon and flipped the switch at the start of an even minute... Here is the Argo display of the unfiltered RF on 30 metres:
Here is the WSPR application display of the reception of this signal:
It seems that WSPR is robust enough for me to get cavalier about timing and non-phase continuous FSK modulation. Nice work Joe Taylor!
So, for the curious, here is the entire WSPR beacon test code thus far. Remember it sends "KO7M CN87 20" as the message. Use Joe's application to generate your own WSPR message string and paste it into the main procedure. It also does not know when an even minute begins, so that must be done manually by powering on the Propeller board at the correct moment, but not bad for a quick hack...
CON
_CLKMODE = XTAL1 + PLL16X
_XINFREQ = 5_000_000
CLK_FREQ = ((_CLKMODE-XTAL1)>>6)*_XINFREQ
MS_001 = CLK_FREQ / 1_000
RFPin = 27
XcvrDial = 10_138_700
TuneOffset = 1_500
Frequency = XcvrDial + TuneOffset '10.140200 mHz
symbolLength = 683 ' 8192 / 12000 * 1000 = milliseconds
VAR
OBJ
Freq : "Synth"
PUB Main
repeat
' Send symbol set for KO7M CN87 20
sendCode(string("330000023220313002300303311002222012230122220032312011212001101000031032321232030032310003101230201222021003003310112013030201112000230300310200020310303322211002"))
noTone
delay(120000)
PUB delay(ms) | t
t := cnt - 1088 ' 1088 is published time for overhead
repeat ms
waitcnt(t += MS_001)
PUB sendCode(stringptr)
repeat strsize(stringptr)
sendSymbol(byte[stringptr++])
PUB sendSymbol(char)
case char
"0":
sendTone(-3)
delay(symbolLength)
"1":
sendTone(-1)
delay(symbolLength)
"2":
sendTone(1)
delay(symbolLength)
"3":
sendTone(3)
delay(SymbolLength)
PUB sendTone(tone)
Freq.Synth("A",RFPin, Frequency + tone)
PUB noTone
Freq.Synth("A",RFPin, 0)
Next I should look at the Freq object implementation and see if I can get better than 1 Hz resolution on the numerically controlled oscillator.
you might get some clues on what the "reference frequency" is by looking at Genes Arduino code for wspr at http://www.knology.net/~gmarcus/
ReplyDeleteI have both his arduino boards going, including one that does qrss and wspr with band hopping
Dave
ww2r