Difference between revisions of "IQModulation"

From NebarnixWiki
Jump to navigationJump to search
Line 131: Line 131:
 
%%Fs = Fsbackup;
 
%%Fs = Fsbackup;
 
%%clear Fsbackup;
 
%%clear Fsbackup;
%%Signal = resample(y,Fs,Faudio); %audio is NOT sampled at the right rate, resample to our Fs
+
%%Signal = resample(y/mean(abs(y)),Fs,Faudio); %audio is NOT sampled at the right rate, resample to our Fs and normalize avg amplitude to 1
 
%%Signal = [Signal' zeros(1,(Fs*max(t))-numel(Signal))]'; %extend the 8 second audio clip to our max(t) using zeros
 
%%Signal = [Signal' zeros(1,(Fs*max(t))-numel(Signal))]'; %extend the 8 second audio clip to our max(t) using zeros
  

Revision as of 07:53, 31 May 2017

Problem Statement

Standard methods of explaining modulation seem to fall flat on their faces when we start to talk about things like singlesideband, in fact, when we talk about sidebands at all. A much more natural way to understand modulation is to describe it at the baseband level using a unit circle. At this level, a single frequency is represented by a rotating vector of constant speed (angular velocity). An unmoving vector is simply a DC offset, thus, a carrier wave.

One of the traps here is that this does involve complex numbers, and therefore, imaginary amplitudes and negative frequencies. Regardless, I believe that this is the easiest way to understand and synthesize modulated waveforms for transmission in zero-IF systems which include most SDRs (Software Defined Radios).

What do these examples do?

These MATLAB examples are designed to be played back either directly in an SDR application (as a RAW IQ file) or transmitted using, for example, a hackRF using hackRF_transfer.exe. This allows us to sanity check our waveforms and even see things like bandwidth, carrier level, and filtering etc.




DSB

The most 'natural' wave to generate is "Double Side Band". This is basically AM (amplitude modulation) sans carrier wave. This means that the instantaneous output power is directly proportional to the input signal's instantaneous amplitude -- silence on the input means the transmitter is effectively turned off.

Summary

We will modulate the amplitude of I with the input signal by the modulation constant K

  • K = Gain => Gain can be whatever it needs to be here, it will only affect the average output power.
  • I = K*Signal => The real axis will be set to the input signal times a gain constant.
  • Q = 0 => we will NOT modulate the imaginary axis at all.
  • Because we set Q to 0, we will see both positive AND negative parts of all frequency components. (See Euler's equation for cos(x) in terms of e^jw)
  • If we input pure sinusoids (like we will get from an audio signal), we will have NO CARRIER.

DSB Code

%% Generate DSB
clear all;
K = 1; %Modulation Constant
Fs = 1e6; %Sample Rate. 1e6 is the minimum sample rate accepted by HackRF
Ts = 1/Fs; %Sample Period
t = 0:Ts:10; %Time axis (0 to 10 seconds at Ts interval)

%Generate our input signal, which MUST be sampled at (or resampled to) Fs
%We have options! Constant frequency, sinusoidally fading in and out at a constant frequency, and frequency sweep
%Feel free to play around here!

%Constant Frequency
fs = 1000; %Signal frequency
Signal = sin(2*pi*fs.*t); 

%Single frequency, faded in and out sinusodially
%%fs = 1000; %Signal frequency
%%Signal = cos(2*pi*(1/10).*t) .* sin(2*pi*fs.*t); %This is our input signal, which MUST be sampled at Fs as presented here

%Frequency sweep upwards
%%fs = linspace(1e3,10e3,numel(t)); %Signal frequency, from 1khz to 10khz linearly spaced array 
%%Signal = sin(2*pi.*fs.*t);  

%Want more fun? Load some real audio data!
%%Fsbackup = Fs; 
%%load Handel; %This will overwrite Fs!
%%Faudio = Fs;
%%Fs = Fsbackup;
%%clear Fsbackup;
%%Signal = resample(y/mean(abs(y)),Fs,Faudio); %audio is NOT sampled at the right rate, resample to our Fs and normalize avg amplitude to 1
%%Signal = [Signal' zeros(1,(Fs*max(t))-numel(Signal))]'; %extend the 8 second audio clip to our max(t) using zeros

I = K*Signal;         %Modulate I
Q = 0;                  %Do not modulate Q to preserve symmetric upper and lower sideband (neg and pos frequencies)
dataStream = I + Q*1i;

%% Format data for playback on hackrf
idxo=1;
scale = max(real(dataStream));
for idx=1:numel(t)    
    dataStreamFile(idxo) = int8(real(dataStream(idx))*(127/scale));
    dataStreamFile(idxo+1) = int8(imag(dataStream(idx))*(127/scale));
    idxo = idxo+2;
end

%% Write to RAW file
fhandle = fopen('DSB.iq','w');
fwrite(fhandle,dataStreamFile,'int8');
fclose(fhandle);




AM

If you try to tune to the DSB signal but are off by a few Khz or even a few HZ, you will notice that the audio sounds distorted and horrible. Without a carrier, we have no way to lock into the true signal frequency, especially during periods of silence. There are complex ways to estimate the carrier and lock, but AM gets around this by adding a DC offset to the signal. Remember that a DC offset is just a zero frequency component at a constant level. This will become the carrier when it gets shifted up the spectrum by the SDR hardware.

Summary

We will modulate the amplitude of I with the input signal by the modulation constant K

  • Pc = relative carrier power. If your signal is 1 and Pc is 1 you will have a 50% power split between carrier and signal.
    • Real shortwave stations use more power in the carrier to help lock on when band conditions are weak.
    • This means you might see the carrier but not the signal at all from a weak/distant station!
  • K = Gain => Gain can be whatever it needs to be here, it will only affect the average output power.
  • I = K*Signal+Pc => The real axis will be set to the input signal times a gain constant. Pc is the DC offset which is our carrier (centered at 0Hz)
  • Q = 0 => we will NOT modulate the imaginary axis at all.
  • Because we set Q to 0, we will see both positive AND negative parts of all frequency components. (See Euler's equation for cos(x) in terms of e^jw)
  • If we input pure sinusoids (like we will get from an audio signal), we will have a carrier split between the signal's average power and the Pc term.

AM Code

%% Generate AM
clear all;
Pc = 1; %carrier power (ratio of signal level to this number will determine power split)
K = 1; %Modulation Constant
Fs = 1e6; %Sample Rate. 1e6 is the minimum sample rate accepted by HackRF
Ts = 1/Fs; %Sample Period
t = 0:Ts:10; %Time axis (0 to 10 seconds at Ts interval)

%Generate our input signal, which MUST be sampled at (or resampled to) Fs
%We have options! Constant frequency, sinusoidally fading in and out at a constant frequency, and frequency sweep
%Feel free to play around here!

%Constant Frequency
fs = 1000; %Signal frequency
Signal = sin(2*pi*fs.*t); 

%Single frequency, faded in and out sinusodially
%%fs = 1000; %Signal frequency
%%Signal = cos(2*pi*(1/10).*t) .* sin(2*pi*fs.*t); %This is our input signal, which MUST be sampled at Fs as presented here

%Frequency sweep upwards
%%fs = linspace(1e3,10e3,numel(t)); %Signal frequency, from 1khz to 10khz linearly spaced array 
%%Signal = sin(2*pi.*fs.*t);  

%Want more fun? Load some real audio data!
%%Fsbackup = Fs; 
%%load Handel; %This will overwrite Fs!
%%Faudio = Fs;
%%Fs = Fsbackup;
%%clear Fsbackup;
%%Signal = resample(y/mean(abs(y)),Fs,Faudio); %audio is NOT sampled at the right rate, resample to our Fs and normalize avg amplitude to 1
%%Signal = [Signal' zeros(1,(Fs*max(t))-numel(Signal))]'; %extend the 8 second audio clip to our max(t) using zeros

I = K*Signal+Pc;         %Modulate I
Q = 0;                %Do not modulate Q to preserve symmetric upper and lower sideband (neg and pos frequencies)
dataStream = I + Q*1i;

%% Format data for playback on hackrf
idxo=1;
scale = max(real(dataStream));
for idx=1:numel(t)    
    dataStreamFile(idxo) = int8(real(dataStream(idx))*(127/scale));
    dataStreamFile(idxo+1) = int8(imag(dataStream(idx))*(127/scale));
    idxo = idxo+2;
end

%% Write to RAW file
fhandle = fopen('AM.iq','w');
fwrite(fhandle,dataStreamFile,'int8');
fclose(fhandle);