PSK31 Demodulation (Kurt & Michael): Difference between revisions
Line 17: | Line 17: | ||
# We read in the signal from a wav file and generate utility variables and matrices. | # 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. | # We run the signal through an FFT and take an average over the range of the FFT spike to obtain a carrier frequency guess. | ||
# PID | # 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 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 filter the multiplied signal through a butterworth filter with a 75Hz cutoff frequency to remove the high frequency component. |
Revision as of 22:10, 12 December 2012
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