PSK31 Demodulation (Kurt & Michael)
Project Description
The goal of this project is to design and code a Matlab script that will encode and decode a PSK31 signal including signals with noise. The receiver should be able to read in signals (as a wav file) from other sources as well.
PSK31 is a audible text encoding that can be sent over the air by amateur radio operators. A computer's sound card can be used to send and receive the signal since the signal is audible. For more information regarding PSK31 see the Wikipedia article.[1]
Our Approach
Code Overview
Transmitter
Our code creates a PSK31 signal given an input carrier frequency and message. For testing our receiver code, the transmitter is setup to generate a random carrier frequency and phase. It also adds random noise to the signal before writing it to a wav file.
Receiver
Our receiver is split into several steps:
- We read in the signal from a wav file and generate utility variables and matrices.
- We run the signal through an FFT and take an average over the range of the FFT spike to obtain a carrier frequency guess.
- A PID controller was implemented to help offset the fact that a carrier frequency derived from the FFT produces an inaccurate carrier frequency. An offset in the carrier frequency causes the constellation diagram to rotate in a circle. The PID tries to compensate for this by adding to or subtracting from the phase of the signal while trying to drive the Q-component of the signal to zero. The feedback loop is described by the code below.
% PID controller constants Kp = 25; Ki = 50; Kd = 1; output = zeros(1, length(v)); % Init setpoint = 0; % Sets the feedback point to control to. previous_error = 0; % In this case, you want to set yt to 0. integral = 0; xt_filt = []; yt_filt = []; for k=51:length(v) xt(k) = v(k)*cos(2*pi*u_fc*t(k)+output(k)); yt(k) = v(k)*sin(2*pi*u_fc*t(k)+output(k)); xt_filt(k:-1:k-50) = filter(b, a, xt(k:-1:k-50)); yt_filt(k:-1:k-50) = filter(b, a, yt(k:-1:k-50)); if(sign(xt(k)) == sign(yt(k))) error = setpoint - yt_filt(k); else error = setpoint + yt_filt(k); end % PID Feedback Controller compensates for inaccurate fc guess. % error = setpoint - yt_filt(k); integral = integral + error*10; derivative = (error - previous_error)/10; output(k+1) = Kp*error + Ki*integral + Kd*derivative; previous_error = error; end
- We multiply the signal with a cosine wave at our guess frequency. This splits the signal into two parts: a high frequency component (with frequency equal to the sum of the actual carrier frequency and our guess frequency) and a low frequency component (due to the difference of the two frequencies).
- We filter the multiplied signal through a butterworth filter with a 75Hz cutoff frequency to remove the high frequency component.
- We mark the locations where the filtered signal changes sign