In a series of previous posts (search this blog for "fox hunt"), I have described a fox hunt transmitter for simultaneous HF and VHF fox hunting.
I have made some slight changes to the code to select a VHF frequency based on serial number and made different recordings for the voice announcement on VHF that will identify the fox beacon code. I have reduced the audio sample rate to 8 kHz and set the deviation to +/- 12.75 kHz.
I decided that given I don't have any experience yet with the VHF fox that I would put each of them on a different VHF FM simplex frequency based on it's serial number.
SN 0 - 147.420
SN 1 - 147.435
SN 2 - 147.450
SN 3 - 147.465
Once I have some experience with locating a VHF fox, I may experiment with putting multiple foxes on the same frequency and staggering their announcements.
Here you can see my four little foxes ready for their fox den. The eye bolts on the end will be attached to lengths of wire to provide both the HF and VHF antenna connections and a convenient way to hang the fox up in a tree or other hiding place. The end caps are not glued in place, so they can be removed to facilitate repairs, firmware changes or battery replacement. They will keep dust and rain at bay however quite nicely.
A standard 9V battery powers these devices for several days with only the HF beacon running on CW. It remains to be seen how much the VHF FM mode reduces that battery life figure.
Showing posts with label FM. Show all posts
Showing posts with label FM. Show all posts
Sunday, June 19, 2016
Sunday, June 5, 2016
Summertime! Let's get out there and fox hunt! (Part 2)
In my previous post, I described the first half of a hidden transmitter (fox) implemented using a Propeller Mini board for an HF CW beacon and some simple firmware. In this installment, I will describe the 2 meter FM portion of the firmware.
My first thought was to implement the VHF beacon transmitter using the same design as used on the HF CW beacon except to use MCW rather than CW using FM modulation of the 2 meter carrier.
This approach is simple enough, but rather than generate the audio CW signal to FM modulate the carrier, why not just modulate it with any recorded audio? In this way a vocal announcement could be use to identify the beacon.
In my case I decided to use a free Windows application called "Audacity" to make an audio recording of a 2 second announcement "Salmoncon Fox Hunt" and save it as a .wav file. The file is exported from Audacity as a 11.025 kHz sample rate, 8 bit, monaural recording which is then loaded into the program flash of the Propeller chip and used to FM modulate the 146 MHz carrier. At 11.025 kHz, two seconds of audio will be 11025 * 2 bytes plus 44 bytes of wav file header.
Using 8 bit samples, the sample byte is multiplied by 32 and added to the frequency being generated. SInce this deviation of the carrier frequency is happening at an audio rate, we have achieved FM modulation of the transmitter. This yields a maximum of 256 * 32 = 8.192 kHz of frequency deviation. A multiplier of 58 will get you to just shy of 15 kHz. For my purposes, 8 kHz is just fine.
Let's take a quick walk through the code as it is pretty trivial. Up top we see the same structure defining the necessary constants used in the code. In the comments we can see the formula for calculating the value used to set the RF frequency. For example:
146520000 / (16 * 80000000) * 2^32 = 491639537.664. Truncating to an integer is sufficient for this purpose. This value is loaded into the counter FRQA register to generate the desired 146.52 MHz signal.
' 2 meter FM fox hunt beacon
'
' ko7m - Jeff Whitlatch
'
' FRQx = frequency / (16 * CLKFREQ) * 2^32
'
' Propeller manual recommends limiting upper frequency to 128 MHz for best stabillity
' We of course ignore such advice and utilize it at 146.52 MHz
CON
_clkmode = XTAL1 + PLL16X
_xinfreq = 5_000_000
WMin = 381
RFPin = 8
FRQAvalue = 491_639_537 ' For 146.52 MHz (146520000 / (16 * 80000000) * 4294967296)
sampleRate = 11025 ' 11.025 kHz audio
waitKeyDn = 1000 ' Delay before audio starts with key down
waitKeyUp = 2000 ' Delay after audio ends before key up
wavHdrSize = 44 ' Size of wave file header
devScale = 5 ' deviation scaler for audio samples (256 * 32 = 8.192 kHz)
The only local variables used are when we are running this code on its own core. In this case we define the Stack space required and keep track of which core (cog) was assigned.
VAR
LONG Stack[16]
BYTE Cog
The Main function initializes the VHF beacon and runs the main function. To enable this code to be run on separate cores, Start and Stop functions are provided.
PUB Main
doInit
doBeacon
PUB Start : fSuccess
fSuccess := (Cog := cognew(Main, @Stack) + 1) > 0
PUB Stop
if Cog
cogstop(Cog~ - 1)
The doInit function sets up the RF pin as an output and configures the counter to enable RF generation on 2 metres
pri doInit
DIRA[RFPin]~~ ' Set RF pin as an output
CTRA := constant(010_111 << 23) + RFPin ' Configure the counter
This is the main function of the beacon. The CPU clocks per sample of audio at the audio sample rate is calculated. The index of the first byte of audio is calculated and RF generation of a carrier is initiated. After a brief pause, each byte of the audio data is used to FM modulate the carrier. Once the entire message is sent, the carrier is kept on for a couple seconds to help fox hunters zero in on the transmitter. The RF is then shut down and after a short delay, the process repeats.
PRI doBeacon | p, time, clocksPerSample
clocksPerSample := clkfreq / sampleRate ' System clocks per audio sample
p := constant(@audioStart + wavHdrSize) ' Pointer into our audio data just past the wav file header
FRQA := FRQAvalue ' Go key down
delay(waitKeyDn) ' Wait before modulation starts
time := cnt
' Play the audio file once through
repeat while p++ < @audioEnd
FRQA := FRQAvalue + byte[p] << devScale ' Scale amplitude byte by 32 (2^8 * 32 = 8.192 kHz deviation max)
waitcnt(time += clocksPerSample) ' Wait until time for the next sample
delay(waitKeyUp) ' Delay before dropping carrier
FRQA := 0 ' Turn off NCO
pri delay(Duration)
waitcnt(((clkfreq / 1_000 * Duration - 3932) #> WMin) + cnt)
The audio data is stored in the data secion of the code. Since there is only 64 kb of ROM on the device, the amount of recorded data is limited to available ROM space. If desired, the audio sample rate could be reduced to 8 kB to enable increased message length. The actual audio data is stored in the "foxhunt.wav" file specified in the same directory as this file.
DAT
audioStart byte
File "foxhunt.wav" ' Audio data to be transmitted
audioEnd byte 0
Ok, so now we have two beacons that can be used independently. In my next installment, I shall tie these two modules together so they can be used simultaneously. I will also provide a hex file of the compiled code should you not wish to mess with installing the Propeller Tools for code development.
Improvements of course could be made. Any sample rate of audio could be used and the encoded rate read from the .wav file header for example rather than needing to change a constant for a different sample rate file. Let your imagination be your guide. Have fun and as always if you get stuck, drop me a note at ko7m at arrl dot net and I will try my best to help you out.
See you in the next installment. For your convenience, the entire source code is reproduced below.
' 2 meter FM fox hunt beacon
'
' ko7m - Jeff Whitlatch
'
' FRQx = frequency / (16 * CLKFREQ) * 2^32
'
' Propeller manual recommends limiting upper frequency to 128 MHz for best stabillity
' We of course ignore such advice and utilize it at 146.52 MHz
CON
_clkmode = XTAL1 + PLL16X
_xinfreq = 5_000_000
WMin = 381
RFPin = 8
FRQAvalue = 491_639_537 ' For 146.52 MHz (146520000 / (16 * 80000000) * 4294967296)
sampleRate = 11025 ' 11.025 kHz audio
waitKeyDn = 1000 ' Delay before audio starts with key down
waitKeyUp = 2000 ' Delay after audio ends before key up
wavHdrSize = 44 ' Size of wave file header
devScale = 5 ' deviation scaler for audio samples (256 * 32 = 8.192 kHz)
VAR
LONG Stack[16]
BYTE Cog
PUB Main
doInit
doBeacon
PUB Start : fSuccess
fSuccess := (Cog := cognew(Main, @Stack) + 1) > 0
PUB Stop
if Cog
cogstop(Cog~ - 1)
pri doInit
DIRA[RFPin]~~ ' Set RF pin as an output
CTRA := constant(010_111 << 23) + RFPin ' Configure the counter
PRI doBeacon | p, time, clocksPerSample
clocksPerSample := clkfreq / sampleRate ' System clocks per audio sample
p := constant(@audioStart + wavHdrSize) ' Pointer into our audio data just past the wav file header
FRQA := FRQAvalue ' Go key down
delay(waitKeyDn) ' Wait before modulation starts
time := cnt
' Play the audio file once through
repeat while p++ < @audioEnd
FRQA := FRQAvalue + byte[p] << devScale ' Scale amplitude byte by 32 (2^8 * 32 = 8.192 kHz deviation max)
waitcnt(time += clocksPerSample) ' Wait until time for the next sample
delay(waitKeyUp) ' Delay before dropping carrier
FRQA := 0 ' Turn off NCO
pri delay(Duration)
waitcnt(((clkfreq / 1_000 * Duration - 3932) #> WMin) + cnt)
DAT
audioStart byte
File "foxhunt.wav" ' Audio data to be transmitted
audioEnd byte 0
My first thought was to implement the VHF beacon transmitter using the same design as used on the HF CW beacon except to use MCW rather than CW using FM modulation of the 2 meter carrier.
This approach is simple enough, but rather than generate the audio CW signal to FM modulate the carrier, why not just modulate it with any recorded audio? In this way a vocal announcement could be use to identify the beacon.
In my case I decided to use a free Windows application called "Audacity" to make an audio recording of a 2 second announcement "Salmoncon Fox Hunt" and save it as a .wav file. The file is exported from Audacity as a 11.025 kHz sample rate, 8 bit, monaural recording which is then loaded into the program flash of the Propeller chip and used to FM modulate the 146 MHz carrier. At 11.025 kHz, two seconds of audio will be 11025 * 2 bytes plus 44 bytes of wav file header.
Using 8 bit samples, the sample byte is multiplied by 32 and added to the frequency being generated. SInce this deviation of the carrier frequency is happening at an audio rate, we have achieved FM modulation of the transmitter. This yields a maximum of 256 * 32 = 8.192 kHz of frequency deviation. A multiplier of 58 will get you to just shy of 15 kHz. For my purposes, 8 kHz is just fine.
Let's take a quick walk through the code as it is pretty trivial. Up top we see the same structure defining the necessary constants used in the code. In the comments we can see the formula for calculating the value used to set the RF frequency. For example:
146520000 / (16 * 80000000) * 2^32 = 491639537.664. Truncating to an integer is sufficient for this purpose. This value is loaded into the counter FRQA register to generate the desired 146.52 MHz signal.
' 2 meter FM fox hunt beacon
'
' ko7m - Jeff Whitlatch
'
' FRQx = frequency / (16 * CLKFREQ) * 2^32
'
' Propeller manual recommends limiting upper frequency to 128 MHz for best stabillity
' We of course ignore such advice and utilize it at 146.52 MHz
CON
_clkmode = XTAL1 + PLL16X
_xinfreq = 5_000_000
WMin = 381
RFPin = 8
FRQAvalue = 491_639_537 ' For 146.52 MHz (146520000 / (16 * 80000000) * 4294967296)
sampleRate = 11025 ' 11.025 kHz audio
waitKeyDn = 1000 ' Delay before audio starts with key down
waitKeyUp = 2000 ' Delay after audio ends before key up
wavHdrSize = 44 ' Size of wave file header
devScale = 5 ' deviation scaler for audio samples (256 * 32 = 8.192 kHz)
The only local variables used are when we are running this code on its own core. In this case we define the Stack space required and keep track of which core (cog) was assigned.
VAR
LONG Stack[16]
BYTE Cog
The Main function initializes the VHF beacon and runs the main function. To enable this code to be run on separate cores, Start and Stop functions are provided.
PUB Main
doInit
doBeacon
PUB Start : fSuccess
fSuccess := (Cog := cognew(Main, @Stack) + 1) > 0
PUB Stop
if Cog
cogstop(Cog~ - 1)
The doInit function sets up the RF pin as an output and configures the counter to enable RF generation on 2 metres
pri doInit
DIRA[RFPin]~~ ' Set RF pin as an output
CTRA := constant(010_111 << 23) + RFPin ' Configure the counter
This is the main function of the beacon. The CPU clocks per sample of audio at the audio sample rate is calculated. The index of the first byte of audio is calculated and RF generation of a carrier is initiated. After a brief pause, each byte of the audio data is used to FM modulate the carrier. Once the entire message is sent, the carrier is kept on for a couple seconds to help fox hunters zero in on the transmitter. The RF is then shut down and after a short delay, the process repeats.
PRI doBeacon | p, time, clocksPerSample
clocksPerSample := clkfreq / sampleRate ' System clocks per audio sample
p := constant(@audioStart + wavHdrSize) ' Pointer into our audio data just past the wav file header
FRQA := FRQAvalue ' Go key down
delay(waitKeyDn) ' Wait before modulation starts
time := cnt
' Play the audio file once through
repeat while p++ < @audioEnd
FRQA := FRQAvalue + byte[p] << devScale ' Scale amplitude byte by 32 (2^8 * 32 = 8.192 kHz deviation max)
waitcnt(time += clocksPerSample) ' Wait until time for the next sample
delay(waitKeyUp) ' Delay before dropping carrier
FRQA := 0 ' Turn off NCO
pri delay(Duration)
waitcnt(((clkfreq / 1_000 * Duration - 3932) #> WMin) + cnt)
The audio data is stored in the data secion of the code. Since there is only 64 kb of ROM on the device, the amount of recorded data is limited to available ROM space. If desired, the audio sample rate could be reduced to 8 kB to enable increased message length. The actual audio data is stored in the "foxhunt.wav" file specified in the same directory as this file.
DAT
audioStart byte
File "foxhunt.wav" ' Audio data to be transmitted
audioEnd byte 0
Ok, so now we have two beacons that can be used independently. In my next installment, I shall tie these two modules together so they can be used simultaneously. I will also provide a hex file of the compiled code should you not wish to mess with installing the Propeller Tools for code development.
Improvements of course could be made. Any sample rate of audio could be used and the encoded rate read from the .wav file header for example rather than needing to change a constant for a different sample rate file. Let your imagination be your guide. Have fun and as always if you get stuck, drop me a note at ko7m at arrl dot net and I will try my best to help you out.
See you in the next installment. For your convenience, the entire source code is reproduced below.
' 2 meter FM fox hunt beacon
'
' ko7m - Jeff Whitlatch
'
' FRQx = frequency / (16 * CLKFREQ) * 2^32
'
' Propeller manual recommends limiting upper frequency to 128 MHz for best stabillity
' We of course ignore such advice and utilize it at 146.52 MHz
CON
_clkmode = XTAL1 + PLL16X
_xinfreq = 5_000_000
WMin = 381
RFPin = 8
FRQAvalue = 491_639_537 ' For 146.52 MHz (146520000 / (16 * 80000000) * 4294967296)
sampleRate = 11025 ' 11.025 kHz audio
waitKeyDn = 1000 ' Delay before audio starts with key down
waitKeyUp = 2000 ' Delay after audio ends before key up
wavHdrSize = 44 ' Size of wave file header
devScale = 5 ' deviation scaler for audio samples (256 * 32 = 8.192 kHz)
VAR
LONG Stack[16]
BYTE Cog
PUB Main
doInit
doBeacon
PUB Start : fSuccess
fSuccess := (Cog := cognew(Main, @Stack) + 1) > 0
PUB Stop
if Cog
cogstop(Cog~ - 1)
pri doInit
DIRA[RFPin]~~ ' Set RF pin as an output
CTRA := constant(010_111 << 23) + RFPin ' Configure the counter
PRI doBeacon | p, time, clocksPerSample
clocksPerSample := clkfreq / sampleRate ' System clocks per audio sample
p := constant(@audioStart + wavHdrSize) ' Pointer into our audio data just past the wav file header
FRQA := FRQAvalue ' Go key down
delay(waitKeyDn) ' Wait before modulation starts
time := cnt
' Play the audio file once through
repeat while p++ < @audioEnd
FRQA := FRQAvalue + byte[p] << devScale ' Scale amplitude byte by 32 (2^8 * 32 = 8.192 kHz deviation max)
waitcnt(time += clocksPerSample) ' Wait until time for the next sample
delay(waitKeyUp) ' Delay before dropping carrier
FRQA := 0 ' Turn off NCO
pri delay(Duration)
waitcnt(((clkfreq / 1_000 * Duration - 3932) #> WMin) + cnt)
DAT
audioStart byte
File "foxhunt.wav" ' Audio data to be transmitted
audioEnd byte 0
Subscribe to:
Posts (Atom)