You are on page 1of 18

A Variable Bitrate OFDM Modem Over an

Audio Channel

Dag Björklund

Turku Centre for Computer Science (TUCS)


4th June 2002

1
Contents
1 Introduction 3
1.1 Using the Modem . . . . . . . . . . . . . . . . . . . . . . . . . . 3

2 Channel Characteristics 4

3 Modulation 4

4 Error Coding 7

5 Synchronization and Handshaking 7


5.1 Transmission Parameter Negotiation . . . . . . . . . . . . . . . . 8

6 Protocol 9
6.1 Reliable Transmission . . . . . . . . . . . . . . . . . . . . . . . . 9

7 Tricks and Hacks 10

8 Results and Future Improvements 11

A Main Files 12

B Modulate, Demodulate 14

C Noise Calculation 15

D OFDM 17

E CRC 17

2
1 Introduction
This report describes an implementation of a OFDM modem using PC sound cards
and Matlab c
[2]. Currently the system can be used to transmit files from a com-
puter running Matlab to another. It would take some amount of trivial work to
be able to generate C code and a standalone application. To achieve a more real
modem, would take some C programming, so that e.g. program would fork hav-
ing one process listening for messages over the channel and another listening for
input from the local user.
The system was developed on a Pentium III laptop with a cable looping back
the speaker connector to the microphone. This channel was very poor, and thus the
modem performance is modest. On other systems one could perhaps achieve a lot
better transmission. It would be very difficult to create a modem, that could nego-
tiate all parameters so that it would work on any PC/sound card etc. combination.
Therefore, this system is mainly intended to work on my specific computer.
Figure 1 shows the basic blocks of the system. The convolutional and cyclic
coding will be described in Section 4 and the OFDM blocks in Section 3. The
labels on the connections show the size of the message, Mt is a binary message of
size n, the convolutional coding currently in use will double it etc. (probably not
good). The OFDM modulator will leave the message length about the same with
a QAM constellation of four points, QAM-16 would result in half the length of
the vector.

Mt n conv. 2n cyclic 2n+k 2n+k+1


OFDMt D/A
encode encode

cyclic conv Mr
A/D OFDMr
decode decode

Figure 1: Basic blocks of the receiver and transmitter

1.1 Using the Modem


As mentioned, the modem can send a file from a computer running Matlab, to
another. The functions to call are send and receive. The receiver first calls

3
receive to start receiving, whereafter the sender calls send( filename ),
where filename is the file to be sent.

2 Channel Characteristics
An important question associated with a communication channel is the maximum
rate at which it can transfer information.
The spectrum of the noise for a received message Si is Ni = Si − S, where S
was the original signal. The average standard deviation of the noise in M trans-
mitted messages becomes:
M
1 X
σN = σN
M i=1 i
I use chirp signals to obtain experimental results for σN , the Matlab code for this
is included in Appendix C.
The error probability Pe can now be calculated using:
 
j−1 d
Pe = 2 Q j = 2i
j σN
Where i is the number of levels and d is the signal level. For my channel I obtained
σN ≈ 17. With two levels and a signal level of 2 the error probability would
become ≈ 0.69, which is very high (the value for Q(x) was obtained from a table).
On my computer I only seem to be able to use sampling rates of 8000Hz, so
the maximum bandwidth would be B=Fs/2=4000Hz. The theoretical maximum
bitrate can now be calculated using:

C = 2B(1 + Pe log2 (Pe ) + (1 − Pe )log2 (1 − Pe ))

For my channel I obtained the bitrate 3Kb/s. This theory sets the upper limit for
the transmission rate; however, it does not say anything about how to achieve it.

3 Modulation
The serial digital data signal is modulated using orthogonal frequency division
multiplexing (OFDM), which was introduced by Robert W. Chang in [1]. The
OFDM transmitter block from section 1 is refined as depicted in Figure 3, the
receiver is implemented in the reversed order. OFDM can be considered a sum of

4
Mt n conv. 2n cyclic 2n+k 2n+k+1
OFDMt D/A
encode encode

QAM IFFT CP
encoder

Figure 2: OFDM subsystem

series of QAM signals:


N
X
xOF DM (t) = m1 (n)cos(2ωn t) + m2 (n)sin(2ωn t)
n=1

The m1 and m2 components can be considered real and imaginary components


of a signal and thus the summation can be done using IDFT. This means that the
data stream needs to be mapped into a complex vector in a smart way, namely ac-
cording to a certain QAM constellation. In a 4-symbol constellation for example,
the components could take on the value of (± 1, ± 1) and the result would be the
constellation shown in Figure 3 (a). Since the 16-point constellation has more lev-
els, we can transmit more data over the same timeslot, but this will require better
signal-to-noise ratio of the channel. In Figure 3 we see that the signal takes on all
values between the -1,1 that the soundcard uses.
Orthogonality of OFDM subcarriers is critical since it prevents interchannel
interference. As such, OFDM is highly sensitive to frequency dispersion. This

QASK Constellation QASK Constellation

3 13 9 8 12

1 1 0

1 5 1 0 4
Quadrature

Quadrature

−1 7 3 2 6

−1 3 2

−3 15 11 10 14

−1 1 −3 −1 1 3
In−phase In−phase

(a) (b)
Figure 3: (a) 4-symbol QAM constellation (b) 16-symbol QAM constellation

5
Eye Diagram
1

0.8

0.6

0.4

0.2
Amplitude

−0.2

−0.4

−0.6

−0.8

−1
−6 −4 −2 0 2 4 6
Time −5
x 10

Figure 4: Eye diagram of the transmitted signal using QAM-4

can be overcome by attaching a copy of the OFDM symbol in front of the trans-
mitted symbol as depicted in Figure 3. When this cyclic prefix is longer than the
channel impulse response, the received signal is a cyclic convolution of the trans-
mitted signal and the channel response, which maintains the orthogonality of the
subcarriers over a dispersive channel. The Matlab code for the OFDM transmitter
and receiver can be found in appendix 3. The OFDMt function accepts a matrix of
binary values as input, as do the modulate, demodulate etc. functions. Each
row in the matrix is modulated separately, so the widht of the matrix, becomes the
N points in the OFDM. This is because the more points we have for the OFDM,
the better performance is required from the channel. The sender would split the
message to be sent into this matrix format, so that we can have larger frames;
however, because of some problems sending longer messages over the channel on
my computer, I do not use this capability, but it is still implemented in the modem.

Cyclic
prefix
Time

Figure 5: The Cyclic Prefix

6
That is, I only send vectors.

4 Error Coding
The modem uses convolutional and cyclic coding for error correction, and CRC
coding for error detection. The convolutional coding uses the trellis in the figure
below.
00 00
00
00
01 01
01

10
01 01
00
11
01 01

Figure 6: Trellis used for convolutional coding

The convolutional coding doubles the length of the message. Both convolu-
tional and cyclic coding improve the bit error rate; however, they produce a lot of
overhead which is particularly bad since the frame length is very restricted.
The modem is lacking a data scrambling block, which should be added to
avoid long sequences of 1’s or 0’s.
The CRC coding is descring in section 6.

5 Synchronization and Handshaking


Before sending a frame, the receiver must be polling the channel for something
to happen, and the sender has to put something on the channel to tell the receiver
to begin receiving. On my system, this is the part that takes the most time. I
have been using only loop-back with one computer, which probably is one of the
problems, since it seems that sitting in a tight loop, polling a pilot message in one
Matlab window, while another Matlab tries to send will slow down the processing
a lot, making it very hard to synchronize; furthemore, Matlab often returns with
error messages, when there is too much going on with the soundcard.
Figure 5 shows a signal obtained by the receiver. The first two bursts in the
signal are the poll signals consisting of alternating zeros and ones. In front of the

7
0.8

0.6

0.4

0.2

−0.2

−0.4

−0.6

−0.8
Poll signal
Chrip Message
−1
0.02 0.04 0.06 0.08 0.1 0.12 0.14 0.16 0.18 0.2

Figure 7: Synchronization

actual message, a chirp pilot signal resides. The Matlab code below is used by
the transmitter to send the poll signals. So the distance between the poll signals
in the figure is actually the loop overhead from this for loop. This overhead is
essentially the thing that makes the synchronization so difficult.
for k=1:10
wavplay( poll_sig, TxFs, ’sync’ )
end
The receiver reads input, e.g. 5 times longer sequences from the sound card, and
checks if there is a poll signal within this input, if so, it tries to read a message. The
chirp signal is then used to synchronize exactly to the first value of the message,
by detecting the peak of correlation between the read vector, and a chirp.

5.1 Transmission Parameter Negotiation


The system includes very simple parameter negotiation, to achieve variable bi-
trates. The functions handshaket and handshaker are used to determine

8
transmission parameters. The handshaket function very simply tries to send
a message using the 16-symbol QAM constellation (see section 3), if it receives
acknowledgement from the receiver, it will return the value 4, denoting 16-symbol
QAM, otherwise it returns 2. The hanshaker function analogically returns 4, if
it receives a message.

6 Protocol
The modem uses a very simple protocol.

6.1 Reliable Transmission


Frames are sometimes corrupted while in transit. While the error coding schemes
also have error correcting capabilities in practice they cannot handle the range
of bit and burst errors that can be introduced on the channel. As a consequence,
corrupt frames must be discarded. I use CRC to detect errors, and the simplest au-
tomatic repeat request (ARQ) i.e. stop-and-wait scheme to achieve more reliable
communication. After transmitting one frame, the sender waits for an acknowl-
edgement before transmitting the next frame. If the acknowledgement does not
arrive after a certain period of time, the sender times out and retransmits the orig-
inal frame.
There are a few scenarios where this approach might fail, one is depicted in
Figure 6.1. The ACK is lost, so the sender will think that the receiver did not
get the frame, consequently retransmitting it leaving the receiver with two copies.
This problem would call for a 1-bit sequence number in the header of the frame;
however, I did not address this problem in the implementation. The ACK is very
rarely lost anyway in the modem.
The stop-and-wait scheme is implemented in the send and receive files A

Cyclic Redundancy Check


For error detection, I use Cyclic Redundancy Check (CRC), more specifically,
CRC-8, which means I am using CRC polynomial C(x) = x8 +x2 +x1 +1. This is
the shortest one of the common CRC polynomial, consequently it is not foolproof.
The CRC coding can be implemented very nicely using Matlab convolution and
deconvolution functions ??.

9
Sender Receiver Sender Receiver
Fram Fram
Timeout e e

Timeout
Time

ACK ACK

(a) (b)

Figure 8: Timeline showing two different scenarios (a) The ACK is received be-
fore the timer expires; (b) the ACK is lost

Frame Format
The format of the frames now simply becomes as in figure 6.1. The CRC takes up
8 bits.
16 8
Body CRC

Figure 9: Frame format

There is some problem with the channel that makes the signal die out when
sending longer messages. This limits the length of the frames I am able to send
very brutally. Figure 6.1 shows a signal obtained by the receiver, the signal should
fill out the whole figure, but dies out too soon. As seen in Figure 6.1, I am using
only 16 bits body in the frame.

7 Tricks and Hacks


It turned out to be quite difficult to obtain any descent transmission over the
channel. I discovered, for instance, that the sampling rates when using the A/D
and D/A converters differed on my computer. The sampling rate when receiving
turned out to be higher. Only after solving this problem, by simply removing every
40th or so sample, could I transmit anything what so ever through the channel.
After this, I still was not able to transmit using OFDM, I tried different win-
dowing etc. to smoothen the signal. Finally I tried to oversample the message at
the transmitter! This, I guess, gives the receiver double the change to hit the right

10
1

0.8

0.6

0.4

0.2

−0.2

−0.4

−0.6

−0.8

−1
0 0.005 0.01 0.015 0.02 0.025

Figure 10: Signal dying out

values from the signal. Naturally this again doubles the vector to be sent, which
is a bad thing.

8 Results and Future Improvements


The achieved bit rate is very poor, below is fairly typical test run, with a bitrate of
2 bit per second:
>> receive
Answering...
received errorfree message
received errorfree message
received errorfree message
error
received errorfree message
error
error

11
received errorfree message
received errorfree message
error
error
received errorfree message
received 12 bytes in 32 s (3 b/s)

It can sometimes take seconds between received error free frames, and since
the frames are only 16 bits long, the data rate is low. I believe that it is impos-
sible to achieve fast synchronization on my system, so the first goal should be to
increase the frame sizes. Currently I giving

References
[1] Robert W. Chang. Synthesis of bandlimited orthogonal signals for multichan-
nel data transmission. Bell System Tech. Journal, pages 1775–1796, Decem-
ber 1966.

[2] The MathWorks web site. Internet: http://www.mathworks.com.

Appendix
The appendix contains some of the matlab files implementing the modem.

A Main Files
send.m
function send( filename )
% this is the main file for the transmitter

CommSetup

fid=fopen( filename );

sentm=[];

% negotiate transmission parameters


const=handshaket;

NoMsgQAM=NoMsgCyclic/(const/2)+2+(mod(NoMsgCyclic,2)~=0); %+2;
NoMsgQAMCP=NoMsgQAM+PreFixNo;
NoMsgWinQAM=NoMsgQAMCP;
NoMsgOS=2*NoMsgWinQAM;

12
% loop till end of file
eof=0;
while eof==0
b=[];
for k=1:2
if feof(fid)==0
b=[b fread(fid,1,’uchar’)];
end
end
sentm=[sentm b];

if feof(fid)
fprintf(’end of file encoutered\n’)
eof=1;
b=EOF;
else
b=iv2bv(b);
end

m=modulate( b,Chirpp,NoMsgWinQAM,PreFixNo,RcosSyncLevel,r,tblen, const );

m=[m m]; %(:,5:end)]; %(end-10:end)];

while 1
%connect(sig, TxFs)
for k=1:11
wavplay( [sig sig sig ],TxFs,’sync’)
end

wavplay(m,TxFs,’sync’);

% listen for acknowledgement


connection=answer(10,RxFs,sig);

if connection
fprintf(1,’Got ACK\n’)
pause(0.2)
break;
end
end
end
sentm
fclose(fid);

receive.m
% this is the main function for the receiver

CommSetup;

msg=[];
fprintf(1,’Answering...\n’)
tic

% negotiate transmission parameters


const=handshaker;

NoMsgQAM=NoMsgCyclic/(const/2)+2+(mod(NoMsgCyclic,2)~=0);
NoMsgQAMCP=NoMsgQAM+PreFixNo;
NoMsgWinQAM=NoMsgQAMCP;
NoMsgOS=2*NoMsgWinQAM;

in=0;
rows=1;

NoFrames=0;
eof=0;
while eof==0
gotit=0;
while gotit ~= 1
mat=0;

% try to ’answer’
if answer(1, RxFs, sig )

13
mat=1;
end

if mat==1 %connection
y = wavrecord((rows*NoMsgOS+2*NoChirp+NoDelayRx),RxFs)’;
if max(y) > 0.3

[m,err]=demodulate( rows, Chirpp, y,NoMsgOS,RcosSyncLevel,PreFixNo,tblen,const );


if ~err
fprintf(1,’received errorfree message\n’)
gotit=1;
if sum( EOF==m ) == length(m)
eof=1;
else
NoFrames=NoFrames+1;
msg=[msg bv2iv(m)];
end
connect(sig,TxFs);
else
fprintf(1,’error\n’)
end
end
end
end
end

t=round(toc);
fprintf(1,’received %d bytes in %d s (%d b/s)’,NoFrames*2,t,round(NoFrames*2*8/t) )
msg

B Modulate, Demodulate
modulate.m
function m=modulate( Msg, Chirp, NoMsgWinQAM, PreFixNo,
RcosSyncLevel,r,tblen,const )

Win = kaiser(NoMsgWinQAM+1,r)’;
for k=1:size(Msg,1)-1
Win=[Win ; Win];
end

Msg2=CRCencode(Msg);

Msg2=[Msg2 zeros(size(Msg2,1),tblen)]; % compenstate for the convolutional loss


Msg2=convencode(Msg2);
Msg2=cyclicencode(Msg2);
Msg3=OFDMt( Msg2, const ); % NoMsg+2

% add cyclic prefix


Msg4=[Msg3(:,end-PreFixNo+1:end) Msg3];
Msg5=[Msg4 zeros(size(Msg4,1),1)].*Win;
Msg5=oversample(Msg5);

Msg6=linearmap1(Msg5,RcosSyncLevel,-RcosSyncLevel);

% reshape the matrix into a vector


Msg7=[];
for h=1:size(Msg6,1)
Msg7=[Msg7 Msg6(h,:)];
end

Msg7=[Chirp Msg7];

m=Msg7;

14
demodulate.m
function [m,err]=demodulate( rows, Chirp, y,NoMsgOS,
RcosSyncLevel,PreFixNo,tblen,const )

A=[];

Xc=conv(Chirp(end:-1:1),y);
[Max,Ind]=max(Xc);

if length(y)>rows*NoMsgOS+Ind
A=y(Ind+1:Ind+rows*NoMsgOS+1); %(rows-1)*5);

% make a matrix out of the vector


if rows==2
A=[A(1:length(A)/2) ; A(length(A)/2+1:end)];
end
% there are extra values at the back, remove ’em
A=A(:,1:NoMsgOS);

% compensate for difference in TxFs and RxFs


sync=[];
for k=1:length(A)
if mod(k,51) ~= 0 %51
sync=[sync A(:,k)]; %o1=[o1 y1(k)];
end
end
A=[sync zeros(rows,length(A)-length(sync))];

% downsample
downsample=[];
k=1;
while 1
downsample=[downsample A(:,k+1)];
k=k+2;
if k>length(A)
break;
end
end
A=downsample;

A=linearmap1(A*sum((Chirp).^2)/Max,RcosSyncLevel,-RcosSyncLevel);

% remove cyclic prefix


A=A(:,PreFixNo+1:end);
A=OFDMr(A,const);
A=cyclicdecode(A,tblen);
A=convdecode(A);

A=A(:,tblen+1:end);

[A,err]=CRCdecode(A);
else
fprintf(’Transmission error: Could not synchronize with pilot’)
err=1;
end
m=reshape(A’,1,size(A,1)*size(A,2));

C Noise Calculation
send.m
RxFs=11025;
TxFs=11025;
Td=0.1;
NoChirp=2^10;

Chirp=chirp(linspace(0,Td,NoChirp),200,Td,RxFs/12); %/2);

Msg=[Chirp Chirp Chirp Chirp Chirp Chirp Chirp Chirp Chirp];


Msg=linearmap1(Msg,-1,1);

15
save TxSync;
fid=-1;
fprintf(1,’Syncing on Rx ...\n’);
while(fid==-1)
fid=fopen(’RxSync.mat’,’r’);
end
fclose(fid);
wavplay(Msg,TxFs,’sync’);

rec.m
RxFs=11025;
TxFs=11025;
Td=0.1;
NoChirp=2^10;

Chirp=chirp(linspace(0,Td,NoChirp),200,Td,RxFs/12); %/2);

save RxSync;

y = wavrecord(15*NoChirp,RxFs);
delete(’RxSync.mat’)

for k=1:length(y)
if abs(y(k))+abs(y(k+1))>0.2
k
y=y(k-50:end);
break;
end
end

sync=[];
for k=1:length(y)
if mod(k,51) ~= 0 %51
sync=[sync y(k)]; %o1=[o1 y1(k)];
end
end
y=sync;
y=linearmap1(y,-1,1);

Ss=zeros(9,NoChirp);
for k=1:9
Xc=conv( Chirp(end:-1:1), y(1:NoChirp+50) );
[Max,Ind]=max(Xc)

yc=y(Ind+1-NoChirp:Ind);
%y=y(Ind-50:end);
%figure,plot(yc),hold on, plot(Chirp,’r’)
Ss(k,:)=yc;

N(k,:)=abs(fft(yc))-abs(fft(Chirp));
%figure,plot(abs(fft(yc))),hold on, plot(abs(fft(Chirp)),’r’), hold off
%figure,plot(N(k,:))
end

%s=sum(Ss)/9;
%S=fft(s);
vars=[];
for k=1:9
N(k,:)
vars(k)=var(N(k,:))
%vars(k)=var( abs(fft(s(k))-S) );
end

power=sum(vars)/9

16
D OFDM
OFDMt.m
function y = OFDMt( x, const )

%if mod(length(x),2) ~= 0
% x = [x 0];
%end
x = [x zeros( size(x,1), ceil(length(x)/const)*const-length(x) )];
%y=zeros(size(x,1),size(x,2)/(const/2) +2);

for m=1:size(x,1)

dec=bi2de(reshape(x(m,:),const,length(x)/const)’)’;

% dec can now be modmapped


quam=modmap(dec,1,1,’qask’,2^const);

% fill out the stuff


MsgI=[0 quam(:,1)’ 0 quam(end:-1:1,1)’];
MsgQ=[0 -quam(:,2)’ 0 quam(end:-1:1,2)’];

% create the complex vector


comp=MsgI+j.*MsgQ;

y(m,:)=real(ifft(comp));
end

OFDMr.m
function X = OFDMr( x, const )
% function that implements a OFDM receiver. If x is matrix
% it will be OFDM ’encoded’ row by row

CommSetup
X=zeros(size(x,1),NoMsgCyclic ); %size(x,2)-3);
for m=1:size(x,1)
comp=fft(x(m,:));

comp=comp(2:length(x)/2);
dec=demodmap([real(comp); -imag(comp)]’ ,1,1,’qask’,2^const);

bi=de2bi(dec);

% sometimes bi doesn’t get two columns for som reason


% just stuff it up and let the error detection correct the problem
if size(bi,2) < 2
bi=[dec zeros(length(bi),1)];
end
re=reshape(bi’,1,size(bi,1)*size(bi,2)); %2*max(size(bi)))
X(m,:)=re(1:NoMsgCyclic); % end-1);
end

E CRC
CRCencode.m
function code=CRCencode( msg )
% function for row by row CRC encoding of msg

% generator polynomial
generator=[1 0 0 0 0 0 1 1 1];

c=[1 0 0 0 0 0 0 0 0]; % x^k

for k=1:size(msg,1)

17
multip=conv(c,msg(k,:));

[divid,remainder]=deconv(multip,generator);

divid=mod(divid,2);
remainder=mod(remainder,2);

code(k,:)=xor(multip,remainder);
end

CRCdecode.m
function [msg,error]=CRCdecode( code )
% function for checking for errors row by row in tht matrix code
% where each row should be a CRC encoded message, and decoding the
% messages i.e. removing the CRC field from the back

% generator polynomial
generator=[1 0 0 0 0 0 1 1 1];

error=0;
for k=1:size(code,1)
[m,r]=deconv(code(k,:), generator );
error=error | sum(mod(r,2));
end

msg=code(:,1:end-length(generator)+1);

18