Thursday, January 19, 2012

Winter Wonderland

We have had a bit of a winter storm hit over here and it has dumped about 8 inches of snow on the KO7M QTH.



The power went out this morning with the mains dropping to about 60 volts per side of the 220 mains.  Not good...  I pulled the main breaker and connected up my little Honda generator and am able to keep the furnace fan, refrigerator and a few lights running as well as the computer.  Right now we are having freezing rain.  The packed snow on the roads is rapidly turning to an ice rink.  Lots of fun in Seattle.

Wednesday, January 18, 2012

Beacon Power Output

My Propeller beacon is now on the air on 30 metres.  Currently running QRSS near the bottom of the band (10.140.000) sending "KO7M CN87" in 5 hz FSK.  Would love to have any reception reports.  Currently running around 7 mW into a fence-mounted vertical.  SWR is 1:1 fortunately.  :)  I will from time-to-time (on a whim) reconfigure it as I am now working on getting the WSPR beacon code to be autonomous which involves figuring out how to do the strict WSPR timing of transmissions.

More Propeller Frequency Stability

After wrapping the propeller board in foam, from a cold start, after about 30 minutes the frequency stabilized at about 30 Hz lower than the cold start value.


So, it appears that my chasing of this error correction value has been a bit of a boondoggle as I had not attended to the temperature stability of the device.  (Doh!)  I should be able to zero in on my ErrorOffset value and be able to let it be, or so I hope.


Tuesday, January 17, 2012

Propeller frequency stability

This evening, I have been experimenting a bit with my Propeller device.  I have a small script that turns on the RF synthesizer at 10_140_000 mHz for 30 seconds, off for 10 seconds etc.  I use it for calibration of the frequency of the board in use as different Propeller boards will have different amounts of error in frequency generation.  The script looks like this:

CON
  _CLKMODE = XTAL1 + PLL16X
  _XINFREQ = 5_000_000

 
  CLK_FREQ = ((_CLKMODE-XTAL1)>>6)*_XINFREQ
  MS_001 = CLK_FREQ / 1_000

 
  RFPin  = 27
 
  TxFreq      = 10_140_000
  ErrorOffset =       -467
  
  Frequency = TxFreq + ErrorOffset
 
VAR

OBJ
  Freq : "Synth"
 
PUB Main

  repeat
    sendTone(0)
    delay(30000)
    noTone   
    delay(10000)

PUB delay(ms) | t
  t := cnt - 1088               ' 1088 is published time for overhead
  repeat ms
    waitcnt(t += MS_001)


PUB sendTone(tone)
  Freq.Synth("A",RFPin, Frequency + tone)


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


This simple little script I find to be very useful when I need to generate a signal at some frequency.  The on/off modulation of the signal allows me to find it more easily on uncalibrated receivers.

Viewing the output from a local receiver using Argo we find this waveform.  As you can see, my board has approximately -467 Hz of error which is corrected for in this script.  Nevertheless, as the board changes temperature, it does drift a bit.  As can be seen below I have drifted a hertz or two lower since calibration of the board was last done.


  I begin to wonder however why this ErrorOffset value seems to change when using the same board, just a different application.  For example my Hellscrieber code appears to transmit about 3 Hz lower with the same ErrorOffset value.  I added a 30 second carrier at the beginning of the code to see exactly what frequency it is on before launching into the transmission of FeldHell codes.  With the transmit frequency set to 10_139_980 and the same -467 ErrorOffset value, the following is observed:


I am clearly 5-6 Hz low.  The frequency is also different than in the previous example, so that may be related.  I think however that it may just be the drift of the device.  Going back to the Tune application, which should be a hertz or two low at 10_140_000, we see the following:


Hmmm...  So it appears that I am just chasing a temperature drift of the Propeller board over time.  Adding some thermal stabilization to it would probably help.  I will wrap it up in some foam and let it run for a while and see if the frequency stabilizes.

Here is a cold start image of my QRSS signal.  Out of the box, it seems that there is a significant drift:


And a few minutes later we can see it has drifted over 20 Hz:


 I will let it run and see where it stabilizes.

Monday, January 16, 2012

Hellschreiber QRSS using Propeller

Last evening, I shared the experience of creating a FeldHell-like QRSS beacon.  The bulk of the effort was in creating an acceptable font.  The Propeller chip has a rather nice font already in ROM but it is more suited for TV video output than for QRSS due to its 16x32 size.  I felt that this was too much bandwidth to occupy for a single signal in the QRSS band.

I created the font definition in a text editor and decided to try a 5x7 font initially.  With this format, each character is 5 bytes (one byte for each column of the font character).  For example, the letter "A" is represented thus:

     XXX
    X   X
    X   X
    XXXXX
    X   X
    X   X
    X   X

Each colum of the character in the 5x7 grid is encoded as a byte where the "X" character above is encoded as a set bit and the lack of an "X" is encoded as a 0.  So to create this, I defined all my characters (0..9, A..Z) as shown above in a text file.  I then imported the text file into a spreadsheet and rotated the rows and columns 90 degrees using the spreadsheet "Transpose" function.  This had the effect of laying all the characters down on their sides, thus:

     XXXXXX
    X  X
    X  X
    X  X
     XXXXXX

I then exported the file back to a text file for further processing.  You have to now imagine each of the font characters lying on their sides like the example above, occupying five very long lines of my text file.  I then globally replaced all the space characters (there is a space in each 5x7 grid anyplace there is no "X") with a "0" character and replaced the "X" characters with "1".  For the "A" character above, this resulted in:

    0111111
    1001000
    1001000
    1001000
    0111111

I then turned this mess into a valid DAT block containing binary byte values like so:

DAT
    ' FeldHell font definitions
    '             A         B         etc
    Col5 BYTE %0111111, %xxxxxxx, ...
    Col4 BYTE %1001000, %xxxxxxx, ...
    Col3 BYTE %1001000, %xxxxxxx, ...
    Col2 BYTE %1001000, %xxxxxxx, ...
    Col1 BYTE %0111111, %xxxxxxx, ...

Now I can index into this table and obtain the column data I need for each character.  So now in the main loop, I can call this procedure to process the beacon text:

PUB doFeldHellBeacon
    ' Send Feld Hell beacon text
    sendFeldHellString(string("KO7M CN87xp"))


PUB sendFeldHellString(strMsg)
    repeat STRSIZE(strMsg)
      sendFeldHellChar(BYTE[strMsg++])


The code to send each character is a quick hack, so don't beat me up too much.  I am still playing around with the timing to make it look nice.  Each character of the message text is looked up in the DAT table above to obtain the byte containing each of the 5 column definitions.  The character is sent from bottom left (least significant bit of Col1) to the top of the column and then proceeding with the next column until all five columns have been sent.  I test the least significant bit of each byte of column data and send a tone if it is set and send nothing if unset.  Right shift to get the next bit and continue for all 7 bits.

PUB sendFeldHellChar(ch) | i, j, iCol, columnData, Time
   
    Time := 300
   
    ' set up column index to default to space character
    iCol := -1
   
    case ch
      "a".."z": iCol := ch - "a" + 10
      "A".."Z": iCol := ch - "A" + 10
      "0".."9": iCol := ch - "0"
   
    if iCol < 0
      delay(Time*12)            ' Handle the space character specially
    else
      repeat i from 4 to 0               ' 5 columns in reverse order
        columnData := Col5[iCol+(i*36)]  ' get the current column data
        repeat j from 0 to 6
          if columnData & 1    ' If the font bit is set, send a tone
            sendTone(j*2)
          else
            noTone
          columnData >>= 1     ' Right shift font data to get next bit
          delay(Time)          ' Give a little space between columns

        noTone
      delay(Time*6)            ' Give a little more space between letters


So, that is it...  Simple, eh?  Since the font definition is  five really long lines of text, I am not going to post the entire program here.  If you would like to have a copy of it however, I will be happy to email it to you if you will drop me a comment to this post on the blog.

I will be creating "a".."z" characters in the font and some punctuation, but have no plans to create any characters beyond what would be in a typical QRSS message.  I am using Eldon's 10 minute QRSS sync algorithm for stacked grabbers.  See his article here.

Here is what it looks like on the air:

More Propeller Madness

Well, my old pal Eldon has really done it now...  So much for sleep it seems with new toys to play with...

I decided to implement FeldHell mode on my Propeller based QRSS/WSPR/Opera/CW beacon.  It was a bit fun figuring out the timing and the font, but here is a sample:


It is a simple 5x7 font and I draw each character from the lower left to the upper right resulting in the slight forward slant of the characters.  Right now I have only defined upper case characters and numerics in the font.

I will post the complete code after I have gotten some sleep...  :)

Sunday, January 15, 2012

Propeller Opera beacon up and running tonight

Today I have built a low-pass filter for my Propeller beacon on 30 metres.  The spectrum analyzer shows the second and subsequent harmonics more than 45 db down, so I have put it on the air tonight.  I am beaconing every 15 minutes using Opera mode running only 5.6 mW currently.

Here is the current setup.  As you can see Eldon and I have shared the low pass filter design that he created with the aide of a design program.


I am eager, but not too hopeful that this little pennywhistle signal will be picked up somewhere this evening.  We shall see.  Thanks Eldon for sharing your design and the components necessary to build the low pass filter!

WSPR on the propeller

Well, I could not help myself and started implementing a WSPR beacon on the propeller board.  For now, I am just going to impelement the transmit portion with a precompiled message and fixed delay between beacons.

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
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
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
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
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.



Saturday, January 14, 2012

First Opera reception

Well, thanks to my buddy Eldon WA0UWH, I have been drug kicking and screaming into the world of Opera QRSS and the Propeller processor.

Stealing judiciously from the work of others, I have put together a beacon using the propeller processor and have Opera v1.1.0 beta up and running.  This morning I heard myself first (imagine that...) and then N7VVX down in Utah.  So, it seems another diversion is born...  Thanks Eldon...  :|


Before I can really put the propeller on the air, I will need to build a low pass filter for it as the output is a square wave.  The reception of my own call (KO7M) is without any antenna on the propeller board.  My idea for my low pass filter board is to have a set of switchable (via software) low pass filters on a single board that should be useful for this and my Arduino WSPR beacon.

Wednesday, January 4, 2012

Az-El mount

Found an interesting Az-El / Pan-Tilt mount today at http://www.flir.com/mcs/products/ptu-d300/rf/Documentation/index.cfm.  Quite the nice little unit.  I suspect they are quite proud ($$$) of it but have not been able to find any pricing information online.