PSK31 is a digital communications mode which is intended for live keyboard-to-keyboard conversations, similar to radioteletype. The data rate is 31.25 baud (about 50 word-per-minute). PSK31's ITU emission designator is 60H0J2B. It uses BPSK modulation without error correction.
Instead of traditional frequency-shift keying, the information is transmitted by patterns of polarity-reversals (sometimes called 180-degree phase shifts). One way to think about this would be to swap antenna terminals on each phase reversal.
The 31.25 baud data rate was chosen so that the system will handle hand-sent typed text easily. There is a problem with PSK keying, namely the effect of key-clicks. If hard keying of phase reversals were done, the result would be a very broad emission. The solution is to filter the output or to shape the envelope amplitude of each bit, which amounts to the same thing.
In PSK31 a cosine shape is used. Phase reversals are done at the minimum amplitude points. The spectrum during a continuous sequence of polarity reversals at 31 baud will consist of two pure tones at +15/-15 Hz from the center frequency and no splatter. A binary 0 is represented by a phase reversal and a binary 1 by no phase reversal.
My initial implementation will be to generate PSK at audio frequencies and later to investigate strategies to generate at RF frequencies. The audio tone chosen is 1 KHz constructed from 32 eight-bit samples at full amplitude per cycle. The period of a 1 KHz tone cycle is 1 millisecond. Each of the 32 samples per cycle has a period of 31.25 microseconds. The audio samples are eight bit values from $00 - $FF with the zero crossing value at the midpoint $80.
The PSK31 character bit time is 32 ms constructed of 1024 samples. A binary zero is represented by a phase reversal while a binary one is presented by the absence of a phase reversal. Characters are encoded with a variable bit length code (varicode) where the length of each character is inversely proportional to the frequency of use. Characters are encoded with a bit pattern where there are no sequential zero bits. Two zero bits in a row signify the end of a character.
In order to implement the ramp up/down scenarios at phase reversals, I have constructed a couple of tables of sinusoid information. The first consists of 512 table entries defining the 16 cycles of ramping up from zero to full amplitude. I have plotted the data in Excel as follows:
Once I get up to full amplitude, I use a separate 32 eight-byte table consisting of a single sinusoid. For a binary zero, I ramp down (512 samples) by processing the above table in reverse, reverse the phase and immediately ramp back up again (another 512 samples), this time processing the table in the forward direction. For a binary one, I use the 32 eight bit sample table below and repeat it 32 times for 1024 total samples.
The PSK31 engine is a PASM module that runs continuously in its own cog. Once started, it will begin playing a series of double zeros (continuous phase reversals) indicating there is no data to send until the cog is stopped or a data string is passed to it. A string buffer is passed to the cog with the first four bytes containing the length of the string, the data bytes following immediately.
The audio output is generated using PWM generated from the cog's counter in Duty mode. The zero crossing point is represented by a 50% duty cycle. A simple RC low pass filter is used to clean up the audio before amplification. Alternatively an external operational amplifier could be used to accomplish the same task. I am using a Propeller demo board which has a nice fixed gain stereo headset amplifier connected to pins 10 and 11 of the Propeller board. This configuration works quite nicely. Here is a partial schematic showing this setup:
I have completed the PSK engine with the exeption of the ability to pass in a string to send. For now I have hard coded a CQ message for testing purposes. I have been able to decode the audio using several PSK applications on both Windows and Macintosh platforms. A little more code and I think this little beacon will be ready to integrate with my collection of other beacons. I have implemented a $00 - $7F varicode table to translate ASCII characters into varicode before transmission.
Next I hope to investigate the possibility of implementing an RF solution rather than an audio solution.