Line 67: Line 67:
 
Before implementing my code on the ATTiny, I wanted to do some verification and evaluate performance.  Fortunately, Octave has a [https://www.gnu.org/software/octave/doc/v4.0.1/Getting-Started-with-Oct_002dFiles.html C/C++ api] which allowed me to test my code with the same bit-precision as I would have on the microcontroller.  Shown below is my first shot at modulating and demodulating a signal at 600 bits/s.
 
Before implementing my code on the ATTiny, I wanted to do some verification and evaluate performance.  Fortunately, Octave has a [https://www.gnu.org/software/octave/doc/v4.0.1/Getting-Started-with-Oct_002dFiles.html C/C++ api] which allowed me to test my code with the same bit-precision as I would have on the microcontroller.  Shown below is my first shot at modulating and demodulating a signal at 600 bits/s.
  
     [[File:Fsk_modulation.png|thumb|center|800px|Modulated signal]]
+
     {caption_box|[[File:Fsk_modulation.png|thumb|center|800px|Modulated signal]]}
     [[File:demod.png|thumb|center|800px|Demodulation]]
+
     {caption_box|[[File:demod.png|thumb|center|800px|Demodulation]]}
 
     [[File:demod_lpf.png|thumb|center|800px|Demodulation with lowpass applied]]
 
     [[File:demod_lpf.png|thumb|center|800px|Demodulation with lowpass applied]]
  
Line 97: Line 97:
 
* DTFT coefficient generation - compute_coefficients.m
 
* DTFT coefficient generation - compute_coefficients.m
 
* binary fraction converter - dec2binfrac.m
 
* binary fraction converter - dec2binfrac.m
* DTFT computation - compute.cpp
+
* DTFT computation - compute_cpp.cpp
 
* ATTiny85 modem - main.c
 
* ATTiny85 modem - main.c

Revision as of 21:18, 26 November 2016


This is a prototype for a high altitude balloon project I worked on with the Purdue Orbital rocketry team. I designed this board to test the range and power draw of our comms system and threw on a relay and microcontroller so that it can be used for triggering things on a real flight.

Parts list

   * Baofeng DRA818V
   * Attiny 84
   * Attiny 85
   * Relay
   * Regulator

One of the FAA requirements is that balloons over a certain weight have four cutdown systems (two on the balloon envelope and two on the payload tether) and that these systems must be independent, meaning they are electrically disconnected from each other and have separate batteries. Many amateurs balloonists overlook this rule, but due to our close work with the FAA it is important that we follow the regulations.

To save on cost, I avoided the higher end radio specific devices on the market and stuck to hobby-tier components. First was the Baofeng DRA818V. This is cheap Chinese VHF transceiver that costs less than $20 on Amazon and has a decent amount of power. Some users claim that these devices bleed onto other channels and should have a lowpass filter on the output (mine is inline with the coax). There is also a UHF band available, but I chose VHF for potential future compatibility with the APRS system. APRS will be an essential part of the system, because most radios in this power level (0.5 - 1W transmission) can only achieve a few dozen miles tops transmitting from ground to balloon. The incorporation of APRS will greatly extend this range by taking advantage of amateur repeating stations called `digipeaters`.

Since this radio module is for handheld units that transmit audio, I needed some sort of modem for converting data to an analog format and vice-versa. One of the methods of modulation I investigated was DTMF, which is used commonly in amateur radio and is built in to many consumer units. However, DTMF modems tend to be rather large pin-wise and aren't compatible with most digipeaters, so I decided to build one from scratch using my favorite microcontroller, the ATTiny85. For starters, I need to modulate and demodulate incoming data (known as `symbols` in communications) so they can be transmitted over the air. In this case, most digipeaters use a standard known as `Bell-202` (also known as AFSK-1200), which is a simple modulation scheme where a logic 1 (mark) is represented by a 1200 Hz tone and a logic 0 (space) is represented by a 2200 Hz tone. I accomplished this by calculating an 8-point DTFT at 1200 Hz and 2200 Hz at a sample rate of 9600 Hz (determined through testing). I didn't use the FFT here because I'm only interested in the spectral power at two points.

I took some inspiration from this blogpost where somebody used an ATTiny as a software modulator/demodulator at 1200baud. It was written in assembly for the ATTiny10, which has incompatible hardware with the ATTiny85 and is not portable to other platforms.

Once I generated my DTFT coefficients, I used the Q number format, which is a method of handling signed fractional numbers within fixed point datatypes. I wrote a bit of code to do the conversion.

Calculating coefficients

     #!/bin/octave
     ## Evan Widloski - 2016-10-15
     ## calculate DTFT coefficients and express as binary fractions
     ## ----- Convert decimal numbers to n bit signed binary fractions -----
     function out = dec2binfrac(x,n)
       ## round input array to nearest 1/(2^n)
       x = round(x * 2^n)/(2^n);
       k = [1:n-1];
       if (x < 0)
         x = 1+x;
         out = -2^(n-1);
       else
         out = 0;
       endif
       twos_complement = mod(abs(x),.5.^(k-1)) >= .5.^k;
       bin_values = 2.^[n-2:-1:0];
       out += sum(bin_values .* twos_complement);
     endfunction
     ## ----- Create coefficients for implementation in C -----
     N = 8
     ## generate DFT coefficients
     Xd1 = e.^(-i*2*pi*(1200/9600)*[0:N-1]);
     Xd2 = e.^(-i*2*pi*(2200/9600)*[0:N-1]);
     ## scale down coefficients by 1 bit, since `1` can't be expressed as binary fraction
     ## e.g. scale 1 to 127/128
     Xd1 = Xd1*((2^(N-1) - 1)/2^(N-1));
     Xd2 = Xd2*((2^(N-1) - 1)/2^(N-1));
     ## express coefficients as signed N-bit binary fractions (Q7)
     arrayfun(@(x) dec2binfrac(x,N),real(Xd1))
     arrayfun(@(x) dec2binfrac(x,N),imag(Xd1))
     arrayfun(@(x) dec2binfrac(x,N),real(Xd2))
     arrayfun(@(x) dec2binfrac(x,N),imag(Xd2))

This yielded 4 arrays which would calculate the DFT at 1200 and 2200 Hz with a 9600 Hz sample rate.

Simulation

Before implementing my code on the ATTiny, I wanted to do some verification and evaluate performance. Fortunately, Octave has a C/C++ api which allowed me to test my code with the same bit-precision as I would have on the microcontroller. Shown below is my first shot at modulating and demodulating a signal at 600 bits/s.

{caption_box|
Modulated signal
} {caption_box|
Demodulation
}
Demodulation with lowpass applied

Initially, I generated my test signals incoherently, meaning that the phase resets each time the signal transitions from a mark to a space and vice versa. This creates discontinuities and adds noise to the spectrum in the transition regions. From the results below, it was clear that my implementation really needed to be coherent.

Incoherent test signal. Notice jumps in the generated signal
Spectrogram view of incoherent test signal. There is noticeable fuzziness in the transition regions.
Coherent test signal. No more discontinuities.
Spectrogram view of coherent test signal. cleaner transitions between frequencies.

I did some testing simulating the effects of gaussian noise as well.

4:1 SNR. Square wave still visible. Small blip on bit transition.
2:1 SNR. Square wave begins to distort. More problems in transition regions.

Once the modem was working in simulation, I designed some PCBs, moved it to the ATTiny85 and began physical testing.

Direct modem-to-modem comms testing
Radio breadboarding and testing
Schematic
Board
PCB Received
Finished pair

Source code

File:Source.zip

  • modem simulation - simulation.m
  • DTFT coefficient generation - compute_coefficients.m
  • binary fraction converter - dec2binfrac.m
  • DTFT computation - compute_cpp.cpp
  • ATTiny85 modem - main.c

Alumni Liaison

Abstract algebra continues the conceptual developments of linear algebra, on an even grander scale.

Dr. Paul Garrett