The goal of this project is to create a simple model of a super heterodyne receiver on Matlab and test the efficiency of it as we try to demodulate sample radio files that are given to us. By the end of this post you will understand each stage of this receiver, how it works and what the code implementation of it in Matlab is.
This project was done for the EL022A module of Mid Sweden University: Applied Digital Filters.The code for this project can be found in github
The basic components that are also going to be implemented in this project can be seen in figure 1. The input of our receiver is going to be a signal from the antenna, which is going to be amplified through a proper amplifier. The next stage will be the mixing of the input signal with a signal generated by a local oscillator. The mixing will bring our signal to an “Intermediate Frequency” which is known and we can apply a band pass filter around that frequency, so that noise can be eliminated. After we have filtered our signal we can demodulate it (in this project we will use an envelope detector to achieve this result) and finally the output of that will be sent to our speaker, so that we can hear and verify the result.
After this short introduction, we need to see the theory for some parts of the receiver before we start examining the Matlab code and the results for each step.
The mixer component that we utilize is effectively a multiplier. Let us assume that our input signal is sin(a) and the local oscillator is sin(b) with a=2πfa and b=2πfb. Due to trigonometric properties of the sine we will get . What we see here is the creation of two mirror components (fa+fb and fa-fb) that have half the amplitude of the original signals. It is pretty obvious that we are going to set one of those frequencies as our intermediate frequency. So, we will use . We are going to use this equation later.
A filter, by definition, is a construct that lets us get a signal within specified frequency boundaries, while rejecting all the other frequencies that are not wanted. In this project we worked with IIR filters. An infinite Impulse Response filter is a type of filter that its response does not become zero after a certain point, but continues indefinitely. This is achieved by the feedback topology that is fed back to the input.
A block diagram of that can be seen below, where x is our input, y is out output and k is coefficients, while D is a delay element. We can see that the output is the result of the input, through some coefficient, to which it is added the feedback from the output though some delay.
The code for the implementation of this structure will be shown later.
The last part of our signal being processed is the demodulation procedure. In this procedure we will try to get our desired signal by the use of an envelope detector. The envelope detector is a circuit that actually removes the high frequency components of a signal (in our case the carrier signal) and gives us the low frequency audio signal. This can be achieved by getting the absolute value of the signal in the time domain and then using a low pass filter on it as it can be seen below.
Now that we have seen some very basic concepts about the components that make up the receiver, we will see the actual code that can implement those in order to get our result. We will proceed, step by step and see what our code is and what the result is.
For this project we were given two files, named “radioA” and “radioB” respectively. Those 2 files have information modulated into channels, while noise is being added. The first file was given to us for test purposes; to actually see if our code worked with it and when we were ready we could utilize our code to demodulate the information in the second file, which contained three short audio clips.
To load the file, this is the code that we are writing.
%% File Loading Script % Here the user shall be given the choice to % load one of the two different files given radio_file = menu('Choose the radio signal you want to load','radioA','radioB'); if radio_file == 1 load('radioA.mat'); end if radio_file == 2 load('radioB.mat'); end
This will create a menu icon that will prompt the user to choose one of the two files. Let us choose “radioA” for our convenience. After that we will plot the raw radio input as it can be seen in figure 6, using a function called TimePlot(). The code for all the functions used will be shown in the appendix so as to not disrupt the flow of this report.
For the amplification part, there was trial-and-error experimentation which led to the result that can be seen in the code. Because the audio clips were a little bit quiet, I decided to implement a sort of “Amplification” part, where the amplitude of the input is multiplied by a coefficient. In our case 3 as it was the minimum value that would not cause clipping in the end. The code can be seen below.
%% Amplification radio = 3*radio; %Simple Amplification
After having loaded our input, we need to analyze the spectrum of our radio input. This is done with the following lines of code:
%% Spectrum analyzing script SpectrumPlot(radio); %Plotting the Frequency Response of the Input
SpectrumPlot() is a function that does an FFT transform on a signal and can also be seen in the appendix. The result of the plot is really interesting. It seems that we have 3 channels present in our signal, at 1MHz, 1.2 MHz and 1.4 MHz. We also know that our Intermediate frequency by specification is 450 kHz. This means that we will need to implement in our next stage, the local oscillator modeling 3 frequencies: 550 kHz, 750 kHz and 950 kHz because of
The first thing we will do when we set the local oscillator is chose the channel that we want to demodulate. This is done in the same way that the loading has been achieved. In this example let us choose Channel 1.
%% Mixer modeling % Local Oscillator Parameters %----------------------------------------------- %Setting the Frequency of the Oscillator in Hz freq_option = menu('Choose the channel you want to hear','Channel 1','Channel 2','Channel 3'); if freq_option == 1 sigF1 =550000; % First channel sinewave (550kHz) end if freq_option == 2 sigF1 =750000; % Second channel sinewave (750kHz) end if freq_option == 3 sigF1 =950000; % Third channel sinewave (950kHz) end
The rest of the parameters can be seen below. We know that our sampling frequency should be 6MHz by specification. So we create a sine wave that has the frequency chosen in the previous part and has an amplitude of 1.
Fs = 6E6; % 6 MHz of sampling frequency sigA1 = 1; % Amplitude of Local Osc Signal nos = length(radio); % Number of Samples used for simulation sp = 1/Fs; % Sampling period t = linspace(0,sp*nos,nos);% Signal duration osc_signal = sigA1*sin(2*pi*sigF1*t); % Creation of sine wave
For the mixing part, what we need to do is element-wise multiplication 1 to 1 of our input signal and the local oscillator’s one. This can be achieved by the following command.
mix_out = osc_signal.*radio;% Element-wise multiplication
The result of it can be seen below. We can realize that we have created the modulated spectrum of our input, as well as the mirror one and Channel 1 is located exactly at 450 kHz. We achieved what we wanted in the first place and now we are ready for the filtering.
After the modulation, we need to filter our signal around the Intermediate Frequency. For this reason, we are using an IIR filter and more specifically a direct form 2. The code can be seen in the Appendix. It is a function that takes as an input our signal and some specific parameters from the filter design and returns us the filtered result. Before the application of the filter we need to design it. By typing fdatool in the console we can start the filter design tool.
A design of our filter as well as all the parameters can be seen in the saved session below. We are using a band pass elliptic IIR filter at around 450 kHz which is also a sixth order filter. After the design we convert to single point and see that it is stable so we export the Numerator and Denominator to be used with our filter (Num and Den variables).
After we test it with the benchmark already designed in earlier labs, we apply it to our signal with the following lines of code:
%% Intermediate Frequency Filtering %Implement a band pass filter load('BandPassIF.mat'); %Loading the filter parameters IF_signal = filterIIR2t(mix_out,Num,Den); %Applying the filter on the signal
After that, we plot the spectrum of the signal and find out that the result is pretty acceptable.
At this stage we have filtered our signal and now we just want to remove the carrier signal. For that reason we need to design a Low Pass filter, with a cutoff frequency of 15 kHz. The fdatool session again is visible below.
As it was already mentioned in the introduction, we needed to take the absolute value of our signal, apply a low pas filter and we should be set.
The corresponding code for Matlab is the following:
%% Demodulation load('LowPass2.mat'); %Load LPF Parameters Abs_IF = abs(IF_signal);%Implement peak detection lf = filterIIR2t(Abs_IF,Num2,Den2); %Low pass filtering
The final part of our project is to make the audio signal able to be heard. That is why we resample it to 44 kHz and save the result to an audio file. Depending also on the option we implemented before on what channel to listen to, we save the corresponding audio snippet to a different audio file.
%% Resampling and result sf = resample(lf,44100,Fs)'; % Resampling our result to 44.1kHz sf = sf - mean(sf); %Removing the mean value P = audioplayer(sf, 44100); %Creating the audio player %play(P); %Play the resulting audio clip %Depending on the channel, we save the result to a different file if freq_option == 1 audiowrite('decoded1.wav',sf,44100); end if freq_option == 2 audiowrite('decoded2.wav',sf,44100); end if freq_option == 3 audiowrite('decoded3.wav',sf,44100); end
So, by listening to the result of this file, we get pretty much nothing! This is because if we see the duration of the audio file, we realize that it is a few ms long, which is to be expected for a 200kb file. If we choose “radioB” in the beginning of our script we would have a result that is depicted in figure 14. Also with the report are attached the 3 music clips that I was able to extract from this data file that was given.
To sum up, this was an interesting and very fun project and through the duration of it I personally learned a lot about filter design, filter application and the whole structure and functionality of the super heterodyne receiver. Although the result is not that great as you can hear, we must take into consideration the fact that Amplitude modulation is a technique used not too often anymore and with good reasons. Our data file might be “ideally” filled with white noise, but in real life the chapter called noise is too complex for that a simple technique.
I hope you had as much fun reading this report as I had making this project! Below is the Appendix, where all the functions used in this project are located as well as the benchmark.
Here are the functions used for this project. The code is pretty much explained in the commentary so no further explanation in needed.
function SpectrumPlot(y) %Plots out the filter response Fs=6E6; %Sampling Frequency N = length(y); %Signal Length spectrum_magnitude = 20*log10(abs(fft(y))); %FFT Implementation freq_ax_bins = (0:N-1); %Frequency axis in bins freq_ax_Hz = freq_ax_bins*Fs/N; %Frequency axis in Hz N_2=ceil(N/2); %Nyquist Rate %Amplitude plotting plot(freq_ax_Hz(1:N_2),spectrum_magnitude(1:N_2)); title('Amplitude Response'); xlabel('Frequency [Hz]'); ylabel('Amplitude [dB]'); end
function TimePlot(y) %Plots out the time spectrum Fs=6E6; %Sampling Frequency N = length(y); %Signal Length sp=1/Fs; %Sampling Period t = linspace(0,sp*N,N); %Signal duration %Amplitude plotting plot(t,y); xlabel('Time [s]'); ylabel('Voltage [V]'); end
function y = filterIIR2t(x,Num,Den) %% IIR filter Code c = Num; %Numerator coefficients of system function d = Den; %Denominator coefficients of system function sz = size(Num); k = sz(2) - 1; % Filter order determines from the length of the % Number coefficient vector reg = zeros(k,1); % Initial condition ind = 1; % Index for v = x % Iterate all values from input data vector y(ind) = v*c(1) + reg(1); reg(1:k-1) = (v*c(2:k) -y(ind)*d(2:k))' + reg(2:k); reg(k)= v*c(k+1) - y(ind)*d(k+1); ind = ind +1; end