Simulating Turbo Codes using a Modular Simulation Platform

198
Simulating Turbo Codes using a Modular Simulation Platform by David C. Lee Submitted to the Department of Electrical Engineering and Computer Science in Partial Fulfillment of the Requirements for the Degree of Master of Engineering in Electrical Engineering and Computer Science at the aitKEN MASSACHUSETTS INSTITUTE OF TECHNOLOGY May 24, 2002, Copyright 2002 David C. Lee. All rights reserved. The author hereby grants to M.I.T. permission to MASSACHUSETS WSTITUTE OF TECHNOLOGY JUL 3 1 200? LIBRARIES reproduce and distribute publicly paper and electronic copies of this thesis and to grant others the right to do so. Author Department of Electrical Engineering and Computer Science May 24, 2002 Certified by Nick Zogakis VI-A Company Thesis Supervisor Certified by_ Vahid Tarokh M.I.T. Thesis Supervisor Accepted by_ Arthur C. Smith Chairman, Department Committee on Graduate Theses

Transcript of Simulating Turbo Codes using a Modular Simulation Platform

Page 1: Simulating Turbo Codes using a Modular Simulation Platform

Simulating Turbo Codes using a Modular Simulation Platform

by

David C. Lee

Submitted to the Department of Electrical Engineering and Computer Sciencein Partial Fulfillment of the Requirements for the Degree of

Master of Engineering in Electrical Engineering and Computer Science

at the aitKEN

MASSACHUSETTS INSTITUTE OF TECHNOLOGY

May 24, 2002,

Copyright 2002 David C. Lee. All rights reserved.

The author hereby grants to M.I.T. permission to

MASSACHUSETS WSTITUTEOF TECHNOLOGY

JUL 3 1 200?

LIBRARIES

reproduce and distribute publicly paper and electronic copies of this thesisand to grant others the right to do so.

AuthorDepartment of Electrical Engineering and Computer Science

May 24, 2002

Certified byNick Zogakis

VI-A Company Thesis Supervisor

Certified by_Vahid Tarokh

M.I.T. Thesis Supervisor

Accepted by_Arthur C. Smith

Chairman, Department Committee on Graduate Theses

Page 2: Simulating Turbo Codes using a Modular Simulation Platform

-4

Page 3: Simulating Turbo Codes using a Modular Simulation Platform

Simulating Turbo Codes using a Modular Simulation Platform

by

David C. Lee

Submitted to theDepartment of Electrical Engineering and Computer Science

May 24, 2002

In Partial Fulfillment of the Requirements for the Degree ofMaster of Engineering in Electrical Engineering and Computer Science

ABSTRACT

A simulation tool was created to evaluate the performance of Turbo codes proposed fordigital subscriber loop channels. The tool is modular and was designed to be highlyflexible. In particular, the use of linked list data structures to handle module input andoutput data flow allows the tool to be structurally flexible. Module definitions aredefined comprehensively and allow for high component flexibility, as well. Expressionsare provided for MAP decoding of convolutional codes under 4-QAM and under higherspectral efficiency modulations. Simulation results match cited results relatively well andindicate that Turbo code algorithms are implemented correctly in the tool. Results offerconfidence in the ability of the simulation tool to correctly estimate the performance ofTurbo codes.

Thesis advisor: Vahid TarokhTitle: Associate Professor

VI-A company supervisor: Nick ZogakisTitle: Systems Engineer

-3-

Page 4: Simulating Turbo Codes using a Modular Simulation Platform

-4-

Page 5: Simulating Turbo Codes using a Modular Simulation Platform

ACKNOWLEDGMENTS

The majority of work for this thesis was completed on-site at Texas Instruments,Incorporated, under the mentorship of my supervisor Nick Zogakis. His suggestions andreviews were invaluable throughout the course of this study.

The other members of my group at Texas Instruments were of great help in theirgenerous contribution of time and resources. In particular, my many insightfuldiscussions with Chia-Ning Peng and Elisa Pasquali helped to clarify several issues.During the simulation intensive phase of this study, Texas Instruments contributedvaluable computing time through the use of its workstations. In particular, Nick Zogakis,Konrad Kratochwil, and Brian Weise, were generous in allowing me to use theirworkstations for the simulations. I would also like to thank Krista Jacobsen and PatrickWang for their welcome support and encouragement throughout this study.

At MIT, my thesis advisor Vahid Tarokh was very enlightening in his responsesto my technical questions. Further, his comments and suggestions about the content ofthis thesis greatly helped to shape it into its final form.

I thank Professor Marcus Zahn and Ms. Lydia Wereminski of the MIT VI-Aprogram, and my VI-A advisor Judy Hoyt, for my very positive experiences under theprogram. Lastly, I thank both Texas Instruments and MIT for their support of this study.It has been a rewarding experience!

-5-

Page 6: Simulating Turbo Codes using a Modular Simulation Platform

-6-

Page 7: Simulating Turbo Codes using a Modular Simulation Platform

CONTENTS

I Introduction 15

2 Background 192.1 Transm ission using Signal Sets ........................................................... 192.2 T he Shannon L im it .............................................................................. 202.3 Probability of E rror .............................................................................. 222.4 Calculating BER for an AWGN Channel ............................................. 23.2.5 C hannel C oding .................................................................................... 242.6 The C onvolutional C ode ....................................................................... 25

2.6.1 Recursive Systematic Convolutional Code ........................... 262.6.2 Markov Structure of Convolutional Codes ............................ 272.6.3 Decoding using Maximum a posteriori Probability .............. 28

2.7 Symbol Mapping and Channel Observations ...................................... 312.7.1 4-Q A M M odulation ............................................................... 322.7.2 Higher Spectral Efficiency Modulation ................................. 33

2.8 T he T urbo C ode .................................................................................... 362.8.1 The Turbo Encoder ................................................................ 372.8.2 Iterative Decoding and the Turbo Decoder ........................... 382.8.3 Fast Decoding for Rate-1/2 Component Encoders ................ 41

3 The Simulation Tool 453.1 Sim ulation Tool Scope ........................................................................ 453.2 Design Considerations for Structural Flexibility .................................. 47

3.2.1 Simulation Tool Language .................................................... 473.2.2 Module Flow Implementation ............................................... 483.2.3 Data Transfer between Modules ........................................... 493.2.4 M odule Execution .................................................................. 50

3.3 Design Considerations for Component Flexibility ............................... 513.3.1 Linked List Design and Implementation ............................... 523.3.2 Interleaver Design and Implementation ............................... 533.3.3 Convolutional Encoder Design and Implementation ............. 55

3.3.3.1 Use of the Trellis Diagram for Encoding ............... 553.3.3.2 Generating Polynomials ........................................ 573.3.3.3 Constructing the Trellis Diagram ........................... 58

3.3.4 Puncturing / Un-puncturing Module Design and Implementation................................................................................................. 6 0

3.3.5 Signal Mapper Design and Implementation .......................... 62

-7-

Page 8: Simulating Turbo Codes using a Modular Simulation Platform

3.3.6 Channel and Demodulator Design and Implementation ........3.3.7 MAP Decoder Module Design and Implementation .............

3.4 Sim ulation C ode O rganization .............................................................

4 Simulation Results4.1 Results for Double Parallel Concatenated Turbo Code

4.1.1 Sim ulation 1: Rate-1/2 Turbo code .......................................4.1.2 Simulation 2: Rate-1/2 Turbo code .......................................4.1.3 Sim ulation 3: Rate-2/4 Turbo code .......................................4.1.4 Simulation 4: Rate-2/4 Turbo code .......................................4.1.5 Simulation 5: Rate-2/4 Turbo code .......................................4.1.6 Sim ulation 6: Rate-3/4 Turbo code .......................................4.1.7 Simulation 7: Rate-3/4 Turbo code .......................................4.1.8 Simulation 8: Rate-3/6 Turbo code .......................................4.1.9 Sim ulation 9: Rate-4/6 Turbo code .......................................4.1.10 Sim ulation 10: Rate-4/6 Turbo code .....................................

4.2 Results for Triple Parallel Concatenated Turbo Code ..........................4.2.1 Sim ulation 11: Rate-1/2 Turbo code .....................................4.2.2 Simulation 12: Rate-1/2 Turbo code .....................................

4.3 Sum m ary of Results ..............................................................................

5 Discussion5.1 Reliability of Simulation Tool ..............................................................5.2 Unexpected Simulation Results ............................................................5.3 Sim ulation Speed and M em ory Usage .................................................

6 Conclusions

A Main Simulation Codeturbosim -std.c .......................................................................................turbosim -icoding.c ..............................................................................turbosim -uncoded.c ............................................................................

B Sample Output for turbosim-std.cScreen Output .......................................................................................Output File test. txt .......................................

C Simulation Codegeneral.h ................................................................................................general.c ................................................................................................linkedlist.h ............................................................................................linkedlist.c .............................................................................................source.h .................................................................................................source.c .................................................................................................interleave.h ...........................................................................................interleave.c ............................................................................................

-8-

646566

69707173757678808183858789899192

95959697

99

101101108114

119119123

125125126128129135136139140

Page 9: Simulating Turbo Codes using a Modular Simulation Platform

co n v .h ................................................................................................... 14 8co n v .c .................................................................................................... 14 9puncture.h ............................................................................................. 159puncturex ............................................................................................. 160mapper.h ............................................................................................... 165m apperx ............................................................................................... 166channel.h ............................................................................................... 177ch an n el.c ............................................................................................... 17 8demod.h ................................................................................................ 180d em o d .c ................................................................................................. 18 1decoder.h ............................................................................................... 184d eco d er.c ............................................................................................... 18 5

References 197

-9-

Page 10: Simulating Turbo Codes using a Modular Simulation Platform

-10-

Page 11: Simulating Turbo Codes using a Modular Simulation Platform

LIST OF FIGURES

2-1 BER curve for uncoded 4-QAM ................................................................ 252-2 Rate-1/2 recursive, systematic convolutional code .................................... 262-3 Rate-2/3 recursive, systematic convolutional code .................................... 262-4 Markov diagram of a four state, rate-1/2 convolutional code .................... 272-5 T rellis diagram ............................................................................................ 282-6 C hannel coding .......................................................................................... 292-7 Signal points and labels for 4-QAM ........................................................... 322-8 Signal points and labels for 16-QAM ......................................................... 342-9 Turbo encoder structure .............................................................................. 372-10 Turbo decoder structure .............................................................................. 40

3-1 Turbo encoder from RN-027 .................................................................... 463-2 Turbo encoder from CF-072 ....................................................................... 463-3 Turbo encoder from RN-079 .................................................................... 463 -4 L inked list .................................................................................................. 50

4-1 4-Q A M signal set ........................................................................................ 704-2 16-Q A M signal set ...................................................................................... 704-3 Simulation 1 BER curves for Table 4.2 and Table 4.3 ............................... 734-4 Simulation 2 BER curves for Table 4.2 and Table 4.4 ............................... 744-5 Simulation 3 BER curves for Table 4.6 and Table 4.7 ............................... 764-6 Simulation 4 BER curves for Table 4.6 and Table 4.8 ............................... 774-7 Simulation 5 BER curves for Table 4.6 and Table 4.9 ............................... 794-8 Simulation 6 BER curves for Table 4.11 and Table 4.12 .......................... 814-9 Simulation 8 BER curves for Table 4.16 and Table 4.17 ........................... 844-10 Simulation 9 BER curves for Table 4.19 and Table 4.20 ........................... 864-11 Simulation 10 BER curves for Table 4.19 and Table 4.22 ......................... 884-12 Simulation 11 BER curves for Table 4.24 .................................................. 904-13 Simulation 12 BER curves for Table 4.25 .................................................. 92

- II -

Page 12: Simulating Turbo Codes using a Modular Simulation Platform

- 12-

Page 13: Simulating Turbo Codes using a Modular Simulation Platform

LIST OF TABLES

3.1 Sum m ary of sim ulation files ............................................................................. 68

4.1 Simulation I puncturing and mapping scheme ................................................. 714.2 Approximate BER values from cited graphs for simulation I Turbo code ....... 714.3 Simulated BER values for simulation 1 after 10,000 and 100,000 blocks ........ 724.4 Simulated BER values for simulation 2 after 10,000 and 100,000 blocks ........ 744.5 Simulation 3 puncturing and mapping scheme ................................................. 754.6 Approximate BER values from cited graphs for simulation 3 Turbo code ....... 754.7 Simulated BER values for simulation 3 after 10,000 and 100,000 blocks ........ 754.8 Simulated BER values for simulation 4 after 2,500 and 25,000 blocks ............ 774.9 Simulated BER values for simulation 5 after 10,000 and 100,000 blocks ........ 784.10 Simulation 6 puncturing and mapping scheme ................................................. 804.11 Approximate BER values from cited graphs for simulation 6 Turbo code ....... 804.12 Simulated BER values for simulation 6 after 1,666 AND 16,666 blocks ......... 804.13 Simulation 7 puncturing and mapping scheme ................................................. 824.14 Simulated BER values for simulation 7 after 1,666 AND 16,666 blocks ......... 824.15 Simulation 8 puncturing and mapping scheme ................................................. 834.16 Approximate BER values from cited graphs for simulation 8 Turbo code ....... 834.17 Simulated BER values for simulation 8 after 1,666 blocks ............................... 834.18 Simulation 9 puncturing and mapping scheme ................................................. 854.19 Approximate BER values from cited graphs for simulation 9 Turbo code ....... 854.20 Simulated BER values for simulation 9 after 2,500 blocks ............................... 854.21 Simulation 10 puncturing and mapping scheme ............................................... 874.22 Simulated BER values for simulation 10 after 2,500 and 25,000 blocks .......... 874.23 Simulation 11 puncturing and mapping scheme ............................................... 894.24 Simulated BER values for simulation 11 after 650 blocks ................................ 904.25 Simulated BER values for simulation 12 after 1,666 blocks ............................ 914.26 Sum m ary of sim ulation results .......................................................................... 93

5.1 Sim ulation tool m em ory usage .......................................................................... 985.2 Sim ulation tool speed ....................................................................................... 98

- 13 -

Page 14: Simulating Turbo Codes using a Modular Simulation Platform

- 14-

Page 15: Simulating Turbo Codes using a Modular Simulation Platform

CHAPTER ONE

INTRODUCTION

Almost every household in the United States uses the telephone system for voice

communications and the cable system for broadcast video. Although traditional uses for

the telephone and cable networks are different, developments in digital communications

in the last fifty years have enabled both systems to be similarly used for data

communications. The telephone system was originally intended for low-bandwidth voice

communications, and its network is optimized to operate primarily in the voice band [1].

Within this band, current computer modems can achieve a data rate of 56 kilobits per

second (kbit/s). Compared to a cable modem, which operates over a system designed for

high-bandwidth video broadcasting, this transfer rate is meager at best. However, with

the advent of digital subscriber loop (DSL) technology, data communications over the

- 15 -

Page 16: Simulating Turbo Codes using a Modular Simulation Platform

16 CHAPTER ONE

telephone network can now operate beyond the voice band and can achieve

communication speeds similar to that of the cable modem.

One variant of DSL technology is the asymmetrical digital subscriber loop, or

ADSL. In ADSL, the data rate from the end-user to the central office (upstream) is about

one-tenth the rate from the central office to the end-user (downstream). The specification

for ADSL is contained in International Telecommunications Union (ITU) standard

G.992.1, also known as G.dmt. G.dmt specifies an optional channel code as a

performance enhancement feature. Although the use of this code is optional, its use

greatly improves data rate.

Since the adoption of the channel code in G.dmt, even more powerful codes have

been discovered. In particular, the Turbo code has been the focus of much research

effort. The Turbo code is a class of parallel-concatenated codes discovered in 1993.

Research efforts have shown that with the use of Turbo codes, achievable data rates

approach very close to theoretical limits [2].

As part of the ITU's ongoing commitment to improve its standards, it has posted

question 4/15 (question 4, study group 15) to the telecommunications industry to solicit

enhancements to G.dmt and other DSL standards. The response is that many companies

have recommended various Turbo codes as a replacement for the current channel code in

G.dmt. These recommendations specify different types of Turbo codes and some cite

simulation results. There is currently no sure way to compare the different

recommendations because there may be differences in simulation implementations and

test parameters. Thus, there is need for a Turbo code simulation platform that can easily

and efficiently simulate the different Turbo codes specified in the recommendations.

Page 17: Simulating Turbo Codes using a Modular Simulation Platform

INTRODUCTION 17

This thesis will discuss implementation issues in simulating Turbo codes, present

a modular software tool for simulating Turbo codes, and analyze the performance of the

software tool and the reliability of simulated results. Of particular interest is the modular

implementation of the tool, which allows the tool to be highly flexible. Further, the thesis

describes in detail maximum a posteriori (MAP) probability decoding of convolutional

codes under 4-QAM and under higher spectral efficiency modulations.

Page 18: Simulating Turbo Codes using a Modular Simulation Platform
Page 19: Simulating Turbo Codes using a Modular Simulation Platform

CHAPTER TWO

BACKGROUND

The principles of digital communication stem from a field of research called information

theory. This field originated about fifty years ago through the seminal work of Claude

Shannon. Shannon theorized that information can be expressed as binary digits and that

the transmission of information can be quantified. Shannon was one of earliest scientists

to realize binary information, and his work held important notions that paved the way for

modern communication technology. This section will review concepts fundamental to

digital communication and will discuss the Turbo code.

2.1 Transmission using Signal Sets

In a communication channel, information is transmitted through the use of signal carriers.

Each carrier occupies a specific frequency and information is placed onto a carrier by

- 19-

Page 20: Simulating Turbo Codes using a Modular Simulation Platform

20 CHAPTER TWO

modulating the carrier's amplitude or phase. The set of all possible modulations is called

a signal set, which can be represented as points in a Cartesian space. A group of b

information bits is transmitted by modulating a carrier with one of M = 2bpoints from a

signal set. Each of the M points represents a distinct group of b bits and is also called a

symbol.

A Cartesian space representation is powerful in that it allows us to use familiar

concepts such as magnitude and distance on signal sets. Let P,, i=0, 1, 2, ... , M-1, be

points in a signal set. The average symbol energy E, of the signal set is

M-1 2

where F,.l is the magnitude of Pi. The concept of information bits will become clear in

the sections that follow, but for now suppose that of the b bits in a symbol, only q bits are

categorized as information bits. The average energy per information bit is defined as

EEj -- ES .(2)

2.2 The Shannon Limit

A channel model that is widely used in information theory is the ideal band-limited

additive white Gaussian noise (AWGN) channel. This model reflects important

characteristics of real communication channels and is relatively simple and analytic [3].

In an AWGN channel, the channel is gain insensitive, and transmitted symbols are

altered only by additive noise. The ratio of signal power to noise power is called the

signal-to-noise ratio, or SNR, and it is an important figure in channel coding.

Page 21: Simulating Turbo Codes using a Modular Simulation Platform

BACKGROUND 21

Using SNR, Shannon expressed in a formula the rate R at which information could

be transmitted with low probability of error. The formula defines a quantity called

channel capacity, and for a channel with bandwidth W, it is (in [bits/second])

C= W log 2 (1+SNR) . (3)

Shannon theorized that it is possible to transmit information at an arbitrarily low

probability of error only if R < C; low probability of error is otherwise unattainable.

Thus, channel capacity acts as an upper bound for transmission rates and is also known as

the Shannon limit.

The Shannon limit can also be interpreted as a lower bound for SNR:

R<W log 2 (1+ SNR)

R <log2 (1+ SNR)

W

R

SNR > 2w -1. (4)

The quantity p = R /W is called spectral efficiency and has units [(bits/second)/Hertz].

The relation in (4) is usually normalized with respect to p and becomes

SNR 2P -I

p p

The quantity SNR /p is equivalent to the ratio E. /NO, where No is the two-sided noise

power spectral density (PSD) of the channel. The quantity Eb /No is widely used in

channel coding and is often expressed in decibels [dB]. The Shannon limit is then

Eb [dB]>10log,0 21 (5)No p )

Page 22: Simulating Turbo Codes using a Modular Simulation Platform

22 CHAPTER TWO

2.3 Probability of Error

As previously mentioned, symbols transmitted in an AWGN channel are altered by

additive noise. The receiver must try to determine, from the altered symbols, what was

actually transmitted. A simple decision rule, called the minimum distance (MD) decision

rule, chooses the point in the signal set that is closest in distance to the received point.

For example, suppose that a signal set is one-dimensional so that signal set points

are real numbers. Further, assume that the distance between adjacent points in the signal

set is constant and equal to d. Using the MD rule, an erroneous decision will occur if a

symbol is altered by noise n with magnitude greater than d /2. The probability of error

can be expressed using the cumulative distribution function for the Gaussian noise

random variable:

Prn->!= 2 N a 2 dy . (6)

Expressed using the Gaussian probability of error function

Q(x)=fj e 2 dy

the error probability in (6) becomes

probability of error = Q . (7)2(TN

The quantity d /(2JN) is directly related to E /No . The energy per information bit E

is inextricably related to the distance d between adjacent points in the signal set such that

Page 23: Simulating Turbo Codes using a Modular Simulation Platform

BACKGROUND 23

any increase or decrease in d will affect a similar increase or decrease in Eb .

parameter oN is directly related to No in an AWGN channel by UN2 = No /2.

The

Although

various assumptions were made to arrive at the probability of error expression in (7), the

underlying principle is that probability of error depends on Eb INO. The main point,

shown by this particular case and applicable to other cases, is that probability of error can

be and most often is calculated as a function of E, / NO .

Probability of error is defined as the probability that a bit error will occur given

that all previous bits were correctly decoded. A more practical measure of error is the

percentage of bits that are decoded incorrectly, called the bit error rate (BER). The BER

is also calculated as a function of E, INO .

2.4 Calculating BER for an AWGN Channel

As previously mentioned, the noise variance is uN2 = No /2 for an AWGN channel with

two-sided noise power No. Using this expression together with (2), the noise variance

can be expressed as

2 No( EJN 2_. iqs =E,2 q2 b) .No

Parameters E, and q are predetermined and are generally not altered,'leaving E, /No as

the sole variable. Using (8) for a specific value of E, NO, white noise samples can be

2generated from a Gaussian process with variance aN . Then, these samples can be added

to transmit symbols to simulate an AWGN channel. Using the MD decision rule, the

(8)

BACKGROUND 23

Page 24: Simulating Turbo Codes using a Modular Simulation Platform

24 CHAPTER TWO

BER curve for a square QAM signal set with M=4 (b=2) is shown in Figure 2-1. This

curve is called an uncoded BER curve because the shape of the curve does not come from

any coding scheme.

2.5 Channel Coding

The BER curve in Figure 2-1 shows that an increase in the quantity E, INO results in a

decrease in the bit error rate. The noise power No is a fixed characteristic of the channel

and cannot be altered. Thus, Eb /No can only be increased by making E, larger, which

can be accomplished by increasing the minimum distance d between points in the signal

set. However, Eb is often limited by regulations specifying maximum transmit power, so

the BER for a signal set can be decreased only to a certain point. With the use of channel

codes, we can achieve lower BERs than that of Figure 2-1 at the same E, /No values.

The BER curve generated using a channel code is called a coded BER curve.

Channel coding relies on a metric called the Hamming distance, which is a

measure of the number of bits that differ between two binary numbers of the same length.

Channel coding adds extra bits to a group of binary numbers, called codewords in coding

jargon, to increase their minimum Hamming distance. For example, the minimum

Hamming distance is I for the set of codewords U = {00, 01, 10, 11}; that is, the

minimum number of bits that differ between any two codewords in the set is 1. Suppose

that the 2-bit codewords in U are each mapped to 3-bit codewords as follows: 00 4 000;

01 + 011; 10 + 101; 11 + 110. Now, the minimum Hamming distance between

codewords in the new set P = {000, 011, 101, 1101 is 2. By increasing the minimum

Page 25: Simulating Turbo Codes using a Modular Simulation Platform

Hamming distance of a set of codewords, the decoder can better distinguish between

them. The result is that the decoder possesses a limited ability to correct errors. In the

codewords of set P, only two out of three bits are part of the original codewords in U; the

other bit is extra. Since this extra bit must also be transmitted, the overall data

transmission rate is reduced. This reduced data rate is the cost of channel coding.

1.E+00

1.E-01

wI

1.E-02

1.E-03

1.E-04

1.E-05

1.E-06

1.E-07

______________________ [ ______________________ _______________________

__ __ __ 4 __ __ __

3 4 5

Figure 2-1. BER

6 7 8 9

Eb/No [dB]

curve for uncoded 4-QAM

2.6 The Convolutional Code

A convolutional code is a channel code in which each output bit is formed from a linear

sum of present input bits and past input and output bits. The process of generating output

bits requires memory and is the same as a discrete-time convolution operation. A

convolutional code with k input bits and n output bits is denoted as a rate-k/n code, with n

> k.

10

BACKGROUND 25

Page 26: Simulating Turbo Codes using a Modular Simulation Platform

26 CHAPTER TWO

2.6.1 The Recursive Systematic Convolutional Code

One type of convolutional code is the recursive, systematic convolutional code (RSCC),

which is used as a component of the Turbo code. The term systematic means that k of the

n output bits are exact duplicates of the input bits; these bits are called information bits or

systematic bits. Thus, only (n-k) output bits are formed by convolution; these (n-k) bits

are called parity bits. The term recursive means that the output bits are fed back so that

each parity bit is also a linear sum of previous output bits. Figure 2-2 below shows one

implementation of a rate-1/n RSCC encoder, and Figure 2-3 shows a rate-k/(k+1) RSCC

encoder. In the diagrams below, S1 denotes a memory register, u1 denotes an input bit,

and p1 denotes an output bit.

P1

U 0 3~S

Figure 2-2. Rate-1/2 recursive, systematic convolutional code

U0 p1

)( P~111 30

Figure 2-3. Rate-2/3 recursive, systematic convolutional code

Page 27: Simulating Turbo Codes using a Modular Simulation Platform

BACKGROUND 27

2.6.2 Markov Structure of Convolutional Codes

A convolutional code can be described using a Markov model in which each state

corresponds to the memory register values of the encoder and each branch corresponds to

a distinct group of input bits. If there are v memory registers and k input bits, the Markov

model will have 2 branches exiting each state and 2' states. The convolutional codes in

Figures 2-2 and 2-3 both have 24 = 16 states, but where the code in Figure 2-2 has two

branches exiting and two branches entering each state, the one in Figure 2-3 has four.

The Markov diagram for a four state, rate-l/2 code might be:

u0o= 10 U0

Figure 2-4. Markov diagram of a four state, rate-1/2 convolutional code

Depending on how memory register bits are assigned, the bit So can correspond to either

the most-significant bit (MSB) or least-significant bit (LSB) of the state. The example in

Figure 2-4 does not make a distinction.

Page 28: Simulating Turbo Codes using a Modular Simulation Platform

28 CHAPTER TWO

A convolutional code is typically initialized to the zero state. The input bits at

each time period determine which branch is taken and thus, the next state of the code.

When the Markov diagram in Figure 2-4 is laid out for each time period, the resulting

structure is called a trellis. The trellis for the Markov diagram in Figure 2-4 is shown

below. When a convolutional code also ends in the zero state, its trellis is said to be

terminated.

00 00 00

10/ 10

11 11

Figure 2-5. Trellis diagram

2.6.3 Decoding using Maximum a posteriori Probability

The output bits of a convolutional code are mapped to a signal set point, and the point is

transmitted across an AWGN channel. The output of the channel is called an observation

and is also a point in Cartesian space. In two-dimensional space, the observation is

R =(r, r,). The task of the decoder is to determine, from the observation, which

information bits were most probably at the input of the convolutional encoder.

One way to decode the convolutional code is to calculate a posteriori probabilities

(APP) and to choose the largest one. For a rate-k/n convolutional code, the data bits

Page 29: Simulating Turbo Codes using a Modular Simulation Platform

BACKGROUND 29

U, = i (t corresponding to a discrete time index) can have values i = 0, 1, 2, ... , 2 k_-

The decoder calculates the 2 a posteriori probabilities Pr(u, = i observations), and the

value of i corresponding to the maximum APP is used as the decoded data bits. Thus, the

decision rule is called maximum a posteriori (MAP) probability decision rule.

signJ set

U t MSCC(

* t

AtJJGN channelobsenrdion

U M decoder :

R= (r., ry)

Figure 2-6. Channel coding

MAP decoding of the convolutional code is performed using observations over

several time indices starting at index t =1 to an ending index t = 'r. Therefore,

information bits are decoded in blocks. For a rate-k/n code, the information bits u, at

time t correspond to a trellis branch from a state S,_, = m' to another state St = I,

producing parity bits pt.

Suppose there are N observation points for each block of information bits, and the

vector of those points is denoted by R7N = (R-, RN ). The APP is expressed as:

Pr( u, = i RN )= K Za,_(m'y(R,,mn', m),(in) . (9)t~~~~ ni )i(RI 13 M

Page 30: Simulating Turbo Codes using a Modular Simulation Platform

30 CHAPTER TWO

K,,,),, is a factor used to normalize the sum of Pr(u, = i RI N ) across all i to unity [12].

The a and # terms in (9) are called state parameters and are defined as

a, (m) = Pr(S, = in R[)

Pr(R, 1 St = m).8t(in)= Pr(R, 1 R[

N+

(10)

(11)

They are recursively calculated using

a, (in) = Ka a,_ (m')y (R,, in', m)

,(M')=- Kg yj(R,, 17', m#4()t+1 m)8+nm

(12)

(13)

K, and K8 are normalization parameters used to ensure that the sum of a, (in) across all

m and of /, (in') across all in' is unity. The a recursion in equation (12) is initialized by

realizing that if a convolutional code starts in state 0, then by the definition in (10)

a(0) = 1 and ao(m)= 0 for in # 0. For the 8 recursion in (13), if a code is terminated,

then we can initialize f, (0) = 1 and P, (in) = 0 for in # 0.

terminated, then there are two ways to initialize #(m).

However, if the code is not

The first way is to make all

8# (m) equiprobable by setting each term to 2 -, where v is the number of memory

registers in the code. The second way [4] is to first calculate the a recursion in (12) and

then equate #,(in)= a,(in) for each m.

The y term in (9) is called a branch parameter is defined as

y,(R,,m',in)= Pr(R,|u, = i, S,, = in', S, = in)-

Pr(u, = i|S,1 = m', S, = M)Pr(S, = mIS,_, = n').

(14)

30 CHAPTER TWO

Page 31: Simulating Turbo Codes using a Modular Simulation Platform

BACKGROUND 31

The first probability on the right side of (14) is discussed in Section 2.7. The second term

on the right side of (14) is either 0 or 1, depending on whether information bits u, =i

correspond to the branch transition from St, =' to S, =m. The last term in equation

(14) is the a priori probability, which can also be written as Pr(u, =i) for all values of i.

The a priori probability is discussed in Section 2.8.

Note that the subscript for the observation point R is somewhat ambiguous. There

are r time indices and N observations per block, and the two may not be equal. In (9),

the observation R, simply refers to the observation, out of the N in a block, which

contains information for time index t. Thus, a specific observation may be used over

multiple time indices ( N > r) or multiple observations may be required for each time

index ( N < r). In general, r is an integer multiple of N.

2.7 Symbol Mapping and Channel Observations

The beginning of Section 2.6.3 briefly stated that the output bits of a convolutional code

are mapped to a symbol and that channel observations are used in decoding. This section

addresses symbol mapping and channel observations in detail and develops expressions

for the probabilities in (14).

After encoding, the n bits in u, and p, are mapped to a point in the signal set.

Each of the M = 2" symbols in a signal set represents a distinct group, or label, of b bits.

It is possible that b # n, in which case u, and p, will either be spread over multiple

symbols (b < n) or be only part of one symbol (b > n). In most cases, b is a multiple of n.

Page 32: Simulating Turbo Codes using a Modular Simulation Platform

32 CHAPTER TWO

The following two sub-sections discuss symbol mapping and decoding under 4-

QAM and under higher spectral efficiency modulations for b n.

2.7.1 4-QAM Modulation

Each signal point in a 4-QAM signal set represents two bits. The first bit corresponds to

the x-coordinate, and the second bit corresponds to the y-coordinate. Thus, 4-QAM only

supports rate-1/2 convolutional codes. In this case, b = n, and the number of observation

points N equals the number of time indices r in a block.

01 11* 1- 0

-1 1

* -1- 0

00 10

Figure 2-7. Signal points and labels for 4-QAM

An observation R = (rr, ry ) is a point in two-dimensional space. In the first

probability on the right side of (14), we notice that the x- and y-coordinates are

uncorrelated Gaussian variables, given u, =i,S,_ = m',S, =m. Thus, (14) can be re-

written as

Pr(RIu, = i,S,_, = m',S, = m)= Pr(r ,|u, = i,S,_1 = m',S, = m) (15)

Pr(r,|, = i, S,_, = m', S, = M).

Page 33: Simulating Turbo Codes using a Modular Simulation Platform

BACKGROUND 33

From the condition u, =i,S,_, =n',St = i, we know the trellis branch at time t and, thus,

the parity bit p, for that branch. If P =(P,, P is the transmit symbol mapped by u,

and p,, then the two probabilities on the right side of (15) are

Pr(r, I = i, S,_ =i', S,= ) = 2 -T' 12 (16)

and

Pr(r, l u, = i, S,_ = m', S, = M)= e- 29 (17)

where o2 is the channel noise variance per real dimension.

2.7.2 Higher Spectral Efficiency Modulations

Equations (15) through (17) do not hold for modulations with spectral efficiencies higher

than 4-QAM. There are only two coordinates per symbol representing more than two bits

per symbol. Regardless of whether b = n or b > n, we still need information for each of

the b bits. The way to generate this information is to calculate a log likelihood ratio

(LLR) for each bit in a symbol [6].

For the purpose of illustration, suppose that the convolutional encoders have rate-

1/2 and that b = 2n = 4 bits. The Turbo encoder generates 1 information bit and 1 parity

bit each time index t. The outputs of the Turbo encoder are arranged in the order u,, ,,t

U,,, p,, and are mapped to a transmit symbol from the 16-QAM signal set shown in

Figure 2-8; there are N = r /2 symbols over the period t = I ... r. Each observation now

corresponds to 4 bits and two trellis branches.

Page 34: Simulating Turbo Codes using a Modular Simulation Platform

34 CHAPTER TWO

To calculate a bit LLR, we begin by observing that noise in the AWGN channel is

one-dimensional, and the noise samples that move the x- and y-coordinates are

independent. Further, the first b/2 bits of each point are associated with the x-

coordinate, and the last b/2 bits are associated with the y-coordinate. These facts allow

us to consider only the x-coordinate when calculating the LLRs for the first b/2 bits and

to consider only the y-coordinate when calculating the LLRs for the last b/2 bits [6].

00100

01100

0011 01110 0

00010

0000S

0101

0100

1110 1010

1111 1011

1101 10010 0

1100 10000 S

Figure 2-8. Signal points and labels for 16-QAM

The formula [4] for calculating the LLR of the j1h bit L(b) is

le 2U.2

L(bj) n P1:b =1

Ye- 20 U 2 (12

P0~b =0

bfor J <-, and

2(18)

Page 35: Simulating Turbo Codes using a Modular Simulation Platform

BACKGROUND 35

L(b)= In P1:bj =1

I):h =0

In equations (18) and (19), T is the channel noise variance per real dimension;

R = (rx, r, ) is the observation point; P and P, are the x-coordinates of points where

b, is I and 0, respectively; and P,, and P. are the y-coordinates of points where b is I

and 0, respectively. As shown mathematically in (18) and (19), the LLR is a measure of

the likelihood that Gaussian noise moved the transmitted point from points where b I

versus from points where b, =0.

The probability

shown in (15).

Pr(RIu, =i,S,_, =m',S = m) can no longer be separated as

Instead, the observation point is now separated according to the part of

R, that represents systematic bits u, and the part that represents parity bits p,. Denote

the systematic part as R t and the parity part as RP. Using these two variables, the

analog to equation (15) is

Pr(R,|u, = i, S,1 = m', S, = m)= Pr(R;' u, = i, S,_1 = n', S = m)-Pr(RP|u, = i, S,_ = m', S, = m) .

Using the LLRs from (18) and (19), the probabilities in (20) are calculated as

Pr(R; |u, =i,S,4 =m',S, =in)= hle i bb)t ~b E 11 -- 6eL~i

(20)

(21)

and

Pr(RIu , =i,S, - = m',S, = m)= rHe b)L(b)biep E I+e~b )

for j b .2

(19)

(22)

BACKGROUND 35

Page 36: Simulating Turbo Codes using a Modular Simulation Platform

36 CHAPTER TWO

The bits b in (21) correspond to u, and the bits in (22) correspond to the parity bits p,

for the trellis branch given by the condition. Equation (21) assumes mutual conditional

independence for the bits in u, , and thus, their individual probabilities are multiplied.

Equation (22) makes the same assumption for p,.

The received coordinates r, and r, in (15) can be analytically expressed as a

transmit value plus Gaussian noise. Further, it is certain that they are probabilistically

separable. In contrast, the parts R;' and R,' in (20) do not have a general analytical form.

The most we can say is that R,' is a function of LLRs in the set { L(bJ) b1 e u, } and

that R,' is a function of LLRs in the set t L(b,) b1 e p, }. Equation (20) assumes that

R;' and R, are conditionally independent even though they may not be [6]. Even so,

assuming independence greatly simplifies the calculations and does not noticeably

degrade decoding performance [6]. Thus, conditional independence is always assumed.

It has been noted [6] that the higher spectral efficiency modulation equations in

this section can be used for decoding 4-QAM modulation without much degradation in

performance. Thus, the equations in this section are used for decoding all types of

modulation.

2.8 The Turbo Code

It has been noted that code concatenation and interleaving can achieve lower error

probabilities [5]. The Turbo code uses both of these concepts.

Page 37: Simulating Turbo Codes using a Modular Simulation Platform

BACKGROUND 37

2.8.1 The Turbo Encoder

The basic structure of the Turbo encoder is formed by a parallel concatenation of two

RSCCs. The input to one convolutional encoder is a sequence of information bits, and

the input to the second convolutional encoder is an interleaved sequence of those bits.

Then, in a process called puncturing, some of the parity bits from the two encoders are

selectively used while others are discarded. Puncturing allows the overall rate of the

Turbo code to be conveniently tailored.

In Figure 2-9 below, the outputs of the RSCC encoders show only the parity bits.

The two convolutional encoders are usually the same, although they do not need to be. If

the convolutional codes have rate-k/n, then u, represents k bits and p, represents (n-k)

bits.

U Lt

Lit :pit(

t= encoder 1 puncturingmechanism

intereaer Pt010101...

Ut , RCC 101010...encoder 2

Figure 2-9. Turbo encoder structure

The output bits of the Turbo encoder are mapped to a transmit symbol and sent

across the channel, as discussed in Section 2.7. Using the channel observations, bit LLRs

are calculated using equations (18) and (19). Before the parity bit LLRs are used by the

Turbo decoder, they first need to be un-punctured to reverse the puncturing process from

Page 38: Simulating Turbo Codes using a Modular Simulation Platform

38 CHAPTER TWO

the Turbo encoder. During un-puncturing, a LLR = 0 is inserted in place of a punctured

bit. In the absence of any information about the punctured bit, it is equally likely to be a

zero or a one, producing a LLR of zero.

2.8.2 Iterative Decoding and the Turbo Decoder

The Turbo decoder consists of two MAP decoders, with each one used for decoding one

of the two convolutional codes in the Turbo encoder. The APP depends primarily on

calculating the y parameter, which is composed of the channel observation probability

Pr(R, I u, = i, S,_, = m', S, = M) and an a priori probability Pr(S, = m|S,_, = M') =

Pr(u, = i). From equations (21) and (22), we see that the channel observation probability

is calculated from bit LLRs. A LLR tell us two things about a bit - the sign indicates

whether the bit is zero or one, and the magnitude of the LLR indicates the degree of

certain that the sign is correct. A very negative LLR indicates high certainty that the bit

is zero, whereas a slightly positive LLR indicates low certainty that the bit is one. Thus,

the magnitude of a LLR is called the reliability of a bit decision.

The LLR is called soft data because it provides information for making a bit

decision and for determining the reliability that decision. The MAP decoder is called a

"soft-in soft-out" decoder because it uses soft data input and generates soft data output.

Expanding the y parameter in equation (9), the APP can also be written as

Pr( ut = i R = K,,,, Pr(R, u, = i).Pr(u, = i). (23)

Pr(R, I|u = i, S,_i = m', S, = m)Pr(u, = i|St, = m', S = m).a,, (m'),, (M)n] 112

Page 39: Simulating Turbo Codes using a Modular Simulation Platform

BACKGROUND 39

The right side of equation (23) has three parts: the systematic channel observation

probability Pr(Rs u, = i) the a priori probability Pr(u, =i), and the last part called the

extrinsic information [2]:

E Pr(R' |u, = i,S,_1 = m', S, = m)Pr(ut = i|S,_1 = m', S, = im). at,(m')t (m)

Pr(ut =i RN

Pr(Rt I u, = i)- Pr(u, = i)

From the extrinsic information, we define the extrinsic probability P,- as

Pr(ut =i RN< =Kex Pr (RIu, = i) Pr(ut = i) (25)

The factor Kx, normalizes the sum of the extrinsic information across all i to unity.

The extrinsic probability is generated by the MAP decoder and is also soft data.

For a time t, the probabilities P,"C correspond to the values of u, =i, and the magnitude

of each P," indicates the certainty of that value of i. Thus, the extrinsic probability

provides soft information about u, = i and can be used as a priori information.

The Turbo decoder has two MAP decoders, and the extrinsic probability at the

output of each MAP decoder is used as the a priori probability in equation (23) in the

other MAP decoder. The point of the extrinsic information is to pass information to the

other MAP decoder that it does not already have. Notice that the extrinsic information

produced by each MAP decoder is a function of the parity bit information for that

decoder. As a result of the puncturing process, each MAP decoder does not possess the

parity bit information in the other decoder. Thus, the extrinsic information produced by

Page 40: Simulating Turbo Codes using a Modular Simulation Platform

one decoder supplements the information in the other decoder. Further, equation (24)

shows that the systematic channel observation probability Pr(R, Iu, =i) and the a priori

Pr(u, = i) are not part of the extrinsic information. Both MAP decoders

already possess the systematic channel observation, and the a priori probability used in

one decoder is just the extrinsic probability generated by the other decoder. Thus,

Pr(RsIu, = i) and Pr(u, = i) are correctly excluded from the extrinsic information.

The entire process described above is called iterative decoding and is illustrated

below in Example 2-1.

Pr (u=i)

Pr (u'=i) t

P

LfL(L(u) : 0nee e

MAP decoder 1 MAP decoder 2

L(p 1) L(p2)

APP'

APPI

mFximum APPdecision

Figure 2-10. Turbo decoder structure

Example 2-1.

Iteration 1

Iterative decoding using extrinsic probabilities

* MAP decoderPr(u, =i)= 2 -k

I has no a priori input during the first iteration, so it uses

in equation (23) to calculate the APP and generates P eli using

equation (25), for all i = 0, ... , 2 k-' and t =1, ... ,r.

probability

40 CHAPTER TWO

Page 41: Simulating Turbo Codes using a Modular Simulation Platform

MAP decoder 2 uses the time-interleaved sequence Pr(u,. = i)= P," in equation (23)to calculate the APPs:

Pr( ut, = i RN )= Pr(R u, = i)- P" .

IIPr(R~t'ut, = i, St,,_, = m', St,. = m)Prfut,. = i|S,_, = M', St,. = M)- a,.

MAP decoder 2 generates t,< using (25) for all i and t'.

interleaved sequence with respect to t.

Iteration 2 and beyond

Here, t' refers to an

- MAP decoder I uses the de-interleaved sequence Pr(u, = i)= Pt22 in equation (23) tocalculate the APPs:

Pr(u = i RN =Pr(R;| u,= t .

YJ Pr(R,u, =i,S_ =m',S,

MAP decoder I generates P,'' using (25) for all i and t.

MAP decoder 2 uses the time-interleaved sequence Pr(u,. =i)= P,<' in equation (23)to calculate the APPs:

Pr(u,. =i RN )=Pr(Ri Iu,. = i). Pti

Pr(RmtIu,. = i, S,._, = m', S,, = m)Pr(u, =|_, = m' , -I _ ',(M)

MAP decoder 2 generates p, 2 ,i using (25) for all i and t'. Here, t' refers to aninterleaved sequence with respect to t.

2.8.3 Fast Decoding of Rate-1/n Component Encoders

With minor modifications, we can reduce the amount of computation for MAP decoding

of rate-I/n convolutional codes. There is only one information bit, so k = I and there are

only two APPs. Define the quantity A to be the natural log of the ratio of the two APPs :

BACKGROUND 41

_ (M'),.t,(M)

m)Pr fu, = i|S,_1 = m', St = M). a,_] (M'),t(M)

Page 42: Simulating Turbo Codes using a Modular Simulation Platform

42 CHAPTER TWO

Pr(u, =1 RN -N(m')y,1 (R,,m,m),(m)A(u )=ln In (26)

' Pru, =01 R, a,- (y 0(R,,Inm)'1 (mn)

Expanding the y parameters in (26) the same way as in (23), equation (26) becomes

A(u, )=L + L' + L

where

L' = In P u 1 =i) and L' =In Pr(u )Pr(R, u, =0) Pr(u, = 0)

Then, the extrinsic information L is calculated by

Et = A(u )-Lt - L' (27)

which is analogous to (25).

Using equation (26), the decoded bit corresponds to the sign of A rather than the

maximum APP. For the case of rate-1/2 RSCCs, using equation (27) instead of equation

(25) to generate extrinsic information results in faster decoding because the operations in

(27) are additive rather than multiplicative. Further, equation (25) generates two extrinsic

probabilities, one for each value of i, while equation (27) only generates one extrinsic

value.

Using these new quantities, the iterative decoding process for rate-1/2 component

codes is illustrated in Example 2-2.

Page 43: Simulating Turbo Codes using a Modular Simulation Platform

BACKGROUND

Example 2-2. Iterative decoding with rate-k/n (k > 1) component RSCCs

Iteration 1

MAP decoder I has no a priori input during the first iteration,Pr(u, = i) =0.5 in the y terms in equation (26) and generates L, using equation (27),

for all t = l,..., r .

MAP decoder 2 uses the time-interleaved sequence K, to calculate the a priori

probabilities in the the y terms in equation (26) as follows:

Pr(u, = i) =I + e

MAP decoder 2 generates L, using (27) for all t'. Here, t' refers to an interleaved

sequence with respect to t.

Iteration 2 and beyond

- MAP decoder I uses the de-interleaved sequence Lt to calculate the a priori

probabilities in the the y terms in equation (26) as follows:e j2

Pr(u, = i) = ueLtM+ e '

MAP decoder I generates Lt using (27) for all t .

MAP decoder 2 uses the time-interleaved sequence L, to calculate the a priori

probabilities in the the y terms in equation (26) as follows:

Pr(u, =i)= eI+ e 4

MAP decoder 2 generates L using (27) for all t'. Here, t' refers to an interleaved

sequence with respect to t.

so it uses

43

Page 44: Simulating Turbo Codes using a Modular Simulation Platform
Page 45: Simulating Turbo Codes using a Modular Simulation Platform

CHAPTER THREE

THE SIMULATION TOOL

The purpose of the tool is to simulate Turbo codes described in the various ITU

contributions. The tool is designed for that specific purpose and will have certain

limitations that make it unsuitable for other applications. These limitations will become

apparent in the sections that follow.

3.1 Simulation Tool Scope

The main Turbo code contributions considered in designing the tool include ITU

documents CF-037 [15], CF-072 [17], RN-027 [20], RN-079 [18], and IC-024 [19]. The

Turbo encoder proposed in CF-037 is the standard structure in Figure 2-9, while other

companies have proposed the variations shown in Figures 3-1 through 3-3.

-45 -

Page 46: Simulating Turbo Codes using a Modular Simulation Platform

46 CHAPTER THREE

interleaer 2 ?. U"t

Ut '' RSCencoder 1 puncturng

t = ... - -mechanism

t010101...

UF RS(r 32 101010 ...encoder2 I

Figure 3- 1. Turbo encoder from RN-027

Ut

Ut 4 RSCC tencoder 1 punctung

t mechanism

interleaver 11 100100 ... P t010010 ...

U t RS~C 001001 ...encoder 2

- intede;Der 2 n1c de 3S p3 t

Figure 3-2. Turbo encoder from CF-072

Ut interleaer 0 re-3A4 t

Figure 3-3. Turbo encoder from RN-079

The different Turbo encoder structures include parallel concatenations of more

than two RSCC encoders and also serial concatenation of RSCC encoders. The Turbo

decoder structures that correspond to the encoders in Figures 3-1 through 3-3 also differ

,

Page 47: Simulating Turbo Codes using a Modular Simulation Platform

THE SIMULATION TOOL 47

from the standard structure in Figure 2-10; the differences are straightforward and are not

shown here. Aside from structural differences, the proposed Turbo codes also have

component differences; one Turbo code may work especially well with one type of

interleaver or RSCC encoder while other codes may use other types. Thus, the

simulation tool needs to accommodate both structural and component differences for

different Turbo codes.

3.2 Design Considerations for Structural Flexibility

The simulation platform is designed to be highly flexible, requiring minimal code

changes to simulate different Turbo code proposals. As mentioned in the previous

section, the design should account for structural flexibility and component flexibility.

Structural flexibility is addressed first in this section.

3.2.1 Simulation Tool Language

Figures 2-9, 3-1, 3-2, and 3-3 reveal that the Turbo code is composed of several

independent blocks connected via flow lines. To implement a Turbo code, we can simply

execute each block, or module, in order by following the direction of flow lines.

Although the modules operate independently, data in the form of bits or real values are

still passed between them. Thus, there is need for a system to define connections

between modules and to implement data transfer between them.

The needs of the system fit the description of object-oriented programming

(OOP). However, OOP requires the use of syntax not supported by the compilers

prevalent on most workstations. Thus, the simulation tool is implemented using regular

Page 48: Simulating Turbo Codes using a Modular Simulation Platform

48 CHAPTER THREE

procedural programming in ANSI-C. Such an implementation still adheres to the design

goals above without any loss of flexibility. The only direct disadvantage of not using

OOP is slightly worse module abstraction and program structure, which does not affect

simulation performance.

3.2.2 Module Flow Implementation

Using ANSI-C, each module can be implemented as a struct, with flow connections

specified by input and output fields:

struct basic-module {

flow type* input;flow-type* output;

Code 1. Module template

Each module must have the input and output fields in code 1, and both fields must be of

the same variable type. This system guarantees that any two modules can be connected

together regardless of whether their connection might make sense at the present time.

Using this system, module flows can be specified by directly equating inputs and outputs:

encoderl.input = bitSource.output;

interleaver.input = bitSource.output;

encoder2.input = interleaver.output;

puncturer.inputl = encoderl.output;

puncturer.input2 = encoder2.output;

Code 2. Module flow connections

Page 49: Simulating Turbo Codes using a Modular Simulation Platform

THE SIMULATION TOOL 49

The flow implementation in code 2 offers high structural flexibility because

modules are linked by simply defining input and output connections. Thus, modules can

be inserted or deleted with ease.

3.2.3 Data Transfer between Modules

Each module's input and output point to a specific memory location. By equating inputs

and outputs as shown in code 2, we are actually assigning the memory locations of the

input pointers. However, the memory locations of output pointers are not specified. The

flow connection implementation requires each module to allocate memory for its output

pointer internally, while input pointers are assigned externally. When a module places

data at the memory location specified by its output pointer, it is in effect transferring data

to the input of another module. Thus, each module can take data from its input pointer

and write resulting data to its output pointer without having to specifically communicate

with other modules. Simply executing the modules in order of flow direction will

transfer data through the encoder and decoder structures.

The next design issue is to determine how data is organized at each module's

input and output memory locations. Specifically, the generic flow-type designation in

code 1 needs to be replaced with an appropriate data structure type. Consider that data

transferred through the Turbo code is ordered with respect to time and that the actual

amount of data that is transferred can vary depending on the types of components in the

Turbo code. Thus, the data structure must be ordered and must allow data elements to be

easily added or deleted. The most appropriate structure for implementing these

requirements is a linked list.

Page 50: Simulating Turbo Codes using a Modular Simulation Platform

50 CHAPTER THREE

head

n ext

-3. 1 01 004

tail

Figure 3-4. Linked list

A linked list is a chain of elements, with the first element called the head of the

list and the last element called the tail of the list. Each element contains a pointer to the

previous element in the list and a pointer to the next element in the list. The head has no

previous element and the tail has no next element. The next and previous pointers allow

the linked list to be ordered, and elements can be easily added to or deleted from the list

by changing those pointers. Each element also contains variables to hold data.

3.2.4 Module Execution

The previous sections have created a system for making directional connections between

modules and for transferring data between modules. The only task that remains is to

execute each module in the correct order and allow the data to automatically flow through

the Turbo code structure. The lines in code 3 perform Turbo encoding according to the

structure in Figure 2-9; the variables are the same as those used in code 2.

Each function accepts a struct and uses the variables in the struct to perform its

task. The function reads data from the module's input linked list, and resulting data is

placed in the output linked list. The order of the function calls correctly corresponds to

the flows in Figure 2-9 and to the connections made in code 2. While this ordering can

Page 51: Simulating Turbo Codes using a Modular Simulation Platform

THE SIMULATION TOOL 51

be automated solely from the flow connections defined in code 2, doing so would likely

detract from the run-time efficiency of the tool. Further, the user can order the functions

quickly and easily, making the automation feature unnecessary.

generate bits(bitSource);doencode(encoderi);terminate(encoderi);

do interleave (interleaver);

doencode (encoder2);

do puncture(puncturer);

Code 3. Turbo encoding

3.3 Design Considerations for Component Flexibility

Section 3.2 created a framework for implementing structural flexibility and for module

execution. This section now addresses considerations for component flexibility.

Component flexibility is based on two factors: 1) the comprehensiveness of module

definitions, and 2) the amount of code changes necessary to create different types of the

same module. The aim is to maximize factor one while minimizing factor two.

Factor one depends on the variable definitions in a module struct. For the purpose

of this simulation tool, factor one can be sufficiently satisfied if the module is capable of

taking on the forms specified in the Turbo code proposals listed in Section 3.1. However,

when obvious extensions of those forms do not unreasonably complicate module

implementation, variable definitions are made intentionally broad to cover those'

extensions.

Factor two depends on module implementation and can rely in part on industry

standards. To minimize the amount of code changes, the user should only need to specify

numerical or string parameters for a module, and the module should create the data

Page 52: Simulating Turbo Codes using a Modular Simulation Platform

52 CHAPTER THREE

structures it needs from those parameters. Thus, factor two is mainly concerned with

module initialization. The following sections will discuss design and implementation

considerations for all modules available in the simulation tool. Code for these modules

are shown in Appendix C.

3.3.1 Linked List Design and Implementation

The linked list can itself act as a module for generating bits, operating as a bit source.

The theory of a linked list as described in Section 3.2.3 is quite general, and the data

structure can be implemented in *a variety of ways. One simple implementation is to

create an array of elements and to keep track of the number of elements in the list. The

next and previous pointers of each element are implemented as integer values

corresponding to the array index of adjacent elements in the list. Although this

implementation is straightforward, there are two obvious drawbacks. The first is that we

must be sure to allocate enough array cells to hold the maximum possible number of

elements, and this number may not be available during module initialization. The second

drawback is that the list will not always hold the maximum number of elements, and

memory allocated for empty slots in the array is wasted. The use of dynamic memory

allocation and deallocation solves both of these concerns.

typedef struct linkListStructint valueLength;listElement *head, *tail;

struct linkListStruct *output;} linkList;

Code 4. Linked list definition

Page 53: Simulating Turbo Codes using a Modular Simulation Platform

THE SIMULATION TOOL 53

Code 4 shows the linked list definition used by the simulation tool. During

module initialization, both the head and tail pointers are set to NULL. When the first

element is added to the linked list, memory for the new element is allocated and both the

head and tail point to the same element. As elements are added or deleted, memory for

those elements are allocated or de-allocated, respectively. Thus, there is no need to know

the memory requirements during module initialization, and memory is not wasted.

Each list element is designed to correspond to a specific time index. During a

time index, an element may need to store multiple bits or multiple signal points, so each

list element is designed to hold an array of bits and an array of two-dimensional Cartesian

coordinates. The lengths of the arrays are the same and are specified by the variable

valueLength in code 4. Thus, all elements of a linked list are implemented with the

same data array lengths.

Lastly, during module initialization, the output pointer is set to point back to the

linked list itself. The reason for this redundancy is simply to allow the linked list itself to

be used as an input for module connections, as shown in code 2.

3.3.2 Interleaver Design and Implementation

The interleaver function is relatively simple to implement. An interleaver takes a

sequence of elements and rearranges its order according to a permutation pattern, which

is implemented by a lookup table in the simulation. It is important to note, however, that

because of memory constraints in real-life systems, an actual interleaver implementation

would be algorithmic and would not be a lookup table.

Page 54: Simulating Turbo Codes using a Modular Simulation Platform

54 CHAPTER THREE

Recall that each MAP decoding process works with a block of bits corresponding

to trellis branch transitions. The number of branch transitions is the same as the number

of time indices and depends on the rate of the convolutional code. Thus, the length of the

input sequence is the same as the number of time indices in a block of bits and depends

on parameters from other modules.

Unlike sequence length, the permutation pattern is unrelated to other module

parameters. However, initializing the variable is not completely straightforward. The

permute pattern is generated algorithmically during module initialization, and new

initialization functions need to be written for new algorithms. ITU proposal RN-029 [21]

describes a two-step semi-random algorithm for generating a permutation pattern, and the

algorithm has been implemented in this tool. Algorithms described in other proposals

[15] may use permutation matrices instead of a permutation pattern in array format. Even

so, the effect of the matrix is to rearrange the order of the input sequence, and that

operation can always be described by a permutation pattern [13]. Thus, some

permutation algorithms may need to be adapted to the array structure used in. the

interleaver module.

Variables for the interleaver module are shown below in code 5.

typedef struct interleaverVarsStructint blockSize;int* permutePattern;

linkList* input;

linkList* output;

interleaverVars;

Code 5. Interleaver module definition

Page 55: Simulating Turbo Codes using a Modular Simulation Platform

THE SIMULATION TOOL 55

3.3.3 Convolutional Encoder Design and Implementation

Every convolutional encoder structure takes in some number k of input bits and generates

another number n > k of output bits. In doing so, the encoder stores v bits in memory

registers that are each a linear sum of past input and output bits. In a RSCC, k of the n

output bits are exact replicas of the input bits, and the other r = (n - k) are parity bits.

Thus, a RSCC has rate-k/(k+r).

3.3.3.1 Use of the Trellis Diagram for Encoding

Convolutional codes can have very different encoder structures, as shown in Figures 2-2

and 2-3. However, the similarity among all convolutional codes is that their behavior can

be mapped out in a trellis diagram, and the parameters k, r, and v, determine certain

characteristics of the diagram. A trellis diagram has 2' states, with 2k branches entering

each state and 2 branches exiting each state. Each branch corresponds to a unique k-bit

input and also to a r-bit parity number.

In real-life systems, a VLSI implementation of a convolutional encoder is easy

and fast, and allowing the encoder structure to be used for encoding. However, for the

simulation tool, using a trellis diagram to perform convolutional encoding is much more

efficient than using the encoder structure. A trellis branch can be calculated by using a k-

bit input with an encoder starting state and by recording the resulting state and parity bits.

Only 2 k* branch calculations are required to construct a trellis diagram. Then, to

perform encoding, we simply traverse the trellis by following the correct branches. In

contrast, using the encoder structure to perform encoding requires one branch calculation

Page 56: Simulating Turbo Codes using a Modular Simulation Platform

56 CHAPTER THREE

per time index, and the number of time indices is greater than 2 k+ by several orders of

magnitude.

As shown in code 6, the trellis description is stored in a two-dimensional array.

The first dimension has 2' indices and corresponds to the encoder states. The second

dimension has 2k indices and corresponds to the branches exiting a state. Each branch

stores the starting and ending states, as well as input and parity bits.

typedef struct encoderVarsStructbranch** trellis;int* terminator;char* state;int k;

int r;int V;

linkList* input;linkList* output;

encoderVars;

Code 6. Convolutional encoder module definition

The one-dimensional array terminator describes the path from any state to the

zero state. The index of an array cell is the current state, and the content of the array cell

is the k-bit input corresponding to the next branch to take. The general rule for

terminating a convolutional code with v delay registers is that v input bits are required to

complete the termination. If the code has rate-k/(k+r), then those input bits correspond to

v/k branches. However, since k may not be a multiple of v, the simulation tool uses

-] -k bits to perform the termination.k

Page 57: Simulating Turbo Codes using a Modular Simulation Platform

3.3.3.2 Generating Polynomials

As described in Section 2.6, the output bits of a convolutional encoder are formed from a

linear sum of current and past input and output bits. For k input bits uo ... Uk], v memory

registers, and r output bits yo ... Yr-I,

k-Iv

010 t (ti=0 j=0

(28)j) + b" y(t-j).i=0 J=I

a"i is the coefficient for calculating output bit y,, using input bit u with delay j.

Similarly, b"' is the coefficient for calculating output bit y,, using output bit y, with

delay j > 0. The binary coefficients a' and b"' determine the encoder connections

shown in Figures 2-2 and 2-3.

For a bit b, +b = -b. Thus, (28) can also be expressed as

r-I v k-I v

Y, (t)+ Y b|" yi(t - j)= a,"' ui(t - j)j.i=0 j=I i=0 j-0

Then, taking the D-transform of (29) and rearranging, we have

y,, (D 1 + JDj ) +0 Y(D (j=0

b7jDk-I

= ut(Di=0

The sequences a,'=ia'0 ... a'" and b"=( b'. .. bt"' are referred to as generating

polynomials because they determine the terms of the delay polynomials in (30) that

generate the output bits. For clarity, the sequences a,"I will be referred to as feed-forward

polynomials, and b"' will be referred to as feedback polynomials.

The convention for describing a convolutional code is to express the feed-forward

and feedback polynomials as octal numbers. The most significant bit (MSB) of the feed-

(29)

(30)a,"'JDJ- 0

THE SIMULATION TOOL 57

Page 58: Simulating Turbo Codes using a Modular Simulation Platform

58 CHAPTER THREE

forward octal number is a", corresponding to no delay, and the least significant bit

(LSB) is a.", corresponding to highest delay. The feedback polynomial follows the same

delay order.

Using octal notation for the encoder in Figure 2-3, the feed-forward polynomials

for the parity bit are ao = 35 and ao = 278, and the feedback polynomial is bo = 318.

Following the connections for the encoder in Figure 2-2, the generating polynomials are

not immediately obvious. The output is not fed back, and the recursive connections seem

to make the feed-forward polynomial infinitely long even though there are only four

delay registers. In this case, the polynomials can be obtained by analysis:

So(D)= u (D)+ So(D)(D' + D4)

u (D)1+ D' + D4

pO(D)= S,(D)(1+ D + D2 + D4)

PO(D)= + (+D 4 (I+D+D2+D4)

pO(D)(+D'+ D4)=u,(D)(1+D+D2 +D4)

Thus, the feed-forward polynomial is ao = 35,, and the feedback polynomial is bo = 23

3.3.3.3 Constructing the Trellis Diagram

Although every convolutional code can be fully described by its generating polynomials,

implementing the codes can require very different encoder structures, i.e. the placement

of memory registers and bit adders, and the direction of feed-forward and feedback paths.

As an example, the convolutional codes of Figures 2-2 and 2-3 can both be

Page 59: Simulating Turbo Codes using a Modular Simulation Platform

THE SIMULATION TOOL 59

mathematically described by their generating polynomials, shown in Section 3.3.3.2.

Even so, the encoder in Figure 2-2 is specifically designed for a rate-1/n RSCC, and the

encoder in Figure 2-3 is specifically designed for a rate-k/(k+1) RSCC. It is difficult to

imagine how the generating polynomials for the code in Figure 2-3 would be

implemented on the structure in Figure 2-2. Thus, constructing a trellis diagram requires

knowledge of the encoder structure in addition to the generating polynomials. In fact, it

is interesting to note that the structures in Figures 2-2 and 2-3 can both be used to

implement a rate- 1/2 RSCC and that the two implementations produce different trellises

for the same generating polynomials. This confirms that a trellis diagram depends on

knowledge of both the generating polynomials and the encoder structure.

When constructing the trellis, the simulation tool stores generating polynomials in

two separate variables. Feed-forward polynomials are stored in a three-dimensional

array. The content of each array cell is a coefficient a,', with the first array index

corresponding to output bit p,,, the second to input bit u,, and the third to delay j.

Feedback polynomials are stored in a one-dimensional array, with the array index

corresponding to delay j. The convolutional codes encountered thus far in the ITU Turbo

code proposals only generate one parity bit, so the simulation tool assumes that only one

feedback polynomial is needed. Consequently, only the rate-1/n and the rate-k/(k+1)

RSCC encoder structures in Figures 2-2 and 2-3, respectively, are implemented in the

tool. The rate-1/n structure is only used to implement rate-1/2 codes. The trellis diagram

for RSCCs can be constructed using those two structures, but new code must be written

to implement other types of encoder structures. Of course, the rate-1/n structure can be

Page 60: Simulating Turbo Codes using a Modular Simulation Platform

60 CHAPTER THREE

used for n > 2, but the feedback array must be modified to hold more than one

polynomial.

3.3.4 Puncturing / Un-Puncturing Module Design and Implementation

The task of the puncturing module is to adjust the overall rate of a Turbo code by

selectively discarding parity bits according to a set pattern. Regardless of how many

linked lists are at the input of the puncturing module, there is only one output list. The

job of the un-puncturing module is to perform the reverse operation and to generate

multiple' outputs from one input list, also according to the same pattern. Thus, the

puncturing module and its counterpart have nearly identical definitions.

typedef struct punctureVarsStructint numInputs;int punctureLength;int currIndex;char** puncturePattern;

linkList** input;linkList* output;

punctureVars;

Code 7. Puncturing module definition

The pattern for each input list is stored in a one-dimensional array, and all of

those patterns are stored in another one-dimensional array. Thus, the patterns for all

inputs are stored in a two-dimensional array. The puncturing patterns are accessed

circularly, and the puncturing module will work for any number of input bits. In general,

though, the number of parity bits per input will be a multiple of the pattern length.

Where the puncturing module works with bits, the un-puncturing module works

with log-likelihood-ratios. When performing un-puncturing, a discarded bit is replaced

Page 61: Simulating Turbo Codes using a Modular Simulation Platform

THE SIMULATION TOOL 61

with LLR = 0, indicating that the bit is equally likely to be zero or one. Since the

puncturing module will work for any number of input bits, the stop condition for un-

puncturing must make certain that the number of LLRs at each output of the un-

puncturing module is at least the number of parity bits at each input to the puncturing

module.

Consider the two puncturing patterns below:

Pattern 1 Pattern 2

index 0123 012345

input 1: 1010 010000input 2: 0101 000010

In pattern 1, the un-puncturing process can stop when no more LLRs remain at the input

to the un-puncturing module, which can occur at any index. However, the same

condition will not suffice for pattern 2. Suppose that the final LLR input is used at index

I in pattern 2. According to the pattern I stop condition, un-puncturing would end at

index 1. However, it is possible that the puncturing process actually ended at index 2 or

index 3, which would not produce any more parity bits beyond the final bit at index 1.

Thus, the un-puncturing process must not end at index 1. The problem is that the un-

puncturing module does not know whether to end at index 2 or index 3. It only knows

that un-puncturing must end before index 4, when another LLR input is required.

Without any more information, we must assume that having more LLRs than are actually

required is better than having less. Thus, the most appropriate stop condition to use when

performing un-puncturing is ending when the next pattern index requires an input LLR

and none remain.

Page 62: Simulating Turbo Codes using a Modular Simulation Platform

62 CHAPTER THREE

typedef struct unPunctureVarsStruct

int numOutputs;

int punctureLength;

int currIndex;

char** puncturePattern;

linkList* input;

linkList* output;

unPunctureVars;

Code 8. Un-puncturing module definition

The only main tasks that need to be performed when initialization the puncturing

and un-puncturing modules are assigning the puncturing patterns to the two-dimensional

array puncturePattern and allocating the correct number of input and output linked

lists.

3.3.5 Signal Mapper Design and Implementation

A signal mapper has the task of assigning information bits and parity bits from a Turbo

encoder to points in a signal set. This task can be performed in two steps. The first step

takes the correct number of information and parity bits from the module's inputs and

orders those bit according to a set arrangement. The second step takes the arranged bits

and finds the signal point with a matching label. This process is described in Section 2.7.

The only information needed to perform the first step is the bit arrangement order,

which is specified during module initialization. The simulation tool assumes that if bits

generated from different time indices are grouped together, bits that are generated earlier

will be placed before bits that are generated later. Since the input information and parity

linked lists are already ordered with respect to time, taking the bits sequentially from

those lists automatically satisfies the ordering assumed by the tool. The arrangement

Page 63: Simulating Turbo Codes using a Modular Simulation Platform

THE SIMULATION TOOL 63

order is stored in a one-dimensional array in which a 's' character specifies an

information bit and a 'p' character specifies a parity bit.

In step two, mapping the bit grouping from step one to a signal point is

straightforward and can be implemented using a lookup table. The lookup table consists

of an array of signal points and array of point labels, and the same indices in the two

arrays correspond to a point-label pair. The signal points and labels are generated during

module initialization. The simulation tool currently uses two-dimensional coordinates for

signal points, and new code must be written for other coordinate types. Further, the tool

has only implemented the square-QAM signal set, and normal and gray labeling. New

code needs to be written for other types of signal sets or labeling schemes.

The module definition is shown in code 9. The variable bitMapper holds the bit

arrangement order needed for step one, and the variable symbolMapper holds the signal

set and point labels needed for step two.

typedef struct twoDsignalMapVarsStructbitMapVars bitMapper;twoDsymbolMapVars symbolMapper;

linkList* inputU;linkList* inputS;linkList* inputP;linkList* output;

} twoDsignalMapVars;

Code 9. Signal mapper module definition

As shown in code 9, the signal mapper module is also designed to accommodate uncoded

bits. For the bit arrangement order stored in bitMapper, the character 'u' specifies an

uncoded bit. However, the simulation tool does not currently use uncoded bits.

Page 64: Simulating Turbo Codes using a Modular Simulation Platform

64 CHAPTER THREE

3.3.6 Channel and Demodulator Design and Implementation

The channel model used by the simulation tool is the AWGN channel, which is described

2by noise variance O-N . As described in Section 2.4, the noise variance can be calculated

using equation (8), which is shown again below for convenience.

N = E,2q E'No

Es, the average energy per symbol, is stored in the symbolMapper variable of the signal

mapper module defined in Section 3.3.5, and 7, the number of information bits per

symbol, is stored in the bitMapper variable of the same module. E INO is defined in

the main simulation program.

typedef struct channelVarsStructdouble n variance;

linkL ist* input;linkList* output;

} channelvars;

Code 10. Channel module definition

The simulation tool has only implemented the AWGN channel, and new code needs to be

written for other types of channels.

The task of the demodulator module is to calculate bit LLRs from observations at

the output of the channel module. This process is described in Section 2.7.2, and LLR

equations are given in (18) and (19). In calculating bit LLRs, the demodulator module

uses information from the signal mapper module and from the channel module. This

information is not stored in the demodulator module itself and is passed in to the module

function. Although the use of external information in performing the module function

Page 65: Simulating Turbo Codes using a Modular Simulation Platform

THE SIMULATION TOOL 65

violates module abstraction, making the information internal does not offer any added

benefits from a simulation perspective. Thus, the module was designed to use external

information, and its definition does not contain internal variables.

typedef struct demodulatorVarsStruct

linkList* input;linkList* outputS;linkList* outputP;

demodulatorvars;

Code 11. Demodulator module definition

Section 2.8.1 states that the decoding modules will always use bit LLRs to perform

decoding. Thus, the demodulator module will always output LLRs, and as the next

section will show, the MAP decoder module will always assume that its information and

parity input lists contain LLRs.

3.3.7 MAP Decoder Module Design and Implementation

The main tasks of the MAP decoder module are to produce the a posteriori probabilities

given in (9) and to generate extrinsic information for the iterative decoding process. The

MAP decoding algorithm is described in Section 2.6.3, and the extrinsic information is

shown in equations (25) and (27) in Section 2.8.2 and Section 2.8.3, respectively.

As shown in 2.6.3, producing the APPs requires calculating the a, fl, and y

parameters shown in equations (12), (13), and (14), respectively. Further, the y

parameter must be calculated first since the recursions in (12) and (13) depend on this

parameter. The parameters at (m) and ,(in) are state parameters and each is stored in a

two-dimensional array, with the first dimension in time t and the second in trellis state m.

Page 66: Simulating Turbo Codes using a Modular Simulation Platform

66 CHAPTER THREE

The gamma parameter y (R,,m',m) is stored in a three-dimensional array, with first

dimension in time t, second dimension in information bits u, = i, and third dimension in

parity bits p, = j. The value of y depends only on the values of i and j for the

information bits and parity bits, respectively. Because the trellis structure from the

convolutional encoder is such an integral part of MAP decoding, the decoder module

stores its own trellis description.

The array bitValue is used in calculating the probability in equation (21) and

holds the individual bits corresponding to u, = i. The module definition is shown below.

typedef struct MAPdecoderVarsStruct {int blockSize, numStates, numInputs;

double explimit;

double ***gamma;double **alpha;double **beta;

char **bitValue;branch **trellis;

linkList* inputS;linkList* inputP;

linkList* inputA;

linkList* outputDprob;

linkList* output-extrinsic;

MAPdecoderVars;

Code 12. MAP decoder module definition

3.4 Simulation Code Organization

The simulation tool is composed of a collection main program files, C header files, and C

source files. Each module has a header file, which contains struct definitions and

function declarations, and a source file, which contains function code. Module source

files primarily include three types of functions - initialization functions, execution

Page 67: Simulating Turbo Codes using a Modular Simulation Platform

THE SIMULATION TOOL 67

functions, and memory de-allocation functions. Each Turbo code structure is

implemented in a different main program file. Table 3.1 summarizes the different files.

Code for all files are included in Appendices A and C.

Page 68: Simulating Turbo Codes using a Modular Simulation Platform

68 CHAPTER THREE

File name Descriptionturbosim-std.c main simulation file for double parallel concatenated Turbo code from CF-037

turbosim-icoding.c main simulation file for triple parallel concatenated Turbo code from CF-072

turbosim-uncoded.c main simulation file for uncoded simulation

File name Module Ifunction(s) Module initialization functionsgeneral.hgeneral.c general functions

linkedlist.hlinkedlist.c linked list llistInitVars( )

source.h bit generator module /source.c genBits() selectBlockSize()

Random pattern - randomPatterninitVars( )interleave.h interleaver module / Semi-random pattern - SrandomInitVars( )interleave.c doInterleave( ) Get pattern from a file - interleaverFileInitVars()

convolutional encoderconv.h module / Rate-1/2 - rate] 2initVars()conv.c encodeBlock() Rate-k/(k+l) - ratekk]InitVars()

terminateEncoder() Copy an encoder - duplicateEncoder()

puncture module / 2-input puncturer - twoPuncturelnitVars()puncture.h punctureBlock( ) 3-input puncturer - threePunctureInitVars()puncture.c unpuncture module /

unpunctureBlock() Un-puncturer - unPunctureInitVars()

Bit map pattern - bitMapInitVars( )mapper.h signal mapper module / QAM signal set - QAMSignalSet()mapper.c mapBlock() Normal bit labels - normalMappingInitVars()

Gray code labels - createGrayCode()

channel.h channel module /channel.c sendAWGNblock() channellnitVars()

demodulator module /demod.h demodulateTwoDBlock() demodulatorInitVars()demod.c decodeuncoded()

MAP decoder module Idecoder.h doMAPdecoding() MAPdecoderInitVars()decoder.c doFastRl2MAPdecoding()

Table 3.1. Summary of simulation files

68 CHAPTER THREE

Page 69: Simulating Turbo Codes using a Modular Simulation Platform

CHAPTER FOUR

SIMULATION RESULTS

The files and modules shown in Table 3.1 form the entire simulation tool. The tool was

used to simulate the Turbo codes from CF-037 and CF-072, and results are compared to

those cited in these documents. Both simulation and cited results are shown in the

sections below.

Simulation results are gathered from running the tool on PCs with Microsoft

Visual C++ and on SUN workstations using the gcc compiler. As different compilers and

computers generate random numbers differently, the simulated results shown below may

not be reproducible in all environments. Even so, results should be similar and BER

curves should fall within the same order of magnitude.

All simulations used square-QAM signal sets with gray labels, which have been

shown to be ideal [8]. The coordinates of the QAM symbols are odd. The all zero label

- 69 -

Page 70: Simulating Turbo Codes using a Modular Simulation Platform

corresponds to the most negative coordinate. The 4-QAM and 16-QAM signals sets are

shown below in Figures 4-1 and 4-2.

01.

-1

. -1 -00

11.

--

10

10

Figure 4-1. 4-QAM signal set

00100

01100 3

0011 01110 0

-3

0001

0000

Figure 4-2.

-1

0101

00100

-1

-3

1110 10100 0

1111

1S

1101

1100

16-QAM signal set with gray labels

4.1 Results for Double Parallel Concatenated Turbo Code

The encoder structure for the Turbo code in CF-037 is that of Figure 2-9. Both of the

RSCC encoders have rate-1/2, and the generator polynomials

ao = 35 and b =23,. The encoders are implemented using the structure in Figure 2-2.

1011S

3

1001

01000

component are

i ' | 1

70 CHAPTER FOUR

I

Page 71: Simulating Turbo Codes using a Modular Simulation Platform

SIMULATION RESULTS 71

The simulations used the semi-random interleaver algorithm from [21], which is not same

interleaver specified by CF-037. Even so, it has been noted that interleavers of the same

length have approximately the same performance, so results should not differ much for

the two interleavers. The simulations only used square QAM signal sets. CF-037 is

based primarily on the initial proposal [15], which contains the majority of cited results.

4.1.1 Simulation 1: Rate-1/2 Turbo code

This simulation uses 1024 bits per block and generator polynomials ao = 35 and

b = 238. The signal set is square 4-QAM.

Information bit (u) u1 U2Parity bit (p) pParity bit (p2) P22

Bit mapping per symbol (bo , b1) = (u1 ,p (bo , b1 ) = (u2 , 2)

Table 4.1. Simulation I puncturing and mapping scheme

The values in Table 4.2 are approximations of graph points shown in [15].

Although the values are not exact, they are good guidelines of what the BERs should be.

IterationEWNo 1 2 3 4 8.

0.5 1.00E-01 1.00E-01 1.00E-01 1.00E-01 1.0E-011.0 8.OOE-02 5.OOE-02 2.50E-02 2.OOE-02 1.OOE-021.5 4.50E-02 8.OOE-03 1.00E-03 4.OOE-04 9.OOE-052.0 1.70E-02 2.50E-04 2.50E-06 8.OOE-07 1.1 OE-07

BER values fromTable 4.2. Approximate cited graphs for simulation I Turbo code

Page 72: Simulating Turbo Codes using a Modular Simulation Platform

72 CHAPTER FOUR

The data in Table 4.3 shows simulated BER values over the same range as Table

4.2. To produce more accurate BER values, ten times more blocks were simulated for the

BERs in the lower part of Table 4.3 than for the upper part. After 8 iterations at

E /No =2.00 [dB], there were only 1.95E-07 - 1024E+05 ~ 20 bit errors. In the

extreme case that these 20 bit errors all occurred during the first 10,000 blocks, the BER

would have been one magnitude higher. Thus, simulating a higher number of blocks for

large Eb / No allows the BER to decrease after an error occurs. In order to produce a

reliable value for a BER in the order of 10-x, a general rule is to simulate 10,+2 bits. Not

all values in Table 4.3 adhere to this rule, however.

IterationEd/No 1 2 3 4 80.50 1.16E-01 1.04E-01 9.86E-02 9.47E-02 8.82E-020.75 1.00E-0 I 7.87E-02 6.52E-02 5.64E-02 4.47E-021.00 8.24E-02 4.93E-02 3.03E-02 2.15E-02 1.30E-021.25 6.38E-02 2.32E-02 8.50E-03 4.46E-03 1.86E-031.50 4.58E-02 7.54E-03 1.37E-03 5.1OE-04 1.55E-04

1.75 2.95E-02 1.58E-03 1.06E-04 2.11 E-05 3.78E-062.00 1.71 E-02 2.22E-04 5.77E-06 1.21 E-06 1.95E-07

Table 4.3. Simulated BER values for simulation I after 10,000 and 100,000 blocks

Cited results in Figure 4-3 and all subsequent plots are marked by square boxes

and dotted lines, while simulated results are marked by crosses and solid lines. BER

curves for 1, 2, 3, 4, and 8 iterations are shown. Figure 4-3 shows that simulated results

match cited results relatively well.

Page 73: Simulating Turbo Codes using a Modular Simulation Platform

SIMULATION RESULTS 73

1.E+00 -

1.E-01 -

1.E-02 -

1.E-03 -

M1.E-04 -

1.E-05 -

1.E-06 -

1.E-07 -

0

___-_ _

- - - - -X

0.5 1 1.5

Eb/No

Figure 4-3. Simulation I BER curves for Table 4.2 and Table 4.3

4.1.2 Simulation 2: Rate-1/2 Turbo code

The ITU proposal in [20] suggests the use of a rate-1/2 convolutional encoder with

generator polynomials a~ =178 and b =58. This encoder is used in place of the one in

simulation 1 from Section 4.1.1. All other parameters from simulation 1 remain

unchanged.

Figure 4-4 shows that for the Turbo encoder structure from [15], using component

codes with polynomials a~ =35 and b =238 yields better BER performance than using

codes with polynomials ao = 178 and bo = 15.

2 2.5

SIMULATION RESULTS 73

Page 74: Simulating Turbo Codes using a Modular Simulation Platform

74 CHAPTER FOUR

IterationsEb/No 1 2 3 4 80.50 1.02E-01 8.59E-02 7.92E-02 7.54E-02 6.91E-010.75 8.77E-02 6.43E-02 5.21E-02 4.47E-02 3.36E-021.00 7.28E-02 4.23E-02 2.63E-02 1.80E-02 9.95E-031.25 5.78E-02 2.33E-02 9.28E-03 4.63E-03 I .59E-031.50 4.38E-02 1.02E-02 2.14E-03 6.76E-04 1.12E-04

1.75 3.14E-02 3.62E-03 3.49E-04 6.99E-05 7.26E-062.00 2.11E-02 9.83E-04 3.85E-05 4.78E-06 1.12E-06

Table 4.4. Simulated BER values for simulation 2 after 10,000 and 100,000 blocks

1.E+00

w

1.E-01

1.E-02

1.E-03

1.E-04

1.E-05

1.E-06

1.E-07

"

0

0

0.5 1 1.5 2 2.5

Eb/No

Figure 4-4. Simulation 2 BER curves for Table 4.2 and Table 4.4

74 CHAPTER FOUR

Page 75: Simulating Turbo Codes using a Modular Simulation Platform

SIMULATION RESULTS 75

4.1.3 Simulation 3: Rate-2/4 Turbo code

This simulation uses 1024 bits per block and generator polynomials a =35 and

b = 238. The signal set is square 16-QAM.

Information bit (u) u1 U2Parity bit (pI) pParity bit (p2) P2

Bit mapping per symbol (bo, b, , b2 , b3) = (up , p , u2 , p 2)

Table 4.5. Simulation 3 puncturing and mapping scheme

IterationsEg/NO 1 2 3 4 8

2.0 9.00E-02 9.00E-02 9.OOE-02 9.OOE-02 9.OOE-022.5 8.OOE-02 7.OOE-02 6.OOE-02 5.50E-02 5.00E-023.0 6.50E-02 3.00E-02 2.50E-02 2.20E-02 1.1OE-023.5 4.00E-02 9.00E-03 2.00E-03 9.00E-04 3.00E-044.0 2.00E-02 8.00E-04 5.OOE-05 2.00E-05 2.00E-064.5 6.00E-03 3.OOE-05 6.00E-07 3.OOE-07 9.00E-085.0 1.00E-03 1.00E-06 5.OOE-08 5.OOE-08 2.00E-08

Table 4.6. Approximate BER values from cited graphs for simulation 3 Turbo code

IterationsEdNo 1 2 3 4 8

2.0 9.34E-02 8.96E-02 8.89E-02 8.88E-02 8.86E-022.5 7.49E-02 6.38E-02 5.93E-02 5.67E-02 5.31E-023.0 5.34E-02 3.1OE-02 2.01E-02 1.51E-02 1.00E-023.5 3.16E-02 6.84E-03 1.77E-03 7.55E-04 2.63E-044.0 1.41E-02 5.23E-04 3.OOE-05 7.52E-06 2.25E-06

4.5 4.56E-03 2.04E-05 8.40E-07 6.05E-07 2.73E-075.0 1.07E-03 9.77E-07 1.27E-07 7.81E-08 4.88E-08

Table 4.7. Simulated BER values for simulation 3 after 10,000 and 100,000 blocks

Page 76: Simulating Turbo Codes using a Modular Simulation Platform

76 CHAPTER FOUR

w

1.E+00

1.E-01

1.E-02

1.E-03

1.E-04

1.E-05

1.E-06

1.E-07

1.E-08

1.5 2 2.5 3 3.5 4 4.5 5 5.5

Eb/No

Figure 4-5. Simulation 3 BER curves for Table 4.6 and Table 4.7

Figure 4-5 shows that for BER above 1.E-07, simulated results match cited results

relatively closely. For lower BERs, the tool may not have simulated enough blocks, and

results do not match as well.

4.1.4 Simulation 4: Rate-2/4 Turbo code

This simulation uses a block size of 4096 bits with the Turbo code parameters of

simulation 3. The interleaver depth increases to 4096, which should improve the

performance of the Turbo code. The lack of a BER value for Eb /No = 3.5 [dB]

indicates that not enough blocks were simulated to generate error.

76 CHAPTER FOUR

Page 77: Simulating Turbo Codes using a Modular Simulation Platform

SIMULATION RESULTS

IterationsEb/No 1 2 3 4 8

2.5 7.60E-02 6.56E-02 6.18E-02 6.01E-02 5.69E-023.0 5.45E-02 3.08E-02 8.52E-03 8.52E-03 1.50E-033.5 3.20E-02 4.85E-03 1.07E-05 1.07E-05

4.0 1.41E-02 1.59E-04 5.18E-07 5.86E-08 1.95E-08

Table 4.8. Simulated BER values for simulation 4 after 2,500 and 25,000 blocks

1.E+00

1.E-01

1.E-02

1.E-03

u1.E-04In

1.E-05

1.E-06

1.E-07

1.E-08

2 2.5 3 3.5 4 4.5

Eb/No

Figure 4-6. Simulation 4 BER curves for Table 4.6 and Table 4.8

Figure 4-6 shows that, as expected, using a longer interleaver improves the performance

of the Turbo code.

77

Page 78: Simulating Turbo Codes using a Modular Simulation Platform

78 CHAPTER FOUR

4.1.5 Simulation 5: Rate-2/4 Turbo code

This simulation uses generator polynomials ao = 17, and b =15, with the Turbo code

parameters of simulation 3. The block size is 1024 bits.

IterationsE/No 1 2 3 4 8

2.0 8.62E-02 8.05E-02 7.96E-02 7.94E-02 7.93E-022.5 6.84E-02 5.68E-02 5.30E-02 5.13E-02 4.93E-023.0 4.95E-02 3.02E-02 2.18E-02 1.75E-02 1.29E-023.5 3.15E-02 9.84E-03 3.66E-03 1.88E-03 8.24E-044.0 1.68E-02 1.68E-03 2.26E-04 8.01E-05 1.91E-05

4.5 7.42E-03 1.66E-04 1.08E-05 5.00E-06 1.78E-065.0 2.56E-03 1.14E-05 6.48E-07 3.91E-07 1.95E-07

Table 4.9. Simulated BER values for simulation 5 after 10,000 and 100,000 blocks

As with simulation 2, Figure 4-7 shows again that for the Turbo encoder structure

from [15], using component codes with polynomials ao = 35 and bo =23 yields better

BER performance than using codes with polynomials ao = 17, and bo = 158.

Page 79: Simulating Turbo Codes using a Modular Simulation Platform

SIMULATION RESULTS

1.E+00

1.E-01

1. E-02

1. E-03

w 1.E-04

1.E-05

1.E-06

1.E-07

1. E-08

1

1.5 2 2.5 3 3.5 4 4.5 5 5.5

Eb/No

Figure 4-7. Simulation 5 BER curves for Table 4.6 and Table 4.9

i i -- i

xI -

79

N-

%P I % Ne %

Page 80: Simulating Turbo Codes using a Modular Simulation Platform

80 CHAPTER FOUR

4.1.6 Simulation 6: Rate-3/4 Turbo code

This simulation uses 6144 bits per block and generator polynomials a =35, and

bo = 23,. The signal set is square 16-QAM.

Information bit (u) u1 u2 u3 u4 U5 U6Parity bit (p') - P2 - -

Parity bit (p2) _ _ p25Bit mapping (bo ,b1 ,b2 ,b3) = (uI, u2 , u3 p 1p2) (bo ,b1 ,b2 ,b3) = (u4 , u5 , u6 , p 5)

Table 4.10. Simulation 6 puncturing and mapping scheme

IterationsEdNo 1 2 3 4 8

4.5 6.00E-02 6.00E-02 6.00E-02 6.OOE-02 6.OOE-025.0 4.00E-02 3.50E-02 2.50E-02 2.00E-02 1.50E-025.5 2.50E-02 7.OOE-03 9.OOE-04 1.1 OE-04 1.1 0E-076.0 9.OOE-03 2.00E-04 9.OOE-07 9.50E-08 -

Table 4.11. Approximate BER values from cited graphs for simulation 6 Turbo code

IterationsEWNo 1 2 3 4 84.50 5.49E-02 5.23E-02 5.19E-02 5.18E-02 5.18E-024.75 4.74E-02 4.24E-02 4.07E-02 3.98E-02 3.82E-025.00 3.94E-02 3.03E-02 2.49E-02 2.05E-02 1.19E-025.25 3.09E-02 1.70E-03 8.07E-03 3.34E-03 5.64E-045.50 2.25E-02 6.34E-03 8.46E-04 1.08E-04 3.9 1E-07

5.75 1.52E-02 1.45E-03 3.38E-05 8.40E-07 -

6.00 9.08E-03 1.89E-04 8.40E-07 1.56E-07 -

Table 4.12. Simulated BER values for simulation 6 after 1,666 AND 16,666 blocks

Page 81: Simulating Turbo Codes using a Modular Simulation Platform

SIMULATION RESULTS 81

1.E+00

1.E-01

1.E-02

1.E-03

1.E-04

1.E-05

1.E-06

1.E-07

1.E-08

4 4.5 5 5.5 6 6.5Eb/No

Figure 4-8. Simulation 6 BER curves for Table 4.11 and Table 4.12

Aside from the lower BERs, Figure 4-8 shows that simulated results match cited results

relatively well.

4.1.7 Simulation 7: Rate-3/4 Turbo code

This simulation uses 6144 bits per block and rate-3/4

polynomials ao =118, a0 =158, a =178, and bg =138.

specified in [18] and is one of the encoders in Figure 3-3.

QAM.

convolutional encoders with

The rate-3/4 code is the one

The signal set is square 16-

M 01-

Page 82: Simulating Turbo Codes using a Modular Simulation Platform

82 CHAPTER FOUR

Information bits (u) u1, u2 , u3 U4 , U5, U6

Parity bit (p1) p 1Parity bit (p2 ) P2Bit mapping (bo ,b1 ,b2 ,b3) = (u I, , u) Ip1 1) (bo ,b1 ,b2 ,b3 ) = (u4 , u5 , u6 , p 2)

Table 4.13. Simulation 7 puncturing and mapping scheme

IterationsEb/No 1 2 3 4 8

4.5 5.42E-02 5.07E-02 4.99E-02 4.96E-02 4.94E-025.0 3.84E-02 2.81E-02 2.16E-02 1.68E-02 8.15E-035.5 2.19E-02 6.31E-03 1.14E-03 2.79E-04 3.91E-036.0 9.12E-03 4.08E-04 7.70E-05 1.22E-04 9.89E-04

Simulated BER values for simulation 7 after 1,666 AND 16,666 blocks

The results in Table 4.14 are

puncturing pattern in 4.13, much fewer

Table 4.10. Intuitively, having more

improve the performance of the Turbo c

4.14 shows, performance is actually

monotonically decrease with increasing i

puzzling. Using a rate-3/4 encoder and the

parity bits are punctured than in the scheme in

parity bits, and thus more information, should

ode relative to simulation 6. However, as Table

much worse. Further, the BER does not

terations, which is odd.

Table 4.14.

Page 83: Simulating Turbo Codes using a Modular Simulation Platform

SIMULATION RESULTS 83

4.1.8 Simulation 8: Rate-3/6 Turbo code

This simulation uses 6144 bits per block and generator polynomials a = 35 and

b = 23,. The signal set is square 64-QAM.

Information bit (u) u1 u 2 u3 u4 u5 U6Parity bit (p) p1 -p P5 -5Parity bit (p2) P 22 - P2 P 26Bit mapping (bo ,b1 ,b2 ,b3, b4, b5 ) = (bo ,b1 ,b2 ,b3, b4 , b5 ) =

(u], u 2 , p i, u3 , P22, p 3) (u4, u5 , p 24, u6 , p 5, P26)

Table 4.15. Simulation 8 puncturing and mapping scheme

IterationsEdNo 1 2 3 4 8

5.0 6.OOE-02 6.OOE-02 6.OOE-02 6.OOE-02 6.OOE-025.5 4.OOE-02 2.1OE-02 1.00E-02 5.50E-03 5.50E-046.0 2.1OE-02 3.OOE-03 1.1OE-04 2.OOE-06 3.OOE-076.5 1.00E-02 1.00E-04 6.OOE-07 -

Table 4.16. Approximate BER values from cited graphs for simulation 8 Turbo code

IterationsEWNo 1 2 3 4 85.00 6.51E-02 6.48E-02 5.08E-02 4.86E-02 4.46E-025.25 5.65E-02 4.09E-02 3.19E-02 2.52E-02 1.13E-025.50 4.75E-02 2.60E-02 1.27E-02 5.13E-03 3.59E-025.75 3.83E-02 1.30E-02 2.30E-03 2.75E-046.00 2.94E-02 4.70E-03 1.85E-04 1.27E-066.25 2.13E-02 1.18E-03 7.03E-06 -

6.50 1.44E-02 2.OOE-04 1.95E-07 -

Table 4.17. Simulated BER values for simulation 8 after 1,666 blocks

Page 84: Simulating Turbo Codes using a Modular Simulation Platform

1.E+00 _-_---

1.E-01 -_-

1.E-02 -_ - - --_-

1.E-03 -

1.E-04

1.E-05 -

1 .E-06

1.E-074.75 5 5.25 5.5 5.75 6 6.25 6.5 6.75

Eb/No

Figure 4-9. Simulation 8 BER curves for Table 4.16 and Table 4.17

Figure 4-9 shows that cited results and simulated results match relatively well.

84 CHAPTER FOUR

Page 85: Simulating Turbo Codes using a Modular Simulation Platform

SIMULATION RESULTS 85

4.1.9 Simulation 9: Rate-4/6 Turbo code

This simulation uses 4096 bits per block and generator polynomials ao = 35 and

bo = 238. The signal set is square 64-QAM.

Information bit (u) u1 u2 u3 U4Parity bit (p) p_Parity bit (p2Bit mapping (bo ,b ,b2 ,b3, b4, b5 ) = (ul, u2 , p 1, u3 , u4 , p 3)

Table 4.18. Simulation 9 puncturing and mapping scheme

IterationsEb/No 1 2 3 4 86.75 7.00E-02 6.00E-02 6.00E-02 5.00E-02 4.00E-027.00 6.00E-02 5.00E-02 4.00E-02 4.00E-02 3.00E-027.25 5.OOE-02 3.50E-02 2.20E-02 2.00E-02 1.70E-027.50 4.00E-02 2.70E-02 9.OOE-03 5.00E-03 1.70E-037.75 3.00E-02 1.00E-02 2.00E-03 5.00E-04 5.0E-058.00 2.GOE-02 3.O0E-03 3.OE-04 4.OOE-05 2.00E-068.25 1.00E-02 8.50E-04 2.50E-05 1.1 OE-06 2.GOE-07

Table 4.19. Approximate BER values from cited graphs for simulation 9 Turbo code

IterationsEb/No 1 2 3 4 86.75 5.08E-02 4.61E-02 4.50E-02 4.46E-02 4.43E-027.25 4.46E-02 3.73E-02 3.45E-02 3.29E-02 3.0IE-027.75 3.81E-02 2.72E-02 2.15E-02 1.75E-02 1.11E-028.00 3.13E-02 1.69E-02 8.90E-03 4.70E-03 1.19E-037.75 2.45E-02 8.26E-03 2.04E-03 4.77E-04 1.60E-058.00 1.83E-02 2.97E-03 2.43E-04 2.50E-05 2.34E-068.25 1.27E-02 7.55E-04 2.0GE-05 1.89E-06 5.86E-07

Table 4.20. Simulated BER values for simulation 9 after 2,500 blocks

Page 86: Simulating Turbo Codes using a Modular Simulation Platform

86 CHAPTER FOUR

wUIn

1.E+00

1.E-01

1.E-02

1.E-03

1.E-04

1.E-05

1.E-06

1.E-07

6.5 6.75 7 7.25 7.5 7.75 8 8.25 8.5

Eb/No

Figure 4-10. Simulation 9 BER curves for Table 4.19 and Table 4.20

Figure 4-10 shows that simulated results and cited results match relatively well.

L+j

86 CHAPTER FOUR

Page 87: Simulating Turbo Codes using a Modular Simulation Platform

SIMULATION RESULTS 87

4.1.10 Simulation 10: Rate-4/6 Turbo code

This simulation uses 4096 bits per block and a rate-2/3 convolutional encoder with

polynomials a = 35, a," =278, and be = 238. The rate-2/3 code is the one specified in

[18] and is one of the encoder in Figure 3-3. The signal set is square 64-QAM.

Information bit (u) u1, u2 u3 , u4

Parity bit (p') pI1Parity bit (p2) P 2 2Bit mapping (bo ,bI ,b2 ,b3, b4, b5 ) = (uI, u2 , P 1, u3 , u4 , p22)

Table 4.21. Simulation 10 puncturing and mapping scheme

IterationsEdNo 1 2 3 4 86.75 5.17E-02 4.76E-02 4.66E-02 4.63E-02 4.60E-027.25 3.89E-02 2.79E-02 2.14E-02 1.69E-02 9.90E-037.75 2.48E-02 7.35E-03 1.40E-03 2.77E-04 9.67E-068.00 1.82E-02 2.34E-03 1.19E-04 8.33E-06 2.64E-078.25 1.21E-02 4.37E-04 3.32E-06 1.95E-07 1.95E-07

Table 4.22. Simulated BER values for simulation 10 after 2,500 and 25,000 blocks

Page 88: Simulating Turbo Codes using a Modular Simulation Platform

88 CHAPTER FOUR

1. E+00

1.E-01 -

1.E-02 -

1

ccLuM0

1.E-04

1.E-05

1. E-06

1.E-07

E-03 -

_______ 71f§_______

2I~<~I7T~

-Xi X~ '. 1 XK7~kL

-~ -- I -- V - r - i-

6.5 6.75 7 7.25 7.5 7.75 8 8.25 8.5

Eb/No

Figure 4-11. Simulation 10 BER curves for Table 4.19 and Table 4.22

The rate-2/3 convolutional code allows more parity bits to be retained than the scheme in

simulation 9, while maintaining an overall code rate of 4/6. Figure 4-11 shows that, as

expected, puncturing fewer parity bits results in better performance. This result matches

what is intuitively correct.

88

\ xi i r

CHAPTER FOUR

Page 89: Simulating Turbo Codes using a Modular Simulation Platform

SIMULATION RESULTS 89

4.2 Results for Triple Parallel Concatenated Turbo Code

The encoder structure for the Turbo code in CF-072 is that of Figure 3-2. All

three component RSCC encoders have rate-1/2 and generator polynomials ao =7 and

b0 =5 The encoders are implemented using the structure in Figure 2-2. The

simulations used the semi-random interleaver algorithm from [21], which is equivalent to

the generatable interleaver used in CF-072 [17]. The simulations only use square QAM

signal sets.

4.2.1 Simulation 11: Rate-1/2 Turbo code

This simulation uses 15844 bits per block and square 4-QAM. Cited results for this

simulation indicate that a BER on the order of 10 -7 is achievable at Eb INO =1.6 [dB]

with four decoder iterations.

Information bit (u) u1 u2 U3Parity bit (p1) p1_Parity bit (p) 2

Parity bit (p ) -2 p 33Bit mapping (bo , b1 ) = (ui ,p 1) (bo , b1 ) = (u 2 p2) (bo , bi) = (u3, p 3)

Table 4.23. Simulation 11 puncturing and mapping scheme

Page 90: Simulating Turbo Codes using a Modular Simulation Platform

IterationEb/No 1 2 3 4

0.5 1.20E-01 1.19E-01 1.19E-01 1.19E-011.0 9.62E-02 9.35E-02 9.34E-02 9.34E-021.5 7.12E-02 6.49E-02 6.40E-02 6.39E-022.0 4.64E-02 3.51E-02 3.20E-02 3.09E-022.5 2.54E-02 1.23E-02 8.37E-03 6.70E-033.0 1.1 3E-02 2.60E-03 1.03E-03 5.76E-043.5 4.OOE-03 3.69E-04 7.51E-05 2.39E-054.0 1.17E-03 3.22E-05 2.72E-06 1.36E-06

Table 4.24. Simulated BER values for simulation 11 after 650 blocks

As the tables above show, simulated results do not achieve a BER of 10-7 at E, /No = 1.6

[dB]. In fact, simulated results for this Turbo code are much worse than what is cited.

1.E+00

M

1.E-01

1.E-02

1.E-03

1.E-04

1.E-05

1.E-060 1 2 3 4 5

Eb/No

Figure 4-12. Simulation 11 BER curves for Table 4.24

X---- ifX.

90 CHAPTER FOUR

Page 91: Simulating Turbo Codes using a Modular Simulation Platform

SIMULATION RESULTS 91

4.2.2 Simulation 12: Rate-1/2 Turbo code

In this simulation, the rate-1/2 convolutional encoder with generator polynomials ao = 7

and b = 5 is used in place of the one in simulation I from Section 4.1.1. The results of

this simulation will provide insight into the performance of the CF-072 component code

relative to the CF-037 component code. The block size is 6144 bits per block, and the

signal set is 4-QAM.

IterationsEJNo 1 2 3 4 8

0.5 1.02E-01 8.59E-02 7.92E-02 7.54E-02 6.91E-011.0 8.77E-02 6.43E-02 5.21E-02 4.47E-02 3.36E-021.5 7.28E-02 4.23E-02 2.63E-02 1.80E-02 9.95E-032.0 5.78E-02 2.33E-02 9.28E-03 4.63E-03 1.59E-032.5 4.38E-02 1.02E-02 2.14E-03 6.76E-04 1.12E-043.0 3.14E-02 3.62E-03 3.49E-04 6.99E-05 7.26E-063.5 2.11 E-02 9.83E-04 3.85E-05 4.78E-06 1.12E-06

Table 4.25. Simulated BER values for simulation 12 after 1,666 blocks

Page 92: Simulating Turbo Codes using a Modular Simulation Platform

92 CHAPTER FOUR

1.E+00

1.E-01 -

2 2.5 3 3.5 41.5

Figure 4-13. Simulation 12

Eb/No

BER curves for Table 4.25

Figure 4-13 shows that the code with polynomials ao = 7 and bo = 5 performs much

worse than simulation 1, even with a much longer interleaver length. Further, the curves

do not exhibit sharply decreasing BERs. Thus, it is not surprising that simulation 11 did

not perform as well as simulation 1, even though cited results indicate it should.

4.3 Summary of Results

Simulations 1, 3, 6, 8, and 9, used the Turbo encoder structure from Figure 2-9 and the

exact parameters described in [15]. These simulation results matched cited results

relatively well. Simulations 2, 4, 5, 7, 10, used the same Turbo encoder structure but

different parameters. Of these five simulations, all but simulation 4 tested the

1%W-

cc 1.E-02 -

1.E-03

1.E-04

0 0.5 1

- Jfk V _________

1~

________ -7__________________ ______________ ________ ~1~~______________ ______________ - _____________ I _________ ___

______ ______ ______ -----H-

I. I

4.5

92 CHAPTER FOUR

Page 93: Simulating Turbo Codes using a Modular Simulation Platform

SIMULATION RESULTS 93

performance of different component codes and corresponding puncturing patterns. These

results are summarized below in Table 4.26.

simulation structure details simulated results1 Fig. 2-9 rate-1/2 turbo code matcbed-BA-020RI results2 Fig. 2-9 used RN-027 RSCC and RN-027 RSCC performed

compared to simulation I worse than BA-020R13 Fig. 2-9 rate-2/4 turbo code matched BA-020R1 results4 Fig. 2-9 used longer interleaver and longer interleaver improved

compared to simulation 3 BER performance5 Fig. 2-9 used RN-027 RSCC and RN-027 RSCC performed

compared to simulation 3 worse than BA-02OR1I6 Fig. 2-9 rate-3/4 turbo code matched BA-020R1 results7 Fig. 2-9 used rate-3/4 RSCC and results do not match

compared to simulation 6 expectations and are odd8 Fig. 2-9 rate-3/6 turbo code matched BA-020R1 results9 Fig. 2-9 rate-4/6 turbo code matched BA-020R1 results10 Fig. 2-9 used rate-2/3 RSCC and less puncturing improved

compared to simulation 9 BER performance11 Fig. 3-2 compared to CF-072 results did not match citedrtesuls12 Fig. 2-9 used CF-072 RSCC and CF-072 RSCC performed

Scompared to simulation I worse than BA-020R1

Table 4.26. Summary of simulation results

Page 94: Simulating Turbo Codes using a Modular Simulation Platform
Page 95: Simulating Turbo Codes using a Modular Simulation Platform

CHAPTER FIVE

DISCUSSION

The simulation tool was used to evaluate two Turbo code structures: the encoders in

Figure 2-9 and Figure 3-2. Simulation results for those structures were compared to cited

results in [15] and [17], respectively, and only the results in [15] were reproduced. The

other ITU Turbo code proposals listed in section 3.1 were not detailed enough to

simulate. Even so, the twelve simulations shown in Chapter 4 are amply sufficient to

determine the reliability of the simulation tool. The following sections will discuss the

reliability of the simulation tool and will also analyze its performance in terms of

resource consumption.

5.1 Reliability of Simulation Tool

The main purpose of the simulation tool is to measure the performance of different Turbo

codes. The only way to simulate the true performance of a Turbo code using block size N

- 95 -

Page 96: Simulating Turbo Codes using a Modular Simulation Platform

96 CHAPTER FIVE

is to send all 2 N possible blocks through the code. However, any practical value of N

would be too large to allow the simulation to finish. Thus, to simulate a BER of 10', a

general rule is to send ceil(lO x+2 IN) blocks through the code. A BER produced using

this rule can be considered a good estimate of the performance of the Turbo code.

Simulations 1, 3, 6, 8, and 9, used exact Turbo code parameters from [15] and

produced results that match cited performance curves relatively well. The cited results

were taken from [15], and it was fortunate that the proposal was described in sufficient

detail for simulation. The fact that these simulations were able to match cited results

indicates that Turbo code encoding and decoding algorithms were implemented correctly

in the tool. Simulations 4 and 10 provide further confidence that the tool is able to

produce correct results. The parameter changes in both simulations were meant to

improve BER performance over simulations 3 and 9, respectively, and results indicate

that they did. Thus, the tool was also able to produce uncited results that match intuitive

trends.

5.2 Unexpected Simulation Results

Simulations 7 and 11 produced unexpected results. Simulation 7 used a component

RSCC that had a higher rate than simulation 6, allowing for fewer parity bits to be

punctured. Although the simulation 7 RSCC is different from the simulation 6 RSCC, we

can still reasonably expect this change to improve BER performance over simulation 6.

As results show, not only was performance in simulation 7 worse than in simulation 6,

but the BER also increased at higher iterations. The BER increase at higher iterations is

unlikely a result of overflow errors because program code exists to limit the values of

Page 97: Simulating Turbo Codes using a Modular Simulation Platform

DISCUSSION 97

MAP decoding parameters. It is possible that some property of the RSCC used in

simulation 7 caused extrinsic information to behave in a manner that diverges towards

greater errors. In contrast, a higher rate RSCC was used in simulation 10 to improve

BER performance over simulation 9, and the results produced in that trial did not exhibit

the abnormalities seen in simulation 7. Simulation 10 suggests that simulation tool

algorithms are indeed correctly implemented.

Simulation II results performed worse than cited results by more than 2 dB.

Simulation 12 used the same component RSCCs as in simulation 11, but on the Figure 2-

9 Turbo code structure. Results indicate that the RSCC used in simulation II yields

performance that is much worse than either of the RSCCs used in simulations I or 2.

Thus, the results generated by simulation 11 are not completely surprising. CF-072 [17]

did not provide complete details on all Turbo code parameters, and it is possible that

simulation I I was incorrectly configured.

5.3 Simulation Speed and Memory Usage

The simulation tool used double precision floating point variables to hold all real values.

Each double variable is 8 bytes. Table 5.1 below shows the approximate memory usage

for each type of module. The variable blockSize refers to the number of information bits

per block. When possible, variables from a module definition are used in the memory

usage equation.

Page 98: Simulating Turbo Codes using a Modular Simulation Platform

98 CHAPTER FIVE

Module / Memory usage (bytes)data structure

one linked list LL( # of elements, valueLength)=16 + (# of elements) - ( 8 + 17 valueLength)

bit source For a rate-k/(k+1) RSCC: LL( (blockSize 1k), k)

interleaver 4 - ( (blockSize/k) + 2 ) + LL((blockSize/k), k)

convolutional Rate-k/(k+r) code, 2" statesencoder 16 + 5 -2v + 2 v+k+4 + LL(blockSize, r)

puncturer 12 + numInputs - (punctureLength + 4) + LL( # of elements, 1)

symbol mapper 40 + (M + 2) -(log 2M) + 8 -M + LL(# of symbols, 1)

channel 12 + LL(# of symbols, 1)

demodulator 2 -LL(blockSize, 1)

unpuncturer 16 + numOutputs - punctureLength + LL( # of elements, 1)numOutputs

MAP decoder 32 + k -2k + 8 - blockSize -2 k*v + 2 -LL(blockSize, 2 k)

main program 120 + (# of iterations) - LL(blockSize, 1)

Table 5.1. Simulation tool memory usage

Table 5.2 below shows the approximate simulation speed when using a rate-1/2

16-state RSCC, 1024 bits per block, and 8 decoder iterations.

System blocks / minDell Optiplex GX150, P111-1GHz, 512K memory 204Dell Optiplex GX100, PIII-800MHz, 256K memory 143SUN Sunblade 100 workstation 74SUN Ultra 5 workstation 60

Table 5.2. Simulation tool speed

Page 99: Simulating Turbo Codes using a Modular Simulation Platform

CHAPTER SIX

CONCLUSION

In conclusion, simulation results indicate that the modular simulation tool described in

this thesis can be used with confidence to approximate the performance of Turbo codes

proposed for ADSL. The simulation tool modules are designed to accommodate a wide

range of parameters and should not need to be modified to simulate different Turbo

codes. However, it is likely that new initialization routines need to be written to correctly

configure modules for new Turbo code structures.

The computational power available in current computing systems allows the tool

to simulate BERs on the order of 10-7 in a reasonable amount of time. This BER is

sufficient for ADSL applications. Using the tool to simulate a BER on the order of 10-8

or smaller will require a much longer amount of time.

The main accomplishment of this thesis is the design of a flexible, modular

framework for simulating Turbo codes. The initialization and execution functions listed

-99 -

Page 100: Simulating Turbo Codes using a Modular Simulation Platform

100 CHAPTER SIX

in Table 3.1 and shown in Appendix C were written to work within this framework.

They comprise only a small portion of possible Turbo code parameters. Barbelescu

describes a "simile" interleave [13] that terminates both component RSCC encoders,

which should improve the performance of the MAP decoder as compared to when one

encoder is left unterminated. The use of non-square-QAM constellations is discussed in

[8] and [16]. Le Goff shows in [8] that certain non-square-QAM constellations yield

better performance. A feature that has not been implemented is the Turbo Trellis-coded

modulation (TTCM) described in [12]. Various contributions have actually proposed

TTCM [18] [19] [20], although details in these proposals are vague. While the parameter

options and systems mentioned above are currently unavailable in the simulation tool,

they are supported by the comprehensive module definitions shown in Chapter 3. The

careful design described in Chapter 3 allows these new features to be implemented

without needing to alter module definitions.

Lastly, although the intent of this thesis is not to compare Turbo codes, simulation

results do indicate that of the different rate-1/2 RSCCs recommended in [14], [1.7], and

[20], the code from [14] with polynomials ao = 35, and b = 238 yields the best

performance.

Page 101: Simulating Turbo Codes using a Modular Simulation Platform

APPENDIX A

Main Simulation Code

turbo sim-std.c

file: turbo_sim-std.c

This is the main program file that simulates turbo codes.

#include#include#include#include#include#include#include#include#include

"linkedlist.h""source.h""interleave.h"

"conv.h""puncture.h"

"mapper.h""channel.h""demod.h""decoder.h"

#include <math.h>#include <time.h>#include <stdio.h>#include <string.h>#include <stdlib.h>

int main(int argc, char* argv[})

== DECLARE GENERAL VARIABLES

/* general simulation variables */FILE* fp;

int sourceSeed;char filename[80];double EbOverNo, start, finish, delta;int blockSize;long num blocks;int iter;long total-bits;long* total-errors;int terminateBits;

int untermBits;

int numSymbols;

char *patl, *pat2;char *bitmap;

/* misc variables */timet starttime, curr time;float tl, t2, t3;int hrs, mins, secs;int i;int k;int selection;long block;long blocks-left, blocks-done;char error;double

/* charcharchar

temp;tempname[80]; */terminated;notTerminated;

file to write results */seed for random # gen */store file name */Eb/No simulation range */# of bits per block */# of blocks per Eb/No */

/* # of decoder iterationstotal bits per Eb/No */total decode errors per Eb/No */

# of bits to terminate trellis */blockSize - terminateBits */

# of symbols sent thru channel *//* puncture pattern *//* symbol bit mapping */

keeps track of time */scanf variables */printf: time variables */for loop index */selection variables */scanf: code structure */

for loop index */keeps track of progress */error indicator */temporary variable */

== DECLARE SIMULATION MODULES

101 -

/*

Page 102: Simulating Turbo Codes using a Modular Simulation Platform

MAIN SIMULATION CODE

simulation modules */

* bit linked listslinkListlinkListlinkList*

* ENCODER modulesinterleaverVarsencoderVarsencoderVarspunctureVarstwoDsignalMapVars

*/origBitsLL;uncodedBitsLL;decodedBitsLL;

*/interleaverl;encoderl;encoder2;puncturer;mapper;

/* channel, soft-data modules */channelVars channel;demodulatorvars demodulator;unPunctureVars unpuncturer;

/* systematic buffer/* uncoded bits buffer/* decoded bits buffer

/* interleaver/* encoder 1/* encoder 2/* puncturer/* signal mapper

/* AWGN channel/* demodulator/* unpuncture LLR values

DECODER modulesMAPdecoderVarsMAPdecoderVarsinterleaverVarsinterleaverVarsinterleaverVarsinterleaverVars

MAPl;MAP2;extrinsicinterleaver;extrinsic deinterleaver;Sinterleaver;Dprobdeinterleaver;

MAP decoder 1 */MAP decoder 2 */extrins info interleaver */extrin. info deinterleaver */systematic bits interleaver*/a posteriori prob deinterleaver */

-= INIT GENERAL VARIABLES ==

- 1;= 0;= 171;

= 0;

== INITIALIZE SIMULATION MODULES -=

\n

printf("=printf("= TURBO-CODE SIMULATI

printf("printf("\n");printf("\n");printf(",--------------------------------------printf("\n");printf(" I

printf("I .---------- >------------->-

printf(" Iprintf("I information bits -- > encoderl

printf(" Iprintf('I interleaverl --> encoder2 --.printf(" Iprintf("I punctureprintf(" \n");

printf('----------------------------------------printf("\n");

/* output file name */printf(",--------------------------------------printf("I Enter output file name\n");printf("I >> ");

scanf("%s", filename);printf('--------------------------------------fp = fopen(filename, "a");if (fp == NULL)

printf("\n\nError opening file %s, programelse

fclose(fp);

ON ====\n")

------------------ \n");

s \n");>i \n");

g m \n");n a \n");

a p \n');

|1 p \n");|e \n") ;

r \n');

------------------ \n");

------------------ \n");

------------------ \n");

terminating\n", filename);

/* choices for modules: encoderl, encoder2, puncturer, mapper */

printf("\n\n");printf(",---------------printf("\n");printf(" Iprintf("ll conv codeprintf("' ---------printf(" 1 rate-1/2printf(" Iprintf("I \n");

printf("j 2 rate-1/2printf(" Iprintf("I \n");printf("I 3 rate-1/2printf(" Iprintf("I \n");printf("I 4 rate-3/4

--------------------------------------\n");

parity symbol overall \n");puncture bit map code rate\n");

------------ ---------- --------- \n');10 sp rate-1/2\n");01\n")

1001\n")

010000000010\n");

10

spsp rate-2/4\n");

sssp rate-3/4\n");

sssp rate-3/4\n");

102

terminated

notTerminatedsourceSeedblocks done

Page 103: Simulating Turbo Codes using a Modular Simulation Platform

printf("I 01\n")printf("I \n");printf("I 0 see more selections...\n");printf("I \n");

printf("j---------------------------------------printf("1 Enter selection\n");

/* check for erroneous input */error = 1;while (error)

printf("I >> ");scanf("%d", &selection);if ((selection >= 0) && (selection <= 4)

error = 0;else

printf(" ** invalid selection **\n");

printf("-----if (selection == 0)

printf("\n\n");

printf(",------printf(" Iprintf(" J cprintf("I -printf("|I 5 rprintf("|printf("I \n")

printf(" [ 6 r

printf("|printf("I \n")printf("| 7 rprintf(" Iprintf("I \n")

printf("I 8 r

printf("|printf("| \n")printf("I 0 sprintf("I \n");

parityonv code puncture

ate-1/2

ate-1/2

ate-2/3

ate-1/2

ee more

- ------------ -1001\n");

10000010\n");

1001\n");

10001001000010010001\n");

selections...\n");

--------------------- \n".);symbol \n");bit map code rate\n");--------- --------- \n");

sspspp rate-3/6\n") ;

sspssp rate-4/6\n");

sspssp rate-4/6\n");

ssspsspp rate-5/8\n");

---------------------Enter selection\n");

/* check for erroneous input */while (error)

printf("I >> ");scanf("%d", &selection);if ((selection == 0) 11 ((selection

error = 0;else

if

>=5) && (selection <= 8)))

printf ("I ** invalid selection **\n");};printf("'---------------------- -----------------

(selection == 0)

printf("\n\n");printf(",-----------------------------------printf(" parityprintf(" conv code punctureprintf("| --------- ------------printf(" I 9 rate-3/4 10printf("I 01\n");printf("j \n");printf("1 10 rate-1/2 00100000printf("| 00000100\n");printf(I \n");printf("j 0 quit\n");printf(I \n");printf("I-----------------------------------printf ("I Enter selection\n");

/* check for erroneous input */error = 1;while (error)

--------------------- \n") ;symbol \n");bit map code rate\n");--------- --------- \n");-

ssspsssp rate-6/8\n");

sssspssssp rate-8/10\n");

printf ("I >> );scanf("%d", &selection);if ((selection == 0) 11 ((selection >=9) && (selection <= 10)))

error = 0;

elseprintf("| ** invalid selection **\n");

printf("'--------------------------------------------------------\n"printf("\n\n");

I;

/* set initialization variables based on selection from menu above */switch (selection)

case 1:k = 1;pati = "10";

turbo sim-std.c 103

printf("printf("Ierror = 1

--- \n");

n") ;

n") ;

Page 104: Simulating Turbo Codes using a Modular Simulation Platform

104 MAIN SIMULATION CODE

pat2 = "01";bitmap = "sp";break;

case 2:k = 1;patl = "10";

pat2 = "01";bitmap = "spsp";break;

case 3:

k = 1;patl = "010000";

pat2 = "000010";

bitmap = "sssp";break;

case 4:k = 3;

patl = "10";pat2 = "01";bitmap = "sssp";break;

case 5:

k = 1;patl = "10";pat2 = "01";bitmap = "sspspp";break;

case 6:k = 1;pati = "1000";

pat2 = "0010";

bitmap = "sspssp";break;

case 7:

k = 2;

patl = "10";pat2 = "01";bitmap = "sspssp";break;

case 8:

k = 1;patl = "1000100100";

pat2 = "0010010001";

bitmap = "ssspsspp";break;

case 9:k = 3;patl = "10";pat2 = "01";bitmap = "ssspsssp";break;

case 10:k = 1;patl = "00100000";

pat2 = "00000100";

bitmap = "essspssssp";break;

}; /* switch */

Initialize encoders, puncture/unpuncture, signal mapper, interleavers */if (selection != 0)

printf("\n\n");

printf(",--------------------------------------------------------\n")printf("I MODULES: encoderl, encoder2\n");

selectEncoder(&encoderl, k);printf("'--------------------------------------------------------\n");

duplicateEncoder(&encoderl, &encoder2);

we need v bits to terminate, but if code is rate-k/k+1, then v must be

a multiple of k. so we round up v to the next higher multiple of k s/

terminateBits = (int)ceil(encoderl.v / encoderl.k) * encoderl.k;

twoPunctureInitVars(&puncturer, pati, pat2);

unPunctureInitVars(&unpuncturer, &puncturer);

bitMapInitVars(&mapper.bitMapper, bitmap);

printf("\n\n");printf( ",--------------------------------------------------------\n")printf("I MODULE: information bits\n");selectBlockSize(&blockSize, encoderi.k, mapper.bitMapper.numSys); /* select blockSize */

printf("------------------------------------ -------------------- \n");

untermBits = blockSize - terminateBits; /* initialize untermBits s/numSymbols = (int) (blockSize / mapper.bitMapper.numSys);

printf("\n\n");

printf(",--------------------------------------------------------\n");printf("| MODULE: interleaverl\n");

/* if encoder is rate k/(k+l) where k > 1, then we need to interleavegroups of k bits together. Thus, there will be only (blockSize / k)elements in the linked list to interleave s/selectInterleaver(&interleaverl, (int) (blockSize / encoderl.k));

Page 105: Simulating Turbo Codes using a Modular Simulation Platform

printf("'--

uncomment the code below to write an interleave pattern to file forretreival later. Also uncomment tempname[] in variable section above */

printf("write pattern to file (y/n)?scanf("%s", temp name);

if (tempname[O] == 'y')

printf("enter output file name\n");printf("--> ");scanf ("%s", tempname);fp = fopen(tempname, "w");outputPattern(&interleaverl, fp)fclose(fp);

llistInitVars(&origBitsLL, encoderl.k)

llistInitVars(&uncodedBitsLL, 1);

printf("\n\n");printf(",----------------------------------printf("I MODULE: 2-D signal mapper\n");selectSignalMapper(&mapper);printf("'----------------------------------

channelInitVars(&channel);

demodulatorInitVars (&demodulator);

/* initialize Eb/No simulation range */printf("\n\n");

printf(",----------------------------------printf ("I ENTER:\n");printf("I \n");printf(" Eb/No to start simulation\n");printf(I >> ");scanf("%f", &tl);printf("J Eb/No to end simulation\n");printf("j >> ");scanf("%f", &t2);

printf(" I Eb/No step size\n");printf("I >> ");scanf("%f", &t3);printf("( \n");start = (double)tl;finish = (double)t2;delta = (double)t3;

printf ("I Number of blocks per Eb/No\n");printf ("I >> );scanf("%d", &num blocks);

/* initialize info bits */

/* initialize uncoded bits */

--------------------- \n");

/* initialize signal mapper */--------------------- \n");

/* initialize channel */

/* initialize demodulator */

/* number of blocks per Eb/No *

blocksleft = (long) (floor((finish - start) / delta) + 1) * numblocks;

/* initialize decoder parameters and decoder variables */printf(" 1 Number of decoder iterations per block\n")printf("l >> ");scanf ("%d", &iter); /* select # of decode iterations */printf("'---------------------------------------------------------\n")

deinterleaverInitVars(&extrinsicdeinterleaver, &interleaverl);deinterleaverInitVars(&Dprob_deinterleaver, &interleaverl);deinterleaverInitVars(&extrinsic interleaver, &extrinsic deinterleaver);deinterleaverInitVars(&Sinterleaver, &extrinsicdeinterleaver);

MAPdecoderInitVars(&MAP1, &encoderl, interleaverl.blockSize, &mapper. symbolMapper)MAPdecoderInitVars(&MAP2, &encoder2, interleaverl.blockSize, &mapper. symbolMapper);

totalerrors = (long*)calloc(iter, sizeof (long)); /* init total errors array */

decodedBitsLL = (linkList*)calloc(iter, sizeof(linkList))for (i=O; i < iter; i++)

llistInitVars(&decodedBitsLL[i], 1);

== DEFINE MODULE CONNECTIONS ==

/* ENCODER modules */encoderl.input =interleaverl.input=encoder2.input -

puncturer.input[0]=puncturer.input[1]=mapper.inputU =mapper.inputS -

mapper.inputP -

origBitsLL.output;origBitsLL.output;interleaverl.output;encoderl.output;encoder2.output;uncodedBitsLL.output;origBitsLL.output;puncturer.output;

/* channel, demodulator, unpuncturer */channel.input = mapper.output;demodulator.input = channel.output;

turbosim-std.c 105

-------------- \n".);

-------------------- \n"-);

Page 106: Simulating Turbo Codes using a Modular Simulation Platform

MAIN SIMULATION CODE

unpuncturer.input = demodulator.outputP;

/* DECODER modules */MAPl.inputA = extrinsic_deinterleaver.output;MAPl.inputS = demodulator.outputS;MAPl.inputP = &unpuncturer.output[0];

Sinterleaver.input= demodulator.outputS;extrinsic interleaver.input = MAPi.output extrinsic;MAP2.inputA = extrinsic interleaver.output;

MAP2.inputS = Sinterleaver.output;MAP2.inputP = &unpuncturer.output[l];

extrinsicdeinterleaver.input = MAP2.output extrinsic;Dprobdeinterleaver.input = MAP2.outputDprob;

== BEGIN SIMULATION PROGRAM ==

time(&starttime);

for (EbOverNo = start; EbOverNo = finish; EbOverNo += delta) { /* this is in dB */

/* initialize bit and error counts to zero */for (i=0; i < iter; i++)

totalerrors[i] = 0;totalbits = 0;

/* calculate channel noise variance for current Eb/No and constellation C/

channel.n variance = mapper.symbolMapper.Eav / (2 * mapper.bitMapper.numSys * pow(10, (EbOverNo/10)));printf("Eb/No = %f, n-variance = %f\n", EbOverNo, channel.n variance);

/* initialize random # generator with same seed for each Eb/No to use same bit sequences C/

srand(sourceSeed);for (block = 0; block < num blocks; block++)

totalbits += blockSize;

genBits(&origBitsLL, untermBits); /* generate one block of bits C/

encodeslock(&encoderl); /* encoder original block */terminateEncoder(&encoderl);doInterleave(&interleaverl); /* do interleavingencodeBlock(&encoder2); /* encode interleaved block C/

punctureBlock(&puncturer); /* puncture parity bitsgenBits(&uncodedBitsLL, (mapper.bitMapper.numUncoded * numSymbols)); /* uncoded bits C/

/* regroup the systematic bits for use by the signal mapper */if (encoderl.k > 1)

regroupKtol(origBitsLL.output, encoderl.k);

mapBlock(&mapper); /* generate symbolssendAWGNblock(&channel); /* send through AWGN channel C/

demodulateTwoDBlock(&demodulator, &mapper, channel.n_variance) ; /* get LLRs */unpunctureBlock(&unpuncturer); /* unpuncture parity LLRs */if (encoderl.k > 1)

/* note: for some reason,bits = (int) (log((*decoder).numInputs) / log(2));

does not give the right number, butbits = (int) (loglO((*decoder).numInputs) / loglo(2));does.

regroupltoK(demodulator.outputS, (int) (loglO(MAPl.numInputs)/loglO(2)));

calcprobS(&MAPl);calcgamma(&MAPl);initprobA(&MAP1, 1);doInterleave(&Sinterleaver); /* only need to interleave L(dk) once */calcgamma(&MAP2);for (i=G; i < iter; i++)

initAB(&MAP1, terminated);

doMAPdecoding(&MAPl);doInterleave(&extrinsicinterleaver);initAB(&MAP2, notTerminated);doMAPdecoding(&MAP2);doInterleave(&extrinsicdeinterleaver);doInterleave(&Dprobdeinterleaver);probDecision(Dprobdeinterleaver.output, &decodedBitsLL[i]);

1;

regroup_Ktol (demodulator.outputS, (int) (loglO(MAPl.numInputs)/loglO(2)));

else

init_probA(&MAPl, 0);calcgammaRl2(&MAPl);doInterleave(&Sinterleaver);calcgammaRl2 (&MAP2);for (i=0; i < iter; i++)

initAB(&MAPl, terminated);

doFastRl2MAPdecoding(&MAPl);doInterleave(&extrinsicinterleaveinitAB(&MAP2, notTerminated);doFastRl2MAPdecoding(&MAP2);

only need to interleave L(dk) once */

106

Page 107: Simulating Turbo Codes using a Modular Simulation Platform

turbosim-std.c 107

doInterleave(&extrinsicdeinterleaver);doInterleave(&Dprobdeinterleaver);signDecision(Dprob deinterleaver.output, &decodedBitsLL[i]);

};

/ calculate and display decoded bit errors */for (i=0; i < iter; i++)

totalerrors[i] += (long)floor(blockSize * showErrorPercentage(&origBitsLL,&decodedBitsLL[i]));

printf("Eb/No [dB] = %f, block %d / %d\n", EbOverNo, (block+l), num blocks);for (i=0; i < iter; i++)

printf ("iteration %d: %e\n", (i+1), ((double) total errors[ii / totalbits))printf ("\n");

/ regroup origBitsLL from 1 bit per element back to k bits per element */if (encoderl.k > 1)

regroupltoK(origBitsLL.output, encoderl.k);

/* find simulation time remaining */blocksdone++;blocksleft--;time(&curr time);

/* elapsedtime / blocksdone = remaining time / blocksleftremainingtime = elapsedtime / blocksdone blocksleft

*/temp = (double) (blocks left * difftime(currtime, start time)/3600 / blocksdone); /* hours

remaining */hrs = (int)floor(temp);

mins = (int)floor((temp - floor(temp)) * 60);temp *= 60; /* number of minutes remaining */secs = (int)ceil((temp - floor(temp)) * 60);

printf(" total time remaining: %dh %dm %ds\n\n", hrs, mins, secs);

}; /* for loop: blocks */

/* append results for completed Eb/No to the output file */fp = fopen(filename,"a");

fprintf(fp, "sourceSeed=%d\n", sourceSeed);fprintf(fp, "%d-QAM\n", mapper.symbolMapper.M);showTwoDmapping(&mapper.symbolMapper, fp);fprintf(fp, "\nbit map: );for (i=0; i < mapper.bitMapper.b; i++)

fprintf(fp, "%c", mapper.bitMapper.pattern[i]);fprintf(fp, "\nEav = %f\n", mapper.symbolMapper.Eav);fprintf(fp, "Eb/No = %f, nvariance = %f\n", EbOverNo, channel.n variance);fprintf(fp, "\nd bits -- Error probability:\n", totalbits);for (i=0; i < iter; i++)

fprintf(fp, "iteration %d: %e\n", (i+1), ((double)totalerrors[i] / totalbits));fprintf(fp, "\n");temp = (double) (difftime(curr time, start-time)/3600 / (blocks done/num blocks)); /* elapsed for this

Eb/No "hrs = (int)floor(temp);mins = (int)floor((temp - floor(temp)) * 60);temp *= 60; /* number of minutes remaining */secs = (int)ceil((temp - floor(temp)) * 60);printf("simulation time for %d blocks: %dh %dm %ds\n", num blocks, hrs,mins,secs);fprintf(fp, "simulation time for %d blocks: %dh %dm %ds\n\n\n", numblocks, hrs,mins,secs);

fclose(fp);

/* for loop: Eb/No range */

/* free all dynamically allocated variables */

deleteList(&origBitsLL); /* cannot use freeList because list not dynamically allocated */freeTwoDsignalMapVars(&mapper);freeChannelvars(&channel);freeDemodulatorVars(&demodulator);freeEncoderVars(&encoderl);freelnterleaverVars(&interleaverl);freeEncoderVars(&encoder2);freePunctureVars(&puncturer);deleteList(&uncodedBitsLL);

freeUnpunctureVars(&unpuncturer); */ /* causes problems, don't use yet */freeMAPDecoderVars(&MAPl);freeMAPDecoderVars(&MAP2);freeInterleaverVars (&extrinsic_interleaver)freelnterleaverVars(&extrinsic deinterleaver);freeInterleaverVars(&Sinterleaver);freeInterleaverVars(&Dprob_deinterleaver);for (i=0; i < iter; i++)

deleteList(&decodedBitsLL[i);free(decodedBitsLL);

}; /* if selection != 0 */}; /* error opening file */return 0;

/* main */

Page 108: Simulating Turbo Codes using a Modular Simulation Platform

108 MAIN SIMULATION CODE

turbo sim-icoding.c

file: turbo sim-icoding.c

This is the main program file that simulates turbo codes proposedby ICoding. ICoding only proposes to use rate-l/2 constituentcodes, and full coding of every bit.

*/

#include "StdAfx.h"#include "linkedlist.h"#include "source.h"#include "interleave.h"#include "conv.h"#include "puncture.h"#include "mapper.h"#include "channel.h"#include "demod.h"#include "decoder.h"

#include <math.h>#include <time.h>#include <stdio.h>#include <string.h>#include <stdlib.h>

int main(int argc, char* argv[])

== DECLARE GENERAL VARIABLES ===== == == == == == === == == == == *

/* general simulation variables */FILE* fp;

int sourceSeed;char filename[80;double EbOverNo, start, finish, delta;int blockSize;long numblocks;int iter;long total_bits;long* total_errors;int terminateBits;int untermBits;int numSymbols;char *patl, *pat2, *pat3;char *bitmap;

/* misc variables *timet starttime, currtime;float tl, t2, t3;int hrs, mins, secs;int i;int k;int selection;long block;long blocks_left, blocks_done;char error;double temp;

/* char temp_name[80]; *char terminated;char notTerminated;

file to write results Vseed for random # gen Vstore file name *Eb/No simulation range *# of bits per block *# of blocks per Eb/No *

/* # of decoder iterationstotal bits per Eb/No *total decode errors per Eb/No *

# of bits to terminate trellis *blockSize - terminateBits *

# of symbols sent thru channel */* puncture pattern */* symbol bit mapping /

keeps track of timescanf variablesprintf: time variablesfor loop indexselection variablesscanf: code structurefor loop indexkeeps track of progresserror indicatortemporary variable

VVVVVV

VV

== CREATE SIMULATION MODULES ==

/* simulation modules /

/* bit linked lists *linkList origBitsLL;linkList* decodedBitsLL;

/* ENCODER modules *interleaverVars interleaverl;interleaverVars interleaver2;encoderVars encoderl;encoderVars encoder2;encoderVars encoder3;punctureVars puncturer;

/* systematic buffer/* decoded bits buffer

/* interleaver 1/* interleaver 2/* encoder 1/* encoder 2/* encoder 3/* puncturer

Page 109: Simulating Turbo Codes using a Modular Simulation Platform

turbosim-icoding.c

twoDsignalMapVars mapper;

channel, soft-data modules */channelVars channel;

demodulatorVars demodulator;unPunctureVars unpuncturer;

DECODER modulesMAPdecoderVarsMAPdecoderVarsMAPdecoderVarsinterleaverVarsinterleaverVars

interleaverVars

interleaverVars

interleaverVars

interleaverVarsinterleaverVars

MAPl;MAP2;MAP3;extrinsic-interleaverl;extrinsic-interleaver2;extrinsicdeinterleaverl;extrinsic deinterleaver2;

Sinterleaverl;Sinterleaver2;Dprob deinterleaver;

/* signal mapper */

/* AWGN channel '/* demodulator '//* unpuncture LLR values */

/* MAP decoder 1 *//* MAP decoder 2 '//* MAP decoder 3/* extrins info interleaver 1 *//* extrins info interleaver 2 *//* extrin. info deinterleaver 1*//* extrin. info deinterleaver 2*//* systematic bits interleaver 1*//* systematic bits interleaver 2*//* a posteriori prob deinterleaver

INIT GENERAL VARIABLES

1;0;171;

0;

= INITIALIZE SIMULATION MODULES ==

printf(I"

printf(printf(" === == ==

printf("\n")printf("\n");printf(",-----------------printf (" \n")printf("

printf("| .-------printf("I Iprintf(" I information bits

printf("|l I Iprintf(I" I interleaverlprintf("i" Iprintf(i)" interleaver2 ---printf(I"

printf(" Iprintf("I\n");printf( "-----------------printf ("\n");

output file name */printf(", ----------------------printf(i" Enter output file naprintf("| >> );scanf("%s", filename);printf("'----------------------fp = fopen(filename, "a");if (fp == NULL)

printf("\n\nError openingelse

fclose(fp);

TURBO-CODE SIMULATION

> encoderl

encoder2 --. |

> encoder3 --. I I

puncture

file %s, program terminating\n", filename);

/* choices for modules: encoderl, encoder2, puncturer, mapper

printf("\n\n");printf(",----------------------printf("I\n");

printf("I pprintf("I conv code pprintf("I --------- ---printf("I 1 rate-1/2 1printf("I 0printf("I 0printf("l \n");printf("I 2 rate-1/2 1printf("I 0printf("I 0printf("I \n");printf("I 3 rate-1/2 0printf("I 0printf("I 0printf("! \n");printf(" o see more selectiprintf("I \n");

printf(i"----------------------printf("I Enter selection\n");

----------------------------------- \n");

arity symbol overall \n");uncture bit map code rate\n");--------- ---------- --------- \n") ;00 sp rate-1/2\n");10\n");01\n");

0010\n")01\n")

1000000000010000\n");00000010\n");

ons ... \n");

spsp rate-2/4\n");

sqsp rate-3/4\n");

109

terminated

notTerminated

sourceSeedblocksdone

= = \n")

a \n");i \n");

g \n");n \n");

.-> a m \n");

1 a \n");p \n");p \n");

e \n");r \n");

---------- \n");

Page 110: Simulating Turbo Codes using a Modular Simulation Platform

MAIN SIMULATION CODE

/* check for erroneous input */error = 1;while (error)

printf(" >>scanf("%d", &selection);if ((selection >= 0) && (selection <:

error = 0;else

3))

printf("| ** invalid selection **\n");};printf("'-------------------------------------if (selection == 0)

printf ("\n\n");printf(",---------------------------------printf("j parityprintf(" I conv code punctureprintf("I --------- ------------

printf(" l \n");printf("Ul 0 quit\n");printf("| \n");printf("j--------------------------------

printf("| Enter selection\n");

/* check for erroneous input */error = 1;while (error)

printf("I >>scanf("%d", &selection);if ((selection == 0) 11 ((selection

error = 0;else

---------- \n");

---------------------- \n");

symbol \n");bit map code rate\n");

---------- --------- \n");

>=0) && (selection <= 0)))

printf(" ** invalid selection **\n");1;printf("'---------------------------------------printf ("\n\n")

};

switch (selection)

case 1:k = 1;patl =

pat2 =pat3 =bitmapbreak;

case 2:k = 1;patl =

pat2 =pat3 =bitmapbreak;

case 3:

"100";"010";

"001";

= "sp";

"100";

"010";

"001";

= "spsp";

k = 1;patl = "010000000";pat2 = "000010000";

pat3 = "000000010";

bitmap = "sssp";break;

}; /* switch */

/* Initialize encoders, puncture/unpuncture,if (selection != 0)

signal mapper, interleavers */

printf("\n\n");printf(",--------------------------------------------------------\n");

printf(" I MODULES: encoderl, encoder2, encoder3\n");selectEncoder(&encoderl, k);printf("------------------------------------ -------------------- \n");

duplicateEncoder(&encoderl, &encoder2);duplicateEncoder(&encoderl, &encoder3);

we need v bits to terminate, but if code is rate-k/k+l, then v must bea multiple of k. so we round up v to the next higher multiple of k */terminateBits = (int)ceil(encoderl.v / encoderl.k) * encoderl.k;

threePunctureInitVars(&puncturer, patl, pat2, pat3);

unPunctureInitVars(&unpuncturer, &puncturer);

bitMapInitVars(&mapper.bitMapper, bitmap);

printf ("\n\n") ;printf(",---------------------------------------------------------\n");printf("I MODULE: information bits\n");selectBlockSize(&blockSize, encoderl.k, mapper.bitMapper.numSys); /* select blockSizeprintf("'---------------------------------------------------------\n");untermBits = blockSize - terminateBits; /* initialize untermBits s/numSymbols = (int) (blockSize / mapper-bitMapper.numSys);

110

----------- \n");

Page 111: Simulating Turbo Codes using a Modular Simulation Platform

turbosim-icoding.c 111

printf("\n\n");printf(" --------------------------------------------------------- \n");printf("I MODULE: interleaverl\n");

if encoder is rate k/(k+) where k > 1, then we need to interleavegroups of k bits together. Thus, there will be only (blockSize / k)elements in the linked list to interleave */

selectInterleaver(&interleaverl, (int) (blockSize / encoderl.k)printf(" --------------------- \n");

printf ("\n\n");printf(",-----------------------------------------------------------\n");printf("I MODULE: interleaver2\n");

/* if encoder is rate k/(k+l) where k > 1, then we need to interleavegroups of k bits together. Thus, there will be only (blockSize / k)elements in the linked list to interleave */selectInterleaver(&interleaver2, (int) (blockSize / encoderi.k)printf("'-----------------------------------------------------------\n");

uncomment the code below to write an interleave pattern to file forretreival later. Also uncomment tempname[] in variable section above *

printf("write pattern to file (y/n)?scanf("%s", temp name);if (tempname[O] == 'y')

printf ("enter output file name\n");printf("--> ");scanf("%s", tempname);fp = fopen(tempname, "w");outputPattern(&interleaverl, fp);fclose(fp);

*/

llistInitVars(&origBitsLL, encoderl.k); /* initialize info bits /

printf("\n\n");printf(",---------------------------------------------------- \n")printf("I MODULE: 2-D signal mapper\n");selectSignalMapper(&mapper); /* initialize signal mapper */printf("'--------------------------------------------------------\n");

channelInitVars(&channel); /* initialize channel *

demodulatorInitVars(&demodulator); /* initialize demodulator /

/* initialize Eb/No simulation range /printf("\n\n");printf(", --------------------------------------------------------- \n");printf("I ENTER:\n");printf("I \n");printf ("I Eb/No to start simulation\n");printf("I >> ");scanf("%f", &tl);printf("I Eb/No to end simulation\n");printf("[ >> );scanf("%f", &t2);printf("I Eb/No step size\n");printf("I >> ");scanf("%f", &t3);printf("I \n");start = (double)tl;finish = (double)t2;

delta = (double)t3;

printf("I Number of blocks per Eb/No\n");printf("j >> );scanf("%d", &numhblocks); /* number of blocks per Eb/No *

blocksleft = (long) (floor((finish - start) / delta) + 1) * numblocks;

/* initialize decoder parameters and decoder variables */printf ("I Number of decoder iterations per block\n")printf("j >> );scanf("%d", &iter); /* select # of decode iterations */printf("----------------------------------- ---------------------

deinterleaverInitVars(&extrinsic deinterleaverl, &interleaverl);deinterleaverInitVars(&extrinsicdeinterleaver2, &interleaver2);deinterleaverInitVars(&Dprobdeinterleaver, &interleaver2);deinterleaverInitVars(&extrinsic interleaverl, &extrinsicdeinterleaverl);deinterleaverInitVars(&extrinsicinterleaver2, &extrinsicdeinterleaver2);deinterleaverInitVars(&Sinterleaverl, &extrinsic_deinterleaverl);deinterleaverInitVars(&Sinterleaver2, &extrinsicdeinterleaver2);

MAPdecoderInitVars(&MAP2, &encoderl, interleaverl.blockSize, &mapper.symbolMapper);MAPdecoderInitVars(&MAP2, &encoder2, interleaverl.blockSize, &mapper.symbolMapper);MAPdecoderInitVars(&MAP3, &encoder3, interleaverl.blockSize, &mapper.symbolMapper);

total-errors = (long*)calloc(iter, sizeof(long)); /* init total-errors array */

decodedBitsLL = (linkList*)calloc(iter, sizeof(linkList));for (i=l; i < iter; i++)

llistInitVars(&decodedBitsLL[i}, 1);

Page 112: Simulating Turbo Codes using a Modular Simulation Platform

MAIN SIMULATION CODE

= DEFINE MODULE CONNECTIONS ==

*--- --- REGULAR TURBO CODE

/* ENCODER modules */encoderl.input =interleaveri.input=encoder2.input =interleaver2.input=encoder3.input =puncturer.input[0] =puncturer.input[11]=puncturer.input[2]=mapper.inputS =mapper.inputP =

origBitsLL.output;origBitsLL.output;interleaverl.output;origBitsLL.output;interleaver2.output;encoderl.output;encoder2.output;encoder3.output;origBitsLL.output;puncturer.output;

/* channel, demodulator, unpuncturer */channel.input = mapper.output;demodulator.input = channel.output;unpuncturer.input = demodulator.outputP;

/* DECODER modules */MAPl.inputA = extrinsic deinterleaver2.output;MAPl.inputS = demodulator.outputS;MAPl.inputP = &unpuncturer.output[0];Sinterleaverl.input= demodulator.outputS;extrinsicinterleaverl.input = MAPI.output extrinsic;MAP2.inputA = extrinsic interleaverl.output;MAP2.inputS = Sinterleaverl.output;MAP2.inputP = &unpuncturer.output[l];Sinterleaver2.input= demodulator.outputS;extrinsic deinterleaverl.input = MAP2.output extrinsic;extrinsic interleaver2.input = extrinsic-deinterleaverl.output;MAP3.inputA = extrinsic-interleaver2output;MAP3.inputS = Sinterleaver2.output;MAP3.inputP = &unpuncturer.output[2];extrinsic deinterleaver2.input = MAP3.output extrinsic;Dprob_deinterleaver.input = MAP3.output Dprob;

/*

== BEGIN SIMULATION PROGRAM ==

time(&start time);for (EbOverNo = start; EbOverNo <= finish; EbOverNo += delta) { /* this is in dB */

/* initialize bit and error counts to zero '/for (i=O; i < iter; i++)

totalerrors[i] = 0;totalbits = 0;

/* calculate channel noise variance for current Eb/No and constellation */channel.n variance = mapper.symbolMapper.Eav / (2 * mapper.bitMapper.numSys * pow(10, (EbOverNo/10)));printf("Eb/No = %f, n-variance = %f\n", EbOverNo, channel.n_variance);

/* initialize random # generator with same seed for each Eb/No to use same bit sequences */srand(sourceSeed);for (block = 0; block < numblocks; block++)

total bits += blockSize;

genBits(&origBitsLL, untermBits);encodeBlock(&encoderl);terminateEncoder(&encoderl);doInterleave(&interleaverl);encodeBlock(&encoder2);doInterleave(&interleaver2);encodeBlock(&encoder3);punctureBlock(&puncturer);

/* generate one block of bits *//* encoder original block */

/* do interleaving *//* encode interleaved block *//* do interleaving *//* encode interleaved block *//* puncture parity bits */

mapBlock(&mapper); /* generate symbolssendAWGNblock(&channel); /* send through AWGN channeldemodulateTwoDBlock(&demodulator, &mapper, channel.n variance); /* getunpunctureBlock(&unpuncturer); /* unpuncture parity LLRs

*/LLRs */

/* all constituent codes are rate-1/2, so use fast-ratel2 decoding functions */initprobA(&MAPl, 0);calc gammaR12(&MAP1);doInterleave(&Sinterleaverl); /* only need to interleave L(dk) once */calc gammaR12(&MAP2);doInterleave(&Sinterleaver2); /* only need to interleave L(dk) once */calc gammaR12(&MAP3);for (i=O; i < iter; i++) {

initAB(&MAP1, terminated);

doFastRl2MAPdecoding(&MAPl);doInterleave(&extrinsicinterleaverl);initAB(&MAP2, notTerminated);

doFastRl2MAPdecoding(&MAP2);

doInterleave(&extrinsic deinterleaverl);doInterleave(&extrinsic interleaver2);

112

Page 113: Simulating Turbo Codes using a Modular Simulation Platform

turbosim-icoding.c 113

initAB(&MAP3, notTerminated);doFastRl2MAPdecoding(&MAP3);doInterleave(&extrinsic_deinterleaver2);doInterleave(&Dprob_deinterleaver);signDecision(Dprob_deinterleaver.output, &decodedBitsLL[i]);

};

/* calculate and display decoded bit errorsfor (i=0; i < iter; i++)

totalerrorsi] += (long)floor(blockSize * showErrorPercentage(&origBitsLL,&decodedBitsLL[i]));

printf("Eb/No [dB] = %f, block %d / %d\n", EbOverNo, (block+l), num blocks);for (i=0; i < iter; i++)

printf ("iteration %d: %e\n", (i+l), ((double) totalerrors [ii / total-bits));printf ("\n") ;

/* find simulation time remaining */blocks done++;blocksleft--;time(&curr time);/* elapsedtime / blocks-done = remainingtime / blocksleft

remainingtime = elapsedtime / blocksdone blocks-left*/

temp = (double) (blocksleft * difftime(currtime, starttime)/3600 / blocksdone); /* hoursremaining */

hrs = (int)floor(temp);mins = (int)floor((temp - floor(temp)) * 60);temp 60; /* number of minutes remaining */secs (int)ceil((temp - floor(temp)) * 60);

printf(" total time remaining: %dh %dm %ds\n\n", hrs, mins, secs);

}; /* for loop: blocks */

/* append results for completed Eb/No to the output file '/fp = fopen(filename, a");

fprintf(fp, "sourceSeed=%d\n", sourceSeed);fprintf(fp, "%d-QAM\n", mapper.symbolMapper.M);showTwoDmapping(&mapper.symbolMapper, fp);fprintf(fp, "\nbit map: ");for (i=0; i < mapper.bitMapper.b; i++)

fprintf(fp, "%c", mapper.bitMapper.pattern[i]);fprintf(fp, "\nEav = %f\n", mapper.symbolMapper.Eav);fprintf(fp, "Eb/No = %af, n variance = %f\n", EbOverNo, channel.nvariance);fprintf(fp, "\n%d bits -- Error probability:\n", total-bits);for (i=0; i < iter; i++)

fprintf(fp, "iteration %d: %e\n", (i+l), ((double) totalerrors [i] / total-bits));fprintf(fp, "\n");temp = (double) (difftime(curr time, starttime)/3600 / (blocksdone/num blocks)); /* elapsed for this

Eb/No */hrs = (int)floor(temp);mins = (int)floor((temp - floor(temp)) * 60);temp *= 60; /* number of minutes remaining */secs = (int)ceil((temp - floor(temp)) * 60);printf("simulation time for %d blocks: %dh %dm %ds\n", num blocks, hrs,mins,secs);fprintf(fp, "simulation time for %d blocks: %dh %dm %ds\n\n\n", num blocks, hrs,mins,secs);

fclose(fp);

/* for loop: Eb/No range */

/* free all dynamically allocated variables */

deleteList(&origBitsLL); /* cannot use freeList because list not dynamically allocated */freeTwoDsignalMapVars(&mapper);freeChannelVars(&channel);freeDemodulatorVars(&demodulator);freeEncoderVars(&encoderl);freeInterleaverVars(&interleaverl);freeInterleaverVars(&interleaver2);freeEncoderVars(&encoder2);freePunctureVars(&puncturer);

/* freeUnpunctureVars(&unpuncturer); */ * causes problems, don't use yet */freeMAPDecoderVars(&MAP1);

freeMAPDecoderVars(&MAP2);freeMAPDecoderVars(&MAP3);freeInterleaverVars(&extrinsicinterleaverl);freeInterleaverVars(&extrinsic deinterleaveri);freeInterleaverVars(&Sinterleaverl);freeInterleaverVars(&extrinsic_interleaver2);freeInterleaverVars(&extrinsicdeinterleaver2)freeInterleaverVars(&Sinterleaver2);freeInterleaverVars(&Dprob_deinterleaver);for (i=0; i < iter; i++)

deleteList(&decodedBitsLL[i});free(decodedBitsLL);

}; /* if selection != 0 */}; /* error opening file */

return 0;

/* main */

Page 114: Simulating Turbo Codes using a Modular Simulation Platform

MAIN SIMULATION CODE

file: uncodedsim.c

This is the main programperformance.

*/

#include "linkedlist.h"#include "source.h"#include "interleave.h"#include "conv.h"#include "puncture.h"#include "mapper.h"#include "channel.h"#include "demod.h"#include "decoder.h"

#include#include#include#include#include

int

file that simulates uncoded QAM

<math.h><time.h><stdio.h><string.h><stdlib.h>

main(int argc, char* argv[])

GENERAL VARIABLE DECLARATIONS ==

general simulation variables */int sourceSeed;FILE* fp;

char filename[80];double EbOverNo, start, finish, delta;int blockSize;long num blocks;int iter;

long totalbits;

long* totalerrors;int terminateBits;

int untermBits;

int numSymbols;

/*/*/*/*/*

misc variables */timet starttime, currtime;

int hrs, mins, secs;int i;long block;

floatlongchardouble

tl, t2, t3;

blocks-left, blocks-done;error;temp;

seed for random # gen */file to write results */store file nameEb/No simulation range */# of bits per block */# of blocks per Eb/No */

/* # of decoder iterations */total bits per Eb/No */total decode errors per Eb/No */# of bits to terminate trellis */blockSize - terminateBits */# of symbols sent thru channel */

keeps track of time */printf: time variables */for loop index */for loop index */

scanf variableskeeps track of progresserror indicatortemporary variable

*/*/*/

== CREATE SIMULATION MODULES ==

/* simulation modules */

/* bit linked lists */linkList origBitsLL;

/* ENCODER modules */twoDsignalMapVars mapper;

/* channel, soft-data modules '/channelVars channel;

demodulatorVars demodulator;

/* systematic buffer

/* signal mapper

/* AWGN channel/* demodulator

INITIALIZE SIMULATION MODULES ==

pri==========\n ");

114

turbosim-uncoded.c

print f ( "

Page 115: Simulating Turbo Codes using a Modular Simulation Platform

printf(" = UNCOprintf ( " -== == == =-=printf("\n");

printf ("\n") ;printf(",-------------------printf("I\n");

printf(" information bitsprintf)(I \n");

printf(" -------------------

printf ("\n")printf ("\n")

/* output file name */printf(",------------------printf("| Enter output fiprintf("I >> ");scanf("%s", filename);printf('------------------fp = fopen(filename, "a");if (fp == NULL)

else

DE SIMULATION

-- > signal mapper

------------------ \n");

--> channel\n");

--------------------------------------- \n");le name\n");

--------------------------------------- \n");

printf("\n\nError opening file %s, program terminating\n", filename);

fclose(fp);

* --------- UNCODED SIMULATION -----------------------------

printf("\n\n");printf(" -------------------------------------------------------- \n");printf("I MODULE: information bits\n");selectBlockSize(&blockSize, 1, 1); /* select blockSizeprintf( '---------------------------------- ---------------------- \n");

printt("\n\n");

printf(",--------------------------------------------------------\n");printf("I MODULE: bit mapper\n");selectBitMapper(&mapper.bitMapper);printf("--------------------------------------- ----------------- \n");numSymbols = (int) (blockSize / mapper.bitMapper.numSys);

llistInitvars(&origBitsLL, 1);

terminateBits = 0;untermBits = blockSize - terminateBits;

printf("\n\n");printf(",---------------------------------printf("F MODULE: 2-D signal mapper\n");selectSignalMapper(&mapper);printf("---------------------------------

channelInitVars(&channel);

demodulatorInitVars(&demodulator);

/* initialize Eb/No simulation range */printf("\n\n") ;printf(",---------------------------------printfQ(I ENTER:\n");printf("| \n");printf("|l Eb/No to start simulation\n");printf("I >> ");scanf("%f", &tl);printf("I Eb/No to end simulation\n");printf("I >> ");scanf("%f", &t2);

printf("I' Eb/No step size\n");printf("I >> ");scanf("%f", &t3);printf(" \n");start = (double)tl;finish = (double)t2;delta = (double)t3;

printf("I Number of blocks per Eb/No\n");printf("I >> ");scanf("%d", &num blocks);

/* initialize info bits */

/* initialize untermBits */

.----------------------\n");

/* initialize signal mapper */---------------------- \n");

/* initialize channel */

/* initialize demodulator */

--------------------- \n");

/* number of blocks per Eb/No */

blocks-left = (long) (floor((finish - start) / delta) + 1) * numblocks;

I* initialize decoder parameters and decoder variables */printf("'---------------------------------------------------------\n")

blocks done = 0;blocksleft = (long) (floor((finish - start) / delta) + 1) * numblocks;

iter = 1;

totalerrors = (long*)calloc(iter, sizeof(long)); /* init totalerrors array */

/*

- DEFINE MODULE CONNECTIONS ==

turbo sim-uncoded.c115115

Page 116: Simulating Turbo Codes using a Modular Simulation Platform

116 MAIN SIMULATION CODE

/ ----------- UNCODED SIMULATION ----------------------------- *

mapper.inputS = origBitsLL.output;channel.input = mapper.output;

demodulator.input = channel.output;

CHECK SIMULATION PARAMETERS ==

error = 0;if (error == 0)

BEGIN SIMULATION PROGRAM ==

/* showTwoDmapping(&mapper.symbolMapper, NULL);time(&starttime);sourceSeed = 171;for (EbOverNo = start; EbOverNo <= finish; EbOverNo += delta) { /* this is in dB */

/* initialize bit and error counts to zero '/for (i=0; i < iter; i++)

totalerrors[i) = 0;totalbits = 0;

/* calculate channel noise variance for current Eb/No and constellation */channel.n-variance = mapper.symbolMapper.Eav / (2 * mapper.bitMapper.numSys * pow(10, (EbOverNo/10)))printf("Eb/No = %f, n-variance = %f\n", EbOverNo, channel.n_variance);

/* initialize random # generator with same seed for each Eb/No to use same bit sequences */

srand(sourceSeed);for (block = 0; block < num_blocks; block++)

totalbits += blockSize;

/ ----------- UNCODED SIMULATION ----------------------------- *--

genBits(&origBitsLL, blockSize); /* generate one block of bits */

mapBlock(&mapper); /* generate symbols */sendAWGNblock(&channel); /* send through AWGN channel */

decode uncoded(demodulator.outputS, &mapper, channel.output);/* find error rate */

totalerrors[0) += (long)floor(blockSize * showErrorPercentage(&origBitsLL,demodulator.outputS));

/ find simulation time remaining */blocks_done++;blocks_left--;time(&currtime);

/* elapsedtime / blocks-done = remaining time / blocksleftremaining time = elapsed time / blocks-done blocksleft

temp = (double) (blocksleft * difftime(currtime, start_time)/3600 / blocks_done); /* hours

remaining /hrs = (int)floor(temp);

mins = (int)floor((temp - floor(temp)) * 60);

temp 60; /* number of minutes remaining */secs = (int)ceil((temp - floor(temp)) * 60);

1; /* for loop: blocks /

printf("Eb/No [dB] = %f\n", EbOverNo);

printf("BER: %e\n", ((double)totalerrors[0} / total_bits));printf(" total time remaining: %dh %dm %ds\n\n", hrs, mins, secs);

printf("\n");

/* append results for completed Eb/No to the output file */fp = fopen(filename,"a");

fprintf(fp, "sourceSeed=%d\n", sourceSeed);fprintf(fp, "%d-QAM\n", mapper.symbolMapper.M);showTwoDmapping(&mapper.symbolMapper, fp);fprintf(fp, "\nbit map: ");for (i=0; i < mapper.bitMapper.b; i++)

fprintf(fp, "%c", mapper.bitMapper.pattern[il);fprintf(fp, "\nEav = %f\n", mapper.symbolMapper.Eav);fprintf(fp, "Eb/No = %f, nvariance = %f\n", EbOverNo, channel.nvariance);fprintf(fp, "\n%d bits -- Error probability:\n", total_bits);for (i=0; i < iter; i++)

fprintf(fp, "iteration %d: %e\n", (i+l) , ( (double)totalerrors[i / totalbits));fprintf(fp, "\n");temp = (double) (difftime(currtime, start_time)/3600 / (blocksdone/num blocks)); /* elapsed for this

Eb/No */hrs = (int)floor(temp);mins = (int)floor((temp - floor(temp)) * 60);

temp *= 60; /* number of minutes remaining */secs = (int)ceil((temp - floor(temp)) * 60);printf("simulation time for %d blocks: %dh %dm %ds\n\n", num blocks, hrs,mins,secs);fprintf(fp, "simulation time for %d blocks: %dh %dm %ds\n\n\n", numblocks, hrs,mins,secs);

Page 117: Simulating Turbo Codes using a Modular Simulation Platform

turbosim-uncoded.c 117

fclose(fp);

/* for loop: Eb/No range */

}; /* if !error */

/* free all dynamically allocated variables */

deleteList(&origBitsLL); /* cannot use freeList because list not dynamically allocated */freeTwoDsignalMapVars (&mapper);

freeChannelVars(&channel);

freeDemodulatorVars(&demodulator);

}; /* error opening file */

return 0;

/* main */

Page 118: Simulating Turbo Codes using a Modular Simulation Platform
Page 119: Simulating Turbo Codes using a Modular Simulation Platform

APPENDIX B

Sample Output for turbo_ sim-std.c

Screen Output

TURBO-CODE SIMULATION

s----- -- -- > ---- ----- --- > i

information bits -- > encoder -

interleaverl -- > encoder2 --.

puncture

g mn

> a1

Enter output file name>> test.txt

conv code

1 rate-1/2

2 rate-1/2

3 rate-1/2

4 rate-3/4

paritypuncture

1001

1001

010000000010

10

01

symbolbit map

sp

spsp

sssp

sssp

overallcode rate

rate-1/2

rate-2/4

rate-3/4

rate-3/4

0 see more selections...

Enter selection>> 1

-119-

a

pper

Page 120: Simulating Turbo Codes using a Modular Simulation Platform

120 APPENDIX B

MODULES: encoderi, encoder2

1 fbPoly = 23 ffPoly = 352 fbPoly = 7 ffPoly = 53 fbPoly = 15 ffPoly = 17

select generator polynomials

>> 1

MODULE: information bits

** must be divisible by 1 **

1 10242 4096

3 51204 61445 15844

Select number of bits per block>> 1

MODULE: interleaverl

1 Random permutation2 Two-step semi-random algorithm (AT&T RN-029 standard)3 Read permutation pattern from file

Select interleaver type> 2

** 1024 elements **

S1, S2, seed

1 (16, 6, 151)2 (18, 12, 151)3 (23, 12, 151)4 (25, 15, 151)5 (26, 15, 151)

Select semi-random interleaver parameters

>> 2

generating interleave pattern ...

MODULE: 2-D signal mapper

1 normal bit labeling (00, 01, 10, 11)2 full gray labeling in each dimension (00, 01, 11, 10)3 concatenated gray labeling in each dimension

Select labeling scheme

Page 121: Simulating Turbo Codes using a Modular Simulation Platform

>> 2

ENTER:

Eb/No to start simulation>> 1Eb/No to end simulation>> 1

Eb/No step size>> 1

Number of blocks per Eb/No>> 5Number of decoder iterations per block>> 8

Eb/No = 1.000000, nvariance = 0.794328Eb/No [dB] = 1.000000, block 1 / 5iteration 1: 1.054688e-01iteration 2: 9.960938e-02iteration 3: 9.082031e-02iteration 4: 9.082031e-02iteration 5: 8.691406e-02iteration 6: 8.789062e-02iteration 7: 8.496094e-02iteration 8: 8.496094e-02

total time remaining: Oh Om 4s

Eb/No [dB] =iteration 1:iteration 2:iteration 3:iteration 4:iteration 5:iteration 6:iteration 7:iteration 8:

Eb/No [dB] =iteration 1:iteration 2:iteration 3:iteration 4:iteration 5:iteration 6:iteration 7:iteration 8:

Eb/No [dB] =iteration 1:iteration 2:iteration 3:iteration 4:iteration 5:iteration 6:iteration 7:iteration 8:

Eb/No [dBI =iteration 1:iteration 2:

1.000000, block 2 / 59.765625e-029.61914le-028.691406e-029.033203e-027.421875e-028.05664le-028.496094e-028.300781e-02

total time remaining: Oh Om 2s

1.000000, block 3 / 57.910156e-026.477865e-025.794271e-026.022135e-024.947917e-025.371094e-025.664062e-025.533854e-02

total time remaining: Oh Om ls

1.000000, block 4 / 58.227539e-026.396484e-025.419922e-025.419922e-024.199219e-024.052734e-024.248047e-024.150391e-02

total time remaining: Oh Om ls

1.000000, block 5 / 58.417969e-026.386719e-02

SAMPLE OUTPUT 121

Page 122: Simulating Turbo Codes using a Modular Simulation Platform

122 APPENDIX B

iteration 3: 5.019531e-02iteration 4: 4.375000e-02iteration 5: 3.359375e-02iteration 6: 3.242188e-02iteration 7: 3.398437e-02iteration 8: 3.320312e-02

total time remaining: Oh Om Os

simulation time for 5 blocks: Oh Om 2s

Page 123: Simulating Turbo Codes using a Modular Simulation Platform

SAMPLE OUTPUT

Output File test.txt

sourceSeed=1714-QAM

[point, label]

bit map: spEav = 2.00000Eb/No = 1.000

5120 bitsiterationiterationiterationiterationiterationiterationiterationiteration

1:2:3:4:5:6:

7:

8:

[(-1,-i), 00]

0000, nvariance = 0.794328

Error probability:8.417969e-026.386719e-025.01953le-024.375000e-023.359375e-023.242188e-023.398437e-023.320312e-02

simulation time for 5 blocks: Oh om 2s

123

[(-il), Oi] [(1,-1), 10] [(1,1), 1l]

Page 124: Simulating Turbo Codes using a Modular Simulation Platform
Page 125: Simulating Turbo Codes using a Modular Simulation Platform

APPENDIX C

Simulation Code

general.h

file: general.h

This file contains definitionsused by different modules.

of general purpose functions

/* basic functions */double sqr(double a);double min(double a, double b);double max(double a, double b);

/* convert between char[] and int *void intToCharArray(int s, char binary[], int v);int charArrayToInt(char binary], int v);

- 125 -

Page 126: Simulating Turbo Codes using a Modular Simulation Platform

126 SIMULATION CODE

general.c

/*

file: general.c

This source file contains code for general functions used byother routines.

*/

#include "general.h" /* general.h must come before math.h because max and minare already defined in math.h in some libraries. */

#include <math.h>

/*

function: sqr

This function returns the square of an input double.

Input double a

Output (a * a)

*/double sqr(double a)

return (a * a);

/* sqr /

function: min

This function returns the lesser of two doubles.

Input double adouble b

Output lesser of a and b

*/double min(double a, double b)

return ((a <= b) ? a : b);

} /* min

function: max

This function returns the greater of two doubles.

Input double adouble b

Output greater of a and b

*/double max(double a, double b)

return ((a >= b) ? a : b);

/* max *

function: intToCharArray

This function converts an integer value into binary.binaryt0] is the MSB of the integer, and binarytv-1] is the LSBof the integer.

Input : int s - the integer valuechar binary[] - array to hold binary valueint v - length of the binary array

I Output :

Page 127: Simulating Turbo Codes using a Modular Simulation Platform

general.c 127

I Modify : binary[]

void intToCharArray(int s, char binary(], int v)

/ if s = 6, v=3binary[] is 1 1 0indices are 0 1 2

so index 0 is MSB and index 2 is LSB

int i;

for (i=0; i < v; i++)binary[v-1-i} = ((s >> i) & 1);

/* intToCharArray /

/*

function: charArrayToInt

This function converts a binary number into an integer.binary[0] is the MSB of the integer, and binary[v-1] is the LSBof the integer.

Input char binary[] - array holding binary valueint v - length of array

Output the integer valueModify

int charArrayToInt(char binary[}, int v)

/* if s = 6, v=3binary[] is 1 1 0indices are 0 1 2

so index 0 is MSB and index 2 is LSB*/

int i, sum = 0;

for (i=0; i < v; i++)

sum += (int)binary[i] * (int)pow(2, (v-1-i));

return sum;

/* charArrayToInt /

Page 128: Simulating Turbo Codes using a Modular Simulation Platform

128 SIMULATION CODE

Iinkedlist.h

file: linkedList.h

This header file contains variable and function definitionsfor a linked list.

/* type definitions */typedef struct twoDSignalPointStruct

double i;

double q;

} twoDSignalPoint;

typedef struct listElementStructchar *value;twoDSignalPoint *signal;

struct listElementStruct *next, *prev;

listElement;

typedef struct linkListStructint valueLength;

listElement *head, *tail;

struct linkListStruct *output;

linkList;

/* init/deallocation functions */void llistInitVars(linkList* llist,void freeList(linkList* list);

int arrayLength);

/* adding elements */void addElement(linkList* llist, listElement* newEl);void addLLbits(linkList* llist, char bits[]); /* add 1 element with specified bits */void addLLsignal(linkList* llist, twoDSignalPoint points[]); /* add 1 element with specified signals */void addLLdata(linkList* llist, char bits]], twoDSignalPoint points]]); /* add 1 element with specified data */

/* deleting elements */void deleteFirstElement(linkList* llist);void deleteList(linkList* llist);

/* get element pointer */listElement* getElement(linkList* llist, int n);

char* getValue(linkList* llist, int n);twoDSignalPoint* getSignal(linkList* llist, int n);

/* show list contents */void showLLbits(linkList* llist);void showLLsignals(linkList* llist);

/* other functions */char notEmpty(linkList* llist);int getNumElements(linkList* llist);void copyList(linkList* orig, linkList* copy);

Page 129: Simulating Turbo Codes using a Modular Simulation Platform

linkedlist.c 129

Iinkedlist.c

file: linkedlist.c

This source file contains code for linked list functions.

*/

#include "linkedlist.h"

#include <stdio.h>#include <stdlib.h>

/* -------------- INITIALIZATION / DEALLOCATION FUNCTIONS --------- -----

/*

function: llistInitVars

This function initializes all variables in the input linked list.head and tail pointers are set to NULL, valueLength is set to the

I input variable arrayLength, and output points back to the listitself.

Input linkList *llistint arrayLength

OutputModify llist struct elements

void llistInitVars(linkList* llist, int arrayLength)

(*llist).head = NULL;

(*llist).tail = NULL;

(*llist).valueLength = arrayLength;(*llist).output = llist;

}; / llistInitVars *

function: freeList

Frees all dynamically allocated variables in the input linked list.

Input linkList *list - linked list pointerOutputModify list

void freeList(linkList* list)

deleteList(list);free(list);

S/* freeList */

/* --------- ----- ADDING ELEMENTS -------------------

function: addElement

Add an element to the end of the linked list.

Input linkList *llist - linked list pointerlistElement *newEl - new element pointer

OutputModify : llist, newEl

void addElement(linkList* llist, listElement* newEl)

(*newEl).next = NULL; /* last element, set next to NULL V

Page 130: Simulating Turbo Codes using a Modular Simulation Platform

SIMULATION CODE

if ((*l1ist).head == NULL)

(*llist).head = newEl;(*llist).tail = newEl;(*newEl).prev =NULL;

else

(*l(*list).tail).next = newEl;

(*newEl).prev = (*llist).tail;

(*l1ist).tail = newEl;

};

/* this is first element in the list *//* both head and tail point to this element */

no previous element */

at least one element in list already */

/* new element now at end of linked list */

/* addElement */

/*

function: addLLbits

Add a new element with the specified bits to the end of thelinked list.

Input linkList* llist - linked list pointerchar bits[] - array of bits

OutputModify llist

*/

void addLLbits(linkList* llist, char bits[])

{int i;

listElement* newEl = (listElement*) calloc(1, sizeof(listElement)); /* allocate memory for new element */

(*newEl) value = (char*) calloc( (*llist) .valueLength, sizeof (char)); /* allocate memory to hold bit values V(*newEl) signal = (twoDSignalPoint*) calloc( (*llist) .valueLength, sizeof (twoDSignalPoint)); /* allocate memory

to hold bit values */

for (i=O; i < (*llist).valueLength; i++)(*newEl).value(ii = bits[i]; '* copy bit values to new element */

addElement(llist, newEl);

/* addLLbits */

/*

function: addLLsignal

Add a new element with the specified points to the end of thelinked list.

Input linkList* llist - linked list pointertwoDSignalPoint points)] - array of 2D points

OutputModify

void addLLsignal(linkList* llist, twoDSignalPoint points[])

int i;

listElement* newEl = (listElement*) calloc(1, sizeof(listElement)); /* allocate memory for new element */

(*newEl) value = (char*) calloc((*llist) .valueLength, sizeof (char)); /* allocate memory to hold bit values */(*newEl) signal = (twoDSignalPoint*) calloc((*llist) .valueLength, sizeof(twoDSignalPoint)); /* allocate memory

to hold bit values s/

for (i=O; i < (*llist).valueLength; i++)(*newEl).signal[i] = points[i];

addElement(llist, newEl);

/* addLLsignal */

function: addLLdata

Add a new element withlinked list.

Input linkList*char

twoDSignalPoirOutputModify

the specified points to the end of the

llist - linked list pointerbits[] - array of bits

t points[] - array of 2D points

130

n

Page 131: Simulating Turbo Codes using a Modular Simulation Platform

linkedlist.c 131

*/void addLLdata(linkList* llist, char valueBits)], twoDSignalPoint points[])

int i;

listElement* newEl = (listElement*) calloc(1, sizeof(listElement)); /* allocate memory for new element /(*newEl) value = (char*) calloc( (*list) .valueLength, sizeof(char)); /* allocate memory to hold bit values /(*newEl) signal = (twoDSignalPoint*) calloc( (*llist) .valueLength, sizeof(twoDSignalPoint)); /* allocate memory

to hold bit values /

for (i=O; i < (*Ilist).valueLength; i++)

(*newEl).value[i] = valueBits[i]; /* copy bit values to new element V(*newEl).signal[i] = points[i];

addElement(llist, newEl);

/* addLLdata */

/* --------------- DELETING ELEMENTS --------

function: deleteFirstElement

Delete first element of linked list.

Input linkList* llist - linked list pointerOutputModify llist

void deleteFirstElement(linkList* llist)

listElement *temp;

if ((*Ilist).head != NULL)

temp = (*llist).head;(*llist).head = (* (*list).head).next; /* set next element in list as first /if ((*llist).head 1= NULL)

(*(*llist).head).prev = NULL;free((*temp).signal);free((*temp).value);

free(temp); /* delete previous first element *};

} /* deleteFirstElement *

function: deleteList

Delete all elements in the linked list.

Input : linkList* llist - linked list pointerOutputModify : llist

*/

void deleteList(linkList* llist)

while ((*llist).head != NULL)deleteFirstElement(llist);

S/* deleteList */

/* --------------- GETTING ELEMENT POINTERS -------------------

/*

function: getElement

Get nth element from linked list. n=1,2,3,...

Input : linkList* llist - linked list pointerint n - index of element to get

Output : pointer to the list element to returnModify

Page 132: Simulating Turbo Codes using a Modular Simulation Platform

132 SIMULATION CODE

listElement* getElement(linkList Illist, int n)

* n is from 1 to (# of element in list) */int i;listElement* temp; /* will hold pointer to list element to return */

if (llist == NULL)temp = NULL;

else

temp = (*1list).head; /* begin at first element of list */for (i=O; i<(n-l); i++) /* go down list until we reach nth element */

temp = (*temp).next;

};

return temp; /* return nth element */

/* getElement */

/*

function: getvalue

Get the bit array of an element of the linked list.

Input linkList* llist - linked list pointerint n - index of list element

Output : bit arrayModify

*/

char* getValue(linkList* llist, int n)

return (*(getElement(llist,n))).value;

/* getValue */

/*

function: getSignal

Get the signal point array of an element in the linked list.

Input linkList* llist - linked list pointerint n - index of list element

Output array of 2D pointsModify

twoDSignalPoint* getSignal(linkList* llist, int n)

return (*getElement(llist,n)).signal;

} /* getSignal */

/* ------------- DISPLAY LIST CONTENTS -------------

/*

function: showLLbits

Show the bits in every element of the linked list.

Input linkList* llist - linked list pointerOutputModify

void showLLbits(linkList* llist)

int i;

listElement* temp;

temp = (*llist).head;while (temp != NULL) /* traverse the list */

for (i=G; i < (*llist).valueLength; i++)

Page 133: Simulating Turbo Codes using a Modular Simulation Platform

printf("%d", (*temp).value i]);temp = (*temp).next;

};printf("\n");

} showLLbits */

function: showLLsignals

Show the signal points stored in every element of the list.

Input linkList* llist - linked listOutputModify

*/void showLLsignals(linkList* llist)

int i;listElement* temp;

temp = (*llist).head;while (temp != NULL) /* traverse the list */

for (i=O; i < (*llist).valueLength; i++)printf(" (%g,%g) ", (*temp).signal[i].i, (*temp).signal[i].q);

temp = (*temp).next;};printf("\n");

} /* showLLsignals */

/* --------------- OTHER FUNCTIONS -------------

/*

function: notEmpty

Test if there are any elements in the linked list

Input linkList* llist - linked list pointerOutput 0 if list is empty, else 1Modify

char notEmpty(linkList* llist)

return ((*llist).head != NULL);} /* notEmpty */

function: getNumElements

Get number of elements in the linked list.

Input : linkList* llist - linked list pointerOutput : number of elements in listModify

getNumElements(linkList* llist)

int count = 0;listElement* tempEl;

tempEl = (*llist).head;while (tempEl != NULL)

tempEl = (*tempEl).next;

count++;1;

return count;

/* getNumElements */

linkedlist.c 133

int{t

Page 134: Simulating Turbo Codes using a Modular Simulation Platform

134 SIMULATION CODE

function: copyList

Copy all elements in one list to another.

Input linkList* orig - pointer to original linked listlinkLIst* copy - pointer to linked list copy

OutputModify copy

*/void copyList(linkList* orig, linkList* copy)

int num, i;listElement* currEl;

deleteList(copy);

(*copy).valueLength = (*orig).valueLength;num = getNumElements(orig);currEl = getElement(orig, 1);for (i=0; i < num; i++)

addLLdata(copy, (*currEl).value, (*currEl).signal);currEl = (*currEl).next;

};

} /* copyList */

Page 135: Simulating Turbo Codes using a Modular Simulation Platform

source.h 135

source.h

/*

file: source.h

This header file contains function definitions for generatingbits.

/* selection function */void selectBlockSize(int *blockSize, int k, int numSys);

/* simulation command */void genBits(linkList* llist, int numBits);

/* debug/display function */void showArrayBits(char bits[}, int size);

Page 136: Simulating Turbo Codes using a Modular Simulation Platform

SIMULATION CODE

file: source.c

This file contains code for modules that generate bits.

#include "linkedlist.h"#include "source.h"

#include <math.h>#include <stdlib.h>#include <stdio.h>

--- SELECTION FUNCTION --------

function: selectBlockSize

Selects the number of bits in an encode/decode block. The blocksize must be divisible by the number of bits, k, used as input toa rate-k/n convolutional code. Further, the block size must alsobe divisible by the number of systematic bits per symbol.

Input int *blockSize - pointer to variable to hold block sizeint k - number of bits to input to a rate-k/n conv. encoderint numSys - number of systematic bits per symbol

OutputModify : blockSize

void selectBlockSize(int *blockSize, int k, int numSys)

int selection;char error;int nl, n2, lcm;

ni = k;n2 = numSys;/* assume k < numSys, so thatlcm = n2;

while ((lcm % nl) != 0)1cm += n2;

k fits onto one symbol */

printf("I----------------------------------------printf("I\n");printf(" ** must be divisible by %d **\n", lcm);printf("I\n");printf("I 1 1024\n");printf("I 2 4096\n");printf("I 3 5120\n");printf("I 4 6144\n");printf("I 5 15488\n");

printf("\n");

printf("I----------------------------------------printf("I Select number of bits per block\n");error = 1;while (error)

printf("j >>scanf("%d", &selection);if ((selection >= 1) & (selection <= 5))

error = 0;switch (selection)case 1:

*blockSize = 1024;break;

case 2:*blockSize = 4096;break;

case 3:

*blockSize = 5120;break;

case 4:*blockSize = 6144;break;

case 5:

};if (

*blockSize = 15488;break;

((blockSize) % lcm)

error = 1;

136

source.c

------------- \n");

0)

------- \n");

Page 137: Simulating Turbo Codes using a Modular Simulation Platform

source.c 137

printf("I ** error: block size not divisible by %d **\n", lcm);

elseprintf(" ** invalid selection **\n");

};

} /* selectBlockSize */

/* ------------------------ SIMULATION COMMAND FUNCTION ---------- /

function: genBits

Generate bits randomly. If the list is empty when this functionis called, add the new bits to the list. If the list is not emptywhen this function is called, then simply replace the bits in thelist with new bits. Because other functions may have added bitsto the list, delete remaining elements after enough bits aregenerated.

Input linkList* llist - linked list pointerint numBits - number of bits to generate

OutputModify llist

void genBits(linkList* llist, int numBits)

int i, j;char *bits;listElement *currEl, *headPtr, *tailPtr;

/* If list already exists, go through the list andreplace values. This way, we don't have to delete elements,then add elements again.

*/

bits = (char*) calloc((*llist) .valueLength, sizeof (char));currEl = (*llist).head;

for (i=G; i < (numBits/ (*llist) .valueLength); i++)

for (j=O; j < (*llist).valueLength; j++)

bits[ji = (char) (rand)) % 2);if (currEl != NULL)

(*currEl).value[j] = bits[j];I;if (currEl == NULL)

addLLbits(llist, bits);else

currEl = (*currEl).next;};

/* terminateEncoder) function may have appended bits to llist, soset tail to currEl->prev and delete the remaining elements */

if (currEl != NULL)headPtr = (*llist).head;tailPtr = (*currEl).prev;(*tailPtr).next = NULL;(*llist).head = currEl;deleteList(llist);/* only actually deletes elements starting at currEl */(*llist).head = headPtr;(*llist).tail = tailPtr;

};

free(bits);

/* genBits */

/* ----------------------- DISPLAY/DEBUG FUNCTION ----------------------

function: showArrayBits

Show the bits in an array.

Input : char bits[] - array of bitsint size ~ length of array

OutputModify

Page 138: Simulating Turbo Codes using a Modular Simulation Platform

SIMULATION CODE

showArrayBits(char bits[], int size)

int i;

for (i=0; i<size; i++)printf("%d", (int)bits[i]);

printf ("\n");

} /* showArrayBits */

138

void

Page 139: Simulating Turbo Codes using a Modular Simulation Platform

interleave.h 139

interleave.h

file: interleave.h

This header file contains variable and function definitions forinterleavers.

#include <stdio.h>

/* type definitions */typedef struct interleaverVarsStruct

int blockSize;int* permutePattern;

linkList* input;linkList* output;

} interleaverVars;

/* selection function */void selectInterleaver(interleaverVars* interleaver, int blockSize);

/* simulation command function */void doInterleave(interleaverVars* interleaver);

/* init/deallocation functions */ -void randomPatternInitVars(interleaverVars* interleaver, int numEl);void SrandomInitVars(interleaverVars* interleaver, int S1, int S2, int blockSize, int seed);int interleaverFileInitVars(interleaverVars* interleaver, FILE* fp, int numEl);void deinterleaverInitVars(interleaverVars* deinterleaver, interleaverVars* interleaver)void freeInterleaverVars(interleaverVars* interleaver);

/* display/debug function */void showPermutePattern(interleaverVars* interleaver)

/* other functions */void regroupltoK(linkList* thelist, int k);void regroup Ktol(linkList* thelist, int k);void outputPattern(interleaverVars* interleaver, FILE* fp);

/* AT&T 2-step semi-random interleaver functions */char canFillRest(int remainingIndices[], int index, interleaverVars* interleaver, int S1, int S2);void updateRemaining(int remainingIndices[], int index, int deltalndex);void genSrandomPattern(interleaverVars* interleaver, int Si, int S2);

Page 140: Simulating Turbo Codes using a Modular Simulation Platform

SIMULATION CODE

file: interleave.c

This source file contains code for all interleavers.

#include "linkedlist.h"#include "interleave.h"

#include <math.h>#include <stdio.h>#include <stdlib.h>

* ------------ SELECTION FUNCTION - -

function: selectInterleaver

Selects the type of interleaver to usepattern.

Input interleaverVars* interleaver -int numEl

OutputModify interleaver

in generating a permutation

interleaver pointerinterleaver depth

void selectInterleaver(interleaverVars* interleaver, int numEl)

fint selection;char error;int Sl, S2, seed;

char filename[80];FILE* fp;

printf("I---------------------------------------------------------\n");printf("I\n");printf("l 1 Random permutation \n");printf("I 2 Two-step semi-random algorithm (AT&T RN-029 standard)\n");printf("I 3 Read permutation pattern from file\n");printf("\n");

printf(" ---------------------------------------------------------\n");error = 1;while (error)

printf("I Select interleaver type\n");printf("I >> ");scanf("%d", &selection);if ((selection >= 1) & (selection <= 3))

error = 0;switch (selection)case 1:

srand(151);

randomPatternInitVars(interleaver, numEl);

break;

case 2:/* semi-random interleaver

Uses function: SrandomInitVars() to

printf(" ---------------------------------printf("I\n");printf("I ** %d elements **\n", numEl);printf("I\n");printf("I Sl, S2, seed\n");printf("I ------------ \n");printf("I 1 (16, 6, 151)\n");printf("I 2 (18, 12, 151)\n");printf("I 3 (23, 12, 151\n");printf("I 4 (25, 15, 151)\n");printf("I 5 (26, 15, 151)\n");printf(" \n");printf("I---------------------------------printf("I Select semi-random interleavererror = 1;while (error)

init interleaver

---------------

parameters\n");

printf("I >> ");scanf("%d", &selection);if ((selection >= 1) & (selection <= 5))

error = 0;

140

interleave.c

-\n");

Page 141: Simulating Turbo Codes using a Modular Simulation Platform

interleave.c 141

switch (selection)case 1:

Sl = 16;S2 = 6;seed = 151;break;

case 2:

51 = 18;S2 = 12;

seed = 151;break;

case 3:

Sl = 23;S2 = 12;seed = 151;

break;case 4:

Sl = 25;S2 = 15;seed = 151;

break;case 5:

Sl = 26;

S2 = 15;

seed = 151;break;

}; /* switch semi-random *printf("I generating interleave pattern...\n");printf ("I note: if this takes too long, restart with smaller parameters\n");SrandomInitVars(interleaver, Sl, S2, numEl, seed);

/* if selection ok */else

printf(" I ** invalid selection **\n");

}; /* while error */break;

case 3:/* get interleave pattern from a file

Uses function: interleaverFileInitvars) to init interleaver

printf("I---------------------------------------------------------\n");printf("I Enter input file name for %d elements\n", numEl);printf("I >> ");scanf("%s", filename);fp = fopen(filename, "r");if (fp == NULL)

error = 1;printf(" I * Unable to access file %s **\n", filename);

else

error = interleaverFileInitVars(interleaver, fp, numEl);fclose(fp);

};break;

/* switch selection*/

/* if interleaver selection ok */else

printf("I ** invalid selection **\n");

}; /* while invalid selection, error==l */

) /* selectinterleaver */

* ------------- SIMULATION COMMAND FUNCTION ------------------- f*

/*

function: doInterleave

Performs element by element interleaving on an input linked listand stores the permuted elements in an output linked list. Ifthe output list already exists, simply replace the element arrayswith new values. Otherwise, add new elements to the output list.

This function does not alter the input linked list.

Input : interleaverVars* interleaver - interleaver pointerOutputModify : (*interleaver).output

*/void doInterleave(interleaverVars* interleaver)

int i, j;char* tempchar;twoDSignalPoint* tempPt;listElement **tempEl, *currEl, *outEl;

Page 142: Simulating Turbo Codes using a Modular Simulation Platform

SIMULATION CODE

/* instead of deleteList((*interleaver).output), traverse list and

replace values

tempEl = (listElement**) calloc((*interleaver).blockSize, sizeof(listElement*));

/* makes sure input and output list valueLengths are the same */

(*(*interleaver).output).valueLength = (*(*interleaver).input).valueLength;

currEl = (*interleaver).input->head;/* get memory locations of individual list elements for input */for (i = 0; i < (*interleaver).blockSize; i++)

tempEl[(*interleaver).permutePattern[i]] = currEl;

currEl = (*currEl).next;

i = 0;outEl = (*interleaver).output->head;

while (i < (*interleaver).blockSize)if (outEl == NULL) /* add value and signal as a new element to list *

tempchar = (*tempEl[i]).value;tempPt = (*tempEl[i]).signal;addLLdata((*interleaver).output, tempchar, tempPt);i++;

else /* replace value and signal of current output element */

{for (j=o; j < (*interleaver).input->valueLength; j++)

(*outEl).value[j](*outEl).signal[j]

};outEl - (*outEl).next;i++;

};

free(tempEl);

I; /* doInterleave */

(*tempEl[i]).value[j];(*tempEl[i]).signal[j];

INIT/DEALLOCATE FUNCTIONS

function: randomPatternInitVars

Input : interleaverVars* interleaverint Sl

OutputModify : *interleaver

void

interleaver pointerminimum permute distance

randomPatternInitVars(interleaverVars* interleaver, int numEl)

int i;int rndNum, numDone;int* numbers;

numbers = (int*)calloc(numEl, sizeof(int));for (i=0; i < numEl; i++)

numbers[i] = i;

(*interleaver).blockSize = numEl;(*interleaver).permutePattern = (int*) calloc((*interleaver).blockSize, sizeof(int));(*interleaver).output = (linkList*) calloc(l, sizeof(linkList));llistInitVars((*interleaver).output, 0);

for (numDone=0; numDone < (numEl-1); numDone++)

rndNum = rand() % (numEl - numDone);

(*interleaver).permutePattern[numDone] = numbers[numDone + rndNum];

numbers[numDone + rndNum] = numbers[numDone];i;(*interleaver) .permutePattern~numEl-l] = numbers (numEl-l];

free(numbers);

} /* randomPatternInitVars *

function: SrandomInitVars

142

*/

Page 143: Simulating Turbo Codes using a Modular Simulation Platform

Initializes variables and generates an interleave pattern

according to the semi-random algorithm from ITU proposal RN-029.See description for function genSrandomPattern) for details.

Input : interleavervars* interleaver - interleaver pointer

int S1 - minimum permute distance

int S2 - minimum rearranged distance

int blockSize - number of elements to interleaveint seed - random number generator seed

Output :MOdify : (*interleaver).permutePattern

void SrandomInitVars(interleaverVars* interleaver, int Si, int S2, int blockSize, int seed)

(*interleaver).blockSize = blockSize;

(*interleaver) permutePattern = (int*) calloc( (*interleaver) .blockSize, sizeof (int)

(*interleaver) output = (linkList*) calloc(1, sizeof(linkList))

1listInitVars((*interleaver).output, 0);

srand(seed);

genSrandomPattern(interleaver, Sl, S2);

} /* SrandomInitVars */

function: deinterleaverInitVars

Initializes a de-interleaver based on an

permute pattern. The permute pattern of

the inverse of that of the interleaver.

Input interleaverVars* deinterleaver -interleaverVars* interleaver -

OutputModify deinterleaver

existing irterleaverthe de-interleaver is

deinterleaver pointerinterleaver pointer

void deinterleaverInitVars(interleaverVars* deinterleaver, interleaverVars* interleaver)

int i;

(*deinterleaver) .blockSize = (*interleaver) .blockSize;(*deinterleaver) permutePattern = (int*) calloc( (*deinterleaver) .blockSize, sizeof(int)

for (i=O; i < (*interleaver).blockSize; i++)(*deinterleaver) .permutePattern[(* interleaver) .permutePattern[i]] = i;

(*deinterleaver) .output = (linkList*) calloc(1, sizeof(linkList))

llistinitVars((*deinterleaver).output, 0);

} /* deinterleaverInitVars */

function: interleaverFileInitVars

Reads an interleave pattern from a file. The first entry of thefile is the interleaver depth and must match input parameter numEl.The remaining entries are the permutation indices.

interleaverVars* interleaver

FILE* fpint numEl

t :y : interleaver

interleaver pointerpointer of file to read frominterleaver depth

interleaverFileInitVars(interleaverVars* interleaver, FILE* fp, int numEl)

int i=O;

int size;int error;

fscanf(fp, "%d", &size);if (size == numEl) /* file has correct interleaver depth */

error = 0;(*interleaver).blockSize = size;(*interleaver) permutePattern = (int*) calloc( (*interleaver) blockSize, sizeof(int))

for (i=0; i < (*interleaver) blockSize; i++)fscanf(fp, "Id", &(*interleaver) .permutePattern[i]

(*interleaver) .output = (linkList*) calloc(l, sizeof(linkList))llistInitVars((*interleaver).output, 0);

interleave.c 143

Input

OutpuModif

int

Page 144: Simulating Turbo Codes using a Modular Simulation Platform

144 SIMULATION CODE

else /* file has wrong interleaver depth *

error = 1;printf("\n** Input file contains incorrect interleaver depth **\n\n");

};

return error;

/* interleaverFileInitVars */

function: freeInterleaverVars

Free dynamically allocated memory for interleaver.

Input : interleaverVars* interleaver - interleaver pointer

OutputModify : interleaver

*/void freeInterleaverVars(interleaverVars* interleaver)

free((*interleaver).permutePattern);freeList((*interleaver).output);

/* freeInterleaverVars /

/* ------------- DISPLAY/DEBUG FUNCTIONS -------------------

/*

function: showPermutePattern

Print the permute pattern to the screen.

Input : interleavervars* interleaver - interleaver pointerOutputModify

*/void showPermutePattern(interleaverVars* interleaver)

int i;

printf("Permute pattern: ");for (i=0; i < (*interleaver).blockSize;i++)

printf(" - %d", (*interleaver).permutePattern[i]);

printf(" -\n");

} /* showPermutePattern */

/* ------------- OTHER FUNCTIONS -------------------

function: regroupltoK

The input linked list contains 1 bit per list element. Thisfunction regroups the list so that there are K bits per listelement. The resulting list will have a factor of K lesslist elements.

Input : linkList* thelist - linked list pointerint k - number of bits per list element

OutputModify : thelist

"I

void regroup ltoK(linkList* thelist, int k)

int num, i, j;char *bits;twoDSignalPoint* values;

(*thelist).valueLength = k;bits = (char*) calloc(k, sizeof(char));values = (twoDSignalPoint*) calloc(k, sizeof(twoDSignalPoint));num = (int) (getNumElements(thelist) / k);for (i=O; i < num; i++)

for (j=O; j < k; j++)

Page 145: Simulating Turbo Codes using a Modular Simulation Platform

bits[j] = *getValue(thelist, 1);values[j] = *getSignal(thelist, 1);deleteFirstElement(thelist);

addLLdata(thelist, bits, values);

1;

free(bits);

/* regroup ltoK *

function: regroupKtol

The input linked list contains K bit perfunction regroups the list so that thereelement. The resulting list will have a

list elements.

Input : linkList* thelistint k

OutputModify : thelist

list element. Thisis 1 bit per listfactor of K more

linked list pointernumber of bits per list element

void{

regroup Ktol(linkList* thelist, int k)

int num, i, j;

char bit;

twoDSignalPoint point;

(*thelist).valueLength = 1;num = getNumElements(thelist);for (i=O; i < num; i++)

ffor (j=0; j < k; j++)

bit = (getValue(thelist, 1)) [IjI;point = (getSignal (thelist, 1)) [j];addLLdata(thelist, &bit, &point);

deleteFirstElement(thelist);

/* regroupKtol s/

/*

function: outputPattern

Prints the interleaver depth and permute pattern to a file.

Input interleaverVars* interleaver

FILE* fp

OutputModify : fp

interleaver pointeroutput file pointer

void outputPattern(interleaverVars* interleaver, FILE* fp)

int i=O;

fprintf (fp, "%d\n", (*interleaver) .blockSize)while (i < (*interleaver).blockSize)

fprintf(fp, "%d\n", (*interleaver) .permutePattern[i++]);

/* outputPattern */

/* ------------- AT&T 2-STEP SEMI-RANDOM INTERLEAVER FUNCTIONS --

function: canFillRest

Determines whether the remaining unused permute indices cansatisfy the semi-random algorithm. If not, then the algorithmwill need to be restarted.

Input : int remainingIndices[] - array to keep track of which permute indices have beenused and which are available

int index - index of remainingIndices[ that divides used and

interleave.c 145

{

--- */

Page 146: Simulating Turbo Codes using a Modular Simulation Platform

146 SIMULATION CODE

available permute indicesint Sl - element by element minimum separation distanceint S2 - cell by cell minimum separation distanceinterleaverVars* interleaver - interleaver pointer

Output ;1 if s-random algorithm can be completed, 0 otherwise

*/char canFillRest(int remainingIndices[], int index, interleaverVars* interleaver, int S1, int S2)

int i, j, possIndex;char canFilll=O, canFill2=0;

i = index;while ( (!canFilll 11 !canFill2) && (i < (*interleaver).blockSize) ) /* check both Sl and S2 criteria *

possIndex = remainingIndices[i++];canFill2 = (abs(possIndex-index) > S2);if (canFill2)

j = (index <= Sl) ? 0 : (index-Sl);canFilll = 1;while (j < index)

canFilll = canFilll && (abs((*interleaver)

/* check next permute index/* check S2 criterion */

/* compare to Sl previous cells */

/* see if permute index can satisfy */* the semi-random algorithm */.permutePattern[j) - possIndex) > Sl);

1;};

return (canFilll && canFill2);

}; /* canFillRest */

function: updateRemaining

This function is used byhas "blockSize" cells andremainingIndices[O..(indexremainingIndices[index..(bThis function updates rem

Input : int remainingIndi

int index

int deltaIndex

OutputModify remainingIndices

enSrandomPattern. The array remainingIndices[]contains the permute indices.x-1)] contains permute indices that have already been used.blockSize-1)] contains those that haven't been used.iningIndices[] when another permute index is used.

ces [] array to keep track of which permute indices have beenused and which are availableindex of *remainingIndices that divides used andavailable permute indicesremainingIndices[index + deltaIndex] contains the permuteindex just used

void updateRemaining(int remainingIndices[], int index, int deltaIndex)

int swapIndex, swapValue;

swapIndex = index + deltaIndex; /* index of used permute index *swapValue = remainingIndices[swapIndex]; /* the used permute index *remainingIndices[swapIndex] = remainingIndices[index]; /* update *remainingIndices *remainingIndices[index] = swapValue;

}; /* updateRemaining *

function: genSrandomPattern(void)

Generates a semi-random sequence of dist*inct integers between 0 and

(blockSize-1). p(i) denotes the permuted sequence. Excerpt from RN-029:

"Each randomly selected integer p(i) is compared with the previous selectionsp(j) to check that if (i-j) <= S1 then pi(i)-pi(j) > Sl. We alsoinsist that p) must satisfy li-p(i) > S2."

In the end we will need "blockSize" distinct numbers from 0.. (blockSize-1)Thus, we may find that with a few numbers left to choose from, we are unableto satisfy the algorithm criterion and may have to start the process over fromthe beginning. The functions canFillRest() and updateRemaining() are used toperform this check.

InputOutput

void genSrandomPattern(interleaverVars* interleaver, int S1, int S2){

int index, Sindex, j, deltaIndex;

Page 147: Simulating Turbo Codes using a Modular Simulation Platform

interleave.c 147

int* remainingIndices = (int*) calloc((*interleaver) blockSize, sizeof(int))

while (index < (*interleaver).blockSize) /* don't have all new numbers */

for (j=O; j < (*interleaver) .blockSize;j++)remainingIndices[j]=j; /* initialize *remainingIndices */

index = 0;

while (canFillRest(remainingIndices, index, interleaver, S1, S2))

deltaIndex = rand) % ((*interleaver).blockSize-index); /* choose from remaining permute indices*/

Sindex = remainingIndices[index + deltaIndex]; /* get the unused permute index *if (abs(Sindex - index) > S2) /* check S2 criterion */

j = (index <= Sl) ? 0 : (index-Sl); /* compare with S1 previous indices */while ((abs((*interleaver) .permutePattern[j] - Sindex) > S) && (j < index))

j++;if (j == index) /* new permute index is okay to use /

(*interleaver).permutePattern[index = Sindex;updateRemaining(remainingIndices, index, deltaIndex);index++;

};};

}; /* while we can fill the rest of the permutation pattern */

}; /* while not done generating Sindex's */

free(remainingIndices);

}; /* genSrandomPattern */

Page 148: Simulating Turbo Codes using a Modular Simulation Platform

148 SIMULATION CODE

conv.h

file: convRoutines.h

This header file contains variable and function definitions forconvolutional encoders.

*/

/* type definitions */

typedef struct branchStructint Sl, S2;int d;

int p;branch;

typedef struct encoderVarsStructbranch** trellis;int* terminator;

char* state;int k;int r;

int V;

linkList* input;linkList* output;

encoderVars;

/* selection function */void selectEncoder(encoderVars* encoder, int kSel);

/* simulation command function */void encodeBlock(encoderVars* encoder);void terminateEncoder(encoderVars* encoder);

/* init/deallocate functions */void duplicateEncoder(encoderVars* encoderl, encoderVars* encoder2);void ratel2initVars(encoderVars* encoder, char fbPoly[], char ffPoly[]);void ratekkllnitVars(encoderVars* encoder, char fbPoly[], char** ffPoly, int k);void CCinitVars(encoderVars* encoder, int degree);void freeEncoderVars(encoderVars* encoder);

/* display/debug function */void showTrellis(encoderVars* encoder);

/* generator polynomial functions */void convertoctal(char octalChar, char binaryRep[]);void convertString(char polyString[}, char coeffArray[], int v);int getDegree(char polyString[]);void setFeedback(char* polyString, char* feedbackCoefficient, int v);void setFeedforwG(int parityNum, int inputNum, char* polyString, char*** forwCoefficient, int v);

/* trellis functions */void ratelnSetBranch(branch* br, char*** ffCoeff, char* fbCoeff, int v, int r)void ratekklSetBranch(branch* br, char*** ffCoeff, char* fbCoeff, int v, int k);int nextState(encoderVars* encoder, listElement* inputEl);

Page 149: Simulating Turbo Codes using a Modular Simulation Platform

conv.c

file: convRoutines.c

This source file contains code for convolutional encoder.

*/

#include "general.h"#include "linkedlist.h"#include "conv.h"

#include#include#include#include

<math.h><stdio.h><string.h><stdlib.h>

---- ---------- SELECTION FUNCTION -

function: selectEncoder

Called from the main program to selectlist of options.

Input encoderVars* encoderint kSel

OutputModify : encoder

void selectEncoder(encoderVars*

int selection, k;char error;char *fbPoly, **ffPoly;

----------------- */

an encoder from a specified

pointer to encoder structnumber of input bits to encoder

encoder, int kSel)

if ((kSel >= 1) && (kSel <= 3))

/* kSel=1 rate-1/22 rate-2/3

3 rate-3/4

switch (kSel) {case 1: /* rate-1/2 code */

ffPoly = (char**) calloc(1, sizeof(char*));printf("-----------------------------------------printf("j\n");

printf(" I 1 fbPoly = 23 ffPoly = 35\n");printf(" I 2 fbPoly = 7 ffPoly = 5\n");printf(" I 3 fbPoly = 15 ffPoly = 17\n");printf("I\n");printf("|---------------------------------------

printf ("I select generator polynomials\n");error = 1;while (error)

printf("I >> ");scanf("%d", &selection);if ((selection >= 1) & (selection <= 3))

error = 0;switch (selection)case 1:

fbPoly = "23";ffPoly[0] = "35";break;

case 2:fbPoly = "5";ffPoly[O] = "7";break;

case 3:fbPoly = "15";ffPoly[0] = "17";break;

}; /* switch rate-1/2 *//* if rate-1/2 select ok /

elseprintf("I ** invalid selection **\n");

}; /* while select rate-1/2 error */ratel2initVars(encoder, fbPoly, ffPoly[0]);break; /* break case 1: rate-1/2 */

conv.c 149

Page 150: Simulating Turbo Codes using a Modular Simulation Platform

SIMULATION CODE

case 2: /* rate-2/3 code */ffPoly = (char**) calloc(2, sizeof(char*));printf("I---------------------------------------printf("I\n");printf("I 1 rate-2/3 -- fbPoly = 23, ffPolylprintf("I\n");printf("I---------------------- ------------printf("I Select generator polynomials\n");error = 1;while (error)

printf(" >>"scanf("%d", &selection);if ((selection >= 1) & (selection <= 1))

error = 0;switch (selection)case 1:

fbPoly = "31";

ffPoly[0] = "27";ffPoly[l] = "35";

break;}; /* switch rate-2/3 */

/ if rate-2/3 select ok */else

printf ("I ** invalid selection **\n");}; /* while select rate-2/3 errork = 2;ratekklInitVars(encoder, fbPoly, ffPoly, k);break; /* break case 2: rate-2/3 */

case 3: /* rate-3/4 code */ffPoly = (char**) calloc(3, sizeof(char"));printf("I---------------------------------printf("\n");printf("| 1 rate-3/4 -- fbPoly = 13 ffPolyl

printf(" \n");

printf("I---------------------------------------printf("I Select generator polynomials\n");error = 1;while (error)

printf("j >>scanf("%d", &selection);if ((selection >= 1) & (selection <= 1))

error = 0;switch (selection)case 1:

fbPoly = "15";ffPoly[O] = "11";ffPoly[l] = "13";ffPoly[2] = "17";

break;}; /* switch rate-3/4 */

};

} /* if rate-3/4 select ok */else

printf("I ** invalid selection **\n");/* while select rate-3/4 error */

--------------- \n");

35, ffPoly2 = 27\n") ;

11, ffPoly2 = 15, ffPoly3 = 17\n");

---------------- \n") ;

k = 3;ratekklInitVars(encoder, fbPoly, ffPoly, k);break; /* break case 3: rate-3/4 */

/* switch rate select */

free(ffPoly);

/* if kSel in correct range */

/ selectEncoder */

/* ------------------ SIMULATION COMMAND FUNCTION ----------------

function: encodeBlock

This function encodes an entire block of bits. This functionis called from the simulation main program.

Input : encoderVars* encoder - pointer to encoder structOutputModify : encoder output contains parity bits

void encodeBlock(encodervars* encoder)

int i, j;char* parityBits;listElement *inputEl, *currEl, *headPtr, *tailPtr;

150

Page 151: Simulating Turbo Codes using a Modular Simulation Platform

conv.c 151

parityBits = (char*)calloc((*encoder).r, sizeof(char));currEl = (*encoder).output->head; /* access output list elements */inputEl = (*encoder).input->head; /* access input list elements */

for (i=0; i < (*encoder).v; i++) /* set initial state to 0 */(*encoder).state[i] = 0;

while (inputEl != NULL) /* go through entire input list */

intToCharArray(nextState(encoder, inputEl), parityBits, (*encoder).r); /* generate parity bits */for (j=0; j < (*encoder).r; j++) /* add parity bits to output list */

if (currEl == NULL)addLLbits ((*encoder) output, &parityBits(j])

else{

(*currEl).value[0] = parityBitsfj;currEl = (*currEl).next;

};inputEl = (*inputEl).next;

};

/* now delete the rest of the output list, which may have extra elements appendedby terminateEncoder() */

if (currEl != NULL)

headPtr = (*encoder).output->head;tailPtr = (*currEl).prev;(*tailPtr).next = NULL;(*encoder).output->head = currEl;deleteList((*encoder).output); /* only actually deletes elements starting at currEl "/(*encoder).output->head = headPtr;(*encoder).output->tail = tailPtr;

1;

}; /* encodeBlock */

/*

function: terminateEncoder

Generates bits to terminate the encoder to zero state. Itdoes this by using the trellis termination tree, stored inarray terminator[]. The terminating bits are added to the encoderinput list, and the corresponding parity bits are added to theencoder output.

Input encoderVars* encoder - pointer to encoder structOutputModify encoder.input, encoder.output

void terminateEncoder(encoderVars* encoder)

int S, d, bit;char* temp = (char*) calloc((*encoder).k, sizeof(char));

/* need v bits to terminate, there are k bits / branch, so v/k branches.now if v/k is not an integer, then we'll have ceil(v/k) branches andceil(v/k) * k bits. */

for (bit = 0; bit < ((*encoder).v / (*encoder) .k); bit++)

S = charArrayToInt((*encoder).state, (*encoder).v);d = (*encoder).terminator[S];intToCharArray((*encoder) trellis[S] [d] .d, temp, (*encoder) .k);addLLbits((*encoder).input, temp);intToCharArray((*encoder) trellis [S] [d] .p, temp, (*encoder) .r)addLLbits((*encoder).output, temp);intToCharArray((*encoder) trellis [S) [d] .S2, (*encoder) state, (*encoder) .v)

/* printf("term state: %d\n", (*encoder) .trellis[S] [d] .S2); *.

free(temp);

}; /* terminateEncoder */

/* ------------------ INIT/DEALLOCATE FUNCTION -------------------- /

function: duplicateEncoder

This function initializes a second encoder using the parameters

Page 152: Simulating Turbo Codes using a Modular Simulation Platform

SIMULATION CODE

of a first encoder.

Input encoderVars* encoderlencoderVars* encoder2

OutputModify encoder2

void{

pointer to original encoder structpointer to duplicate encoder struct

duplicateEncoder(encoderVars* encoderl, encoderVars* encoder2)

int state, inp;

(*encoder2).k = (*encoderl).k;CCinitVars(encoder2, (*encoderl).v);for (state = 0; state < pow(2, (*encoder2).v) ; state++)

(*encoder2).terminator[state] = (*encoderl).terminator[state];for (inp = 0; inp < pow(2, (*encoder2).k); inp++)

(*encoder2).trellis[state] [inp] = (*encoderl).trellis[state)[inp];

};

/* duplicateEncoder *

function: ratel2initVars

This function initializefor a rate-1/2 encoder.variables, and uses thegenerate the trellis. Erstored in input arrays fl

Input : encoderVars* en;char fbichar ff1

OutputModify : encoder

void

s convolutional encoder variablesIt allocates memory for all structrate-/n encoder structure toncoder generator functions are alreadybPoly[] and ffPoly[].

coderPoly[]

Poly[}

- pointer to encoder struct- string describing feedback polynomial- string describing feedforwrad polynomial

ratel2initVars(encoderVars* encoder, char fbPoly[], char ffPoly[])

int i, j;char*** forwCoefficient;char* feedbackCoefficient;int numStates;int* done;linkList statelist;twoDSignalPoint S, newS;

/* indices *//* holds feedforward coefficients/* holds feedback coefficients */

/* note: will ffPoly always have the correct degree??(*encoder).k = 1;CCinitVars(encoder,getDegree(ffPoly));

/* rate-l/2 encoder, k = one input */

feedbackCoefficienf = (char*) calloc ((*encoder).v + 1, sizeof(char));setFeedbackG(fbPoly, feedbackCoefficient, (*encoder).v);

forwCoefficient = (char***) calloc ((*encoder).r, sizeof(char**));for (i=0; i < (*encoder).r; i++)

/* allocate memeory *

/* allocate memory */

forwCoefficient[ii = (char**) calloc ((*encoder).k, sizeof(char*));for (j=0; j < (*encoder).k; j++)

forwCoefficient [i] [j] = (char*) calloc ( (*encoder) .v + 1, sizeof (char)); /* (v+l) feedforwardcoefficients */

};setFeedforwG(l, 1, ffPoly, forwCoefficient, (*encoder).v);

numStates = (int)pow(2, (*encoder).v);for (i=0; i < numStates; i++)

for (j=0; j < pow(2, (*encoder).k); j++)ratelnSetBranch(&(*encoder) trellis[i] [j], forwCoefficient, feedbackCoefficient, (*encoder) .v,

(*encoder).r);

llistInitVars(&statelist, 1);S.i = 0; /* set first element in statelist to be zero state, then search backwards *addLLsignal(&statelist, &S);done = (int*) calloc(numStates, sizeof(int));for (i=0; i < numStates; i++)

done[i] = 0;

/* find trellis termination path for each state /while(notEmpty(&statelist))

S = getSignal(&statelist, 1) [0];deleteFirstElement(&statelist);/* now find all states that transition to S */for (i=0; i < numStates; i++)

for (j=0; j < pow(2, (*encoder).k); j++)if (((*encoder).trellis[i} [j].S2 == S.i) && (done[i) == 0))

done[i] = 1;

152

Page 153: Simulating Turbo Codes using a Modular Simulation Platform

conv.c 153

(*encoder).terminator[i] = j;newS.i = i;addLLsignal(&statelist, &newS);

}; /* now know how to terminate trellis from any state-- use (*encoder) terminator[] as encoder input until zero state reached */

for (i=O; i < (*encoder).r; i++)

for (j=G; j < (*encoder).k; j++)free(forwCoefficient[i] [ji);

free(forwCoefficient[i]);

free~feedbackCoefficient);free(done);

S/* rate1nitVars '/

function: ratekklInitVars

This function initializes convolutional encoder variablesfor a rate-k/(k+l) encoder. Encoder generator functions arealready in input arrays fbPoly[] and ffPoly[] [I

Input encoderVars* encoder - pointer to encoder structchar fbPoly[) - string describing feedback polynomialchar ffPoly[] - string describing feedforwrad polynomial

OutputModify encoder

void ratekklInitVars(encoderVars* encoder, char fbPoly[, char** ffPoly, int k){

int i, j; /* indices */int numStates;

int* done;linkList statelist;twoDSignalPoint S, newS;char*** forwCoefficient; /* holds feedforward coefficients *//* each forwCoefficient[r] [k] [] holds the generator coefficient for

parity bit # r and input bit # k.forwCoefficient[r] [k] [0] corresponds to a 1, andforwCoefficient[r] [k] [v] corresponds to D'v

*/

char* feedbackCoefficient; /* holds feedback coefficients */

(*encoder).k = k; /* rate-k/(k+) encoder *//* note: will ffPoly always have the correct degree?? */CCinitVars(encoder,getDegree(ffPoly[o());

feedbackCoefficient = (char*) calloc ((*encoder) .v + 1, sizeof (char)); /* allocate memeory */setFeedbackG(fbPoly, feedbackCoefficient, (*encoder) .v);

forwCoefficient = (char***) calloc ( (*encoder) .r, sizeof (char**)); /* allocate memory */for (i=0; i < (*encoder).r; i++)

{forwCoefficient [i] = (char**) calloc ((*encoder) .k, sizeof (char*)for (j=O; j < (*encoder).k; j++)

forwCoefficient[i] [jI = (char*) calloc ((*encoder) .v + 1, sizeof (char)); /* (v+l) feedforwardcoefficients */

};for (i=O; i < (*encoder).k; i++)

setFeedforwG(l, (i+l) , ffPoly[i] , forwCoefficient, (*encoder) .v)

numStates = (int)pow(2, (*encoder).v);for (i=O; i < numStates; i++)

for (j=0; j < pow(2, (*encoder).k); j++)ratekklSetBranch(&(*encoder) .trellis i] [j , forwCoefficient, feedbackCoefficient, (*encoder) .v,

(*encoder).k);

llistInitVars(&statelist, 1);

S.i = 0; /* set first element in statelist to be zero state, then search backwards '/addLLsignal(&statelist, &S);done = (int*) calloc(numStates, sizeof(int))for (i=0; i < numStates; i++)

done[i] = 0;

/* find trellis termination path for each state */while(notEmpty(&statelist))

S = getSignal(&statelist, 1) [01;deleteFirstElement(&statelist);/* now find all states that transition to S */for (i=0; i < numStates; i++)

for (j=0; j < pow(2, (*encoder).k); j++)if (((*encoder) .trellis[i] [j] .S2 == S.i) && (done[i] == 0))

done[i] = 1;

Page 154: Simulating Turbo Codes using a Modular Simulation Platform

154 SIMULATION CODE

(*encoder).terminator[i] = j;newS.i = i;addLLsignal(&statelist, &newS);

};/* now know how to terminate trellis from any state

-- use (*encoder) .terminator[] as encoder input until zero state reached */

for (i=O; i < (*encoder).r; i++)

for (j=O; j < (*encoder).k; j++)free(forwCoefficient[i][jl);

free(forwCoefficient[i]);};free(feedbackCoefficient);free(done);

/* ratekklInitVars */

/*

function: CCinitVars

Initializes class variables for any rate-k/(k+l) convolutionalcode. Assumes only 1 parity bit.

Input encoderVars* encoder - pointer to encoder structint degree - highest degree of generator polynomials

OutputModify encoder

void CCinitvars(encoderVars* encoder, int degree)

int i , j, states, branches;

(*encoder).r = 1; /* only 1 parity bit */(*encoder).v = degree;

(*encoder).output = (linkList*) calloc (1, sizeof(linkList));llistInitVars((*encoder).output, 1);

(*encoder) .state = (char*) calloc((*encoder).v, sizeof (char));for (i=O; i < (*encoder).v; i++)

(*encoder).state[i] = 0;

states = (int)pow(2, (*encoder).v);(*encoder).terminator = (int*) calloc(states, sizeof(int));

branches = (int)pow(2, (*encoder).k);(*encoder) .trellis = (branch**) calloc(states, sizeof (branch*))for (i=O; i < states; i++) f

(*encoder) .trellis[i] = (branch*) calloc(branches, sizeof (branch));for (j=0; j < branches; j++)

(*encoder).trellis[i] ][j.Sl =i;(*encoder).trellis[i] [j].d =j;

};};

/*CCinitvars */

function: freeEncoderVars

Deallocates memory for encoder struct variables.

Input : encoderVars* encoderOutputModify : encoder.

void freeEncoderVars(encoderVars* encoder)

int m, states, branches;

free((*encoder).state);

states = (int)pow(2, (*encoder).v);branches = (int)pow(2, (*encoder).k);for (m=0; m < states; m++)

free((*encoder).trellis[m]);free((*encoder).trellis);

freeList((*encoder).output);

/* freeEncoderVars */

Page 155: Simulating Turbo Codes using a Modular Simulation Platform

---------------- DISPLAY/DEBUG FUNCTION ---------------------- /

function: showTrellis

Prints the trellis description to the screen.

Input encoderVars* encoder - point to encoder struct variablesOutputModify

void showTrellis(encoderVars* encoder)

int S, d, states, branches;

states = (int)pow(2, (*encoder).v);branches = (int)pow(2, (*encoder).k);printf("Sk-1 dk pk Sk\n");printf( "---- -- ------ ---- \n");for (S=O; S < states; S++)

for (d=O; d < branches; d++)printf("%d %d %d

}; /* showTrellis */

/* ------------------- GENERATOR POLYNOMIAL FUNCTIONS

%d\n", (*encoder).trellis[S] [d].SI,(*encoder).trellis(S} [d].d,(*encoder).trellis[S] [d].p,(*encoder).trellis[S] [d].S2);

function: convertOctal

This function converts the string representation of an octalnumber into binary.

Input char octalChar - octal character, so 0 .. 7char binaryRep[] - 3 cell array to hold binary representation

OutputModify binaryRep

*/void convertOctal(char octalChar, char binaryRep[E)

*binaryRep = 0; /* MSB of octal value */*(binaryRep+l) = 0;*(binaryRep+2) = 0; /* LSB of octal value */if ((octalChar == '1') 1 (octalChar == '3') | (octalChar == '5') I (octalChar == '7'))

*(binaryRep+2) = 1;if ((octalChar == '2') 1 (octalChar == '3') ( (octalChar == '6') (octalChar == '7'))

*(binaryRep+l) = 1;if ((octalChar == '4') 1 (octalChar == '5') (octalChar == '6') (octalChar == '7'))

*binaryRep = 1;

} /* convertOctal */

function: convertString

This function converts the string representation of a generatorpolynomial into a char array.

Input char polyString] - string representation of polynomialchar coeffArray] - array of polynomial coefficients, O's and l's

OutputModify : coeffArray

*/

void convertString(char polyString[E, char coeffArray[], int v)

int i, length;char* temp;

length = strlen(polyString) ; /* numbertemp = (char*) calloc (3*length, sizeof(char)); /* allocfor (i=0; ialength; i++)

convertOctal(polyString[i], &(temp[3*i])); /* converfor (i=0; i<(v+l); i++)

of octal digits */ate max number of binary digits */

t each octal digit, store in temp[]

conv.c 155

Page 156: Simulating Turbo Codes using a Modular Simulation Platform

156 SIMULATION CODE

coeffArray[i) = temp[i+(3*length-(v+l))]; /* transfer last (v+l) values to coeffArray /

free(temp); /* free up memory used by temp[] V

} convertString /

function: getDegree

This function finds the degree of a generator polynomial.The degree of the polynomial is its highest exponent value.

Input char polyString{) - generator polynomial stringOutput (tempDeg-1) - degree of the polynomialModify

*/int getDegree(char polyString[I)

int length, tempDeg;char* temp = (char*) calloc(3, sizeof(char)); /* temporary variable to hold 3 binary values *

length = strlen(polyString); /* number of octal characters in string */tempDeg = 3* (length-1); /* all octal characters except first have 3 bits *convertOctal(polyString[O], temp); /* convert first octal char into binary *if (temp[0) == 1)

tempDeg += 3; /* first octal char has no leading zeros /

else if (temp[l] == 1)tempDeg += 2; /* first octal char has 1 leading zero *

else if (temp)2] == 1)tempDeg++; /* first octal char has 2 leading zeros *

free(temp);

return (tempDeg-1); /* tempDeg = v+l. Return (tempDeg-1) = v *

/* getDegree */

function: setFeedbackG

This function converts the string representation of the feedbackgenerator polynomial into char array.

Input char polyString] - feedback polynomial stringchar feedbackCoefficient[] - array holding binary coefficientsint v - degree of polynomial

OutputModify feedbackCoefficient

*/void setFeedbackG(char polyString[], char feedbackCoefficient[], int v)

convertString(polyString,&feedbackCoefficient[0], v);

/* show conversion results /S int i, length;

length = strlen(polyString);printf("Feedback -- ");for (i=0;i<length;i++)

printf("%d", (int)polyString[i]);printf(" : ");for (i=0;i<(v+l);i++)

printf("%d", (int)feedbackCoefficient[i});printf ("\n")

S/* setFeedbackG *

function: setFeedforwG

This function converts the string representation of a generatorpolynomial into charean and calculates the degree of the polynomial.

Input : int parityNum - indicate which parity bit the polynomial is forint inputNum - indicate which input bit the polynomial is for

char polyString] - the polynomial stringchar*** forwCoefficient - array holding binary coefficientsint v - degree of polynomail

Output :Modify : forwCoefficient

Page 157: Simulating Turbo Codes using a Modular Simulation Platform

void setFeedforwG(int parityNum, int inputNum, char polyString[] char*** forwCoefficient, int v)

convertString(polyString, &forwCoefficient [parityNum-1] [inputNum-1 [0], v)/* show conversion results */

S int i, length;

length = strlen(polyString);printf("parity bit %d, input bit %d, G%d%d -- " parityNum, inputNum,for (i=O;i<length;i++)

printf("%d", (int)polyString[i]);printf(" : ");for (i=O;i<(v+l);i++)

printf ("%d", (int) forwCoefficient[parityNum-1] [inputNum-1] [i])printf ("\n")

setFeedforwG /

parityNum, inputNum);

TRELLIS FUNCTIONS --------

function: ratekklSetBranch

This function takes in k input bits and an encoder state andfinds 1 parity bit and the next state. The first delayregister corresponds to state[0] and the last state registercorresponds to state[v-1.

Input : branch* br - pointer to a Trellis branchchar*** ffCoeff - the feed-forward generator polynomialschar* fbCoeff - the feedback generator polynomialint v - degreeint k - number of input bits

Output :Modify : br

void ratekklSetBranch(branch* br, char*** ffCoeff, char* fbCoeff, int v, int k)

int i, numInputs;

char* state = (char*) calloc (v, sizeof(char));char* feedbackCoefficient = fbCoeff;char*** forwCoefficient = ffCoeff;char y;char* inputBits;

inputBits = (char*) calloc(k, sizeof(char));

intToCharArray((*br).Sl, state, v);intToCharArray((*br).d, inputBits, k);

/* y = (last state) + sum (all inputs with generator value 1) */y = state[v-1];for (numInputs=0; numInputs < k; numInputs++)

y = y ^ (forwCoefficient[I] [numInputs] [0] & inputBits[numInputs]);// The carrot ^ is the "xor" operator.

// state[i] = (state[i-11) + (y if feedback generator has term D^(v-i))D^ (v-i))

for

1;

+ sum (all inputs with generator value

(i=(V-1); i>O; i--) {state[i] = state[i-1] ^ (y & feedbackCoefficient[v-i]);for (numInputs=0; numInputs < k; numInputs++)

state[i] = state[i] ^ (forwCoefficient [0] [numInputs] [v-i] & inputBits [numInputs]

// first state = (y if feedback generator has term D'v) + sum (all inputs with generator value Dv)state[0] = (y & feedbackCoefficient[v]);for (numInputs=0; numInputs < k; numInputs++)

state [0] = state [0] ^ (forwCoefficient [0] [numInputs] [v] & inputBits [numInputs]

(*br).S2 = charArrayToInt(state, v);(*br).p = Oxl && y;

free(state);free(inputBits);

} // ratekklSetBranch

function: ratelnSetBranch

conv.c 157

*/

--------- */

Page 158: Simulating Turbo Codes using a Modular Simulation Platform

SIMULATION CODE

This function takes in 1 input bit and an encoder state and

finds (n-1) parity bits and the next state. The first delayregister corresponds to state[0] and the last state register

corresponds to state[v-1].

Input : brchchin

inOutputModify br

anch*ar*

ar*

tt

brffCoefffbCoeffvr

pointer to a Trellis branch

the feed-forward generator polynomialsthe feedback generator polynomialdegreenumber of parity bits

ratelnSetBranch(branch* br, char*** ffCoeff, char* fbCoeff, int v, int r)

int i, numOutputs;

char stateiTemp; /* temporarily hold statel value; *

char* state = (char*) calloc (v, sizeof(char));char* feedbackCoefficient = fbCoeff;char-*- forwCoefficient = ffCoeff;char input;

char* y;

y = (char*) calloc(r, sizeof(char)); '* y[] - hold r parity bit values */

intToCharArray((*br).S1, state, v);input = ((*br).d == 0) ? 0 : 1;

/* first state = (input bit) + sum (all states i for which feedback has term D^i)statelTemp = input;

for (i=l; i<(v+l); i++)stateiTemp = statelTemp ^ (state [i-1] && feedbackCoefficient [i]

/* output y[j] = sum (all states i for which there is a feedforward term D^i in polynomial j) /for (numOutputs = 0; numOutputs < r; numOutputs++)

y[numOutputs] = statelTemp & forwCoefficient[numOutputs] [0] [0]for (i=l; i<(v+l); i++)

y[numOutputs] = y[numOutputs] ^ (state[i-1] && forwCoefficient[numOutputs] [0] [i);

/* state[i] = state[i-1] */for (i=(v-1); i>0; i--)

state[i] = state[i-1};

/* finally set first state to temporary holding value *state[O] = stateOTemp;

(*br).S2 = charArrayToInt(state, v);(*br).p = charArrayToInt(y, r);

free(state);

/* ratelnsetBranch *

function: nextState

This function transstate. It takes inthe encoder, and re

Input encodervar

listElemenOutput parity bitModify encoder.st

itions a convolutional encoder to the nextput bit(s) from the encoder input, transitionsturns the parity bit generated by the transition.

s* encodert* inputElfrom state

ate

point to encoder structpointer to element with input bitstransition

int nextState(encoderVars* encoder, listElement* inputEl)

int S, d;

/a branch: input = d, parity = p

S ---------- > S2 /

S = charArrayToInt((*encoder).state, (*encoder).v);d = charArrayToInt((*inputEl) value, (*(*encoder) input) .valueLength);/* index 0 of value contains MSB, index (valueLength-1) contains LSB */intToCharArray((*encoder) trellis[S] [d].S2, (*encoder).state, (*encoder).v) ; /* update encoder state

return (*encoder).trellis[S] [d].p;

/* nextState */

158

void

Page 159: Simulating Turbo Codes using a Modular Simulation Platform

puncture.h 159

puncture.h

/*

file: puncture.h

This header file contains variable and function definitions ofpuncturing objects.

/* type definitions *typedef struct punctureVarsStruct

int numInputs;int punctureLength;int currIndex;

char** puncturePattern;

linkList** input;

linkList* output;} puncturevars;

typedef struct unPunctureVarsStructint numOutputs;

int punctureLength;int currIndex;char-- puncturePattern;

linkList* input;linkList* output;

} unPunctureVars;

/* simulation command functions */void punctureBlock(punctureVars* puncturer)void unpunctureBlock(unPunctureVars* unpuncturer);

/* init/deallocate functions */void twoPunctureInitVars(punctureVars* puncturer, char patternl)], char pattern2[]);void threePunctureInitVars(punctureVars* puncturer, char patternl[], char pattern2[], char pattern3[]);void unPunctureInitVars(unPunctureVars* unpunc, punctureVars* punc);void freePunctureVars (punctureVars* puncturer);void freeUnpunctureVars (unPunctureVars* unpuncturer)

/* other functions */char* stringTochar(char theString[], int punctureLength);char punctureBits (punctureVars* puncturer, listElement** inputEl)

Page 160: Simulating Turbo Codes using a Modular Simulation Platform

SIMULATION CODE

puncture.c

file: puncture.c

This source file contains code for puncture functions.

#include "linkedlist.h"#include "puncture.h"

#include <stdio.h>#include <stdlib.h>#include <string.h>

/* ------------------------ SIMULATION COMMAND FUNCTIONS ----

function: punctureBlock

This function punctures bits at the input linked lists. Thepuncture pattern is stored in the puncturer struct. Thisfunction is called from the main simulation program.

Input : punctureVars* puncturer - pointer to puncturer struct

OutputModify : output linked list

void punctureBlock(punctureVars* puncturer)

char result;int i, j, len;listElement **inputEl, *currEl;

(*puncturer).currIndex = 0;currEl = (*puncturer).output->head;inputEl = (listElement**) calloc((*puncturer).numInputs, sizeof(listElement*));for (j=O; j < (*puncturer).numInputs; j++)

inputEl[j} = (*puncturer).input[j]->head;

lenfor

= getNumElements((*puncturer).input[});(i=0; i < len; i++)

result = punctureBits(puncturer, inputEl);/* result > 1 means that all bits were punctured */

if (result <= 1)it (currEL == NULL)

addLLbits((*puncturer).output, &result);else

(*currEl).value[() = result;currEl = (*currEl).next;

};

for (j=S; j < (*puncturer).numInputs; j++)inputEl[j] = (*inputEl[j]).next;

free(inputEl);

I /* punctureBlock

function: unpunctureBlock

This function unpuncturers the input linked list intomultiple output linked lists. The unpuncture patternthe same as the puncture pattern and is stored in theunpuncturer struct. This function is called from theprogram.

Input : unPunctureVars* unpuncturer

OutputModify : output linked lists

is

main

160

Page 161: Simulating Turbo Codes using a Modular Simulation Platform

unpunctureBlock (unPunctureVars* unpuncturer)

int i;twoDSignalPoint LLR, puncturedLLR;

listElement **outputEl, *currEl;char done;

outputEl = (listElement**) calloc((*unpuncturer) numOutputs, sizeof(listElement*)for (i=0; i < (*unpuncturer).numOutputs; i++)

outputEl[i] = (&(*unpuncturer) output [i])->head;currEl = (*unpuncturer).input->head;

puncturedLLR.i = 0;puncturedLLR.q = 0;(*unpuncturer).currIndex = 0;

/* The puncture structure could be:

currIndex 0123

10000010

When currIndex = 3 and (*unpuncturer) input is empty, we still need tounpuncturer the last LLR, which will be 0 for both bits. So the whileloop condition must take this case into account.

alternatively currIndex 012 If blockSize=1024, we will be atindex=1 when (*unpuncturer).input

100 runs out of elements.010001

The condition to end is if the input list is already empty and we are stillrequesting an input element.

*/

done = 0;while (done == 0)

for (i = 0; i < (*unpuncturer).numOutputs; i++)

LLR = puncturedLLR;/* at most one bit will be not punctured... no more than one */if ( (*unpuncturer) .puncturePattern[i] [(*unpuncturer) currIndex] == 1)

if (currEl == NULL)done = 1;

else

LLR = (*currEl).signal[0];currEl = (*currEl).next;

};if (done == 0)

if (outputElti] == NULL)addLLsignal(&(*unpuncturer).output[ii, &LLR);

else

*(outputEl[i]->signal) = LLR;outputEl[i] = outputEl[i]->next;

1; /* if */

}; /* for */(*unpuncturer) .currIndex = ((*unpuncturer) .currIndex + 1) % (*unpuncturer) .punctureLength;

currIndex */

); /* while */

free(outputEl);

} /* unpunctureBlock */

------------------------- INIT/DEALLOCATE FUNCTION ------------

function: twoPunctureInitVars

Initializes class variables and sets up puncturing pattern fortwo input linked lists.

Input : punctureVars* puncturer - pointer to puncture structchar patternl[] - string specifying first puchar pattern2[] - string specifying second p

/* update

ncture patternuncture pattern

void

puncture.c 161

------ */

Page 162: Simulating Turbo Codes using a Modular Simulation Platform

162 SIMULATION CODE

Output :Modify : puncturer

void twoPunctureInitVars(punctureVars* puncturer, char patternl[], char pattern2[])

f(*puncturer).numInputs = 2;

(*puncturer).punctureLength = strlen(patternl);(*puncturer).currIndex = 0;(*puncturer).puncturePattern = (char**) calloc (2, sizeof(char*));(*puncturer) .puncturePattern[0] = stringTochar(patternl, (*puncturer) .punctureLength)(*puncturer) .puncturePattern[1] = stringTochar(pattern2, (*puncturer) .punctureLength)

(*puncturer).input = (linkList**) calloc(2, sizeof(linkList*));

(*puncturer).output = (linkList*) calloc(l, sizeof(linkList));llistInitVars((*puncturer).output, 1);

} /* twoPunctureInitVars */

function: twoPunctureInitVars

Initializes class variables and sets up puncturing pattern fortwo input linked lists.

Input : punctureVars* puncturer - pointer to puncture structchar patterni[] - string specifying first puncture patternchar pattern2[l] - string specifying second puncture patternchar pattern3[] - string specifying third puncture pattern

Output :Modify : puncturer

*/void threePunctureInitVars(punctureVars* puncturer, char patternl[], char pattern2[], char pattern3 []

(*puncturer).numInputs = 3;

(*puncturer).punctureLength = strlen(patternl);(*puncturer).currIndex = 0;(*puncturer).puncturePattern = (char**) calloc (3, sizeof(char*));(*puncturer) .puncturePattern[0] = stringTochar(patternl, (*puncturer) .punctureLength)

(*puncturer) puncturePatternl] = stringTochar(pattern2, (*puncturer) .punctureLength)

(*puncturer) .puncturePattern[2] = stringTochar(pattern3, (*puncturer) .punctureLength)

(*puncturer).input = (linkList**) calloc(3, sizeof(linkList*));

(*puncturer).output = (linkList*) calloc(l, sizeof(linkList));llistInitVars((*puncturer).output, 1);

/* threePunctureInitVars */

function: freePunctureInitVars

Deallocates memory for puncture struct variables.

Input : punctureVars* puncturer - pointer to puncture structOutputModify : puncturer

void freePunctureVars(punctureVars* puncturer)

int i;

for (i=0; i < (*puncturer).numInputs; i++)free((*puncturer).puncturePattern[i]);

free((*puncturer).puncturePattern);freeList((*puncturer).output);

S/* freePunctureVars */

function: unPunctureInitVars

Initializes variables in unpuncturer struct by using variablevalues in puncture struct.

Page 163: Simulating Turbo Codes using a Modular Simulation Platform

puncture.c 163

Input unPunctureVars* unpunc - pointer to unpuncturer structpunctureVars* punc - pointer to puncturer struct

OutputModify unpunc

*/void unPunctureInitVars(unPunctureVars* unpunc, punctureVars* punc)

int i;

(*unpunc).numOutputs = (*punc).numInputs;

(*unpunc).punctureLength = (*punc).punctureLength;(*unpunc).currIndex = 0;(*unpunc) .puncturePattern = (char**) calloc( (*punc) numInputs, sizeof(char*)(*unpunc) output = (linkList*) calloc( (*unpunc) .numOutputs, sizeof(linkList)

for (i=0; i < (*punc).numInputs; i++) I(*unpunc) .puncturePatterntil = (char*) calloc ((*unpunc) punctureLength, sizeof (char));(*unpunc) .puncturePatternfi] = (*punc) .puncturePattern[i]

llistInitVars(&(*unpunc).outputti], 1);};

/* unPunctureInitVars */

/*

function: freeUnpunctureInitVars

Deallocates memory for unpuncturer struct variables.

Input unPunctureVars* unpuncturer - pointer to unpuncturer structOutputModify unpuncturer

void freeUnpunctureVars(unPunctureVars* unpuncturer)

int i;

/* this routine causes problems -- don't use for now */for (i=0; i < (*unpuncturer).numOutputs; i++)

free((*unpuncturer).puncturePattern[i]);

freeList(&(*unpuncturer).output[ii);

};free((*unpuncturer).puncturePattern);

/* freeUnpunctureVars */

* -------- ---------- ----- OTHER FUNCTIONS ----------------------- /

/*

function: stringTochar

Moves a string of O's and l's into a char array of sizepunctureLength.

Input char theString[] - input puncture pattern stringint punctureLength - size of array

Output array containing O's and l'sModify

*/char* stringTochar(char theString[H, int punctureLength)

char* charPtr = (char*) calloc(punctureLength, sizeof (char));int i;

for (i=O; i<punctureLength; i++)charPtr[i] = (theStringi] == '0') ? 0 : 1; /* decide if the character is a 0 */

return charPtr;

/* stringTochar */

I function: punctureBits

Page 164: Simulating Turbo Codes using a Modular Simulation Platform

SIMULATION CODE

Performs bit puncturing according to specified pattern.

Input punctureVars* puncturer - pointer to puncturer struct

listElement** inputEl - pointers to input elements

Output value of the puncturing operation (0 or 1)Modify

*/char punctureBits(punctureVars* puncturer, listElement** inputEl)

int index, i;char temp;

char pout;

pout = 0;index = (*puncturer).currIndex;

(*puncturer) currIndex = ((*puncturer) currIndex + 1) % (*puncturer) .punctureLength;

*/

temp = (*puncturer).puncturePattern[0][index];

for (i=1; i < (*puncturer).numInputs; i++)

temp = temp II (*puncturer) .puncturePattern[i] [index];if (temp) /* not all of the bits are punctured */

pout = *(inputEl[0]->value) * (*puncturer).puncturePattern[0][index];for (i=1; i < (*puncturer).numInputs; i++)

pout = pout (* (inputEl[i) ->value) * (*puncturer) .puncturePattern[i[ [index]);

elsepout = 2;

return pout;

/* punctureBits */

/* update currIndex

164

Page 165: Simulating Turbo Codes using a Modular Simulation Platform

mapper.h 165

mapper.h

file: mapper.h

This header file contains variable and function definitionsfor bit mappers and symbol mappers.

#include <stdio.h>

/* type definitions *typedef struct bitMapVarsStruct

int b;char* pattern;char* symbolBits;int numUncoded, numSys, numParity;

} bitMapVars;

typedef struct oneDsymbolMapVarsStructint M;double* symbols;char** code;double Eav;

} oneDsymbolMapVars;

typedef struct twoDsymbolMapVarsStructint M;

twoDSignalPoint* symbols;char** code;double Eav;

} twoDsymbolMapVars;

typedef struct twoDsignalMapVarsStructbitMapVars bitMapper;twoDsymbolMapVars symbolMapper;

linkList* inputU;

linkList* inputS;linkList* inputP;linkList* output;

} twoDsignalMapvars;

/* selection functions /void selectBitMapper(bitMapVars* map);void selectSignalMapper(twoDsignalMapVars* map);

/* simulation command function */void mapBlock(twoDsignalMapVars* signalMap);

/* init/deallocate functions */void bitMapInitVars(bitMapVars* bitMapper, char* pattern);void normalMappingInitVars(twoDsignalMapVars* signalMapper, int numHalfBits)void QAMgcSignalMapInitVars(twoDsignalMapVars* signalMapper, int InumGBI, int InumGB2, int QnumGB1, int QnumGB2);void freeBitMapVars(bitMapVars* bitMap);void freeTwoDsymbolMapVars(twoDsymbolMapVars* map);void freeTwoDsignalMapVars(twoDsignalMapVars* signalMap);

/* display/debug functions */void showoneDmapping(oneDsymbolMapVars* mapper);void showTwoDmapping(twoDsymbolMapVars* mapper, FILE* fp);

/* bit mapper functions */void getNumBits(bitMapVars* bitMap);

/* symbol mapper functions */void PAMgcSignalSet(oneDsymbolMapVars* mapper, int numdrayBitsl, int numGrayBits2);void QAMSignalSet(twoDsymbolMapVars* symbolMapper, oneDsymbolMapVars tempI, oneDsymbolMapVars tempQ);double* createPAMlevels(int M);twoDSignalPoint formTwoDsymbol (twoDsignalMapVars* signalMapper)double findOneDsymbol(char* bits, oneDsymbolMapVars* map);twoDSignalPoint findTwoDsymbol(char* bits, twoDsymbolMapVars* map);

/* gray code functions */linkList* makeNbitGC(int numBits);linkList* concatCodes(linkList *MSBlist, linkList *LSBlist)char** createGrayCode(int numMSB, int numLSB, int M);

Page 166: Simulating Turbo Codes using a Modular Simulation Platform

SIMULATION CODE

mapper.c

file: mapper.c

This

#include#include#include#include

#include#include#include#include

source file contains code for the signal mapper.

"general.h""linkedlist.h""source.h""mapper.h"

<stdlib.h><stdio.h><string.h>

<math.h>

SELECTION FUNCTION

function: selectBitMapper

This function is called from the main simulation program toselect a bit map pattern for uncoded simulations.

Input : bitMapVars* map - pointer to bit mapperOutputModify map

void selectBitMapper(bitMapVars* map)

int selection;char error;char *pattern;

printf(" .----------------- -------------

printf("\n");printf("| 1 ss 4-pt uncodecprintf("I 2 ssss 16-pt\n");

printf("I 3 ssssss 64-pt\n");printf("I 4 ssssssss 256-pt\n");printf("I\n");

printf("I------------------------------printf("I select bit map pattern\n");

error = 1;while (error)

printf("j >> );scanf("%d", &selection);if ((selection >= 1) & (selection

I

----- \n");

simulation\n");

----------------

<= 4))

error = 0;switch (selection)case 1:

pattern = "ss";break;

case 2:pattern = "ssss";break;

case 3:pattern = "ssssss";break;

case 4:pattern = "ssssssss";break;

; /* switch selection */

bitMapInitVars(map, pattern);

/* if selection ok */else

printf("| ** invalid selection **\n");/* while error

S/* selectBitMapper */

166

d

Page 167: Simulating Turbo Codes using a Modular Simulation Platform

function: selectSignalMapper

This function is called from the main simulation program toselect a signal mapping.

Input : twoDsignalMapVars* mapOutputModify map

*/void selectSignalMapper(twoDsignalMapVars* map)

int half, pts, Igcl, Igc2, Qgcl, Qgc2;int selection;char error;

pts = (int)pow(2, (*map).bitMapper.b);half = (int) ((*map).bitMapper.b/2);

printf("-------------------------------------printf("I\n");printf("| 1 normal bit labeling (00, 01, 1

printf(" j 2 full gray labeling in each dimeprintf(" 3 concatenated gray labeling inprintf ("\n");printf("-------------------------------------error = 1;while (error)

printf("I Select labeling scheme\n"printf(I >> ");scanf("%d", &selection);if ((selection >= 1) & (selection <= 3))

{

-------------------- \n"

0, ll)\n");nsion (00, 01, 11, 10)\n");each dimension\n");

error = 0;switch (selection)case 1:

normalMappingInitVars(map, half);break;

case 2:Igcl = half;Igc2 = 0;Qgcl = half;Qgc2 = 0;

QAMgcSignalMapInitVars(map, Igcl, Igc2, Qgcl, Qgc2);break;

case 3:printf(" ------------------------------------------printf("| * number of upper bits in each dimensionprintf("I \n");

printf(I ENTER:\n");

printf(" I Number of upper bits in I dimension\n");printf("I >> ");scanf("%d", &Igcl);

Igc2 = half - Igcl;printf(" I Number of lower bits in I dimension = %d\printf("I \n");printf(I Number of upper bits in Q dimension\n");printf ("I >> );scanf("%d", Qgcl);Qgc2 = half - Qgcl;

printf(" I Number of lower bits in Q dimension = %d\/* Igcl, Qgc2 must each be <= half /if (Igcl > half)

printf("I ** I parameters invalid: Il > %derror = 1;

};if (Qgcl > half) {

printf("I ** Q parameterserror = 1;

};if (error == 0)

QAMgcSignalMapInitVars(map,printf("\n");

break;.

------------- \n");must be <= %d **", half);

n", Igc2)

n", Qgc2);

\n", half);

invalid: Ql > %d **\n", half);

Igcl, Igc2, Qgcl, Qgc2);

};}; /* switch selection /

/* if input ok /else

printf(" invalid selection **\n");}; /* while error *

} /* selectSignalmapper *

SIMULATION COMMAND FUNCTION

mapper.c 167

Page 168: Simulating Turbo Codes using a Modular Simulation Platform

168 SIMULATION CODE

function: mapslock

The function is called from the main simulation program to

map a block of bits to two-D symbols.

Input twoDsignalMapVars* signalMapperOutputModify signalMapper output linked list

void mapBlock(twoDsignalMapVars* signalMapper)

twoDSignalPoint symbol;listElement *currEl, *Uhead, *Shead, *Phead;

/* function formTwoDsymbol() changes the Iso we temporarily store the real ones I

Shead = (*signalMapper).inputS->head;if ((*signalMapper).inputU != NULL)

Uhead = (*signalMapper).inputU->head;if ((*signalMapper).inputP != NULL)

Phead = (*signalMapper).inputP->head;

ead pointer of each input linked list,ere */

/* no trellis coded modulation *

uncoded simulation no parity bits */

currEl = (*signalMapper).output->head;

while ((*signalMapper).inputS->head 1= NULL)symbol = formTwoDsymbol(signalMapper);if (currEl == NULL)

addLLsignal((*signalMapper).output, &symbol);else

(*currEl).signal[0] = symbol;currEl = (*currEl).next;

};

/* function formTwoDsymbol() changes the head

so we restore the real ones here */(*signalMapper).inputS->head = Shead;if ((*signalMapper).inputU != NULL)

(*signalMapper).inputU->head = Uhead;if ((*signalMapper).inputP != NULL)

(*signalMapper).inputP->head = Phead;

}; /* mapBlock *

pointer of each input linked list,

INIT/DEALLOCATE FUNCTIONS

function: bitM

Initialize bit

Input : DitMachar

OutputModify : bitMa

apInitVars

mapper variables.

pvars* DitMapper -pattern[] -

pper

pointer to nit mapper structarray containing bit map pattern

void bitMapInitVars(bitMapVars* bitMapper, char pattern[])

int i;

(*bitMapper).b = strlen(pattern);(*bitMapper).pattern = (char*) calloc((*bitMapper).b, sizeof(char));for (i=0; i < (*bitMapper).b; i++)

(*bitMapper).pattern[i] = pattern[i];(*bitMapper).symbolBits = (char*) calloc((*bitMapper).b, sizeof(char));getNumBits(bitMapper);

} /* bitMapInitVars *

function: freeBitMapVars

Deallocate memory for bit mapper struct variables.

Input bitMapvars* bitMap - pointer to bit mapper struct

OutputModify bitMap

Page 169: Simulating Turbo Codes using a Modular Simulation Platform

void freeBitMapVars(bitMapVars* bitMap)

free((*bitMap).pattern);

free((*bitMap).symbolBits);

/* freeBitMapVars */

function: freeTwoDsymbolMapVars

Deallocates memory for symbol mapper struct variables

Input twoDsymbolMapVars* map - pointer to symbol mapper structOutputModify map

void freeTwoDsymbolMapVars(twoDsymbolMapVars* map)

int i;

free((*map).symbols);for (i=O; i < (*map).M; i++)

free((*map).code[i]);free((*map).code);

} /* freeTwoDsymbolMapVars */

function: normalMappingInitVars

Input : twoDsymbolMapVars* signalMapperOutputModify : map

pointer to symbol mapper struct

void normalMappingInitVars(twoDsignalMapVars* signalMapper, int numHalfBits)

int i;

oneDsymbolMapVars tempI, tempQ;

tempI.M = (int)pow(2,numHalfBits);

templ.symbols = createPAMlevels(tempI.M);tempI.code = (char**)calloc(tempI.M, sizeof(char*));tempQ.M = (int)pow(2,numHalfBits);

tempQ.symbols = createPAMlevels(tempQ.M);tempQ.code = (char**)calloc(tempQ.M, sizeof(char*));for (i=0; i < tempI.M; i++)

temp{.code[i] = (char*)callocnumalfgits, sizeofchar)tempQ.code[i] = (char*)calloc(numHalfBits, sizeof(char));intToCharArrayi, temp.code[i], numHalfBits)intToCharArray(i, tempQ.code[i], numHalfBits);

QAMSignalSet(&(*signalMapper).symbolMapper, tempI, tempQ);

/* these might not be initialized in case of uncoded simulation */(*signalMapper).inputU = NULL;(*signalMapper).inputP = NULL;

(*signalMapper) output = (linkList*) calloc(l, sizeof(linkList));llistInitVars((*signalMapper).output, 1);

} /* normalMappingInitVars */

/*

function: QAMgcSignalMapInitVars

This function initializes the signal mapper by usingconcatenated gray labels with a square-QAM signal set.

Input : twoDsignalMapVars* signalMapper - pointer to signal mapper structint InumGB1 - upper gray bits in I channelint InumGB2 - lower gray bits in I channelint QnumGB1 - upper gray bits in Q channelint QnumGB2 - lower gray bits in Q channel

Output :Modify : signalMapper

mapper.c 169

Page 170: Simulating Turbo Codes using a Modular Simulation Platform

170 SIMULATION CODE

I

void QAMgcSignalMapInitVars(twoDsignalMapVars* signalMapper, int InumGB1, int InumGB2, int QnumGB, int QnumGB2)

oneDsymbolMapVars tempI, tempQ;

PAMgcSignalSet(&tempI, InumGB1, InumGB2);PAMgcSignalSet(&tempQ, QnumGB1, QnumGB2);QAMSignalSet(&(*signalMapper).symbolMapper, tempI, tempQ);

/* these might not be initialized in case of uncoded simulation *(*signalMapper).inputU = NULL;

(*signalMapper).inputP = NULL;

(*signalMapper).output = (linkList*) calloc(l, sizeof(linkList));llistInitVars((*signalMapper).output, 1);

/* QAMgcInitVars *

function: freeTwoDsignalMapVars

Deallocates memeory for variables in signal mapper struct.

Input twoDsignalMapVars* signalMap

OutputModify : signalMap

*/-.void freeTwoDsignalMapVars(twoDsignalMapVars* signalMap)

freeBitMapVars(&(*signalMap).bitMapper);freeTwoDsymbolMapVars(&(*signalMap).symbolMapper);freeList((*signalMap).output);

/* --------------------- DISPLAY/DEBUG FUNCTIONS ---------------------- *

function: showOneDmapping

Shows points and labels for one-dimensional signal sets.

Input : oneDsymbolMapVars* mapper - pointer to signal mapper structOutputModify

*/

void showOneDmapping(oneDsymbolMapVars* mapper)

int i, j, b;

b = (int) (loglO((*mapper).M)/loglo(2));printf(" (amplitude, label) : ");for (i=O; i < (*mapper).M; i++)

printf("(%g,", (*mapper).symbols[i]);for (j=S; j < b; j++)

printf("%d", (int) (*mapper).code[i] j]);printf(") ");

};printf ("\n")

/* showOneDmapping *

function: showTwoDmapping

Shows points and labels for two-dimensional signal sets. Iffp is NULL, then prints to screen. Otherwise prints to file fp.

Input : twoDsymbolMapVars* mapper - pointer to symbol mapper structFILE* fp - pointer to output file

OutputModify : contents of file fp

void showTwoDmapping(twoDsymbolMapVars* mapper, FILE* fp)

int i, j, b;

Page 171: Simulating Turbo Codes using a Modular Simulation Platform

mapper.c 171

b = (int) (logl0((*mapper).M)/log10(2));if (fp != NULL)

fprintf(fp, "[point, label]for (i=0; i < (*mapper).M; i++)

fprintf(fp, "[(%gg), ", (*mapper) .symbols[i] .i, (*mapper) .symbols[i] .q);for (j=0; j b; j++)

fprintf(fp, "%d", (int) (*mapper) code [i] [j]);fprintf(fp, " "

};fprintf (fp, "\n");

else

printf(" [point, label]for (i=0; i < (*mapper).M; i++)

printf(" [(%g,%g) , ", (*mapper) .symbols[i .i, (*mapper) symbols[i .q)for (j=0; j < b; j++)

printf("%d", (int) (*mapper) .code[i [i);printf("]

};printf ("\n")

}; /* showTwoDmapping /

/* ------- --- ---- BIT MAPPER FUNCTIONS ---------------------- /

function: getNumBits

Find the number of uncoded, systematic, and parity bits persymbol.

Input bitMapVars* bitMap - pointer to bit mapper structOutputModify *bitMap

*/

void getNumBits(bitMapVars* bitMap)

int i;

(*bitMap).numParity = 0;(*bitMap).numSys = 0;(*bitMap).numUncoded = 0;

for (i=0; i < (*bitMap).b; i++) /* initialize symbolPattern[] */if ((*bitMap).pattern[i] == 'u')

(*bitMap).numUncoded += 1; /* count number of uncoded bits per symbol */else if ((*bitMap).pattern[i] == 's')

(*bitMap).numSys += 1; /* count number of systematic bits */else

(*bitMap).numParity += 1; /* count number of parity bits per symbol */

1; /* getNumBits */

/* --- -------- SYMBOL MAPPER FUNCTIONS ----------------------

function: PAMgcSignalSet

Forms a one-dimensional signal set with odd-valued pointscentered evenly about zero.

Input oneDsymbolMapVars* PAMmapper - pointer to symbol map structint numGrayBitsl - upper gray bits for labelsint numGrayBits2 - lower gray bits for labels

OutputModify *PAMmapper

*/void PAMgcSignalSet(oneDsymbolMapVars* PAMmapper, int numGrayBitsl, int numGrayBits2)

(*PAMmapper) .M = (int)pow(2, (numCrayBitsl + numGrayBits2));(*PAMmapper) symbols = createPAMlevels( (*PAMmapper) M);

Page 172: Simulating Turbo Codes using a Modular Simulation Platform

SIMULATION CODE

(*PAMmapper) code = createGrayCode(numGrayBitsl, numGrayBits2, (*PAMmapper) .M)

/* PAMgcSignalSet */

function: QAMSignalSet

Forms a two-dimensional square signal set with odd-valued pointscentered evenly about zero in each direction.

Input twoDsymbolMapVars* symbolMapper - pointer to symbol map structoneDsymbolMapVars tempI - 1-D signal set for I channeloneDsymbolMapVars tempQ - 1-D signal set for Q channel

OutputModify *symbolMapper

void QAMSignalSet(twoDsymbolMapVars* symbolMapper, oneDsymbolMapVars tempI, oneDsymbolMapVars tempQ)

int L1, L2, L;

int i, j, k, pos;

(*symbolMapper).Eav = 0;(*symbolMapper).M = tempI.M * tempQ.M;(*symbolMapper) code = (char**) calloc ( (*symbolMapper) M, sizeof (char*))(*symbolMapper) symbols = (twoDSignalPoint*) calloc( (*symbolMapper) .M, sizeof (twoDSignalPoint)L = (int) (loglO((*symbolMapper).M)/loglO(2));Ll = (int) (logb (tempI.M)/logl (2));L2 = (int)(log10(tempQ.M)/log10(2));for (i=0; i < tempI.M; i++)

for (j=O; j < tempQ.M; j++)

(*symbolMapper).code[i*tempQ.M + j) = (char*) calloc(L, sizeof(char));

(*symbolMapper).symbols[i*tempQ.M + j .i = tempI.symbols[i];(*symbolMapper) .symbols [i*tempQ.M + j.q = tempQ.symbols[j];

(*symbolMapper).Eav += (sqr(tempI.symbols[i}) + sqr(tempQ.symbols[j]));

pos = 0;for (k=O; k < Ll; k++)

(*symbolMapper).code[i*tempQ.M + ji [pos++] = tempI.code[i] [k];for (k=O; k < L2; k++)

(*symbolMapper).code[i*tempQ.M + ji[pos++] = tempQ.code[j] [ki;

};};(*symbolMapper).Eav /= (*symbolMapper).M;

/* QAMSignalSet */

function: findOneDsymbol

Finds the signal point in a one-D signal set with bit labelmatching the input bits.

Input : char bits[] - array containing input bitsoneDsymbolMapVars* map - signal set points and labels

Output : one-dimensional pointModify

double findOneDsymbol(char bits[], oneDsymbolMapVars* map)

int i, j, componentBits;char* tempElement; .char done=O, bitsEqual;

componentBits = (int) (log)((*map).M)/logl(2));i = -1;

while (!done) /* keep on looking for the match */

i++;tempElement = (*map).code[i]; /* get next Gray code element */bitsEqual = 1;for (j=O; j<componentBits; j++) /* check each bit for the match */

bitsEqual = bitsEqual && (tempElementji == bits[j]);done = bitsEqual;

};

return (*map).symbols[i];

} /* findOneDsymbol */

/* return the matched PAM level */

172

Page 173: Simulating Turbo Codes using a Modular Simulation Platform

function: findTwoDsymbol

Finds the point in a two-D signal set that has the same bit

label as the input bit array.

Input char bits[] - input bit arraytwoDsymbolMapVars* map - two-D points and labels

Output two-D point

Modify

*/twoDSignalPoint findTwoDsymbol(char bits[], twoDsymbolMapVars* map)

int i, j, componentBits;char* tempElement;char done=O, bitsEqual;

componentBits = (int) (loglO((*map) .M)/loglO(2));i = -1;

while (!done) /* keep on looking for the match */

i++;

tempElement = (*map).code[i]; /* get next Gray code elementbitsEqual = 1;for (j=O; j<componentBits; j++) /* check each bit for the match *

bitsEqual = bitsEqual && (tempElement[j] == bits[j});

done = bitsEqual;

return (*map).symbols[i];

} /* findTwoDsymbol */

/* return the matched PAM level */

function: createPAMlevels

Creates an array of odd-valued points centered evenly aboutzero.

Input int M - number of total pointsOutput double PAMlevels[] - arrayModify

*/

double* createPAMlevels(int M){

int i;

double *PAMlevels = (double*) calloc(M, sizeof(double));levels */

for (i=O; i<(M/2); i++) /

{PAMlevels[i) = (double) (-l*(M-1) + 2*i)PAMlevels[M-1-i] = -l*PAMlevels[i]; /* the po

* allocate memory to hold PAM

generate the M PAM levels */

/* the negative (M/2) PAM levels *sitive (M/2) PAM levels */

};

return PAMlevels;

}; /* createPAMlevels */

function: formTwoDsymbol

Takes bits from the input linked lists and maps them to asignal point.

Input twoDsignalMapVars* signalMapper - pointer to signal mapperOutputModify output linked list

*/twoDSignalPoint formTwoDsymbol(twoDsignalMapVars* signalMapper)

bitMapVars* map = &(*signalMapper) .bitMapper;int i;

for (i=0; i < (*map).b; i++)if ((*map).pattern[i == 'u')

(*map) .symbolBits[i] = (*signalMapper) .inputU->head->value [0](*signalMapper).inputU->head = (*signalMapper) .inputU->head->next;

else if ((*map).pattern[i] == s')(*map) .symbolBits[i] = (*signalMapper) .inputS->head->value [0];(*signalMapper) inputS->head = (*signalMapper) .inputS->head->next;

mapper.c 173

Page 174: Simulating Turbo Codes using a Modular Simulation Platform

SIMULATION CODE

else

(*map).symbolBits[i] = (*signalMapper) .inputP->head->value [0;(*signalMapper).inputP->head = (*signalMapper).inputP->head->next;

1;

return findTwoDsymbol ((*map) symbolBits, &(*signalMapper) symbolMapper)

/* formTwoDsymbol */

- - GRAY CODE FUNCTIONS ------------- */

function: makeNbitGC

Make a full gray code with the specified number of bits. Gray codescan be formed by a recursive algorithm starting with the 1-bit code0,1. In general, a n-bit gray code can be formed from the (n-l)-bitcode by prepending a '0' to the (n-l)-bit code, followed by prependinga 'l' to the (n-l)-bit code in reverse order.0,1 -- > 0 + (0,I) and 1 + (1,0) = 00,01,11,1000,01,11,10 -- > 0 + (00,01,11,10) and 1 + (10,11,01,00)

= 000,001,011,010,110,111,101,100and so on...

Input int numBits - number of bits in the full gray code.Output *theList - the linked list of gray codesModify

*/linkList* makeNbitGC(int numBits)

linkList *theList = (linkList*) calloc(1, sizeof(linkList)); /*linkList *tempList; /* temporary variableslistElement *tempElement;char *tempchar;int i;

llistInitVars(theList, numBits);

if (numBits == 1)

} /*else

allocate memory for the gray code */*/

make a 2 element linked list with just */* 0 and 1 */

recurse -- first make a (n-l)-bit gray code */

/* base case of recursive algorithm */

tempchar = (char*) calloc(l, sizeof(char));*tempchar = 0; /*

addLLbits(theList, tempchar);*tempchar = 1;

addLLbits(theList, tempchar);free(tempchar);numBits = 1 */

tempList = makeNbitGC(numBits-1); /*

tempcnar = (cnar-) caliocnumBits, sizeot(cnar));tempElement = getElement(tempList, 1); /* now prepend the 0 to the (n-l)-bit gray code */tempchar[0] = 0; /* the prepended 0 */while (tempElement != NULL)

for (i=l; i<numBits; i++) /* copy the remaining (n-1) bits */tempchar[i] = (*tempElement).valueli-1];

addLLbits(theList, tempchar); /* add this n-bit code to the final linked list '/tempElement = (*tempElement).next;

};/* get the last element of the (n-i)-bit gray code -- now prepend the 1 */tempElement = getElement(tempList, (int)pow(2, (*tempList) .valueLength));tempchar[O] = 1; /* the prepended 1 */while (tempElement != NULL)

{for (i=l; i<numBits; i++) /* copy the remaining (n-1) bits */

tempchar[i] = (*tempElement).value[i-1];addLLbits(theList, tempchar); /* add this n-bit code to the final linked list */tempElement = (*tempElement).prev; /* go in reverse order */

deleteList(tempList);free(tempchar);

}; /* numBits >1 *

return theList;

/* makeNbitGC */

/* free up temporary memory allocations */

174

Page 175: Simulating Turbo Codes using a Modular Simulation Platform

function: concatCodes

Concatenate two separate codes contained in separate linked listsThe elements of the second code are appended to each element ofthe first code.Ex.: 0,1 concatenated with 00,01,11,10 becomes

000,001,011,010,100,101,111,110, which is not the same asa 3-bit full gray code.

Input linkList *MSBlist - the first list of codeslinkList *LSBlist - the second list of codes

Output :theList - the list for the concatenated codeModify

*/linkList* concatCodes(linkList *MSBlist, linkList *LSBlist)

linkList *theList = (linkList*) calloc(l, sizeof(linkList));

listElement *tempEll, *tempEl2;int b = (*MSBlist) .valueLength+(*LSBlist) valuEchar *tempchar = (char*) calloc(b, sizeof(charint j;

llistInitVars(theList, b);tempEll = getElement(MSBlist, 1);while (tempEll != NULL)

* allocate memory for concat. list

/* temporary variables */?Length;

/* get first element of first list *//* continue concat until thru first list */

for (j=0; j<(*MSBlist) .valueLength; j++) /* get bits from first codetempchar~j] = (*tempEll).value[j];

tempEl2 = getElement(LSBlist, 1); - /while (tempEl2 != NULL)

for (j=0; j<(*LSBlist).valueLength; j++)tempchar[(*MSBlist).valueLength + j]

addLLbits(theList, tempchar);

tempEl2 = (*tempEl2).next;

}; /* go through LSB gray code list */

tempEll = (*tempEll).next;

}; /* go through MSB gray code list */

deleteList(MSBlist);

deleteList(LSBlist);

return theList;

} /* concatCodes */

go through entire second code */

/* get bits from second code */= (*tempEl2).value[j];

/* add the new code to the final list

go to next element in first code */

function: createGrayCode

Determine whether to create a full gray code (numMSB=O or numLSB=O) ora 2-level concatenated Gray code. The final Gray code is stored in alinked list

Input int numMSB - number of bits in the upper level of the 2-level gray codeint numLSB - number of bits in the lower level of the 2-level gray code

Output : two-D array containing the gray codeModify

*/char** createGrayCode(int numMSB, int numLSB, int M)

linkList *MSBGC, *LSBGC, *finalGC;char** retArray = (char**) calloc(M, sizeof(char*))listElement *element;int i=O, j;

if (numMSB == 0)finalGC = makeNbitGC(numLSB);

else if (numLSB == 0)finalGC = makeNbitGC(numMSB);

else

/* make a full (b/2)-bit gray code */

/* make a full (b/2)-bit gray code */

MSBGC = makeNbitGC(numMSB); /* gray code for upper bits */LSBGC = makeNbitGC(numLSB); /* gray code for lower bits */finalGC = concatCodes(MSBGC,LSBGC); /* concatenate the two codes */

element = (*finalGC).head;while (element != NULL)

retArray[i] = (char*) calloc(numMSB+numLSB, sizeof(char))for (j=O; j < (*finalGC) .valueLength; j++)

retArray[i] [j] = (*element) .value[j];

mapper.c 175

Page 176: Simulating Turbo Codes using a Modular Simulation Platform

SIMULATION CODE

i++;

element = (*element).next;

1;

return retArray;

S/* createGrayCode */

/* return the final gray code *

176

Page 177: Simulating Turbo Codes using a Modular Simulation Platform

channel.h 177

channel.h

file: channel.h

This header file contains definitions for simulation functionsrelated to sending signals through channels, includingAWGN channels.

*/

/* type definitions */typedef struct channelVarsStruct

double nvariance;

linkList* input;linkList* output;

} channelVars;

/* simulation command function s/

void sendAWGNblock(channelVars* channel);

/* init/deallocate functions */void channelInitVars(channelVars* channel);void freeChannelvars(channelVars* channel);

/* other functions */twoDSignalPoint sendAWGNpoint(channelVars* channel, twoDSignalPoint origPt);void Gauss32(double*, double*);

Page 178: Simulating Turbo Codes using a Modular Simulation Platform

178 SIMULATION CODE

channel.c

file: channel.c

This source file contains code for simulation functionsrelated to sending signals through channels, includingAWGN channels.

*/

#include "linkedlist.h"#include "channel.h"

#include <math.h>#include <stdio.h>#include <stdlib.h>

SIMULATION COMMAND FUNCTION

function: sendAWGNblock

This function takes all signal points from the channel input,sends them through an AWGN channel, and adds them to the channeloutput list. This function is called from the main simulationprogram

void sendAWGNblock(channelVars* channel)

int i, len;twoDSignalPoint point;listElement *inputEl, *currEl;

inputEl = (*channel).input->head;currEl = (*channel).output->head;

len = getNumElements((*channel).input);for (i=O; i < len; i++)

point = sendAWGNpoint(channel, (*inputEl).signal[0));if (currEl == NULL)

addLLsignal((*channel).output, &point);else

(*currEl).signal[0) = point;currEl = (*currEl).next;

inputEl = (*inputEl).next;

1;

/ senoAWUnoIock -/

/* ----------------------- INIT/DEALLOCATE FUNCTIONS

function: channelInitVars

This function initializes channel variables.

void channelInitVars(channelVars* channel)

(*channel).n variance = 1;

(*channel).output = (linkList*) calloc (1,llistInitVars((*channel).output, 1);

sizeof(linkList));

S/* channelInitVars */

function: freechannelVars

This function deallocates channel variable memory.

}

Page 179: Simulating Turbo Codes using a Modular Simulation Platform

void freeChannelVars(channelVars* channel)

freeList((*channel).output);

/* freeChannelvars */

OTHER FUNCTIONS ---

function: sendAWGNpoint

This function takes a 2D signal point fromsends it through an AWGN channel, and adds

output list.

the channel input,it to the channel

*/twoDSignalPoint sendAWGNpoint(channelVars* channel, twoDSignalPoint origPt)

twoDSignalPoint point;

Gauss32(&(point.i), &(point.q));point.i *= sqrt((*channel).n variance);point.i origPt.i;point.q sqrt((*channel).nvariance);

point.q += origPt.q;

return point;

/* sendAWGNpoint */

Function: Guass32

Description: Generate two Gaussian

32 bit arithmetic.

*/void Gauss32(double *x, double *y)f

random variables. Assumes

long temp;double ul,u2,r,theta,PI=3.1415;

temp = rand();

/* rand) gen an integer between 0 and RANDMAX '/temp = temp % RAND MAX;/* modulus operation to make sure value of TEMP is less than

Ox7fffffff - which is the greatest value of a LONG data typeul = (double) temp / (double) RANDMAX;/* now convert range to 0 <= ul <1 'temp = rand));

temp = temp % RAND MAX;u2 = (double) temp / (double) RAND MAX;

/* ul must be double because log) takes a double as an argumentr = sqrt(-2.0 * log(l.0-ul)); /* 0 <= r < sqrt(-2*ln(l/RAND M

theta = u2 * 2

t */AX)) */

/* with 0 < (1-ul) <= 1 (no zero) */.0 * PI; /* 0 <= theta < 2pi */

*x = or * cos(theta));*y = or * sin(theta));

}/* Gauss32 */

channel.c 179

Page 180: Simulating Turbo Codes using a Modular Simulation Platform

180 SIMULATION CODE

demod.h

file: demod.h

This header file contains definitions for functions that generatesoft-values from received signal points for input to the MAP decoder.

/* type definitions */typedef struct demodulatorVarsStruct

linkList* input;linkList* outputS;linkList* outputP;

} demodulatorVars;

/* simulation command function */void demodulateTwoDBlock(demodulatorVars* dem, twoDsignalMapVars* mapper, double noisevar);void decode uncoded(linkList* decodedLL, twoDsignalMapVars* mapper, linkList* points);

/* init/deallocate functions */void demodulatorInitVars(demodulatorVars* dem);void freeDemodulatorVars(demodulatorVars* dem);

/* other functions */double calcBitLLR(twoDSignalPoint point, int pos, twoDsymbolMapVars symbolMapper, double noisevar)

Page 181: Simulating Turbo Codes using a Modular Simulation Platform

demod.c 181

demod.c

file: demod.c

This source file contains code for generating soft-values fromreceived signal points for input to the MAP decoder.

#include "general.h"#include "linkedlist.h"#include "mapper.h"#include "demod.h"

#include <stdlib.h>#include <stdio.h>#include <math.h>

- --------------------- SIMULATION COMMAND FUNCTIONS ----------------------

function: demodulateTwuDBlock

This function calculates the LLR of each bit in the received

symbols.

Input demodulatorVars* dem - pointer to demodulator structtwoDsignalMapVars* mapper - pointer to signal mapperdouble noise var - channel noise variance

OutputModify dem

void demodulateTwoDBlock(demodulatorVars* dem, twoDsignalMapVars* mapper, double noise var)

int i, j, num;twoDSignalPoint LLR;listElement *outP, *outS, *ElPtr;

outP = (*dem).outputP->head;

outS = (*dem).outputS->head;ElPtr = (*dem).input->head;

num = getNumElements((*dem).input);for (i=O; i < num; i++)

for (j=O; j < (*mapper).bitMapper.b; j++)if ((*mapper).bitMapper.pattern[j] != 'u')

LLR.i = calcBitLLR((*ElPtr).signal[0], j, (*mapper).symbolMapper, noise var);LLR.q = LLR.i;

if ((*mapper).bitMapper.pattern[j] == 's')

if (outS == NULL)addLLsignal((*dem).outputS, &LLR);

else

(*outS).signal[0] = LLR;outS = (*outS).next;

else if ((*mapper).bitMapper.pattern[j] == 'p')if (outP == NULL)

addLLsignal((*dem).outputP, &LLR);else

(*outP).signal[0] = LLR;outP = (*outP).next;

};}; /* if s or p */

}; /* for loop: bits in a symbol */

ElPtr = (*ElPtr).next;

1;

/* demodulateTwoDBlock */

function: decode_uncoded

This function is used with uncoded QAM to get the upper bound

Page 182: Simulating Turbo Codes using a Modular Simulation Platform

182 SIMULATION CODE

for the QAM bit error rate. It chooses the constellation pointnearest to the received symbol as the point that was sent.There is no struct associated with this operation.

Input linkList* decodedLL - list where decoded bits will be stored

twoDsignalMapVars* mapper - pointer to signal mapperlinkList* points - list of symbol at output of channel

OutputModify decodedLL

void decode uncoded(linkList* decodedLL, twoDsignalMapVars* mapper, linkList* points)

int i, min;double minD, D;twoDSignalPoint signal;

deleteList(decodedLL);

while (notEmpty(points))

signal = getSignal(points, 1) [0];deleteFirstElement(points);min = 0;minD = sqrt(sqr(signal.i - (*mapper).symbolMapper.symbols[0) .i) +

sqr(signal.q - (*mapper).symbolMapper.symbols [0].q))for (i=l; i < (*mapper).symbolMapper.M; i++)

D = sqrt(sqr(signal.i - (*mapper).symbolMapper.symbols[i] .i) +sqr(signal.q - (*mapper) .symbolMapper.symbols[i] .q))

if (D < minD)

minD = D;

min = i;

};

for (i=0; i < (*mapper).bitMapper.b; i++)addLLbits(decodedLL, &(*mapper).symbolMapper.code[min [i]);

};

/* decodeuncoded */

/* --------------------- INIT/DEALLOCATE FUNCTIONS ----------------------

/*

function: demodulatorInitVars

Initializes demodulator struct variables.

Input demodulatorVars* dem - pointer to demodulator structOutputModify dem

void demodulatorInitVars(demodulatorVars* dem)

(*dem).outputS = (linkList*) calloc(1, sizeof(linkList));llistInitVars((*dem).outputS, 1); /* linked list of real values, not bits */

(*dem).outputP = (linkList*) calloc(, sizeof(linkList));llistInitVars((*dem).outputP, 1); /* linked list of real values, not bits *

}/* demodulatorInitVars */

function: freeDemodulatorVars

Deallocates memory for demodulator variables.

Input demodulatorVars* dem - pointer to demodulator sturctOutput

Modify *dem

void freeDemodulatorVars(demodulatorVars* dem)

freeList((*dem).outputP);

freeList((*dem).outputS);

/* freeDemodulatorVars */

Page 183: Simulating Turbo Codes using a Modular Simulation Platform

---- OTHER FUNCTIONS --------

function: calcBitLLR

This function calculates the log-likehood ratio for a bit ina received symbol.

Input : twoDSignalPoint point - received pointint pos - bit to calculate LLR fortwoDsymbolMapVars symbolMapper - symbol mapper structdouble noise var - channel noise variance

Output LLR for the specified bitModify

double calcBitLLR(twoDSignalPoint point, int pos, twoDsymbolMapVars symbolMapper,

int i, half;double metricl=0, metricl=O;double maxlog = 40;double result;

half = (int)floor(loglO(symbolMapper.M)/logl1(2)for (i=0; i < symbolMapper.M; i++)

if (symbolMapper.code[i] [pos] == 0)

if (pos < half)metricO += exp(-1.0/(2*noisevar)

else

else

double noise var)

/2); /* number of bits per dimension in QAM */

* sqr~point.i - symbolMapper.symbols[i].i));

metricO += exp(-l.0/(2*noise var) * sqr(point.q - symbolMapper.symbols[i].q));

if (pos < half)metricl += exp(-1.0/(2*noisevar) * sqr(point.i - symbolMapper.symbols[i].i));

elsemetricl += exp(-l.O/(2*noise var) * sqr(point.q - symbolMapper.symbols[i}.q));

limit magnitude of LLR so it won't cause computational errors later on *(fabs(metricl) < exp(-l*maxlog))metricO = exp(-l * maxlog);

(fabs(metricl) < exp(-l*maxlog))metricl = exp(-l * max_log);

result = log(metricl/metric);if (fabs(result) > maxlog)

result = (result/fabs(result)) * maxlog;

return result;

} /* calcBitLLR */

demod.c 183

if

if

Page 184: Simulating Turbo Codes using a Modular Simulation Platform

184 SIMULATION CODE

decoder.h

file: decoder.h

/* type definitions */

typedef struct MAPdecoderVarsStructint blockSize, numStates, numInputs;double explimit;double ***gamma; /* gamma [k] [dk] [pk] / probA[k] [dk] */double **alpha, **beta; /* alpha[k] [m], beta[k] [m] */

char **bitValue;branch** trellis;

/* twoDsymbolMapVars* symbolMapper; */

linkList* inputS;linkList* inputP;linkList* inputA;

linkList* output_Dprob;linkList* output extrinsic;

MAPdecoderVars;

/* simulation command function */void doMAPdecoding(MAPdecoderVars* decoder);void doFastRl2MAPdecoding(MAPdecoderVars* decoder);

/* init/deallocate functions */void MAPdecoderInitVars(MAPdecoderVars* decoder, encoderVars* convCode, int blockSize, twoDsymbolMapVars*symbolMapper);void freeMAPDecoderVars(MAPdecoderVars* decoder);

/* display/debug functions */float showErrorPercentage(linkList* origBits, linkList* decodedBits)

/* general rate-k/(k+l) RSCC MAP decoder functions */void calc probS(MAPdecoderVars* decoder);void init probA(MAPdecoderVars* decoder, int factor);void calc gamma(MAPdecoderVars* decoder);void calcalpha(MAPdecoderVars* decoder);void calcbeta(MAPdecoderVars* decoder);void initAB(MAPdecoderVars* decoder, char terminated);void initB usingA(MAPdecoderVars* decoder);void probDecision(linkList *input, linkList* output);

/* fast rate-1/2 RSCC MAP decoder functions */void calcgammaR12(MAPdecoderVars* decoder);void calcalphaRl2(MAPdecoderVars* decoder);void calc_betaRl2(MAPdecoderVars* decoder);void signoecision)1inkList* input, iinkList* output);

Page 185: Simulating Turbo Codes using a Modular Simulation Platform

decoder.c 185

decoder.c

/*

file: decoder.c

This source file contains code for turbo decoding, MAP decoding,and the log variants of MAP decoding.

*/

#include "general.h"#include "linkedlist.h"#include "interleave.h"#include "conv.h"#include "mapper.h"#include "demod.h"#include "decoder.h"

#include <math.h>#include <stdio.h>#include <stdlib.h>

/* ------------------------- SIMULATION COMMAND FUNCTION ------ ---

S-------------------------- INIT/DEALLOCATE FUNCTIONS ------ --

/*

function: MAPdecoderInitVars

This function initializes variables used for MAP decoding.

Input : MAPdecodervars* decoder - pointer to MAP structencoderVars* convCode - convolutional code to decodeint blockSize - number of k-bit inputstwoDsymbolMapVars* symbolMapper - pointer to symbol mapper struct

Output :Modify : *decoder

*/

void MAPdecoderInitVars(MAPdecoderVars* decoder, encoderVars* convCode, int blockSize, twoDsymbolMapVars* symbolMapper)

int k, i;

(*decoder).blockSize = blockSize;(*decoder) .numStates = (int)pow(2, (*convCode) .v);(*decoder) numInputs = (int)pow(2, (*convCode) .k);(*decoder).trellis = (*convCode).trellis;

/* (*decoder).symbolMapper = symbolMapper; */(*decoder).explimit = 40;

(*decoder) .gamma = (double***) calloc (blockSize+l, sizeof (double**))

/* betaEkE [m]beta[0] Em] not usedbeta[l... blockSize] [m] hold decoding infobeta[blockSize] [m] holds initialization info

(*decoder) beta = (double**) calloc (blockSize+1, sizeof (double*));

/* alpha~k] [m]alpha[E] [m] hold initialization infoalpha[l... blockSize] [m] hold decoding info

*/(*decoder) alpha = (double**) calloc (blockSize+1, sizeof (double*))

for (k=O; k <= blockSize; k++)(*decoder) .alpha[k] = (double*) calloc( (*decoder) numStates, sizeof(double));(*decoder).beta[k = (double*) calloc ((*decoder) .numStates, sizeof (double));

(*decoder) .gamma[k] = (double") calloc((*decoder) numInputs, sizeof (double*));for (i=; i < (*decoder) numInputs; i++)

(*decoder) gamma[k] il = (double*) calloc (2, sizeof (double));/* assume that all encoders are rate-k/(k+l) -- only 1 parity bit */

/* bitValue[2^k] [k] holds the bit values for an integerfor k=2:

E0] [ = 00El] [] = 01[2] [ = 10

Page 186: Simulating Turbo Codes using a Modular Simulation Platform

186 SIMULATION CODE

[3] [1 = 11

(*decoder).bitValue = (char**) calloc((*decoder).numInputs, sizeof(char*));

for (i=0; i (*decoder).numInputs; i++)

(*decoder).bitValue[i] = (char*) calloc((*convCode).k, sizeof(char));intToCharArray(i, (*decoder).bitValue[i], (*convCode).k);

1;

/* if (*convCode).k = 1, then it is a rate-1/2 code, and we usedoFastRl2decodeBlockO, which uses bit LLR's. Thus, we only needthe MAP module output list to have valueLength = 1.

if (*convCode).k > 1, then it is a rate-k/(k+l) code, and we use

doMAPdecoding(), which uses a posteriori probabilities. Thus, weneed the MAP module output list to have valueLength = 2^ *

k = ((*convCode).k == 1) ? 1 : (*decoder).numInputs;

(*decoder).output_Dprob = (linkList*) calloc (1, sizeof(linkList));llistInitVars((*decoder).output_Dprob, k);

(*decoder).output-extrinsic = (linkList*) calloc (1, sizeof(linkList));llistInitVars((*decoder).output_extrinsic, k);

/* MAPdecoderInitVars */

function: freeMAPDecoderVars

Deallocates memory for decoder struct variables

Input MAPdecodervars* decoderOutputModify *decoder

*/

void freeMAPDecoderVars(MAPdecoderVars* decoder)

int k, i;

for (k=O; k < (*decoder).blockSize; k++)

free((*decoder).alpha[k]);free((*decoder).beta[k]);for (i=0; i < (*decoder).numInputs; i++)

free((*decoder).gamma[k] [i]);free((*decoder).gamma[k]);

1;for (i=0; i < (*decoder).numInputs; i++)

free((*decoder).bitValue[i]);free((*decoder).alpha);free((*decoder).beta);free((*decoder).gamma);free((*decoder).bitValue);deleteList((*decoder).output_Dprob);free((*decoder).output Dprob);deleteList((*decoder).outputextrinsic);free((adecoder).ourput extrinsic);

} /* freeMAPDecoderVars */

/* ------------------------- DISPLAY/DEBUG FUNCTION ------------------ /

/*

function: showErrorPercentage

This function compares the values of two linked lists andcalculates the percentage of values that are different.

Input : linkList* origBits - list of original bitslinkList* decodedBits - list of decoded bits

Output % of values that are differentModify

*/float showErrorPercentage(linkList* origBits, linkList* decodedBits)

float per = 0.0;int i, num;listElement *currEll, *currEl2;

num = getNumElements(origBits);currEll = origBits->head;currE12 = decodedBits->head;

Page 187: Simulating Turbo Codes using a Modular Simulation Platform

decoder.c 187

for (i=0; i < num; i++)

if (* (*currEll) value = (*currEl2) value)per++;

currEll = (*currEll).next;currE12 = (*currE12).next;

};

return (per / (float)num);

/* showErrorPercentage */

/* ---- -------- RATE-K/ (K+1) RSCC MAP DECODER FUNCTIONS ------------------ /

/*

function: calc_probS

Takes an input linked list with bit LLR's and changes thosevalues to Pr(b=O) = 1/(1 + exp(LLR)), and Pr(b=1) =exp(LLR) / (1 + exp(LLR)) . The LLR value is held in an inputelement's signal[].i variable. After Pr(b=O) is calculatedit is stored in signal[] .i, and Pr(b=l) is stored in signal[] .q

LLR is limited to -40 and 40, so probabilities range from1 / (1 + e^40) = e^(-40) to about 1.

Input MAPdecoderVars* decoder - pointer to decoder structOutputModify *decoder

void calc_probS(MAPdecoderVars* decoder)

int k, i, num;

double expval;listElement* currS;

currS = (*decoder).inputS->head;num = getNumElements((*decoder) inputS);for (k=0; k , num; k++)

for (i=0; i < (*(*decoder).inputS).valueLength; i++)

expval = exp((*currS).signal[i].i);(*currS) signal [i].i = 1.0 / (1 + exp val);(*currS) signal [i].q = exp val * (*currS) .signal [ii.i;

};currS =(*currS).next;

} /* calc_probS */

function: calcgamma

This function calculates part of the gamma parameter used in MAPI decoding. gamma][][1 is a three dimensional array. TheI first index is the time index k, the second index is theI input bits integer value i, and the third index is the parityI bit p. If Ak is the LLR associated with the input (systematic)I bits, and Bk is the LLR for the parity bit, then

input i gamma [k] [i] [p]S(k-1) ---------- > S(k) = Pr(Ak) * Pr(Bk)

parity p

In the actual BCJR algorithm, gamma = Pr(AkI...) Pr(Bkj ...) Pr(dk=i).Pr(dk=i) is "a priori" information supplied by the other MAPmodule, and is the only probability in gamma that changes witheach iteration. Thus, the part of gamma calculated here is thepart that does not change between iterations.

Input : MAPdecoderVars* decoderOutputModify

*/void calcgamma(MAPdecoderVars* decoder)

kint k, i, b, bits;

Page 188: Simulating Turbo Codes using a Modular Simulation Platform

SIMULATION CODE

double exp_val;twoDSignalPoint probP;listElement *currElementS, *currElementP;

bits = (int) (loglO((*decoder).numInputs)/ioglO(2));

currElementS = (*decoder).inputS->head;currElementP = (*decoder).inputP->head;for (k=l; k <= (*decoder).blockSize; k++)

exp val = exp((*currElementP).signal[0].i);probP.i = 1.0 / (1 + exp_val); /* pk = 0 */

probP.q = probP.i * exp val; /* pk = 1 *//* ranges from e^(-40) to 1 *//* ranges from e^(-40) to 1 */

for (i=0; i < (*decoder).numInputs; i++)

(*decoder).gamma[k][i] [0] = probPi;(*decoder).gamma[k] [i] [1] = probP.q;

for (b=0; b < bits; b++)

/*

in currElementS, there are valueLength LLR valuessignal[o] corresponds to the MSB LLR, andsignal[valueLenght-1] corresponds to the LSB LLR

This ordering is consistent with ordering used by intToCharArray,so bitValue[i] [b] corresponds to (*currElementS).signal[b].i

(*decoder).gamma[k][i][0] ((*decoder).bitValue[i][b] ==(*currElementS).signal[b.q;

(*decoder).gamma1k][i][1] *= ((*decoder).bitValue[i][bi ==

(*currElemenmtS) signal[b].q;

if ((*decoder).gamma[k][i][01 < (exp(-l* (*decoder).exp_(*decoder).gamma[k] [i] [0] = exp(-l* (*decoder).exp_

if ((*decoder).gamma[k [i][1} < (exp(-l* (*decoder).exp_(*decoder).gamma[k] [i [1] = exp(-l* (*decoder).exp_

};

currElementS = (*currElementS).next;

currElementP = (*currElementP).next;

}; /* for k */

/* calc-gamma s/

0) ? (*currElementS).signal[b].i

0) ? (*currElementS).signal[b].i

limit)limit);limit)))limit)

function: init_probA

This function initializes an empty "a priori" linked listby filling it with equiprobable values if we're decodingrate-k/(k+l), and with O's if we're decoding rate-1/2.The former uses actual "a priori" probabilities, and thelatter uses bit log-likehood ratios.

Input : MAPdecoderVars* decoder - pointer to decoder structint factor - determines if using "a priori" or LLR

OutputModify : decoder->inputA

void init probA(MAPdecoderVars* decoder, int factor)

int k, i, num, vlen;twoDSignalPoint* equiprob;listElement* currEl;

currEl = (*decoder).inputA->head;

equiprob = (twoDSignalPoint*) calloc ((*decoder).numInputs, sizeof(twoDSignalPoint));for (i=0; i < (*decoder).numInputs; i++)

equiprob i].i = 1.0 / (*decoder).numInputs * factor;/* factor is either 0 or 1, depending on if we're using

doMAPdecoding) or doFastR12MAPdecoding(). The former usesprobabilities (factor = 1) and the latter uses LLR's (factor = 0).

num = getNumElements((*decoder).inputS);vlen = (factor == 0) ? 1 : (*decoder).numInputs;(*(*decoder).inputA).valueLength = vlen;for (k=0; k < num; k++)

if (currEl == NULL)addLLsignal((*decoder).inputA, equiprob);

else

for (i=0; i < vlen; i++)

188

{

Page 189: Simulating Turbo Codes using a Modular Simulation Platform

decoder.c 189

(*currEl) signal[i] .i = equiprob[i] .i;currEl = currEl->next;

};

free(equiprob);

4 /* initprobA */

function: calcalpha

This function calculates all the alpha parameters needed inMAP decoding.

Input MAPdecoderVars* decoder - pointer to decoder structOutputModify decoder->alpha

*/void calc alpha()MAPdecoderVars* decoder)

int k, dk, Sk; 7* alpha indices -- alpha[k] [Sk) */int Skprev; /* summation indices */int pk;double sum;listElement* probA;

probA = (*decoder).inputA->head;

for (k-l; k - (*decoder).blockSize; k++)

for (Sk = 0; Sk < (*decoder) numStates; Sk++)(*decoder).alphaik] [Sk] = 0;

/* now loop through branches: each trellis[Sk-1] [dk] is a branch */for (Sk_prev = 0; Skprev < (*decoder) .numStates; Skprev++)

for (dk = 0; dk < (*decoder) numlnputs; dk++)

Sk = (*decoder).trellis[Sk_prev] [dk].S2; /* branch: Sk-l --> Sk, input dk */pk = (*decoder) trellis [Sk prev] [dk].p;(*decoder) .alpha[k] [Sk] += (*decoder) gamma (k] [dk] [pk * (*probA) .signal [dk].i *

(*decoder).alpha[k-l1] [Sk prev;}; /* for Sk-prev *

/* alpha[k] [Sk] is supposed to equal numerator[k] [Sk] / denominator[k]however, because denominator[k] is the same for every state at a time k,it acts like a constant for a time k and divides out in the finalcalculation of L(dk). However, this means that alpha will accumulatefaster with each k, so it'll need to be normalized */

sum = 0;for (Sk=0; Sk < (*decoder) .numStates; Sk++)

sum += (*decoder).alpha[k][Sk];

for (Sk=0; Sk a (-decoder) .numStates; Sk++)

(*decoder).alpha[k] [Sk] /= sum;/* if ((*decoder) .alpha[k] [Sk] < exp(-l*(*decoder) explimit))

(*decoder) .alphalk] [Sk] = exp(-l* (*decoder) explimit);*/

};

probA = (*probA).next;

}; /* for k */

} /* calcalpha */

function: calc_beta

This function calculates all the beta values used in MAPdecoding

Input MAPdecoderVars* decoder - pointer to MAP decoder structOutputModify decoder->beta

*/

void calcbeta()MAPdecoderVars* decoder)

int k, Sk; /* beta indices -- beta[k] [Sk] */int dkfuture, Sk-future; /* summation indices */int pk;double sum;listElement* probA;

Page 190: Simulating Turbo Codes using a Modular Simulation Platform

SIMULATION CODE

probA = (* (*decoder).inputA).tail;for (k = ((*decoder).blockSize - 1); k >= 1; k--)

for (Sk = 0; Sk < (*decoder).numStates; Sk++)(*decoder).beta[k] [Sk] = 0;

/* loop through branches: each trellis[Sk-1] [dk] is a branch */for (Sk = 0; Sk < (*decoder).numStates; Sk++)

for (dkfuture = 0; dk-future < (*decoder).numInputs; dkfuture++)

pk = (*decoder).trellis[Sk] [dk future.p;Skfuture = (*decoder).trellis[Sk]]dkfuture].S2;(*decoder) .beta[k] [Sk] += (*decoder) .gamma[k+1] [dk future] [pk] (*probA) .signal dk future] .i

(*decoder).beta[k+l][Skfuture];

}; /* for dk+l */

sumfor

for

= 0;(Sk=O; Sk < (*decoder).numStates; Sk++)sum += (*decoder).beta]k]]Sk];(Sk=O; Sk < (*decoder).numStates; Sk++)

(*decoder).beta[k] [Sk] /= sum;if ((*decoder).beta[k] [Sk < exp(-l*(*decoder).explimit))

(*decoder).beta[k] [Sk] = exp(-l* (*decoder).explimit);

};probA = (*probA).prev;

}; /* for k */

} /* calcbeta */

function: doMAPdecoding

This function performs MAP decoding.

Input : MAPdecoderVars* decoder - pointerOutputModify *decoder

doMAPdecoding(MAPdecoderVars* decoder)

int k, Skprev, Sk, dk;int pk, b, bits;double *lambda;double probS, sum;twoDSignalPoint *prob;listElement *currElementA, *currElementS,

to decoder struct

*currOutA, *currOutD;

lambda = (double*) calloc((*decoder).numInputs, sizeof(double));prob = (twoDSignalPoint*) calloc((*decoder).numInputs, sizeof(twoDSignalPoint));

/* note: for some reason,bits = (int) (log((*decoder).numInputs) / log(2));

does not give the right number, butbits = (int) (logoO((-decoder).numonputs) / logiu(2));

does.

bits = (int) (logl0((*decoder).numInputs) / logiO(2));calcalpha(decoder);if ((*decoder).beta[(*decoder).blockSize][0] != 1) /* trellis

initB usingA(decoder);calc_beta(decoder);

currElementA = (* (*decoder).inputA).head;currElementS = (*(*decoder).inputS).head;currOutD = (* (*decoder).output_Dprob).head;currOutA = (* (*decoder).output_extrinsic).head;

for (k=i; k <= (*decoder).blockSize; k++)

for (dk=O; dk < (*decoder).numInputs; dk++)lambda[dk] = 0;

for (Skprev=O; Sk prev < (*decoder).numStates; Skprev++)for (dk=O; dk < (*decoder).numInputs; dk++)

is not terminated */

Sk = (*decoder).trellis[Skprev] [dk].S2;pk = (*decoder).trellis[Skprev] [dk].p;lambda[dk] += (*decoder). gamma[k] [dk [pk] * (*currElementA) .signal[dk] .i * (*decoder). alpha[k-

1] [Sk prev] * (*decoder).beta[k] [Sk;};

sum = 0;

for (dk=O; dk < (*decoder).numInputs; dk++)sum += lambda[dk];

for (dk=O; dk < (*decoder).numInputs; dk++)

190

void{

f

Page 191: Simulating Turbo Codes using a Modular Simulation Platform

};if

prob[dk].i = lambda[dk] / sum;/* limit magnitude of probability. prob < 1, so log(prob) < 0if (fabs(log(prob[dk .i)) > (*decoder) .exp_limit)

prob[dk.i = exp(-l (*decoder).explimit);

(currOutD == NULL)

addLLsignal((*decoder).outputDprob, prob);if currOut is NULL, it will remain NULL throughout this MAPdecoding round, and bit probabilities will be added to theoutput list */

else

for (dk=0; dk < (*decoder).numInputs; dk++)(*currOutD).signal[dk].i = prob[dk].i;

currOutD = (*currOutD).next;};

for (dk=0; dk < (*decoder).numInputs; dk++)prob[dk].i /= (*currElementA).signal[dk].i;

for (dk=0; dk < (*decoder).numInputs; dk++)for (b=0; b < bits; b++)

probS = ((*decoder) .bitValue[dk] [b] == 0)(*currElementS).signal[b}.q;

prob[dkl.i /= probS;};

sumfor

for

? (*currElementS).signal[b].i :

= 0;(dk=; dk < (*decoder).numInputs; dk++)

sum += prob[dk].i;(dk=0; dk < (*decoder).numInputs; dk++)

prob[dk].i /= sum;/* limit magnitude of probability. prob < 1, so log(prob) <0 /if (fabs(log(prob[dk].i)) > (*decoder).exp_limit)

prob[dk].i = exp(-l * (*decoder).explimit);

if (currOutA != NULL)(*currOutA).signal[dk].i = prob[dk].i;

if (currOutA == NULL)

addLLsignal((*decoder).output extrinsic, prob);else

currOutA = (*currOutA).next;

currElementA = (*currElementA).next;currElementS = (*currElementS).next;

};

free(lambda);free(prob);

} /* doMAPdecoding */

function: initAB

Initializes alpha and beta parameters

Input : MAPdecoderVars* decoder -char terminated -

OutputModify decoder.alpha, decoder.beta

used in MAP decoding.

pointer to MAP decoder varswhether trellis is terminated

void initAB(MAPdecoderVars* decoder, char terminated)

int m;double equiprob;

(*decoder).alpha[0] [0] = 1;for (m = 1; m < (*decoder).numStates; m++)

(*decoder).alpha[0] [m] = 0;

equiprob = 1.0 / (*decoder).numStates;(*decoder) .beta[(*decoder) .blockSize] [0] = (terminated) ? 1 : equiprob;for (m = 1; m < (*decoder).numStates; m++)

(*decoder) .beta[(*decoder) .blockSize] [m] = (terminated) ? 0 : equiprob;

/* initAB */

/*

Ifunction: initB usingA

decoder.c 191

Page 192: Simulating Turbo Codes using a Modular Simulation Platform

192 SIMULATION CODE

Initializes beta parameters in the case that the trellis isnot terminated.

Input MAPdecoderVars* decoder - pointer to decoderOutputModify (*decoder).beta

*/void initBusingA(MAPdecoderVars* decoder)

int m;

for (m=O; m < (*decoder).numStates; m++)(*decoder) .beta[(*decoder) .blockSize] [m] = (*decoder) .alpha[(*decoder) .blockSize [m];

/* initB_usingA *

/*,

function: probDecision

Choose maximum a posteriori probability.

Input linkList* input - list of the a posteriori probabilitieslinkList* output - list of the decoded bits

OutputModify output list

*/void probDecision(linkList* input, linkList* output)

int i, numEl, bits, j, max;

char b;listElement *currEl, *currOut;

/* in this case, valueLength holds the number of array indices, which foroutput probabilities is already numInputs */

bits = (int) (logl ((*input).valueLength) / log1O(2));numEl = getNumElements(input);currEl = (*input).head;currOut = (*output).head;

for (i=O; i < numEl; i++)

max = 0;/* look for highest probability */

for (j = 1; j < (*input).valueLength; j++)if ((*currEl).signal[j].i > (*currEl).signal[max].i)

max = j;/* add bits for dk with highest probability to output list *

for (j=0; j < bits; j++)

b = (max >> (bits-1 - j)) & Oxl;if (currOut == NULL)

addLLbits(output, &b);else

(*currdut).value[o] = b;currOut = (*currOut).next;

};};

currEl = (*currEl).next;

1;

/* probDecision /

/* ------------------- FAST RATE-1/2 RSCC MAP DECODER FUNCTIONS ------------------ */

/*

function: doFastRl2MAPdecoding

This function performs fast MAP decoding of rate-1/2 RSCC.

Input MAPdecoderVars* decoder - pointer to decoder structOutputModify *decoder

void doFastRl2MAPdecoding(MAPdecoderVars* decoder)

int k, Skprev, Sk;int pk;

Page 193: Simulating Turbo Codes using a Modular Simulation Platform

double lambdal, lambdao;double Ls, La;twoDSignalPoint LLR, Z;const double infinite = le308;double probA[2];listElement *currElementA, *currElementS, *currOutA, *currOutD;

calcalphaRl2(decoder);if ((*decoder) .beta[(*decoder) blockSize] [0] != 1)

initB usingA(decoder);calcbetaRi2(decoder);

currOutD = (* (*decoder).output_Dprob).head;currOutA = (* (*decoder) outputextrinsic) .head;currElementA = getElement (*decoder) inputA, 1)currElementS = getElement (*decoder) inputS, 1)

for (k=l; k <= (*decoder).blockSize; k++)

probA[0] = 1.0 / (1 + exp((*currElementA) signal [0}.i));probA[1] = exp((*currElementA).signal[0].i) * probA[0];

lambdal = 0;lambdaO = 0;for (Sk_prev=0; Sk_prev < (*decoder) .numStates; Skprev++)

Sk = (*decoder) .trellis[Sk_prev] [0) .S2;pk = (*decoder) trellis [Skprev) [0].p;lambdaO += (*decoder) gamma[k] [0] [pkl * probA[0] *

(*decoder).beta[k] [Ski;if (lambdaO > infinite)

pk = 0;Sk = (*decoder) trellis [Sk_prev] [1}.S2;pk = (*decoder) trellis [Sk_prev] [1].p;lambdal i= (*decoder) gamma[k] [1] [pk] * probA[l] (

(*decoder).beta[k][Sk];if (lambdal > infinite)

pk = 0;

decoder).alpha[k-l] [Sk_prev *

decoder).alpha[k-i] [Sk_prcv] *

};

LLR.i = log(lambdal/lambda0);LLR.q = LLR.i; /* set q = i in case accidentally use the q part */if (currOutD == NULL)

addLLsignal((*decoder) .outputDprob, &LLR);/* if currOut is NULL, it will remain NULL throughout this MAP

decoding round, and bit probabilities will be added to theoutput list */

else

(*currOutD).signal(O] = LLR;currOutD = (*currOutD).next;

};

La = (*currElementA).signal[0].i;currElementA = (*currElementA).next;

Ls = (*currElementS).signal[0].i;currElementS = (*currElementS).next;

Z.i = (LLR.i - La - Ls);

/* we need to limit the magnitude of the extrinsic LLR, or a priori information.an LLR of explimit or -explimit means that we are VERY certain that thebit is a 1 or 0, respectively. There's no need to further increase ordecrease the extrinsic LLR because at this point, we are already certain whatthe bit is. This is a non-linear operation, but it should not affect thecorrection power of the turbo code or the performance.

*/if (fabs(Z.i) > (*decoder).explimit)

Z.i = (Z.i)/fabs(Z.i) * (*decoder) .exp limit;Z.q = Z.i;

if (currOutA == NULL)addLLsignal((*decoder)

else

I

.output extrinsic, &Z);

(*currOutA).signal[O] = Z;currOutA = (*currOutA).next;

};

} /* doFastRl2MAPdecoding */

function: calcgammaR12

Calculates the gamma parameter used

Input MAPdecoderVars* decoderOutputModify

in MAP decoding.

decoder.c 193

{

Page 194: Simulating Turbo Codes using a Modular Simulation Platform

194 SIMULATION CODE

void calcgammaR12(MAPdecoderVars* decoder)

int k, a, b;

double expval;twoDSignalPoint probP, probS;listElement *currElementS, *currElementP;

currElementS = (*decoder).inputS->head;currElementP = (*decoder).inputP->head;for (k=1; k <= (*decoder).blockSize; k++)

expval = exp((*currElementP).signal[0[.i);probP.i = 1.0 / (1 + expval); /* pk = 0 *probP.q = probP.i * exp_val; /* pk = 1 *

expval = exp((*currElementS).signal[0].i);

probS.i = 1.0 / (1 + exp_val);probS.q = probS.i * exp_val;

(*decoder).gamma[k][0] [0] = probS.i * probP.i;(*decoder).gamma[k][0][1] = probS.i * probP.q;(*decoder).gamma[k} [1][0] = probS.q * probPi;(*decoder).gamma[k} [1][1] = probS.q * probP.q;

for (a=0; a<2; a++)

for (b=0; b<2; b++)

if (* decoder) .gamma[k] [a] [b] < (exp(-1* (*decoder) .explimit)))(*decoder) gamma[k] [a] [b] = exp(-1* (*decoder) .exp-limit);

currElementS = (*currElementS).next;currElementP = (*currElementP).next;

}; /* for k */

/* calcgammaR12 */

/*

function: calc alphaRi2

This function calculates all the alpha parameters needed inMAP decoding.

Input

OutputModify

void calc alphaRl2(MAPdecoderVars* decoder)

int k, dk, Sk; /* alpha indices -- alpha[k] [dk] [Sk] *int Skprev; /* summation indices */int pk;double sum;listElement* currA;

double probA[2[;

currA = (*decoder).inputA->head;

tor k=1; k -= (*decoder).blockSize; k++)

probA[0] = 1.0 / (1 + exp((*currA).signal[0].i));probA[1] = exp((*currA).signal[0[.i) * probA[0];

for (Sk = 0; Sk < (*decoder).numStates; Sk++)(*decoder).alpha[k] [Sk] = 0;

/* now loop through branches: each trellis[Sk-1] [dk] is a branch */for (Skprev = 0; Skprev < (*decoder).numStates; Skprev++)

for (dk = 0; dk < (*decoder).numInputs; dk++)

{Sk = (*decoder) trellis [Sk_prev] [dk] .S2; /* branch: Sk-1 -- > Sk, input dk */pk = (*decoder) .trellis [Skjprev] [dkj .p;(*decoder) .alpha [k] [Sk] += (*decoder) .gamma[k] [dk] [pk] * probA[dk] (*decoder) .alpha[k-

1] [Skprev;; /* for Skprev /

/* alpha[k] [Sk] is supposed to equal numerator[k] [Sk] / denominator[k]however, because denominator[k] is the same for every state at a time k,it acts like a constant for a time k and divides out in the finalcalculation of L(dk). However, this means that alpha will accumulatefaster with each k, so it'll need to be normalized */

sum = 0;for (Sk=0; Sk < (*decoder).numStates; Sk++)

sum += (*decoder).alpha[k[ [Sk];for (Sk=0; Sk < (*decoder).numStates; Sk++)

(*decoder).alpha[k][Sk] /= sum;/* if ((*decoder) .alpha[k] [Sk] < exp(-l* (*decoder) .exp_limit))

(*decoder) .alpha [k] [Sk] = exp(-1* (*decoder) .exp_limit);*/

};

Page 195: Simulating Turbo Codes using a Modular Simulation Platform

currA = (*currA).next;}; / for k /

S/* calcalphaR12 *

function: calc_betaRl2

This function calculatesdecoding

Input

OutputModify

all the beta values used in MAP

void calcbetaR12(MAPdecoderVars* decoder)

int k, Sk; /* beta indices -- beta[k][Sk] /int dk future, Sk future; /* summation indices /int pk;double sum;listElement* currA;double probA[2];

currA = (*(*decoder).inputA).tail;for (k = ((*decoder).blockSize - 1); k >= 1; k--)

probA[0] = 1.0 / (1 + exp((*currA).signal[O].i));probAil] = exp((*currA).signal[0].i) * probA[0];

for (Sk = 0; Sk < (*decoder).numStates; Sk++)(*decoder).beta[k][Sk] = 0;

/* loop through branches: each trellis[Sk-1] [dk] is a branch *for (Sk = 0; Sk < (*decoder).numStates; Sk++)

for (dkfuture = 0; dkfuture < (*decoder).numInputs; dkfuture++)

pk = (*decoder) trellis [Sk] [dk_future .p;Skfuture = (*decoder).trellis[Sk) [dk future].S2;(*decoder) beta[k] [Sk] += (*decoder) gamma[k+l] [dk future] [pk probA[dk future]

(*decoder).beta[k+l][Skfuture];

}; /* for dk+l */

sumfor

for{

= 0;(Sk=0;

SUM +=(Sk=0;

Sk < (*decoder).numStates; Sk++)(*decoder).beta[k] [Sk];

Sk < (*decoder).numStates; Sk++)

(*decoder).beta[k] [Sk] /= sum;if ((*decoder) .beta[k] [Sk] < exp(-l* (*decoder) explimit))

(*decoder) beta [k] [Sk] = exp(-l*(*decoder) exp-limit);

};

currA = (*currA).prev;

}; /* for k *

} /* calc_betaR12 */

function: signDecision

Performs a sign decision ongenerate the decoded bits.

Input

OutputModify

LLR's used in MAP decoding to

void signDecision(linkList* input, linkList* output)

int i, numEl;

char b;listElement *currEl, *currOut;

numEl = getNumElements(input);currEl = getElement(input, 1);currOut = (*output).head;for (i=O; i a numEl; i++)

b = ((*currEl).signal[0].i >= 0);

decoder.c 195

Page 196: Simulating Turbo Codes using a Modular Simulation Platform

196 SIMULATION CODE

if (currOut == NULL)addLLbits(output, &b);

else

(*currOut).value[O] = b;currOut = (*currOut).next;

}1;

currEl = (*currEl).next;

};

} /* signoecision */

Page 197: Simulating Turbo Codes using a Modular Simulation Platform

REFERENCES

[1] P. Melsa, "Application of Programmable DSPs for DMT and ADSL", in DSPWorld Spring Design Conference, April 1998.

[2] C. Berrou, A. Glavieux, and P. Thitimajshima, "Near shannon limit error-correctingcoding and decoding: Turbo-codes", in Proc. ICC '93, pp. 1064-1070, May 1993.

[3] MIT, "Lecture 10: Introduction to Modems", in 6.401/6.450 Introduction to DigitalCommunications, Fall 2000.

[4] P. Robertson, "Illuminating the structure of code and decoder of parallelconcatenated recursive systematic (Turbo) codes", in Proc. GLOBECOM '94, pp.1298-1303, December 1994.

[5] Stanford University, "Chapter 11: Code Concatenation and Low-Density ParityCheck Codes", in EE379B - Digital Communication H1: Coding, Spring 2001.

[6] S. Le Goff, A. Glavieux, and C. Berrou, "Turbo-codes and high spectral efficiencymodulation", in Proc. ICC '94, pp. 645-649, May 1994.

[7] P. Robertson and T. W6rz, "A novel bandwidth efficient coding scheme employingTurbo codes", in Proc. ICC '96, pp. 962-967, June 1996.

[8] S. Le Goff and F. 0. Al-Ayyan, "Design of bit-interleaved turbo-codedmodulations", Electronic Letters, vol. 37, no. 16, pp. 1030-1031, August 2001.

[9] S. Benedetto, D. Divsalar, G. Montorsi, and F. Pollara, "Bandwidth efficientparallel concatenated coding schemes", Electronic Letters, vol. 31, no. 24, pp.2067-2069, November 1995.

[10] S. Benedetto and Guido Montorsi, "Design of parallel concatenated convolutionalcodes", IEEE Trans. On Communications, vol. 44, no. 5, pp. 591-600, May, 1996.

[11] L. R. Bahl, J. Cocke, F. Jelinek, and J. Raviv, "Optimal decoding of linear codes forminimizing symbol error rate", IEEE Trans. On Information Theory, vol. IT-20, pp.284-287, March 1974.

- 197 -

Page 198: Simulating Turbo Codes using a Modular Simulation Platform

198 REFERENCES

[12] P. Robertson and T. W6rz, "Bandwidth efficient Turbo Trellis-coded modulationusing punctured component codes", IEEE J. on Selected Areas of Comm., vol. 16,no. 2, February 1998.

[13] A. A. Barbalescu and S. S. Pietrobon, "Terminating the trellis of turbo-codes in thesame state", Electronic Letters, vol. 31, no. 1, pp. 22-23, January 1995.

[14] J. Torres, F. Hirzel, and V. Demjanenko, (VOCAL Technologies Ltd), "G.gen: Newproposal of Turbo codes for ADSL modems", ITU standard contribution BA-020R1at Antwerp, Belgium, 19-23 June 2000.

[15] S. A. Barbulescu, J. A. Torres, F. Hirzel, and V. Demjanenko, (VOCALTechnologies Ltd), "G.gen: G.vdsl: G.dmt.bis: G.lite.bis: : Text to include a Turboencoder as mandatory in the transmitter for G.922.1.bis and G.992.2.bis followingthe proposal given in BA-020R1 and HC-037", ITU standard contribution CF-037at Clearwater, Florida, 8-12 January 2001.

[16] F. Hirzel, J. A. Torres, and V. Demjanenko, (VOCAL Technologies), "G.gen:G.vdsl, G.dmt.bis: G.lite.bis: : Method for using non-square QAM constellationswith independent I&Q for Receiver soft-Decision Decoding Techniques", ITUstandard contribution CF-038 at Clearwater, Florida, 8-12 January 2001

[17] W. Farrell, (iCODING Technology), "G.gen : G.dmt.bis : G.lite.bis : Lowcomplexity Turbo coding for the ADSL DMT channel", ITU standard contributionCF-072 at Clearwater, Florida, 8-12 January 2001.

[18] D. V. Bruyssel, (Alcatel), "G.gen: G.dmt.bis: G.lite.bis: Multilevel Turbo SCCCcode: proposal, performance and complexity", ITU standard contribution RN-079 atRed Bank, New Jersey, 21-25 May 2001.

[19] B. I in and A Deczky, (Catena Networks Inc), "G.gen: G.dmt.bis: (.lite hisProposing 'Multi-level" Turbo TCM concatenated with Reed-Solomon codes as theadvanced coding method for G.dmt.bis and G.lite.bis", ITU standard contributionIC-024 at Irvine, California, 9-13 April 2001.

[20] H. Sadjadpour, (AT&T), "G.gen: G.dmt.bis: G.lite.bis: : Encoder structure of Multi-tone Turbo Trellis coded modulation proposal", ITU standard contribution RN-027at Redbank, New Nersey, 21-25 May 2001.

[21] H. Sadjadpour, (AT&T), "G.gen: G.dmt.bis: G.lite.bis: : Interleaver design formulti-tone Turbo Trellis coded modulation scheme for G.dmt.bis and G.lite.bis",ITU standard contribution RN-029 at Redbank, New Jersey, 21-25 May 2001.