Simulating Turbo Codes using a Modular Simulation ... C.

advertisement
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
aitKEN
at the
MASSACHUSETTS INSTITUTE OF TECHNOLOGY
MASSACHUSETS WSTITUTE
OF TECHNOLOGY
May 24, 2002,
JUL 3 1 200?
Copyright 2002 David C. Lee. All rights reserved.
LIBRARIES
The author hereby grants to M.I.T. permission to
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
-4
Simulating Turbo Codes using a Modular Simulation Platform
by
David C. Lee
Submitted to the
Department of Electrical Engineering and Computer Science
May 24, 2002
In Partial Fulfillment of the Requirements for the Degree of
Master of Engineering in Electrical Engineering and Computer Science
ABSTRACT
A simulation tool was created to evaluate the performance of Turbo codes proposed for
digital subscriber loop channels. The tool is modular and was designed to be highly
flexible. In particular, the use of linked list data structures to handle module input and
output data flow allows the tool to be structurally flexible. Module definitions are
defined comprehensively and allow for high component flexibility, as well. Expressions
are provided for MAP decoding of convolutional codes under 4-QAM and under higher
spectral efficiency modulations. Simulation results match cited results relatively well and
indicate that Turbo code algorithms are implemented correctly in the tool. Results offer
confidence in the ability of the simulation tool to correctly estimate the performance of
Turbo codes.
Thesis advisor: Vahid Tarokh
Title: Associate Professor
VI-A company supervisor: Nick Zogakis
Title: Systems Engineer
-3-
-4-
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 and
reviews were invaluable throughout the course of this study.
The other members of my group at Texas Instruments were of great help in their
generous contribution of time and resources. In particular, my many insightful
discussions with Chia-Ning Peng and Elisa Pasquali helped to clarify several issues.
During the simulation intensive phase of this study, Texas Instruments contributed
valuable computing time through the use of its workstations. In particular, Nick Zogakis,
Konrad Kratochwil, and Brian Weise, were generous in allowing me to use their
workstations for the simulations. I would also like to thank Krista Jacobsen and Patrick
Wang for their welcome support and encouragement throughout this study.
At MIT, my thesis advisor Vahid Tarokh was very enlightening in his responses
to my technical questions. Further, his comments and suggestions about the content of
this thesis greatly helped to shape it into its final form.
I thank Professor Marcus Zahn and Ms. Lydia Wereminski of the MIT VI-A
program, and my VI-A advisor Judy Hoyt, for my very positive experiences under the
program. Lastly, I thank both Texas Instruments and MIT for their support of this study.
It has been a rewarding experience!
-5-
-6-
CONTENTS
I
Introduction
15
2
Background
Transm ission using Signal Sets ...........................................................
2.1
T he Shannon L im it ..............................................................................
2.2
Probability of Error ..............................................................................
2.3
2.4
Calculating BER for an AWGN Channel .............................................
C hannel C oding ....................................................................................
.2.5
2.6
The C onvolutional C ode .......................................................................
Recursive Systematic Convolutional Code ...........................
2.6.1
Markov Structure of Convolutional Codes ............................
2.6.2
Decoding using Maximum a posterioriProbability ..............
2.6.3
2.7
Symbol Mapping and Channel Observations ......................................
4-Q A M M odulation ...............................................................
2.7.1
2.7.2
Higher Spectral Efficiency Modulation .................................
2.8
T he T urbo C ode ....................................................................................
The Turbo Encoder ................................................................
2.8.1
2.8.2
Iterative Decoding and the Turbo Decoder ...........................
2.8.3
Fast Decoding for Rate-1/2 Component Encoders ................
19
19
20
22
23
24
25
26
27
28
31
32
33
36
37
38
41
3
45
The Simulation Tool
45
3.1
Simulation Tool Scope ........................................................................
47
..................................
Flexibility
for
Structural
Design
Considerations
3.2
47
3.2.1
Simulation Tool Language ....................................................
48
3.2.2
Module Flow Implementation ...............................................
49
3.2.3
Data Transfer between Modules ...........................................
3.2.4
M odule Execution ..................................................................
50
51
3.3
Design Considerations for Component Flexibility ...............................
52
3.3.1
Linked List Design and Implementation ...............................
53
Interleaver Design and Implementation ...............................
3.3.2
55
3.3.3
Convolutional Encoder Design and Implementation .............
...............
55
for
Encoding
Use
of
the
Trellis
Diagram
3.3.3.1
57
3.3.3.2 Generating Polynomials ........................................
58
3.3.3.3 Constructing the Trellis Diagram ...........................
Puncturing / Un-puncturing Module Design and Implementation
3.3.4
60
.................................................................................................
62
Signal Mapper Design and Implementation ..........................
3.3.5
-7-
3.4
3.3.6
Channel and Demodulator Design and Implementation ........
3.3.7
MAP Decoder Module Design and Implementation .............
Sim ulation C ode O rganization .............................................................
64
65
66
4
Simulation Results
4.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 ..............................................................................
69
70
71
73
75
76
78
80
81
83
85
87
89
89
91
92
5
Discussion
5.1
Reliability of Simulation Tool ..............................................................
5.2
Unexpected Simulation Results ............................................................
5.3
Sim ulation Speed and Mem ory Usage .................................................
95
95
96
97
6
Conclusions
99
A
Main Simulation Code
turbosim -std.c .......................................................................................
turbosim -icoding.c ..............................................................................
turbosim -uncoded.c ............................................................................
101
101
108
114
B
Sample Output for turbosim-std.c
Screen Output .......................................................................................
119
119
123
Output File test.txt
C
.......................................
Simulation Code
general.h ................................................................................................
general.c ................................................................................................
linkedlist.h ............................................................................................
linkedlist.c .............................................................................................
source.h .................................................................................................
source.c .................................................................................................
interleave.h ...........................................................................................
interleave.c ............................................................................................
-8-
125
125
126
128
129
135
136
139
140
co n v .h ...................................................................................................
co n v .c ....................................................................................................
puncture.h .............................................................................................
puncturex .............................................................................................
mapper.h ...............................................................................................
m apperx ...............................................................................................
channel.h ...............................................................................................
ch an nel.c ...............................................................................................
demod.h ................................................................................................
d em o d .c .................................................................................................
decoder.h ...............................................................................................
d eco d er.c ...............................................................................................
14 8
14 9
159
160
165
166
177
17 8
180
18 1
184
18 5
197
References
-9-
-10-
LIST OF FIGURES
2-1
2-2
2-3
2-4
2-5
2-6
2-7
BER curve for uncoded 4-QAM ................................................................
Rate-1/2 recursive, systematic convolutional code ....................................
Rate-2/3 recursive, systematic convolutional code ....................................
Markov diagram of a four state, rate-1/2 convolutional code ....................
Trellis diagram ............................................................................................
C hannel coding ..........................................................................................
Signal points and labels for 4-QAM ...........................................................
25
26
26
27
28
29
32
2-8
2-9
Signal points and labels for 16-QAM .........................................................
Turbo encoder structure ..............................................................................
34
37
2-10 Turbo decoder structure ..............................................................................
40
3-1
3-2
3-3
3 -4
Turbo encoder from RN-027 ....................................................................
Turbo encoder from CF-072 .......................................................................
Turbo encoder from RN-079 ....................................................................
L inked list ..................................................................................................
46
46
46
50
4-1
4-2
4-3
4-4
4-5
4-6
4-7
4-8
4-9
4-10
4-11
4-12
4-13
4-Q A M signal set ........................................................................................
16-Q A M signal set ......................................................................................
Simulation 1 BER curves for Table 4.2 and Table 4.3 ...............................
Simulation 2 BER curves for Table 4.2 and Table 4.4 ...............................
Simulation 3 BER curves for Table 4.6 and Table 4.7 ...............................
Simulation 4 BER curves for Table 4.6 and Table 4.8 ...............................
Simulation 5 BER curves for Table 4.6 and Table 4.9 ...............................
Simulation 6 BER curves for Table 4.11 and Table 4.12 ..........................
Simulation 8 BER curves for Table 4.16 and Table 4.17 ...........................
Simulation 9 BER curves for Table 4.19 and Table 4.20 ...........................
Simulation 10 BER curves for Table 4.19 and Table 4.22 .........................
Simulation 11 BER curves for Table 4.24 ..................................................
Simulation 12 BER curves for Table 4.25 ..................................................
70
70
73
74
76
77
79
81
84
86
88
90
92
- II -
-
12-
LIST OF TABLES
3.1
Sum m ary of sim ulation files .............................................................................
68
4.1
4.2
4.3
4.4
4.5
4.6
4.7
4.8
4.9
4.10
4.11
4.12
4.13
4.14
4.15
4.16
4.17
4.18
4.19
4.20
4.21
4.22
4.23
4.24
4.25
4.26
Simulation I puncturing and mapping scheme .................................................
Approximate BER values from cited graphs for simulation I Turbo code .......
Simulated BER values for simulation 1 after 10,000 and 100,000 blocks ........
Simulated BER values for simulation 2 after 10,000 and 100,000 blocks ........
Simulation 3 puncturing and mapping scheme .................................................
Approximate BER values from cited graphs for simulation 3 Turbo code .......
Simulated BER values for simulation 3 after 10,000 and 100,000 blocks ........
Simulated BER values for simulation 4 after 2,500 and 25,000 blocks ............
Simulated BER values for simulation 5 after 10,000 and 100,000 blocks ........
Simulation 6 puncturing and mapping scheme .................................................
Approximate BER values from cited graphs for simulation 6 Turbo code .......
Simulated BER values for simulation 6 after 1,666 AND 16,666 blocks .........
Simulation 7 puncturing and mapping scheme .................................................
Simulated BER values for simulation 7 after 1,666 AND 16,666 blocks .........
Simulation 8 puncturing and mapping scheme .................................................
Approximate BER values from cited graphs for simulation 8 Turbo code .......
Simulated BER values for simulation 8 after 1,666 blocks ...............................
Simulation 9 puncturing and mapping scheme .................................................
Approximate BER values from cited graphs for simulation 9 Turbo code .......
Simulated BER values for simulation 9 after 2,500 blocks ...............................
Simulation 10 puncturing and mapping scheme ...............................................
Simulated BER values for simulation 10 after 2,500 and 25,000 blocks ..........
Simulation 11 puncturing and mapping scheme ...............................................
Simulated BER values for simulation 11 after 650 blocks ................................
Simulated BER values for simulation 12 after 1,666 blocks ............................
Sum m ary of sim ulation results ..........................................................................
71
71
72
74
75
75
75
77
78
80
80
80
82
82
83
83
83
85
85
85
87
87
89
90
91
93
5.1
5.2
Sim ulation tool m em ory usage ..........................................................................
Sim ulation tool speed .......................................................................................
98
98
- 13
-
-
14-
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
-
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.
effort.
In particular, the Turbo code has been the focus of much research
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.
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.
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-
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
E
Ej -- 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.
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<Wlog 2 (1+ SNR)
R
<log2 (1+
W
SNR)
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
No
[dB]>10log, 0 21
p
(5)
)
22
2.3
CHAPTER TWO
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->!=
a
2
2 dy
.
N
(6)
Expressed using the Gaussianprobabilityof errorfunction
Q(x)=fj
e
2
dy
the error probability in (6) becomes
probabilityof 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
BACKGROUND
23
23
BACKGROUND
any increase or decrease in d will affect a similar increase or decrease in Eb . The
parameter
oN
is directly related to No in an AWGN channel by
UN2
= No /2.
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
JN
2
No(
E
2_. iqs
=E,2 q2 b)
No
.
(8)
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
generated from a Gaussian process with variance
2
aN
.
Then, these samples can be added
to transmit symbols to simulate an AWGN channel. Using the MD decision rule, the
CHAPTER TWO
24
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
BACKGROUND
25
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
1.E-02
1.E-03
wI
1.E-04
[
______________________
______________________
_______________________
1.E-05
1.E-06
1.E-07
__
3
__
4
4
__
5
__
6
7
__
8
__
9
10
Eb/No [dB]
Figure 2-1. BER 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.
CHAPTER TWO
26
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
U0
3~S
Figure 2-2. Rate-1/2 recursive, systematic convolutional code
p1
U0
~111
)(
30
Figure 2-3. Rate-2/3 recursive, systematic convolutional code
P
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= 1
0
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.
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.
R =(r, r,).
In two-dimensional space, the observation is
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 posterioriprobabilities
(APP) and to choose the largest one. For a rate-k/n convolutional code, the data bits
BACKGROUND
29
U, = i (t corresponding to a discrete time index) can have values i = 0, 1, 2, ... ,
2k_-
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
Ut
MSCC(
t
*
AtJJGN channel
obsenrdion
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
t~~~~
Za,_(m'y(R,,mn', m),(in)
ni
)i(RI
13
M
.
(9)
30
30
CHAPTER TWO
CHAPTER TWO
)
K,,,),, is a factor used to normalize the sum of Pr(u, = i RIN 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[)
(10)
Pr(R, 1 St = m)
.8t(in)= Pr(R, 1 R[
N+
(11)
They are recursively calculated using
a, (in) = Ka
a,_ (m')y (R,, in', m)
t+1
,(M')=- Kg
(12)
m)8+nm
yj(R,, 17', m#4()
(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. However, if the code is not
terminated, then there are two ways to initialize
8#(m) equiprobable by setting each term to
2 -,
#(m).
The first way is to make all
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 parameteris 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)
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 prioriprobability, which can also be written as Pr(u, =i) for all values of i.
The a prioriprobability 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.
CHAPTER TWO
32
The following two sub-sections discuss symbol mapping and decoding under 4QAM 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
*
-1
*
11
1-
0
1
-1-
00
0
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)
Pr(r,|,
= i, S,_, = m', S, = M).
(15)
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 rate1/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.
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].
1110
1010
1111
1011
0101
1101
1001
0100
1100
1000
0
S
0010
0110
0
0
0011
0111
0
0
0001
0000
0
0
0
S
Figure 2-8. Signal points and labels for 16-QAM
The formula [4] for calculating the LLR of the j1 h bit L(b) is
le
L(bj)
n
2U.2
b
and
2
P1 :b =1
Ye-0
P0~b =0
for J <-,
2U
2
(12
(18)
BACKGROUND
35
35
BACKGROUND
L(b)= In
P1:bj =1
for j
b .
2
(19)
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 Pr(RIu, =i,S,_, =m',S = m) can no longer be separated as
shown in (15).
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,_
(20)
= 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)=
t
hle
E11
~b
(21)
bb)
i
-- 6eL~i
and
rHeb)L(b)
Pr(RIu, =i,S, - = m',S, = m)=
biep
E
I+e~b
(22)
)
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
that R,' is a function of LLRs in the set t L(b,) b1 e p,
}.
{ L(bJ)
b1 e u,
} and
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.
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.
ULt
Lit
t=
:pit(
encoder 1
puncturing
mechanism
intereaer
Pt
Ut
,
RCC
encoder 2
010101...
101010...
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
CHAPTER TWO
38
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
n]
=
112
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)
BACKGROUND
The right side of equation (23) has three parts:
39
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 Iu, = i)- Pr(u, = i)
From the extrinsic information, we define the extrinsicprobability P,-
<
=Kex
as
Pr(ut =i RN
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 prioriinformation.
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
CHAPTER TWO
40
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
probability 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)
t
Pr (u'=i)
P
LfL(
:
0nee
L(u)
e
MAP decoder 2
MAP decoder 1
1
L(p )
L(p2)
APP'
APPI
mFximum APP
decision
Figure 2-10. Turbo decoder structure
Example 2-1.
Iterative decoding using extrinsic probabilities
Iteration 1
* MAP decoder I has no a priori input during the first iteration, so it uses
Pr(u, =i)= 2 -k in equation (23) to calculate the APP and generates P eli using
equation (25), for all i = 0, ... , 2
k-'
and t
=1,
... ,r.
41
BACKGROUND
MAP decoder 2 uses the time-interleaved sequence Pr(u,. = i)= P,"
to calculate the APPs:
in equation (23)
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,._(M'),.t,(M)
MAP decoder 2 generates
t,< using (25) for all i and t'.
Here, t' refers to an
interleaved sequence with respect to t.
Iteration 2 and beyond
-
MAP decoder I uses the de-interleaved sequence Pr(u,
calculate the APPs:
Pr(u = i RN
YJ
=Pr(R;| u,=
t
=
i)= Pt22 in equation (23) to
.
Pr(R,u, =i,S_ =m',S,
m)Prfu, = i|S,_1 = m', St = M). a,_] (M'),t(M)
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(RiIu,. = i). P t i
Pr(RmtIu,. = i, S,._, = m', S,, = m)Pr(u, =|_,
= m'
MAP decoder 2 generates p, 2 ,i using (25) for all i and t'.
interleaved sequence with respect to t.
,
-I _
',(M)
Here, t' refers to an
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 :
42
CHAPTER TWO
Pr(u, =1 RN
A(u )=ln
' Pru, =01 R,
-N(m')y,
1 (R,,m,m),(m)
In
(26)
0(R,,Inm)'1 (mn)
a,- (y
Expanding the y parameters in (26) the same way as in (23), equation (26) becomes
A(u, )=L + L' + L
where
u 1 =i)
L' = In P
Pr(R, u, =0)
and
L' =In Pr(u )
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.
BACKGROUND
43
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, so it uses
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:
j2e
Pr(u, = i) =
ueLt
M+ 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)= e
MAP decoder 2 generates L
sequence with respect to t.
I+ e 4
using (27) for all t'. Here, t' refers to an interleaved
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
-
CHAPTER THREE
46
interleaer 2
RSC
encoder 1
''
Ut
t --mechanism
=
?. U"t
puncturng
...
t010101...
101010 ...
RS(r 32
UF
encoder2
I
Figure 3- 1. Turbo encoder from RN-027
,
Ut
4
RSCC
encoder
t
1
t
punctung
mechanism
interleaver 11
100100 ...
Ut
intede;Der 2
n1c de 3S
Pt
010010 ...
001001 ...
RS~C
encoder 2
-
Ut
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
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
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
interleaver.input
encoder2.input
puncturer.inputl
puncturer.input2
=
=
=
=
=
bitSource.output;
bitSource.output;
interleaver.output;
encoderl.output;
encoder2.output;
Code 2. Module flow connections
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.
requirements is a linked list.
The most appropriate structure for implementing these
50
CHAPTER THREE
head
next
-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
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
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 linkListStruct
valueLength;
int
listElement *head, *tail;
struct linkListStruct *output;
} linkList;
Code 4. Linked list definition
THE SIMULATION TOOL
Code 4 shows the linked list definition used by the simulation tool.
53
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.
valueLength
The lengths of the arrays are the same and are specified by the variable
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.
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 interleaverVarsStruct
int blockSize;
int* permutePattern;
linkList* input;
linkList* output;
interleaverVars;
Code 5. Interleaver module definition
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 kbit 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
CHAPTER THREE
56
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
branch**
int*
char*
encoderVarsStruct
trellis;
terminator;
state;
int
k;
int
int
r;
V;
linkList*
linkList*
encoderVars;
input;
output;
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
THE SIMULATION TOOL
3.3.3.2
57
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
i=0 j=0
a"i
(t
j) +
i=0 J=I
(28)
b" y(t-j).
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
Y, (t)+ Y
i=0 j=I
k-I
v
b|"yi(t - j)=
i=0 j-0
a,"' ui(t - j)j.
(29)
Then, taking the D-transform of (29) and rearranging, we have
k-I
y,, (D 1 +
JDj ) +0
The sequences a,'=ia'0... a'"
Y(D ( b7jD
j=0
=
and b"=( b'. .. bt"'
a,"'JD
ut(D
i=0
J-
(30)
0
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-
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
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.
array.
Feed-forward polynomials are stored in a three-dimensional
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
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 punctureVarsStruct
numInputs;
int
int
punctureLength;
currIndex;
int
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
THE SIMULATION TOOL
with LLR = 0, indicating that the bit is equally likely to be zero or one.
61
Since the
puncturing module will work for any number of input bits, the stop condition for unpuncturing must make certain that the number of LLRs at each output of the unpuncturing module is at least the number of parity bits at each input to the puncturing
module.
Consider the two puncturing patterns below:
Pattern
index
input 1:
input 2:
1
Pattern
2
0123
012345
1010
0101
010000
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.
62
CHAPTER THREE
typedef struct unPunctureVarsStruct
int
numOutputs;
punctureLength;
int
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
THE SIMULATION TOOL
order is stored in a one-dimensional array in which a 's'
63
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 twoDsignalMapVarsStruct
bitMapVars 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.
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
2
by 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 channelVarsStruct
double 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
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 posterioriprobabilities
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.
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*
linkList*
linkList*
linkList*
inputP;
inputA;
outputDprob;
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
THE SIMULATION TOOL
functions, and memory de-allocation functions.
67
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.
68
68
CHAPTER THREE
CHAPTER THREE
File name
turbosim-std.c
Description
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
Module Ifunction(s)
Module initialization functions
File name
general.h
general.c
general functions
linkedlist.h
linkedlist.c
linked list
llistInitVars( )
source.h
source.c
bit generator module /
genBits()
selectBlockSize()
interleave.h
interleave.c
interleaver module /
doInterleave( )
Random pattern - randomPatterninitVars()
Semi-random pattern - SrandomInitVars( )
Get pattern from a file - interleaverFileInitVars()
conv.h
conv.c
convolutional encoder
module /
encodeBlock()
terminateEncoder()
Rate-1/2 - rate]2initVars()
Rate-k/(k+l) - ratekk]InitVars()
Copy an encoder - duplicateEncoder()
puncture.h
puncture.c
puncture module /
punctureBlock( )
unpuncture module /
unpunctureBlock()
2-input puncturer - twoPuncturelnitVars()
3-input puncturer - threePunctureInitVars()
Un-puncturer - unPunctureInitVars()
Bit map pattern - bitMapInitVars()
QAM signal set - QAMSignalSet()
Normal bit labels - normalMappingInitVars()
Gray code labels - createGrayCode()
mapper.h
mapper.c
signal mapper module /
mapBlock()
channel.h
channel.c
channel module /
sendAWGNblock()
demod.h
demod.c
demodulator module /
demodulateTwoDBlock()
decodeuncoded()
demodulatorInitVars()
decoder.h
decoder.c
MAP decoder module I
doMAPdecoding()
doFastRl2MAPdecoding()
MAPdecoderInitVars()
channellnitVars()
Table 3.1. Summary of simulation files
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
-
70
CHAPTER FOUR
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
.
00
11
I
.
-10
-1 -
10
Figure 4-1. 4-QAM signal set
0010
0110
0
0
0011
0111
0
0
-3
-1
0001
0101
0000
0
0100
3
1110
1010
0
0
1111
1011
S
'
i
|
1
3
1S
-1
1101
1001
1100
0
1000
-3
Figure 4-2. 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
component
RSCC encoders
have rate-1/2, and the
generator polynomials
are
ao = 35 and b =23,. The encoders are implemented using the structure in Figure 2-2.
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)
Parity bit (p)
Parity bit (p2 )
Bit mapping per symbol
u1
p
U2
P22
(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.
Iteration
EWNo
0.5
1.0
1.5
2.0
1
1.00E-01
8.OOE-02
4.50E-02
1.70E-02
2
1.00E-01
5.OOE-02
8.OOE-03
2.50E-04
3
1.00E-01
2.50E-02
1.00E-03
2.50E-06
4
1.00E-01
2.OOE-02
4.OOE-04
8.OOE-07
8.
1.0E-01
1.OOE-02
9.OOE-05
1.1 OE-07
Table 4.2. Approximate BER values from cited graphs for simulation I Turbo code
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.
E
After 8 iterations at
/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.
Iteration
Ed/No
0.50
0.75
1.00
1.25
1.50
1
1.16E-01
1.00E-0 I
8.24E-02
6.38E-02
4.58E-02
2
1.04E-01
7.87E-02
4.93E-02
2.32E-02
7.54E-03
3
9.86E-02
6.52E-02
3.03E-02
8.50E-03
1.37E-03
4
9.47E-02
5.64E-02
2.15E-02
4.46E-03
5.1OE-04
8
8.82E-02
4.47E-02
1.30E-02
1.86E-03
1.55E-04
1.75
2.95E-02
1.58E-03
1.06E-04
2.11 E-05
3.78E-06
2.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.
SIMULATION RESULTS
SIMULATION RESULTS
73
73
1.E+00 1.E-01 1.E-02
-
1.E-03 -
_
___-_
M1.E-04 -
-
1.E-05 -
-
-
- -X
1.E-06 1.E-07
-
0
0.5
1
1.5
2
2.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
codes with polynomials ao = 178 and bo = 15.
yields better BER performance than using
74
74
CHAPTER FOUR
CHAPTER FOUR
Iterations
Eb/No
0.50
0.75
1.00
1.25
1.50
1
1.02E-01
8.77E-02
7.28E-02
5.78E-02
4.38E-02
2
8.59E-02
6.43E-02
4.23E-02
2.33E-02
1.02E-02
3
7.92E-02
5.21E-02
2.63E-02
9.28E-03
2.14E-03
4
7.54E-02
4.47E-02
1.80E-02
4.63E-03
6.76E-04
8
6.91E-01
3.36E-02
9.95E-03
I .59E-03
1.12E-04
1.75
2.00
3.14E-02
2.11E-02
3.62E-03
9.83E-04
3.49E-04
3.85E-05
6.99E-05
4.78E-06
7.26E-06
1.12E-06
Table 4.4. Simulated BER values for simulation 2 after 10,000 and 100,000 blocks
1.E+00
1.E-01
"0
1.E-02
1.E-03
w
1.E-04
1.E-05
1.E-06
1.E-07
0
0.5
1.5
1
2
Eb/No
Figure 4-4. Simulation 2 BER curves for Table 4.2 and Table 4.4
2.5
SIMULATION RESULTS
4.1.3
75
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)
Parity bit (pI)
Parity bit (p2)
Bit mapping per symbol
u1
p
U2
P2
(bo, b, , b2 , b3) = (up, p
,
u2 , p
2)
Table 4.5. Simulation 3 puncturing and mapping scheme
Eg/NO
2.0
2.5
3.0
3.5
4.0
4.5
5.0
1
9.00E-02
8.OOE-02
6.50E-02
4.00E-02
2.00E-02
6.00E-03
1.00E-03
2
9.00E-02
7.OOE-02
3.00E-02
9.00E-03
8.00E-04
3.OOE-05
1.00E-06
Iterations
3
9.OOE-02
6.OOE-02
2.50E-02
2.00E-03
5.OOE-05
6.00E-07
5.OOE-08
4
9.OOE-02
5.50E-02
2.20E-02
9.00E-04
2.00E-05
3.OOE-07
5.OOE-08
8
9.OOE-02
5.00E-02
1.1OE-02
3.00E-04
2.00E-06
9.00E-08
2.00E-08
Table 4.6. Approximate BER values from cited graphs for simulation 3 Turbo code
EdNo
2.0
2.5
3.0
3.5
4.0
1
9.34E-02
7.49E-02
5.34E-02
3.16E-02
1.41E-02
2
8.96E-02
6.38E-02
3.1OE-02
6.84E-03
5.23E-04
Iterations
3
8.89E-02
5.93E-02
2.01E-02
1.77E-03
3.OOE-05
4
8.88E-02
5.67E-02
1.51E-02
7.55E-04
7.52E-06
8
8.86E-02
5.31E-02
1.00E-02
2.63E-04
2.25E-06
4.5
5.0
4.56E-03
1.07E-03
2.04E-05
9.77E-07
8.40E-07
1.27E-07
6.05E-07
7.81E-08
2.73E-07
4.88E-08
Table 4.7. Simulated BER values for simulation 3 after 10,000 and 100,000 blocks
CHAPTER FOUR
CHAPTER FOUR
76
76
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.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.
SIMULATION RESULTS
77
Eb/No
2.5
3.0
3.5
1
7.60E-02
5.45E-02
3.20E-02
2
6.56E-02
3.08E-02
4.85E-03
Iterations
3
6.18E-02
8.52E-03
1.07E-05
4
6.01E-02
8.52E-03
1.07E-05
8
5.69E-02
1.50E-03
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-04
In
1.E-05
1.E-06
1.E-07
1.E-08
2
2.5
3.5
3
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.
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.
Iterations
E/No
2.0
2.5
3.0
3.5
4.0
1
8.62E-02
6.84E-02
4.95E-02
3.15E-02
1.68E-02
2
8.05E-02
5.68E-02
3.02E-02
9.84E-03
1.68E-03
3
7.96E-02
5.30E-02
2.18E-02
3.66E-03
2.26E-04
4
7.94E-02
5.13E-02
1.75E-02
1.88E-03
8.01E-05
8
7.93E-02
4.93E-02
1.29E-02
8.24E-04
1.91E-05
4.5
5.0
7.42E-03
2.56E-03
1.66E-04
1.14E-05
1.08E-05
6.48E-07
5.00E-06
3.91E-07
1.78E-06
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.
SIMULATION RESULTS
1.E+00
79
1
1.E-01
1. E-02
N1. E-03
i
i
--
i
%P
w
I
%
Ne %
1.E-04
1.E-05
xI
-
1.E-06
1.E-07
1. E-08
1.5
2
2.5
3
3.5
4
4.5
5
Eb/No
Figure 4-7. Simulation 5 BER curves for Table 4.6 and Table 4.9
5.5
CHAPTER FOUR
80
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)
Parity bit (p')
Parity bit (p2)
Bit mapping
u1
u2
u3
u4
-
P2
-
-
_
_
(bo ,b1 ,b2 ,b3 ) = (uI, u2 , u3 p 1p2)
U5
U6
p25
(bo ,b1 ,b2 ,b3) = (u4 , u5 , u6 , p 5)
Table 4.10. Simulation 6 puncturing and mapping scheme
Iterations
EdNo
4.5
5.0
5.5
6.0
1
6.00E-02
4.00E-02
2.50E-02
9.OOE-03
2
6.00E-02
3.50E-02
7.OOE-03
2.00E-04
3
6.00E-02
2.50E-02
9.OOE-04
9.OOE-07
4
6.OOE-02
2.00E-02
1.1 OE-04
9.50E-08
8
6.OOE-02
1.50E-02
1.1 0E-07
-
Table 4.11. Approximate BER values from cited graphs for simulation 6 Turbo code
EWNo
4.50
4.75
5.00
5.25
5.50
1
5.49E-02
4.74E-02
3.94E-02
3.09E-02
2.25E-02
2
5.23E-02
4.24E-02
3.03E-02
1.70E-03
6.34E-03
Iterations
3
5.19E-02
4.07E-02
2.49E-02
8.07E-03
8.46E-04
5.75
6.00
1.52E-02
9.08E-03
1.45E-03
1.89E-04
3.38E-05
8.40E-07
4
5.18E-02
3.98E-02
2.05E-02
3.34E-03
1.08E-04
8.40E-07
1.56E-07
8
5.18E-02
3.82E-02
1.19E-02
5.64E-04
3.9 1E-07
-
Table 4.12. Simulated BER values for simulation 6 after 1,666 AND 16,666 blocks
SIMULATION RESULTS
81
1.E+00
1.E-01
1.E-02
1.E-03
M
01-
1.E-04
1.E-05
1.E-06
1.E-07
1.E-08
4
4.5
5
5.5
6
6.5
Eb/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 convolutional encoders with
polynomials ao =118, a0 =158, a =178, and bg =138. The rate-3/4 code is the one
specified in [18] and is one of the encoders in Figure 3-3. The signal set is square 16QAM.
CHAPTER FOUR
82
Information bits (u)
Parity bit (p1 )
Parity bit (p2 )
Bit mapping
u1 , u2 , u3
U4 , U5, U6
p 1
(bo ,b1 ,b2 ,b3) = (u I,
, u)
Ip1
1)
P2
(bo ,b1 ,b2 ,b3 ) = (u4 , u5 , u6 , p
2)
Table 4.13. Simulation 7 puncturing and mapping scheme
Iterations
Eb/No
4.5
5.0
5.5
6.0
1
5.42E-02
3.84E-02
2.19E-02
9.12E-03
2
5.07E-02
2.81E-02
6.31E-03
4.08E-04
3
4.99E-02
2.16E-02
1.14E-03
7.70E-05
4
4.96E-02
1.68E-02
2.79E-04
1.22E-04
8
4.94E-02
8.15E-03
3.91E-03
9.89E-04
Table 4.14. Simulated BER values for simulation 7 after 1,666 AND 16,666 blocks
The results in Table 4.14 are puzzling.
Using a rate-3/4 encoder and the
puncturing pattern in 4.13, much fewer parity bits are punctured than in the scheme in
Table 4.10.
Intuitively, having more parity bits, and thus more information, should
improve the performance of the Turbo c ode relative to simulation 6. However, as Table
4.14 shows, performance is actually much worse.
Further, the BER does not
monotonically decrease with increasing iterations, which is odd.
SIMULATION RESULTS
4.1.8
83
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)
Parity bit (p)
Parity bit (p2)
Bit mapping
u1
p1
u2
u3
u4
-p
P22
-
(bo ,b1 ,b2 ,b3 , b4, b5 ) =
(u], u 2 , p i, u3 , P22, p 3)
u5
U6
P5
-5
P2
P 26
(bo ,b1 ,b2 ,b3, b4 , b5 ) =
(u 4 , u5 , p24, u 6 , p 5, P26)
Table 4.15. Simulation 8 puncturing and mapping scheme
Iterations
EdNo
5.0
5.5
6.0
6.5
1
6.OOE-02
4.OOE-02
2.1OE-02
1.00E-02
2
6.OOE-02
2.1OE-02
3.OOE-03
1.00E-04
3
6.OOE-02
1.00E-02
1.1OE-04
6.OOE-07
4
6.OOE-02
5.50E-03
2.OOE-06
8
6.OOE-02
5.50E-04
3.OOE-07
-
Table 4.16. Approximate BER values from cited graphs for simulation 8 Turbo code
EWNo
5.00
5.25
5.50
5.75
6.00
6.25
6.50
1
6.51E-02
5.65E-02
4.75E-02
3.83E-02
2.94E-02
2.13E-02
1.44E-02
2
6.48E-02
4.09E-02
2.60E-02
1.30E-02
4.70E-03
1.18E-03
2.OOE-04
Iterations
3
5.08E-02
3.19E-02
1.27E-02
2.30E-03
1.85E-04
7.03E-06
1.95E-07
4
4.86E-02
2.52E-02
5.13E-03
2.75E-04
1.27E-06
8
4.46E-02
1.13E-02
3.59E-02
-
Table 4.17. Simulated BER values for simulation 8 after 1,666 blocks
84
CHAPTER FOUR
1.E+00
_-_---
1.E-01
-_-
1.E-02
-_
- -
--
_-
1.E-03
-
1.E-04
1.E-05
-
1 .E-06
1.E-07
4.75
5
5.25
5.5
5.75
6
6.25
6.5
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.
6.75
SIMULATION RESULTS
4.1.9
85
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)
Parity bit (p)
Parity bit (p2
Bit mapping
u1
p_
u2
u3
U4
(bo ,b ,b2 ,b3 , b4 , b5 ) = (ul, u 2 , p 1, u3 , u 4 , p 3)
Table 4.18. Simulation 9 puncturing and mapping scheme
Eb/No
6.75
7.00
7.25
7.50
7.75
8.00
8.25
1
7.00E-02
6.00E-02
5.OOE-02
4.00E-02
3.00E-02
2.GOE-02
1.00E-02
2
6.00E-02
5.00E-02
3.50E-02
2.70E-02
1.00E-02
3.O0E-03
8.50E-04
Iterations
3
6.00E-02
4.00E-02
2.20E-02
9.OOE-03
2.00E-03
3.OE-04
2.50E-05
4
5.00E-02
4.00E-02
2.00E-02
5.00E-03
5.00E-04
4.OOE-05
1.1 OE-06
8
4.00E-02
3.00E-02
1.70E-02
1.70E-03
5.0E-05
2.00E-06
2.GOE-07
Table 4.19. Approximate BER values from cited graphs for simulation 9 Turbo code
Eb/No
6.75
7.25
7.75
8.00
7.75
8.00
8.25
1
5.08E-02
4.46E-02
3.81E-02
3.13E-02
2.45E-02
1.83E-02
1.27E-02
2
4.61E-02
3.73E-02
2.72E-02
1.69E-02
8.26E-03
2.97E-03
7.55E-04
Iterations
3
4.50E-02
3.45E-02
2.15E-02
8.90E-03
2.04E-03
2.43E-04
2.0GE-05
4
4.46E-02
3.29E-02
1.75E-02
4.70E-03
4.77E-04
2.50E-05
1.89E-06
8
4.43E-02
3.0IE-02
1.11E-02
1.19E-03
1.60E-05
2.34E-06
5.86E-07
Table 4.20. Simulated BER values for simulation 9 after 2,500 blocks
86
CHAPTER FOUR
CHAPTER FOUR
86
1.E+00
1.E-01
1.E-02
w
U
In
1.E-03
1.E-04
1.E-05
1.E-06
1.E-07
L+j
6.5
6.75
7
7.25
7.5
7.75
8
8.25
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.
8.5
SIMULATION RESULTS
4.1.10
87
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)
Parity bit (p')
Parity bit (p2)
Bit mapping
u1, u2
pI1
u3 , u 4
P 22
(bo ,bI ,b2 ,b3, b4 , b5 )
=
(uI, u2 , P 1, u3 , u4 , p22)
Table 4.21. Simulation 10 puncturing and mapping scheme
EdNo
6.75
7.25
7.75
8.00
8.25
1
5.17E-02
3.89E-02
2.48E-02
1.82E-02
1.21E-02
2
4.76E-02
2.79E-02
7.35E-03
2.34E-03
4.37E-04
Iterations
3
4.66E-02
2.14E-02
1.40E-03
1.19E-04
3.32E-06
4
4.63E-02
1.69E-02
2.77E-04
8.33E-06
1.95E-07
8
4.60E-02
9.90E-03
9.67E-06
2.64E-07
1.95E-07
Table 4.22. Simulated BER values for simulation 10 after 2,500 and 25,000 blocks
CHAPTER FOUR
88
CHAPTER FOUR
88
1. E+00
71f§_______
_______
1.E-01
-
1.E-02
-
2I~<~I7T~
1 E-03 -
Xi 7~kL
cc
Lu
X~'.
XK
1
\ xi i
r
M0
1.E-04
-~
1.E-05
I
--
V
--
-
-
r i-
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-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.
SIMULATION RESULTS
4.2
89
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.
simulation indicate that a BER on the order of
10
-7 is
Cited results for this
achievable at Eb INO =1.6 [dB]
with four decoder iterations.
Information bit (u)
u1
Parity bit (p1)
p1_
Parity bit (p)
Parity bit (p )
Bit mapping
u2
U3
2
-2
(bo , b1 ) = (ui ,p 1)
p 33
(bo , b1 ) =
(u 2 p2)
(bo , bi)
Table 4.23. Simulation 11 puncturing and mapping scheme
=
(u3, p 3 )
CHAPTER FOUR
90
Iteration
Eb/No
0.5
1.0
1.5
2.0
2.5
3.0
3.5
4.0
1
1.20E-01
9.62E-02
7.12E-02
4.64E-02
2.54E-02
1.1 3E-02
4.OOE-03
1.17E-03
2
1.19E-01
9.35E-02
6.49E-02
3.51E-02
1.23E-02
2.60E-03
3.69E-04
3.22E-05
4
1.19E-01
9.34E-02
6.39E-02
3.09E-02
6.70E-03
5.76E-04
2.39E-05
1.36E-06
3
1.19E-01
9.34E-02
6.40E-02
3.20E-02
8.37E-03
1.03E-03
7.51E-05
2.72E-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
1.E-01
X---- ifX.
1.E-02
M 1.E-03
1.E-04
1.E-05
1.E-06
0
1
2
3
Eb/No
Figure 4-12. Simulation 11 BER curves for Table 4.24
4
5
SIMULATION RESULTS
4.2.2
91
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.
Iterations
EJNo
0.5
1.0
1.5
2.0
2.5
3.0
3.5
1
1.02E-01
8.77E-02
7.28E-02
5.78E-02
4.38E-02
3.14E-02
2.11 E-02
2
8.59E-02
6.43E-02
4.23E-02
2.33E-02
1.02E-02
3.62E-03
9.83E-04
3
7.92E-02
5.21E-02
2.63E-02
9.28E-03
2.14E-03
3.49E-04
3.85E-05
4
7.54E-02
4.47E-02
1.80E-02
4.63E-03
6.76E-04
6.99E-05
4.78E-06
8
6.91E-01
3.36E-02
9.95E-03
1.59E-03
1.12E-04
7.26E-06
1.12E-06
Table 4.25. Simulated BER values for simulation 12 after 1,666 blocks
CHAPTER FOUR
CHAPTER FOUR
92
92
1.E+00
V
Jfk
-
_________
1~
-7
________
1.E-01 -
cc
______________
______________
______________
-
______
______
______
1%W-
__________________
________
~1~~
I
_____________
_________
___
-----H-
1.E-02 -
1.E-03
1.E-04
I.
0
0.5
1
1.5
2
2.5
I
3
3.5
4
4.5
Eb/No
Figure 4-13. Simulation 12 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
SIMULATION RESULTS
93
performance of different component codes and corresponding puncturing patterns. These
results are summarized below in Table 4.26.
simulation
1
2
structure
Fig. 2-9
Fig. 2-9
3
4
Fig. 2-9
Fig. 2-9
5
Fig. 2-9
6
7
Fig. 2-9
Fig. 2-9
8
9
10
Fig. 2-9
Fig. 2-9
Fig. 2-9
11
12
Fig. 3-2
Fig. 2-9
details
rate-1/2 turbo code
used RN-027 RSCC and
compared to simulation I
rate-2/4 turbo code
used longer interleaver and
compared to simulation 3
used RN-027 RSCC and
simulated results
matcbed-BA-020RI results
RN-027 RSCC performed
worse than BA-020R1
matched BA-020R1 results
longer interleaver improved
BER performance
RN-027 RSCC performed
compared to simulation 3
worse than BA-02OR1I
rate-3/4 turbo code
used rate-3/4 RSCC and
compared to simulation 6
rate-3/6 turbo code
rate-4/6 turbo code
used rate-2/3 RSCC and
compared to simulation 9
compared to CF-072 results
used CF-072 RSCC and
Scompared to simulation I
matched BA-020R1 results
results do not match
expectations and are odd
matched BA-020R1 results
matched BA-020R1 results
less puncturing improved
BER performance
did not match citedrtesuls
CF-072 RSCC performed
worse than BA-020R1
Table 4.26. Summary of simulation results
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
-
96
CHAPTER FIVE
is to send all
2N
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(lOx+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
DISCUSSION
MAP decoding parameters.
97
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 29 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.
CHAPTER FIVE
98
Module /
data structure
one linked list
Memory usage (bytes)
bit source
LL( # of elements, valueLength)=
16 + (# of elements) - ( 8 + 17 valueLength)
For a rate-k/(k+1) RSCC: LL( (blockSize 1k), k)
interleaver
4 - ( (blockSize/k) + 2 ) + LL((blockSize/k), k)
convolutional
encoder
Rate-k/(k+r) code, 2" states
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 2 M)
channel
12 + LL(# of symbols, 1)
demodulator
2 -LL(blockSize, 1)
unpuncturer
MAP decoder
16 + numOutputs - punctureLength + LL( # of elements, 1)
numOutputs
32 + k -2k + 8 - blockSize -2 k*v + 2 -LL(blockSize, 2 k)
main program
120 + (# of iterations)- LL(blockSize, 1)
+
8 -M + LL(# of symbols, 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
Dell Optiplex GX150, P111-1GHz, 512K memory
Dell Optiplex GX100, PIII-800MHz, 256K memory
SUN Sunblade 100 workstation
SUN Ultra 5 workstation
Table 5.2. Simulation tool speed
blocks / min
204
143
74
60
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
-
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
performance.
ao = 35,
and b = 238 yields the best
APPENDIX A
Main Simulation Code
turbo sim-std.c
turbo_sim-std.c
file:
This
is the
main program file that simulates turbo codes.
#include
#include
#include
#include
#include
#include
#include
#include
#include
"linkedlist.h"
"source.h"
#include
#include
#include
#include
#include
<math.h>
<time.h>
<stdio.h>
<string.h>
<stdlib.h>
int
"interleave.h"
"conv.h"
"puncture.h"
"mapper.h"
"channel.h"
"demod.h"
"decoder.h"
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
int
int
terminateBits;
untermBits;
numSymbols;
char
char
*patl, *pat2;
*bitmap;
misc variables
*/
timet starttime, curr time;
float tl, t2, t3;
int
hrs, mins, secs;
int
i;
int
int
long
long
char
double
char
char
char
k;
selection;
block;
blocks-left, blocks-done;
error;
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 iterations
*/
total 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
-
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
MAIN SIMULATION CODE
102
*/
simulation modules
*
*
/*
bit linked lists
linkList
linkList
linkList*
*/
origBitsLL;
uncodedBitsLL;
decodedBitsLL;
/* systematic buffer
/* uncoded bits buffer
/* decoded bits buffer
ENCODER modules
interleaverVars
encoderVars
encoderVars
punctureVars
twoDsignalMapVars
*/
interleaverl;
encoderl;
encoder2;
puncturer;
mapper;
/*
/*
/*
/*
/*
channel, soft-data modules */
channel;
channelVars
demodulator;
demodulatorvars
unpuncturer;
unPunctureVars
DECODER modules
MAPdecoderVars
MAPdecoderVars
interleaverVars
interleaverVars
interleaverVars
interleaverVars
MAP decoder 1
*/
MAP decoder 2
*/
extrins info interleaver */
extrin. info deinterleaver */
systematic bits interleaver*/
a posteriori prob deinterleaver */
==
INIT GENERAL VARIABLES
1;
-
terminated
/* AWGN channel
/* demodulator
/* unpuncture LLR values
MAPl;
MAP2;
extrinsicinterleaver;
extrinsic deinterleaver;
Sinterleaver;
Dprobdeinterleaver;
-=
interleaver
encoder 1
encoder 2
puncturer
signal mapper
notTerminated = 0;
= 171;
sourceSeed
= 0;
blocks done
==
INITIALIZE SIMULATION MODULES
-=
\n
printf("=
TURBO-CODE SIMULATI ON
printf("=
====\n")
printf("
printf("\n");
printf("\n");
------------------ \n");
printf(",-------------------------------------printf("\n");
\n");
s
printf(" I
>i
\n");
>------------->.---------printf("I
g
m
\n");
printf("
I
n a \n");
information bits -- > encoderl
printf("I
a p \n');
printf("
I
--.
->
encoder2
p \n");
interleaverl
printf('I
|1
\n") ;
printf(" I
|e
r \n');
puncture
printf("I
printf("
\n");
printf('---------------------------------------------------------printf("\n");
/*
*/
output file name
printf(",-------------------------------------printf("I Enter output file name\n");
printf("I
>>
(fp ==
------------------
\n");
");
scanf("%s", filename);
printf('-------------------------------------fp = fopen(filename, "a");
if
\n");
------------------ \n");
NULL)
printf("\n\nError opening file %s, program terminating\n", filename);
else
fclose(fp);
/*
encoderl, encoder2, puncturer, mapper
choices for modules:
printf("\n\n");
printf(",--------------printf("\n");
printf(" I
conv code
printf("ll
--------printf("'
printf("
1 rate-1/2
printf(" I
printf("I
-------------------------------------- \n");
symbol
bit map
---------sp
overall \n");
code rate\n");
--------- \n');
rate-1/2\n");
10
spsp
rate-2/4\n");
010000
000010\n");
sssp
rate-3/4\n");
10
sssp
rate-3/4\n");
parity
puncture
-----------10
01\n")
\n");
printf("j
printf("
printf("I
printf("I
printf(" I
2
printf("I
\n");
printf("I
4
I
*/
rate-1/2
\n");
3 rate-1/2
rate-3/4
01\n")
turbo sim-std.c
01\n")
printf("I
printf("I
\n");
printf("I
printf("I
0
see more selections...\n");
\n");
printf("j--------------------------------------printf("1 Enter selection\n");
/*
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
0)
(selection ==
printf("\n\n");
printf(",-----printf(" I
c onv code
printf(" J
printf("I
printf("|I
5 r ate-1/2
printf("|
printf("I
printf("
\n")
r
6
printf("I
printf("|
\n")
7
r ate-2/3
[
printf("|
--------------------- \n".);
\n");
symbol
- ------------
- ---------
bit map
code rate\n");
10
01\n");
sspspp
--------- \n");
rate-3/6\n") ;
1000
0010\n");
sspssp
rate-4/6\n");
10
01\n");
sspssp
rate-4/6\n");
ate-1/2
printf(" I
\n")
r ate-1/2
8
printf("I
printf("I
parity
puncture
printf("|
1000100100
ssspsspp
0010010001\n");
rate-5/8\n");
\n")
printf("|
printf("I
0 s ee more selections...\n");
printf("I \n");
--------------------printf("
printf("I Enter selection\n");
error = 1
/*
n") ;
check for erroneous input */
while (error)
>>
printf("I
");
scanf("%d", &selection);
if
((selection == 0) 11 ((selection >=5) && (selection <=
error = 0;
else
printf ("I ** invalid selection **\n");
};
printf("'----------------------
-----------------
8)))
---
\n");
if (selection == 0)
printf("\n\n");
printf(",----------------------------------printf("
parity
printf("
conv code
puncture
-------------------printf("|
printf(" I
9
rate-3/4
10
printf("I
01\n");
printf("j
--------------------- \n") ;
symbol
bit map
\n");
code rate\n");
---------
--------- \n");rate-6/8\n");
ssspsssp
\n");
printf("1
10 rate-1/2
00100000
sssspssssp
printf("|
00000100\n");
printf(I
\n");
printf("j
0 quit\n");
printf(I
\n");
printf("I----------------------------------printf ("I Enter selection\n");
/*
rate-8/10\n");
check for erroneous input */
error = 1;
while
(error)
printf ("I
>>
);
scanf("%d",
if
&selection);
((selection == 0) 11 ((selection >=9) && (selection <= 10)))
error =
0;
else
printf("| ** 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";
103
MAIN SIMULATION CODE
104
pat2 =
"01";
bitmap = "sp";
break;
case 2:
k
=
patl
1;
=
"10";
= "01";
bitmap = "spsp";
break;
pat2
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 =
pat2 =
"10";
"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")
encoderl,
printf("I MODULES:
selectEncoder(&encoderl, k);
encoder2\n");
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
terminateBits = (int)ceil(encoderl.v / encoderl.k) * encoderl.k;
twoPunctureInitVars(&puncturer, pati,
s/
pat2);
unPunctureInitVars(&unpuncturer, &puncturer);
bitMapInitVars(&mapper.bitMapper, bitmap);
printf("\n\n");
printf( ",--------------------------------------------------------\n")
information bits\n");
printf("I MODULE:
selectBlockSize(&blockSize, encoderi.k, mapper.bitMapper.numSys);
printf("------------------------------------
/* select blockSize
-------------------- \n");
/* initialize untermBits s/
untermBits = blockSize - terminateBits;
numSymbols = (int) (blockSize / mapper.bitMapper.numSys);
printf("\n\n");
printf(",--------------------------------------------------------\n");
/*
interleaverl\n");
printf("| MODULE:
if encoder is rate k/(k+l) where k > 1, then we need to interleave
groups of k bits together. Thus, there will be only (blockSize / k)
s/
elements in the linked list to interleave
selectInterleaver(&interleaverl, (int) (blockSize / encoderl.k));
*/
turbosim-std.c
printf("'--
-------------- \n".);
uncomment the code below to write an interleave pattern to file for
retreival 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
printf("--> ");
file
name\n");
scanf ("%s", tempname);
fp = fopen(tempname, "w");
outputPattern(&interleaverl,
fclose(fp);
llistInitVars(&origBitsLL,
fp)
encoderl.k)
/*
initialize info bits
llistInitVars(&uncodedBitsLL, 1);
/*
initialize uncoded bits */
printf("\n\n");
printf(",----------------------------------
---------------------
printf("I
MODULE:
\n");
2-D signal mapper\n");
selectSignalMapper(&mapper);
printf("'----------------------------------
/*
*/
/* initialize signal mapper */
--------------------- \n");
channelInitVars(&channel);
/* initialize channel
*/
demodulatorInitVars (&demodulator);
/* initialize demodulator
*/
initialize Eb/No simulation range */
printf("\n\n");
printf(",---------------------------------printf ("I
printf("I
ENTER:\n");
\n");
printf("
Eb/No to start simulation\n");
printf(I
>>
scanf("%f",
--------------------
\n"-);
");
&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);
blocksleft =
/*
/* number of blocks per Eb/No
(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,
MAPdecoderInitVars(&MAP2,
totalerrors
=
&encoderl, interleaverl.blockSize,
&encoder2, interleaverl.blockSize,
(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;
==
&mapper. symbolMapper)
&mapper. symbolMapper);
105
MAIN SIMULATION CODE
106
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;
totalerrors[i]
totalbits = 0;
/*
=
==
i++)
= 0;
calculate channel noise variance for current Eb/No and constellation C/
channel.n variance = mapper.symbolMapper.Eav / (2 * mapper.bitMapper.numSys
printf("Eb/No = %f, n-variance = %f\n", EbOverNo, channel.n variance);
/*
* pow(10, (EbOverNo/10)));
initialize random # generator with same seed for each Eb/No to use same bit sequences
srand(sourceSeed);
for (block = 0; block < num blocks; block++)
C/
totalbits += blockSize;
genBits(&origBitsLL, untermBits);
/* generate one block of bits
C/
encodeslock(&encoderl);
/* encoder original block
*/
terminateEncoder(&encoderl);
doInterleave(&interleaverl);
/* do interleaving
encodeBlock(&encoder2);
/* encode interleaved block
C/
punctureBlock(&puncturer);
/* puncture parity bits
genBits(&uncodedBitsLL, (mapper.bitMapper.numUncoded * numSymbols)); /* uncoded bits
/*
regroup the systematic bits for use by the signal mapper */
if (encoderl.k > 1)
regroupKtol(origBitsLL.output, encoderl.k);
mapBlock(&mapper);
sendAWGNblock(&channel);
demodulateTwoDBlock(&demodulator,
unpunctureBlock(&unpuncturer);
if (encoderl.k > 1)
/*
note:
/* generate symbols
/* send through AWGN channel
C/
&mapper, channel.n_variance) ; /* get LLRs */
/* unpuncture parity LLRs
*/
for some reason,
log(2));
does not give the right number, but
bits = (int) (loglO((*decoder).numInputs) / loglo(2));
does.
bits
=
(int) (log((*decoder).numInputs) /
regroupltoK(demodulator.outputS, (int) (loglO(MAPl.numInputs)/loglO(2)));
calcprobS(&MAPl);
calcgamma(&MAPl);
initprobA(&MAP1, 1);
doInterleave(&Sinterleaver);
calcgamma(&MAP2);
for
/* only need to interleave L(dk) once
*/
(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(&extrinsicinterleave
initAB(&MAP2, notTerminated);
doFastRl2MAPdecoding(&MAP2);
only need to interleave L(dk) once
*/
C/
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;
totalerrors[i]
i++)
+=
*/
(long)floor(blockSize * showErrorPercentage(&origBitsLL,
&decodedBitsLL[i]));
printf("Eb/No [dB] = %f, block %d / %d\n", EbOverNo, (block+l), num blocks);
for
printf
/
/*
(i=0; i < iter;
printf
("iteration
("\n");
i++)
%d: %e\n", (i+1),
((double) total
errors[ii
/ totalbits))
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 / blocksleft
remainingtime = 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
*/
MAIN SIMULATION CODE
108
turbo sim-icoding.c
file:
turbo sim-icoding.c
This is the main program file that simulates turbo codes proposed
by ICoding. ICoding only proposes to use rate-l/2 constituent
codes, and full coding of every bit.
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
"StdAfx.h"
"linkedlist.h"
"source.h"
"interleave.h"
"conv.h"
"puncture.h"
"mapper.h"
"channel.h"
"demod.h"
"decoder.h"
#include
#include
#include
#include
#include
<math.h>
<time.h>
<stdio.h>
<string.h>
<stdlib.h>
int main(int argc, char* argv[])
==
===
/*
==
==
==
==
==
===
==
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;
==
CREATE
==
*
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
SIMULATION MODULES
/*
simulation modules
/*
bit linked lists
linkList
linkList*
*
origBitsLL;
decodedBitsLL;
ENCODER modules
interleaverVars
interleaverVars
encoderVars
encoderVars
encoderVars
punctureVars
*
interleaverl;
interleaver2;
encoderl;
encoder2;
encoder3;
puncturer;
/*
==
V
file to write results
V
seed for random # gen
*
store file name
*
Eb/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 *
*
/* puncture pattern
/
/* symbol bit mapping
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;
/*
==
general simulation variables */
FILE* fp;
/*
==
DECLARE GENERAL VARIABLES
==
/
/*
/*
systematic buffer
decoded bits buffer
/*
/*
/*
/*
/*
interleaver 1
interleaver 2
encoder 1
encoder 2
encoder 3
/*
puncturer
V
V
V
V
V
V
V
V
turbosim-icoding.c
/* signal mapper
twoDsignalMapVars mapper;
channel, soft-data modules */
channelVars
channel;
demodulatorVars
/* AWGN channel
* demodulator
demodulator;
unPunctureVars
unpuncturer;
DECODER modules
MAPdecoderVars
MAPdecoderVars
MAPdecoderVars
interleaverVars
/*
/*
/*
/*
extrinsic-interleaverl;
/*
extrinsic-interleaver2;
/*
extrinsicdeinterleaverl; /*
extrinsic deinterleaver2; /*
Sinterleaverl;
/*
Sinterleaver2;
/*
Dprob deinterleaver;
/*
MAPl;
MAP2;
MAP3;
interleaverVars
interleaverVars
interleaverVars
interleaverVars
interleaverVars
interleaverVars
*/
'/
'/
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
terminated
notTerminated
1;
0;
sourceSeed
blocksdone
171;
0;
=
printf(I"
printf(
printf("
printf("\n")
printf("\n");
printf(",----------------printf
(" \n")
printf("
printf("|
printf("I
printf("
printf("|l
printf(I"
printf("i"
printf(i)"
==
INITIALIZE SIMULATION MODULES
= = \n")
TURBO-CODE SIMULATION
==
===
==
a
i
.-------
I
> encoderl
information bits
I
I
\n");
\n");
g
I
\n");
n
I
.-> a m
interleaverl
encoder2 --.
I
interleaver2
---
> encoder3 --.
I I
printf(I"
I
printf("
printf("I\n");
"----------------printf(
printf
("\n");
\n");
\n");
1 a \n");
p \n");
p \n");
|
e \n");
r \n");
puncture
*/
output file name
printf(", ----------------------
---------- \n");
printf(i"
Enter output file na
printf("|
>>
);
scanf("%s", filename);
printf("'----------------------
fp = fopen(filename, "a");
if (fp == NULL)
printf("\n\nError opening file %s, program terminating\n", filename);
else
fclose(fp);
/*
choices for modules:
encoderl, encoder2, puncturer, mapper
printf("\n\n");
printf(",----------------------
-----------------------------------
\n");
printf("I\n");
printf("I
printf("I
printf("I
printf("I
printf("I
printf("I
printf("l
printf("I
printf("I
printf("I
printf("I
printf("I
printf("I
printf("I
printf("!
1
conv code
--------rate-1/2
p arity
p uncture
--- --------1 00
symbol
bit map
----------
overall \n");
code rate\n");
--------- \n") ;
sp
rate-1/2\n");
1 00
010\n")
spsp
rate-2/4\n");
0 10000000
0 00010000\n");
0 00000010\n");
sqsp
rate-3/4\n");
010\n");
001\n");
\n");
2 rate-1/2
001\n")
\n");
3 rate-1/2
\n");
printf("
o
printf("I
\n");
see more selecti ons ...\n");
printf(i"---------------------printf("I Enter selection\n");
109
MAIN SIMULATION CODE
110
/*
check for erroneous input */
error = 1;
while (error)
>>
printf("
scanf("%d", &selection);
if ((selection >= 0) && (selection <: 3))
error = 0;
else
printf("| ** invalid selection **\n");
};
---------- \n");
printf("'------------------------------------if (selection == 0)
("\n\n");
printf
printf(",--------------------------------parity
printf("j
puncture
conv code
printf(" I
-------------------printf("I
printf("
l
\n");
printf("Ul
0 quit\n");
printf("|
\n");
printf("j--------------------------------
---------------------- \n");
symbol
bit map
----------
\n");
code rate\n");
--------- \n");
printf("| Enter selection\n");
check for erroneous input */
error = 1;
while (error)
/*
printf("I
>>
scanf("%d", &selection);
if ((selection == 0) 11 ((selection >=0) && (selection <= 0)))
error = 0;
else
printf(" ** invalid selection **\n");
1;
----------- \n");
printf("'---------------------------------------
printf ("\n\n")
};
switch (selection)
case
1:
k =
1;
"100";
patl
=
pat2
pat3
= "010";
= "001";
bitmap
break;
case 2:
=
"sp";
k = 1;
patl = "100";
pat2 = "010";
pat3 = "001";
bitmap = "spsp";
break;
case 3:
k = 1;
patl = "010000000";
pat2 = "000010000";
pat3 = "000000010";
}; /*
/*
bitmap = "sssp";
break;
switch */
Initialize encoders, puncture/unpuncture, signal mapper, interleavers */
if (selection != 0)
printf("\n\n");
printf(",--------------------------------------------------------\n");
printf(" I MODULES:
encoderl, encoder2, encoder3\n");
selectEncoder(&encoderl, k);
-------------------- \n");
printf("-----------------------------------duplicateEncoder(&encoderl,
duplicateEncoder(&encoderl,
&encoder2);
&encoder3);
we need v bits to terminate, but if code is rate-k/k+l, then v must be
a 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");
/* select blockSize
selectBlockSize(&blockSize, encoderl.k, mapper.bitMapper.numSys);
printf("'---------------------------------------------------------\n");
untermBits = blockSize - terminateBits;
/* initialize untermBits s/
numSymbols = (int) (blockSize / mapper-bitMapper.numSys);
turbosim-icoding.c
printf("\n\n");
printf("
--------------------------------------------------------printf("I MODULE:
interleaverl\n");
if
encoder is rate k/(k+)
where k > 1,
groups of k bits together.
elements in the linked list
\n");
then we need to interleave
Thus, there will be only (blockSize / k)
to interleave
*/
selectInterleaver(&interleaverl,
printf("
---------------------
(int)
(blockSize /
encoderl.k)
\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 interleave
groups 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
retreival later.
below to write an interleave pattern
Also uncomment
to file for
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,
outputPattern(&interleaverl,
"w");
fp);
fclose(fp);
*/
llistInitVars(&origBitsLL,
encoderl.k);
/*
initialize
info bits
printf("\n\n");
printf(",---------------------------------------------------printf("I
MODULE:
2-D signal mapper\n");
/
\n")
selectSignalMapper(&mapper);
/*
initialize signal mapper */
channelInitVars(&channel);
/*
initialize channel
demodulatorInitVars(&demodulator);
/*
initialize demodulator
printf("'--------------------------------------------------------\n");
/*
initialize Eb/No simulation range
printf("\n\n");
printf(",
printf("I
printf("I
*
/
/
--------------------------------------------------------ENTER:\n");
\n");
\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);
/*
printf("-----------------------------------
select # of decode iterations */
---------------------
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,
MAPdecoderInitVars(&MAP2,
MAPdecoderInitVars(&MAP3,
&encoderl, interleaverl.blockSize,
&encoder2, interleaverl.blockSize,
&encoder3, interleaverl.blockSize,
total-errors = (long*)calloc(iter,
sizeof(long));
decodedBitsLL
for
= (linkList*)calloc(iter,
(i=l; i < iter;
i++)
llistInitVars(&decodedBitsLL[i},
1);
/*
&mapper.symbolMapper);
&mapper.symbolMapper);
&mapper.symbolMapper);
init total-errors array */
sizeof(linkList));
111
MAIN SIMULATION CODE
112
=
*---
---
/*
/*
==
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 */
= extrinsic deinterleaver2.output;
MAPl.inputA
MAPl.inputS
= demodulator.outputS;
= &unpuncturer.output[0];
MAPl.inputP
Sinterleaverl.input= demodulator.outputS;
= MAPI.output extrinsic;
extrinsicinterleaverl.input
= extrinsic interleaverl.output;
MAP2.inputA
MAP2.inputS
= Sinterleaverl.output;
= &unpuncturer.output[l];
MAP2.inputP
Sinterleaver2.input= demodulator.outputS;
extrinsic deinterleaverl.input = MAP2.output extrinsic;
= extrinsic-deinterleaverl.output;
extrinsic interleaver2.input
= extrinsic-interleaver2output;
= Sinterleaver2.output;
= &unpuncturer.output[2];
MAP3.inputA
MAP3.inputS
MAP3.inputP
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);
mapBlock(&mapper);
sendAWGNblock(&channel);
demodulateTwoDBlock(&demodulator,
unpunctureBlock(&unpuncturer);
/*
all constituent codes are rate-1/2,
initprobA(&MAPl, 0);
calc gammaR12(&MAP1);
doInterleave(&Sinterleaverl);
calc gammaR12(&MAP2);
doInterleave(&Sinterleaver2);
calc gammaR12(&MAP3);
for (i=O; i < iter; i++)
{
/*
/*
generate one block of bits
encoder original block
*/
*/
/*
/*
/*
/*
/*
do interleaving
encode interleaved block
do interleaving
encode interleaved block
puncture parity bits
*/
*/
*/
*/
*/
/* generate symbols
*/
/* send through AWGN channel
&mapper, channel.n variance);
/* get LLRs */
/* unpuncture parity LLRs
so use fast-ratel2 decoding functions */
/*
only need to interleave L(dk) once
*/
/*
only need to interleave L(dk) once
*/
initAB(&MAP1, terminated);
doFastRl2MAPdecoding(&MAPl);
doInterleave(&extrinsicinterleaverl);
initAB(&MAP2, notTerminated);
doFastRl2MAPdecoding(&MAP2);
doInterleave(&extrinsic deinterleaverl);
doInterleave(&extrinsic interleaver2);
turbosim-icoding.c
initAB(&MAP3,
113
notTerminated);
doFastRl2MAPdecoding(&MAP3);
doInterleave(&extrinsic_deinterleaver2);
doInterleave(&Dprob_deinterleaver);
signDecision(Dprob_deinterleaver.output, &decodedBitsLL[i]);
};
/*
calculate and display decoded bit errors
for
(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);
/*
hours
remaining */
hrs =
mins
(int)floor(temp);
=
(int)floor((temp - floor(temp))
printf("
};
/*
* 60);
60;
/* number of minutes remaining */
(int)ceil((temp - floor(temp)) * 60);
temp
secs
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
*/
MAIN SIMULATION CODE
114
turbosim-uncoded.c
file:
uncodedsim.c
This is the main program file that simulates uncoded QAM
performance.
*/
#include "linkedlist.h"
"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
#include
int
<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
long
iter;
totalbits;
long* totalerrors;
terminateBits;
untermBits;
int
int
int
numSymbols;
misc variables
int
int
long
hrs, mins, secs;
i;
block;
float
long
char
double
tl,
t3;
blocks-left, blocks-done;
error;
temp;
==
/*
simulation modules
/*
bit linked lists
linkList
/*
/*
*/
seed for random # gen
*/
file to write results
store file name
Eb/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 */
*/
timet starttime, currtime;
t2,
/*
/*
/*
/*
/*
keeps track of time
printf: time variables
for loop index
for loop index
*/
*/
*/
scanf variables
keeps track of progress
error indicator
temporary variable
*/
*/
*/
CREATE SIMULATION MODULES
*/
origBitsLL;
channel, soft-data modules '/
channelVars
channel;
demodulatorVars
demodulator;
/* systematic buffer
/* signal mapper
/* AWGN channel
/* demodulator
INITIALIZE SIMULATION MODULES
f ("
==
*/
ENCODER modules
*/
twoDsignalMapVars mapper;
print
==
==
pri==========\n ");
*/
*/
turbo sim-uncoded.c
printf("
=
-== ==
printf
("
printf("\n");
printf
("\n") ;
printf(",------------------printf("I\n");
printf("
UNCO DE SIMULATION
=-=
==
------------------
\n");
information bits -- > signal mapper --> channel\n");
printf)(I
\n");
------------------printf("
printf
("\n")
printf ("\n")
/*
output file name
*/
printf(",------------------ --------------------------------------printf("| Enter output fi le name\n");
printf("I
>>
");
scanf("%s", filename);
\n");
printf('------------------ --------------------------------------- \n");
fp = fopen(filename, "a");
if
(fp == NULL)
printf("\n\nError opening file %s, program terminating\n",
else
filename);
fclose(fp);
*
---------
UNCODED
SIMULATION
-----------------------------
printf("\n\n");
printf("
-------------------------------------------------------printf("I
MODULE:
information bits\n");
selectBlockSize(&blockSize,
1,
\n");
1);
/*
'----------------------------------
printf(
select blockSize
----------------------
\n");
printt("\n\n");
printf(",--------------------------------------------------------\n");
printf("I
MODULE:
bit mapper\n");
selectBitMapper(&mapper.bitMapper);
printf("--------------------------------------numSymbols = (int) (blockSize
-----------------
llistInitvars(&origBitsLL, 1);
/*
terminateBits = 0;
untermBits = blockSize
/* initialize untermBits */
terminateBits;
-
printf("\n\n");
printf(",--------------------------------printf("F
MODULE:
initialize info bits
*/
.---------------------\n");
2-D signal mapper\n");
selectSignalMapper(&mapper);
printf("---------------------------------
/*
\n");
/ mapper.bitMapper.numSys);
/* initialize signal mapper */
----------------------\n");
channelInitVars(&channel);
/* initialize channel
*/
demodulatorInitVars(&demodulator);
/* initialize demodulator
*/
initialize Eb/No simulation range */
printf("\n\n")
;
printf(",--------------------------------printfQ(I
---------------------
\n");
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);
blocks-left
I*
= (long) (floor((finish -
/* number of blocks per Eb/No
start) / delta) + 1)
*/
* numblocks;
initialize decoder parameters and decoder variables */
printf("'---------------------------------------------------------\n")
blocks done = 0;
blocksleft = (long) (floor((finish - start) / delta) + 1)
iter
=
* numblocks;
1;
totalerrors = (long*)calloc(iter, sizeof(long));
/*
init totalerrors array */
/*
-
DEFINE MODULE CONNECTIONS
==
115
115
MAIN SIMULATION CODE
116
/
-----------
UNCODED
mapper.inputS
channel.input
demodulator.input
*
----------------------------SIMULATION
= origBitsLL.output;
= mapper.output;
= 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;
0;
totalbits =
calculate channel noise variance for current Eb/No and constellation */
channel.n-variance = mapper.symbolMapper.Eav / (2 * mapper.bitMapper.numSys
printf("Eb/No = %f, n-variance = %f\n", EbOverNo, channel.n_variance);
/*
* pow(10, (EbOverNo/10)))
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 ---------------------------------------
*--
/* generate one block of bits */
genBits(&origBitsLL, blockSize);
*/
/* generate symbols
mapBlock(&mapper);
*/
/* send through AWGN channel
sendAWGNblock(&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 / blocksleft
blocksleft
remaining time = elapsed time / blocks-done
/*
temp = (double) (blocksleft * difftime(currtime, start_time)/3600 / blocks_done);
remaining
/*
hours
/
hrs = (int)floor(temp);
mins = (int)floor((temp -
floor(temp))
* 60);
/* number of minutes remaining */
60;
temp
secs = (int)ceil((temp - floor(temp)) * 60);
1;
/*
for loop: blocks
printf("Eb/No
[dB]
printf("BER: %e\n",
printf("
=
/
%f\n",
EbOverNo);
((double)totalerrors[0} / total_bits));
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++)
/ totalbits));
fprintf(fp, "iteration %d: %e\n", (i+l) , ( (double)totalerrors[i
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);
/* number of minutes remaining */
temp *= 60;
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);
turbosim-uncoded.c
fclose(fp);
/*
};
/*
/*
if
!error
for loop:
Eb/No
/*
cannot use freeList because list not dynamically allocated */
freeTwoDsignalMapVars (&mapper);
freeChannelVars(&channel);
freeDemodulatorVars(&demodulator);
/*
error opening file */
return 0;
/*
*/
free all dynamically allocated variables */
deleteList(&origBitsLL);
};
range
*/
main
*/
117
APPENDIX B
Sample Output for turbo_ sim-std.c
Screen Output
TURBO-CODE SIMULATION
------
--
>
----
-----
information bits -- > encoder
interleaverl
---
>
s
i
g m
n a
> a p
1 p
e
r
-
-- > encoder2 --.
puncture
Enter output file name
>>
test.txt
conv code
parity
puncture
symbol
bit
map
overall
code rate
1
rate-1/2
10
01
sp
rate-1/2
2
rate-1/2
10
01
spsp
rate-2/4
3
rate-1/2
010000
000010
sssp
rate-3/4
4
rate-3/4
10
01
sssp
rate-3/4
0
see more selections...
Enter selection
>>
1
-119-
120
APPENDIX B
encoderi,
MODULES:
1
fbPoly = 23
fbPoly = 7
fbPoly = 15
2
3
encoder2
ffPoly = 35
ffPoly =
5
ffPoly = 17
select generator polynomials
>> 1
information bits
MODULE:
**
must be divisible by 1 **
1
2
3
4
5
1024
4096
5120
6144
15844
Select number of bits per block
>> 1
MODULE:
1
2
3
interleaverl
Random permutation
Two-step semi-random algorithm (AT&T RN-029 standard)
Read permutation pattern from file
Select interleaver type
> 2
**
1024 elements **
S1, S2, seed
1
2
3
4
5
(16,
(18,
(23,
(25,
(26,
6,
12,
12,
15,
15,
151)
151)
151)
151)
151)
Select semi-random interleaver parameters
>>
2
generating interleave pattern ...
MODULE:
1
2
3
2-D signal mapper
normal bit labeling (00, 01, 10, 11)
full gray labeling in each dimension (00, 01,
concatenated gray labeling in each dimension
Select labeling scheme
11,
10)
SAMPLE OUTPUT
>>
2
ENTER:
Eb/No to start
simulation
>> 1
Eb/No to end simulation
>> 1
Eb/No step size
>> 1
Number of blocks per Eb/No
>> 5
Number of decoder iterations per block
>> 8
Eb/No = 1.000000, nvariance = 0.794328
Eb/No [dB] = 1.000000, block 1 / 5
iteration 1: 1.054688e-01
iteration 2:
9.960938e-02
iteration 3: 9.082031e-02
iteration 4: 9.082031e-02
iteration 5: 8.691406e-02
iteration 6:
iteration 7:
8.789062e-02
8.496094e-02
iteration 8: 8.496094e-02
total time remaining:
Eb/No [dB]
iteration
iteration
iteration
iteration
iteration
iteration
iteration
iteration
=
1:
2:
3:
4:
5:
6:
7:
8:
1.000000, block 2 /
9.765625e-02
9.61914le-02
8.691406e-02
9.033203e-02
7.421875e-02
8.05664le-02
8.496094e-02
8.300781e-02
5
total time remaining:
Eb/No [dB]
iteration
iteration
iteration
iteration
iteration
iteration
iteration
iteration
=
1:
2:
3:
4:
5:
6:
7:
8:
=
1:
2:
3:
4:
5:
6:
7:
8:
Oh Om 2s
1.000000, block 3 / 5
7.910156e-02
6.477865e-02
5.794271e-02
6.022135e-02
4.947917e-02
5.371094e-02
5.664062e-02
5.533854e-02
total time remaining:
Eb/No [dB]
iteration
iteration
iteration
iteration
iteration
iteration
iteration
iteration
Oh Om 4s
1.000000, block 4 /
8.227539e-02
6.396484e-02
5.419922e-02
5.419922e-02
4.199219e-02
4.052734e-02
4.248047e-02
4.150391e-02
5
total time remaining:
Eb/No [dBI = 1.000000, block 5 /
iteration 1: 8.417969e-02
iteration 2: 6.386719e-02
Oh Om ls
5
Oh Om ls
121
122
iteration
iteration
iteration
iteration
iteration
iteration
APPENDIX B
3:
4:
5:
6:
7:
8:
5.019531e-02
4.375000e-02
3.359375e-02
3.242188e-02
3.398437e-02
3.320312e-02
total time remaining: Oh Om Os
simulation time for 5 blocks:
Oh Om 2s
SAMPLE OUTPUT
Output File test.txt
sourceSeed=171
4-QAM
[point, label]
[(-1,-i),
00]
[(-il), Oi]
bit
map: sp
Eav = 2.00000 0
Eb/No = 1.000 000, nvariance = 0.794328
5120 bits
iteration
iteration
iteration
iteration
iteration
iteration
iteration
iteration
Error probability:
8.417969e-02
6.386719e-02
5.01953le-02
4.375000e-02
3.359375e-02
3.242188e-02
7:
3.398437e-02
8: 3.320312e-02
1:
2:
3:
4:
5:
6:
simulation time for 5 blocks:
Oh
om
2s
[(1,-1),
10]
[(1,1),
1l]
123
APPENDIX C
Simulation Code
general.h
file:
general.h
This file contains definitions of general purpose functions
used by different modules.
/* 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
int
charArrayToInt(char binary],
int
v);
v);
- 125
-
SIMULATION CODE
126
general.c
/*
general.c
file:
This source file contains code for general functions used by
other routines.
*/
#include "general.h"
/* general.h must come before math.h because max and min
*/
are 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)
(a * a);
return
/*
/
sqr
function: min
This function returns the lesser of two doubles.
double a
double b
lesser of a and b
Input
Output
*/
double min(double a, double b)
return
((a
<= b)
? a
:
b);
} /* min
function: max
This function returns the greater of two doubles.
double a
double b
greater of a and b
Input
Output
*/
double max(double a, double b)
return
/* max
((a
>= b)
? a
:
b);
*
function:
intToCharArray
This function converts an integer value into binary.
binaryt0] is the MSB of the integer, and binarytv-1] is the LSB
of the integer.
Input
I Output
:
:
int s
char binary[]
int v
- the integer value
- array to hold binary value
- length of the binary array
general.c
I
Modify : binary[]
void intToCharArray(int
s,
char binary(],
int v)
= 6, v=3
binary[] is
1 1 0
indices are
0 1 2
/
if s
so index 0 is MSB and index 2 is
LSB
int i;
for (i=0; i < v; i++)
binary[v-1-i} = ((s
/*
intToCharArray
>>
i)
& 1);
/
/*
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 LSB
of
the integer.
char binary[] - array holding binary value
int
v
- length of array
the integer value
Input
Output
Modify
int charArrayToInt(char binary[},
/*
if s = 6, v=3
binary[] is
indices are
int v)
1 1 0
0 1 2
so index 0 is MSB and index 2 is LSB
*/
sum =
int
i,
for
(i=0; i < v; i++)
sum +=
(int)binary[i]
0;
return sum;
/*
charArrayToInt
/
*
(int)pow(2, (v-1-i));
127
128
SIMULATION CODE
Iinkedlist.h
file:
linkedList.h
This header file contains variable and function definitions
for a linked list.
/* type definitions */
typedef struct twoDSignalPointStruct
double i;
double q;
} twoDSignalPoint;
typedef struct listElementStruct
char *value;
twoDSignalPoint *signal;
struct listElementStruct *next, *prev;
listElement;
typedef struct linkListStruct
int valueLength;
listElement *head, *tail;
struct linkListStruct *output;
linkList;
init/deallocation functions */
/*
void llistInitVars(linkList* llist, int arrayLength);
void freeList(linkList* list);
/*
adding elements
*/
void addElement(linkList* llist, listElement* newEl);
/* add 1 element with specified bits */
void addLLbits(linkList* llist, char bits[]);
/* add 1 element with specified signals */
twoDSignalPoint points[]);
void addLLsignal(linkList* llist,
char bits]], twoDSignalPoint points]]); /* add 1 element with specified data */
void addLLdata(linkList* llist,
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);
linkedlist.c
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
input variable arrayLength, and output points back to the list
itself.
I
Input
linkList *llist
int
arrayLength
Output
Modify
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
Output
Modify
linkList *list
-
linked list pointer
list
void freeList(linkList* list)
deleteList(list);
free(list);
S/* freeList */
/*
---------
----- ELEMENTS ------------------ADDING
function: addElement
Add an element to the end of the linked list.
Input
*llist - linked list pointer
linkList
listElement *newEl - new element pointer
Output
Modify : llist, newEl
void addElement(linkList*
(*newEl).next = NULL;
llist, listElement* newEl)
/*
last element,
set next
to NULL
V
129
SIMULATION CODE
130
if
((*l1ist).head
==
NULL)
/*
(*llist).head = newEl;
(*llist).tail = newEl;
this is first element in the list */
/* both head and tail point to this element
no previous element
(*newEl).prev =NULL;
*/
*/
else
at least one element in list already
(*l(*list).tail).next = newEl;
(*newEl).prev = (*llist).tail;
(*l1ist).tail = newEl;
*/
/* new element now at end of linked list
*/
};
/* addElement
*/
/*
function: addLLbits
Add a new element with the specified bits to the end of the
linked list.
linkList* llist
bits[]
char
Input
Output
Modify
-
linked list pointer
array of bits
llist
*/
void addLLbits(linkList* llist, char bits[])
{
int
i;
*/
/* allocate memory for new element
listElement* newEl = (listElement*) calloc(1, sizeof(listElement));
/* allocate memory to hold bit values V
(*newEl) value = (char*) calloc( (*llist) .valueLength, sizeof (char));
/* allocate memory
(*newEl) signal = (twoDSignalPoint*) calloc( (*llist) .valueLength, sizeof (twoDSignalPoint));
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 the
linked list.
Input
- linked list pointer
llist
linkList*
twoDSignalPoint points)] - array of 2D points
Output
Modify
void addLLsignal(linkList* llist, twoDSignalPoint points[])
int i;
listElement* newEl
= (listElement*)
calloc(1,
sizeof(listElement));
/*
allocate memory for new element
*/
*/
/* allocate memory to hold bit values
(*newEl) value = (char*) calloc((*llist) .valueLength, sizeof (char));
/* allocate memory
(*newEl) signal = (twoDSignalPoint*) calloc((*llist) .valueLength, sizeof(twoDSignalPoint));
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 with the specified points to the end of the
linked list.
Input
linkList*
char
llist
bits[]
- linked list pointer
- array of bits
twoDSignalPoirnt points[] - array of 2D points
Output
Modify
linkedlist.c
*/
void addLLdata(linkList*
int
llist,
char valueBits)],
131
twoDSignalPoint points[])
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];
(*newEl).signal[i] = points[i];
copy bit values to new element
V
addElement(llist, newEl);
/*
/*
addLLdata
*/
--------------- DELETING ELEMENTS --------
function: deleteFirstElement
Delete first element of linked list.
linkList* llist - linked list pointer
Input
Output
Modify
llist
void deleteFirstElement(linkList* llist)
listElement *temp;
if ((*Ilist).head
!=
NULL)
temp = (*llist).head;
(*llist).head = (* (*list).head).next;
if
/*
set next element in list as first
((*llist).head 1= NULL)
(*(*llist).head).prev = NULL;
free((*temp).signal);
free((*temp).value);
/*
free(temp);
};
}
/* deleteFirstElement
delete previous first element
*
function: deleteList
Delete all elements in the linked list.
Input
: linkList* llist - linked list pointer
Output
Modify : llist
*/
void deleteList(linkList* llist)
while
((*llist).head
!=
NULL)
deleteFirstElement(llist);
S/*
/*
deleteList */
--------------- GETTING ELEMENT POINTERS
-------------------
/*
function: getElement
Get nth element from linked list.
Input
n=1,2,3,...
: linkList* llist - linked list pointer
int
n
- index of element to get
Output : pointer to the list element to return
Modify
*
/
SIMULATION CODE
132
Illist, int n)
listElement* getElement(linkList
* n is from 1 to (# of element in list)
int i;
temp;
listElement*
if
/* will
*/
hold pointer to list element
to return
*/
(llist == NULL)
temp = NULL;
else
temp = (*1list).head;
for (i=O; i<(n-l); i++)
temp =
/*
/* begin at first element of list
go down list until we reach nth element
(*temp).next;
};
/*
return temp;
/*
getElement
return nth element
*/
*/
/*
function: getvalue
Get the bit array of an element of the linked list.
linkList* llist - linked list pointer
int
n
- index of list element
Output : bit array
Modify
Input
*/
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.
linkList* llist - linked list pointer
int
n
- index of list element
array of 2D points
Input
Output
Modify
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.
linkList* llist - linked list pointer
Input
Output
Modify
void showLLbits(linkList* llist)
int
i;
listElement* temp;
temp = (*llist).head;
while (temp !=NULL)
/* traverse the list */
for (i=G; i < (*llist).valueLength; i++)
*/
*/
linkedlist.c
printf("%d", (*temp).value i]);
temp = (*temp).next;
};
printf("\n");
}
showLLbits
*/
function: showLLsignals
Show the signal points stored in every element of the list.
linkList* llist - linked list
Input
Output
Modify
*/
void showLLsignals(linkList* llist)
int i;
listElement* temp;
temp =
while
(*llist).head;
(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
linkList* llist - linked list pointer
0 if list is empty, else 1
Input
Output
Modify
char notEmpty(linkList* llist)
return ((*llist).head
!=
NULL);
} /* notEmpty */
function: getNumElements
Get number of elements in the linked list.
Input
Output
Modify
int
{t
linkList* llist - linked list pointer
: number of elements in list
:
getNumElements(linkList* llist)
int
count = 0;
listElement* tempEl;
tempEl =
while
(*llist).head;
(tempEl != NULL)
tempEl = (*tempEl).next;
count++;
1;
return count;
/*
getNumElements */
133
SIMULATION CODE
134
function: copyList
Copy all elements in one list to another.
Input
Output
Modify
linkList* orig - pointer to original linked list
linkLIst* copy - pointer to linked list copy
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
};
} /*
copyList */
=
(*currEl).value, (*currEl).signal);
(*currEl).next;
source.h
source.h
/*
file:
source.h
This header file contains function definitions for generating
bits.
/* selection function */
void selectBlockSize(int *blockSize, int k,
/* simulation command */
void genBits(linkList* llist,
/*
int
numBits);
debug/display function */
void showArrayBits(char bits[},
int size);
int numSys);
135
SIMULATION CODE
136
source.c
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 block
size must be divisible by the number of bits, k, used as input to
a rate-k/n convolutional code. Further, the block size must also
be divisible by the number of systematic bits per symbol.
int *blockSize - pointer to variable to hold block size
- number of bits to input to a rate-k/n conv. encoder
int k
int numSys
- number of systematic bits per symbol
Input
Output
Modify : 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 that k fits onto one symbol */
lcm
=
n2;
while ((lcm % nl)
1cm += n2;
!=
0)
printf("I---------------------------------------printf("I\n");
** must be divisible by %d **\n", lcm);
printf("
printf("I\n");
1024\n");
1
printf("I
printf("I
2
4096\n");
3
5120\n");
printf("I
printf("I
4
6144\n");
5
printf("I
printf("\n");
15488\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:
*blockSize = 15488;
break;
};
if
------- \n");
(
((blockSize) %
error
=
1;
lcm)
0)
-------------
\n");
source.c
printf("I
**
error:
block size not
divisible by
%d
**\n",
lcm);
else
printf("
** invalid selection **\n");
};
} /*
/*
selectBlockSize */
------------------------ SIMULATION COMMAND FUNCTION ----------
function:
genBits
Generate bits randomly. If the list is empty when this function
is called, add the new bits to the list.
If the list is not empty
when this function is called, then simply replace the bits in the
list with new bits. Because other functions may have added bits
to the list, delete remaining elements after enough bits are
generated.
Input
- linked list pointer
linkList* llist
int
numBits - number of bits to generate
Output
Modify
llist
void genBits(linkList* llist, int numBits)
int
i, j;
char *bits;
listElement *currEl, *headPtr, *tailPtr;
/*
If list already exists, go through the list and
replace values. This way, we don't have to delete elements,
then add elements again.
*/
bits = (char*) calloc((*llist) .valueLength,
currEl = (*llist).head;
for (i=G;
i < (numBits/ (*llist)
for (j=O; j <
sizeof (char));
.valueLength);
i++)
(*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;
};
/*
if
terminateEncoder)
function may have appended bits to llist,
so
set tail to currEl->prev and delete the remaining elements */
(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
Output
Modify
: char bits[]
int
size
~
array of bits
length of array
/
137
SIMULATION CODE
138
void showArrayBits(char bits[],
int
i;
for
(i=0; i<size; i++)
printf("%d",
printf ("\n");
} /* showArrayBits
*/
int
size)
(int)bits[i]);
interleave.h
interleave.h
file:
interleave.h
This header file contains variable and function definitions for
interleavers.
#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 index, int deltalndex);
void updateRemaining(int remainingIndices[],
void genSrandomPattern(interleaverVars* interleaver, int Si, int S2);
int S1, int S2);
139
140
SIMULATION CODE
interleave.c
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 use in generating a permutation
pattern.
interleaverVars* interleaver - interleaver pointer
numEl
int
interleaver depth
Input
Output
Modify
interleaver
void selectInterleaver(interleaverVars*
interleaver,
int
numEl)
f
int selection;
char error;
int Sl,
S2,
seed;
char filename[80];
FILE* fp;
printf("I---------------------------------------------------------\n");
printf("I\n");
printf("l
printf("I
printf("I
1
2
Random permutation \n");
Two-step semi-random algorithm
3
(AT&T RN-029 standard)\n");
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 init
interleaver
printf(" --------------------------------printf("I\n");
printf("I ** %d elements **\n", numEl);
printf("I\n");
Sl,
printf("I
S2, seed\n");
printf("I
-----------printf("I
1 (16,
6,
printf("I
2 (18,
12,
printf("I
3 (23,
12,
printf("I
4 (25,
15,
printf("I
5 (26,
15,
printf(" \n");
\n");
151)\n");
151)\n");
151\n");
151)\n");
151)\n");
printf("I--------------------------------- --------------printf("I Select semi-random interleaver parameters\n");
error = 1;
while (error)
printf("I
>>
");
scanf("%d", &selection);
if
((selection >= 1)
error = 0;
& (selection <= 5))
-\n");
interleave.c
switch
(selection)
1:
Sl
case
= 16;
= 6;
seed = 151;
S2
break;
case 2:
51
18;
= 12;
seed = 151;
=
S2
break;
case 3:
Sl
S2
= 23;
=
12;
seed = 151;
break;
case 4:
Sl
= 25;
S2 = 15;
seed = 151;
break;
case 5:
Sl
S2
= 26;
= 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)
printf("I---------------------------------------------------------\n");
printf("I
Enter input file
name for
printf("I
>> ");
to init
%d elements\n",
interleaver
numEl);
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,
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 list
and stores the permuted elements in an output linked list. If
the output list
already exists, simply replace the element arrays
with new values. Otherwise, add new elements to the output list.
This function does not alter the input linked list.
Input
:
Output
Modify :
interleaverVars* interleaver - interleaver pointer
(*interleaver).output
*/
void doInterleave(interleaverVars*
int
i,
interleaver)
j;
char* tempchar;
twoDSignalPoint* tempPt;
listElement **tempEl, *currEl, *outEl;
numEl);
141
SIMULATION CODE
142
instead of deleteList((*interleaver).output), traverse
/*
list and
replace values
tempEl =
calloc((*interleaver).blockSize, sizeof(listElement*));
(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).next;
= currEl;
i = 0;
outEl = (*interleaver).output->head;
while (i < (*interleaver).blockSize)
if
/* add value and signal as a new element to list *
(outEl == NULL)
tempchar = (*tempEl[i]).value;
tempPt = (*tempEl[i]).signal;
addLLdata((*interleaver).output, tempchar, tempPt);
i++;
/* replace value and signal of current output element */
else
{
for
(j=o;
j <
(*interleaver).input->valueLength;
(*outEl).value[j]
(*outEl).signal[j]
j++)
(*tempEl[i]).value[j];
(*tempEl[i]).signal[j];
};
outEl
-
(*outEl).next;
i++;
};
free(tempEl);
I;
/* doInterleave
*/
*/
INIT/DEALLOCATE FUNCTIONS
function: randomPatternInitVars
: interleaverVars* interleaver
Input
Sl
int
interleaver pointer
minimum permute distance
Output
Modify : *interleaver
void randomPatternInitVars(interleaverVars* interleaver, int numEl)
int i;
int rndNum, numDone;
int* numbers;
numbers = (int*)calloc(numEl, sizeof(int));
for
(i=0; i < numEl;
numbers[i] = 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 +
numbers[numDone + rndNum]
= numbers[numDone];
i;
(*interleaver) .permutePattern~numEl-l]
free(numbers);
}
/* randomPatternInitVars *
function:
SrandomInitVars
=
numbers (numEl-l];
rndNum];
interleave.c
Initializes variables and generates an interleave pattern
according to the semi-random algorithm from ITU proposal RN-029.
See
for
description
:
Input
Output
:
MOdify
:
function genSrandomPattern)
for details.
interleaver - interleaver pointer
- minimum permute distance
- minimum rearranged distance
interleavervars*
int
int
S1
S2
int
int
blockSize
seed
- number of elements to interleave
- random number generator seed
(*interleaver).permutePattern
void SrandomInitVars(interleaverVars* interleaver, int Si, int S2, int blockSize, int seed)
(*interleaver).blockSize = blockSize;
permutePattern = (int*) calloc( (*interleaver)
(*interleaver)
output = (linkList*) calloc(1, sizeof(linkList))
(*interleaver)
1listInitVars((*interleaver).output,
.blockSize,
sizeof (int)
0);
srand(seed);
genSrandomPattern(interleaver, Sl, S2);
}
/*
*/
SrandomInitVars
function:
deinterleaverInitVars
irterleaver
Initializes a de-interleaver based on an existing
The permute pattern of the de-interleaver
permute pattern.
the inverse of that of the interleaver.
interleaverVars* deinterleaver - deinterleaver pointer
Input
interleaverVars*
Output
Modify
interleaver
-
interleaver
deinterleaver,
interleaver)
.blockSize;
.blockSize = (*interleaver)
permutePattern
for (i=O; i <
=
(int*)
calloc( (*deinterleaver) .blockSize,
sizeof(int)
(*interleaver).blockSize; i++)
.permutePattern[i]]
.permutePattern[(* interleaver)
(*deinterleaver)
.output = (linkList*) calloc(1,
llistinitVars((*deinterleaver).output, 0);
(*deinterleaver)
/*
interleaverVars*
i;
(*deinterleaver)
(*deinterleaver)
}
pointer
deinterleaver
void deinterleaverInitVars(interleaverVars*
int
is
deinterleaverInitVars
= i;
sizeof(linkList))
*/
function: interleaverFileInitVars
Reads an interleave pattern from a file. The first entry of the
file is the interleaver depth and must match input parameter numEl.
The remaining entries are the permutation indices.
Input
interleaverVars* interleaver
FILE*
fp
int
numEl
interleaver pointer
pointer of file to read from
interleaver depth
Outpu t :
Modif y : interleaver
int
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*)
for
(i=0; i <
fscanf(fp,
calloc( (*interleaver) blockSize,
(*interleaver) blockSize; i++)
"Id",
&(*interleaver)
(*interleaver) .output = (linkList*)
llistInitVars((*interleaver).output,
.permutePattern[i]
calloc(l,
0);
sizeof(linkList))
sizeof(int))
143
SIMULATION CODE
144
/*
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
Output
Modify : interleaver
*/
void freeInterleaverVars(interleaverVars* interleaver)
free((*interleaver).permutePattern);
freeList((*interleaver).output);
/*
DISPLAY/DEBUG FUNCTIONS
-------------
/*
/
freeInterleaverVars
-------------------
/*
function: showPermutePattern
Print the permute pattern to the screen.
: interleavervars* interleaver - interleaver pointer
Input
Output
Modify
*/
void showPermutePattern(interleaverVars* interleaver)
int i;
printf("Permute pattern: ");
for (i=0; i < (*interleaver).blockSize;i++)
printf(" printf(" -\n");
} /* showPermutePattern
*/
OTHER FUNCTIONS
-------------
/*
(*interleaver).permutePattern[i]);
%d",
-------------------
function: regroupltoK
The input linked list contains 1 bit per list element. This
function regroups the list so that there are K bits per list
element. The resulting list will have a factor of K less
list elements.
Input
: linkList* thelist - linked list pointer
- number of bits per list element
k
int
Output
Modify : 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++)
interleave.c
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 per list element. This
function regroups the list so that there is 1 bit per list
The resulting list will have a factor of K more
element.
list elements.
:
Input
linked list pointer
number of bits per list element
linkList* thelist
int
k
Output
Modify :
thelist
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++)
f
for
{
(j=0; j < k;
bit
j++)
=
(getValue(thelist,
point = (getSignal
addLLdata(thelist,
1)) [IjI;
(thelist, 1)) [j];
&bit, &point);
deleteFirstElement(thelist);
/*
regroupKtol s/
/*
function: outputPattern
Prints the interleaver depth and permute pattern to a file.
interleaverVars*
FILE*
Input
interleaver
fp
interleaver pointer
output file pointer
Output
Modify : fp
void outputPattern(interleaverVars*
interleaver,
FILE*
fp)
int i=O;
fprintf (fp, "%d\n",
(*interleaver) .blockSize)
while (i < (*interleaver).blockSize)
(*interleaver) .permutePattern[i++]);
"%d\n",
fprintf(fp,
/*
/*
outputPattern */
AT&T 2-STEP SEMI-RANDOM INTERLEAVER FUNCTIONS
-------------
--
---
*/
function: canFillRest
Determines whether the remaining unused permute indices can
satisfy the semi-random algorithm. If not, then the algorithm
will need to be restarted.
Input
:
int remainingIndices[]
int index
- array to keep track of which permute indices have been
used and which are available
- index of remainingIndices[ that divides used and
145
SIMULATION CODE
146
available permute indices
- element by element minimum separation distance
int Sl
- cell by cell minimum separation distance
int S2
interleaverVars* interleaver - interleaver pointer
;1
Output
if
s-random algorithm can be completed,
*/
char canFillRest(int remainingIndices[],
0
otherwise
int index, interleaverVars* interleaver,
int S1,
S2)
int
int i, j, possIndex;
char canFilll=O, canFill2=0;
i = index;
while ( (!canFilll
11
!canFill2) && (i < (*interleaver).blockSize)
possIndex = remainingIndices[i++];
canFill2 = (abs(possIndex-index) >
if (canFill2)
/*
/*
S2);
)
/* check both
Sl
and S2 criteria
check next permute index
check S2 criterion */
/* compare to Sl previous cells
j = (index <= Sl) ? 0 : (index-Sl);
canFilll = 1;
while (j < index)
*/
/* see if permute index can satisfy
/* the semi-random algorithm */
canFilll = canFilll && (abs((*interleaver).permutePattern[j) - possIndex) > Sl);
};
1;
return
}; /*
(canFilll && canFill2);
canFillRest
*/
function: updateRemaining
This function is used by enSrandomPattern. The array remainingIndices[]
has "blockSize" cells and contains the permute indices.
remainingIndices[O..(indexx-1)] contains permute indices that have already been used.
remainingIndices[index..(bblockSize-1)] contains those that haven't been used.
This function updates rem iningIndices[] when another permute index is used.
Input
: int remainingIndi ces []
int index
int deltaIndex
Output
Modify
array to keep track of which permute indices have been
used and which are available
index of *remainingIndices that divides used and
available permute indices
remainingIndices[index + deltaIndex] contains the permute
index just used
remainingIndices
void updateRemaining(int
remainingIndices[],
int index, int deltaIndex)
int swapIndex, swapValue;
swapIndex = index + deltaIndex;
swapValue = remainingIndices[swapIndex];
remainingIndices[swapIndex] = remainingIndices[index];
remainingIndices[index] = swapValue;
}; /* updateRemaining
/* index of used permute index
/* the used permute index *
/* update *remainingIndices *
*
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 selections
We also
> Sl.
p(j) to check that if (i-j) <= S1 then pi(i)-pi(j)
insist 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 unable
to satisfy the algorithm criterion and may have to start the process over from
The functions canFillRest() and updateRemaining() are used to
the beginning.
perform this check.
Input
Output
void genSrandomPattern(interleaverVars*
{
int index,
Sindex,
j, deltaIndex;
interleaver,
int S1,
int
S2)
*
*
*
interleave.c
int*
while
remainingIndices
(index <
for
(j=O;
=
(int*)
calloc((*interleaver)
blockSize,
<
(*interleaver)
/*
/*
all new numbers
initialize *remainingIndices
*/
% ((*interleaver).blockSize-index);
/* choose from remaining permute indices
*/
Sindex = remainingIndices[index + deltaIndex];
if (abs(Sindex - index) > S2)
j = (index <= Sl) ? 0 :
while
/*
/*
(index-Sl);
((abs((*interleaver)
.permutePattern[j]
get the unused permute index
check S2 criterion */
/* compare with
S1
-
&& (j
Sindex)
> S)
*
previous indices
*/
< index))
j++;
if
(j ==
index)
/*
(*interleaver).permutePattern[index
new permute index is okay to use
= 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
*/
*/
S2))
(canFillRest(remainingIndices, index, interleaver, S1,
deltaIndex = rand)
don't have
.blockSize;j++)
remainingIndices[j]=j;
index = 0;
while
sizeof(int))
(*interleaver).blockSize)
j
147
*/
*/
/
SIMULATION CODE
148
conv.h
file:
convRoutines.h
This header file contains variable and function definitions for
convolutional encoders.
*/
/*
type definitions
*/
typedef struct branchStruct
int Sl, S2;
int
d;
int p;
branch;
typedef struct encoderVarsStruct
branch** trellis;
int*
terminator;
char*
int
k;
int
int
linkList*
linkList*
encoderVars;
state;
r;
V;
input;
output;
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,
void CCinitVars(encoderVars* encoder, int degree);
void freeEncoderVars(encoderVars* encoder);
int k);
/*
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[]);
int v);
void setFeedback(char* polyString, char* feedbackCoefficient,
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);
nextState(encoderVars* encoder, listElement* inputEl);
int
conv.c
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>
----
----------
function:
-----------------
SELECTION FUNCTION -
*/
selectEncoder
Called from the main program to select an encoder from a specified
list of options.
Input
encoderVars* encoder
int
kSel
pointer to encoder struct
number of input bits to encoder
Output
Modify : encoder
void selectEncoder(encoderVars* encoder, int kSel)
int selection, k;
char error;
char *fbPoly, **ffPoly;
if
((kSel >= 1) && (kSel <= 3))
/*
kSel=
1
rate-1/2
2
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
printf(" I
1
2
fbPoly = 23
fbPoly = 7
ffPoly = 35\n");
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",
if
");
&selection);
>= 1) & (selection
((selection
error
=
switch
<=
3))
0;
(selection)
case 1:
fbPoly
ffPoly[0]
break;
case 2:
fbPoly
ffPoly[O]
= "23";
= "35";
= "5";
= "7";
break;
case 3:
fbPoly
ffPoly[0]
/*
else
=
=
"15";
"17";
break;
}; /* switch rate-1/2 */
if rate-1/2 select ok /
printf("I ** invalid selection **\n");
}; /* while select rate-1/2 error */
ratel2initVars(encoder, fbPoly, ffPoly[0]);
break;
/* break case 1: rate-1/2 */
149
SIMULATION CODE
150
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, ffPolyl
--
35,
\n");
ffPoly2
= 27\n") ;
printf("I\n");
-----------printf("I---------------------printf("I Select generator polynomials\n");
error = 1;
while (error)
printf("
>>"
scanf("%d", &selection);
if
((selection >=
1)
&
(selection <=
1))
0;
error
switch (selection)
case 1:
=
fbPoly
ffPoly[0]
ffPoly[l]
= "31";
= "27";
= "35";
break;
}; /* switch rate-2/3 */
/ if rate-2/3 select ok */
else
printf ("I ** invalid selection **\n");
}; /* while select rate-2/3 error
= 2;
k
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");
rate-3/4 -printf("|
1
printf(" \n");
fbPoly =
13
ffPolyl
printf("I--------------------------------------printf("I Select generator polynomials\n");
error = 1;
while (error)
printf("j
11,
>>
((selection >=
1)
&
(selection <=
1))
error = 0;
switch (selection)
case 1:
fbPoly =
"15";
ffPoly[O] = "11";
ffPoly[l] = "13";
ffPoly[2]
} /*
else
};
/*
=
"17";
break;
}; /* switch rate-3/4 */
if rate-3/4 select ok */
printf("I ** invalid selection **\n");
while select rate-3/4 error */
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.
is called from the simulation main program.
This function
: encoderVars* encoder - pointer to encoder struct
Input
Output
Modify : encoder output contains parity bits
void encodeBlock(encodervars* encoder)
int i, j;
char* parityBits;
listElement
*inputEl, *currEl,
*headPtr, *tailPtr;
= 15,
ffPoly3
---------------- \n") ;
scanf("%d", &selection);
if
ffPoly2
= 17\n");
151
conv.c
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++)
(*encoder).state[i] = 0;
while
(inputEl
!=
NULL)
/*
set initial state to 0
/*
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 appended
by 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 "/
1;
(*encoder).output->head = headPtr;
(*encoder).output->tail = tailPtr;
}; /* encodeBlock
*/
/*
function: terminateEncoder
Generates bits to terminate the encoder to zero state. It
does this by using the trellis termination tree, stored in
array terminator[].
The terminating bits are added to the encoder
input list, and the corresponding parity bits are added to the
encoder output.
encoderVars* encoder - pointer to encoder struct
Input
Output
Modify
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 and
ceil(v/k) * k bits. */
for (bit = 0; bit < ((*encoder).v / (*encoder) .k); bit++)
S = charArrayToInt((*encoder).state,
d = (*encoder).terminator[S];
intToCharArray((*encoder) trellis[S]
addLLbits((*encoder).input, temp);
intToCharArray((*encoder) trellis
[S]
addLLbits((*encoder).output, temp);
intToCharArray((*encoder) trellis
[S)
/*
printf("term state:
(*encoder).v);
[d] .d, temp,
(*encoder) .k);
[d] .p, temp,
(*encoder) .r)
[d] .S2,
(*encoder) 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
/
(*encoder) .v)
*/
152
SIMULATION CODE
of a first encoder.
encoderVars* encoderl
encoderVars* encoder2
Input
pointer to original encoder struct
pointer to duplicate encoder struct
Output
encoder2
Modify
void 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];
(inp = 0; inp < pow(2, (*encoder2).k); inp++)
(*encoder2).trellis[state] [inp] = (*encoderl).trellis[state)[inp];
for
};
/*
duplicateEncoder *
function:
ratel2initVars
This function initialize s convolutional encoder variables
for a rate-1/2 encoder. It allocates memory for all struct
variables, and uses the rate-/n encoder structure to
Erncoder generator functions are already
generate the trellis.
stored in input arrays flbPoly[] and ffPoly[].
Input
: encoderVars* en;coder
fbiPoly[]
char
char
ff1 Poly[}
- pointer to encoder struct
- string describing feedback polynomial
- string describing feedforwrad polynomial
Output
Modify : encoder
void 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);
/* allocate memeory
*
forwCoefficient = (char***) calloc
for (i=0; i < (*encoder).r; i++)
/*
*/
((*encoder).r, sizeof(char**));
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) feedforward
coefficients */
};
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]
(*encoder).r);
[j],
forwCoefficient,
feedbackCoefficient,
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,
if
(*encoder).k); j++)
(((*encoder).trellis[i} [j].S2 == S.i) && (done[i) == 0))
done[i] = 1;
(*encoder) .v,
153
conv.c
= j;
(*encoder).terminator[i]
newS.i = i;
addLLsignal(&statelist, &newS);
};
/*
now know how to terminate trellis from any state
--
use
for (i=O; i <
(*encoder)
(j=G; j
for
terminator[]
as encoder
input until
zero
state
reached
*/
(*encoder).r; i++)
<
(*encoder).k; j++)
free(forwCoefficient[i] [ji);
free(forwCoefficient[i]);
free~feedbackCoefficient);
free(done);
S/* rate1nitVars '/
function: ratekklInitVars
This function initializes convolutional encoder variables
for a rate-k/(k+l) encoder.
Encoder generator functions are
already in input arrays
fbPoly[] and ffPoly[] [I
Input
Output
Modify
encoderVars*
encoder
- pointer to encoder
char
char
fbPoly[)
ffPoly[]
- string describing feedback polynomial
- string describing feedforwrad polynomial
struct
encoder
void ratekklInitVars(encoderVars*
encoder,
char fbPoly[,
char**
ffPoly,
int k)
{
int i, j;
int
/* indices
*/
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, and
forwCoefficient[r] [k] [v] corresponds to
D'v
*/
char*
/*
feedbackCoefficient;
holds feedback coefficients
(*encoder).k = k;
/* note: will ffPoly always have the correct degree??
CCinitVars(encoder,getDegree(ffPoly[o());
/*
*/
rate-k/(k+)
feedbackCoefficient = (char*) calloc ((*encoder) .v + 1, sizeof (char));
setFeedbackG(fbPoly, feedbackCoefficient, (*encoder) .v);
forwCoefficient =
for
(i=0; i <
(char***)
encoder */
*/
/* allocate memeory
calloc ( (*encoder) .r, sizeof (char**));
/* allocate memory
*/
*/
(*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));
coefficients */
};
for
(i=O; i <
(*encoder).k; i++)
(i+l) , ffPoly[i] ,
setFeedforwG(l,
numStates
=
(int)pow(2,
forwCoefficient,
/*
(*encoder) .v)
i] [j , forwCoefficient,
feedbackCoefficient,
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))
(i=0; i
done[i]
/*
< numStates;
= 0;
i++)
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
feedforward
(*encoder).v);
for (i=O; i < numStates; i++)
for (j=0; j < pow(2, (*encoder).k); j++)
ratekklSetBranch(&(*encoder) .trellis
(*encoder).k);
for
(v+l)
< pow(2,
(*encoder).k);
if (((*encoder) .trellis[i]
done[i]
= 1;
j++)
[j] .S2 == S.i) && (done[i]
==
0))
(*encoder) .v,
SIMULATION CODE
154
(*encoder).terminator[i] = j;
newS.i
= i;
addLLsignal(&statelist, &newS);
};
now know how to terminate trellis from any state
/*
-for
use
(*encoder) .terminator[]
as encoder input until zero state reached */
(i=O; i < (*encoder).r; i++)
(j=O; j < (*encoder).k; j++)
free(forwCoefficient[i][jl);
free(forwCoefficient[i]);
for
};
free(feedbackCoefficient);
free(done);
/*
ratekklInitVars */
/*
function: CCinitVars
Initializes class variables for any rate-k/(k+l) convolutional
code. Assumes only 1 parity bit.
encoderVars* encoder - pointer to encoder struct
degree
- highest degree of generator polynomials
int
Input
Output
Modify
encoder
void CCinitvars(encoderVars* encoder, int degree)
int i , j, states, branches;
(*encoder).r = 1;
(*encoder).v = degree;
/* only 1 parity bit
(*encoder).output = (linkList*) calloc
llistInitVars((*encoder).output, 1);
*/
(1, sizeof(linkList));
(*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);
= (branch**) calloc(states, sizeof (branch*))
(*encoder) .trellis
for (i=O; i < states; i++)
f
= (branch*) calloc(branches, sizeof (branch));
(*encoder) .trellis[i]
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.
: encoderVars* encoder
Input
Output
Modify : 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 */
conv.c
DISPLAY/DEBUG
----------------
FUNCTION
----------------------
/
function: showTrellis
Prints the trellis description to the screen.
encoderVars* encoder - point to encoder struct variables
Input
Output
Modify
void showTrellis(encoderVars* encoder)
S,d,
int
states, branches;
states = (int)pow(2, (*encoder).v);
branches = (int)pow(2, (*encoder).k);
printf("Sk-1
dk
pk
Sk\n");
"----
printf(
for
--
------
printf("%d
}; /*
----
\n");
(S=O; S < states; S++)
for (d=O; d < branches; d++)
showTrellis
%d
%d
%d\n",
(*encoder).trellis[S] [d].SI,
(*encoder).trellis(S} [d].d,
(*encoder).trellis[S] [d].p,
(*encoder).trellis[S] [d].S2);
*/
/* -------------------
GENERATOR POLYNOMIAL FUNCTIONS
function: convertOctal
This function converts the string representation of an octal
number into binary.
octal character, so 0 .. 7
- 3 cell array to hold binary representation
char octalChar
char binaryRep[]
Input
Output
Modify
-
binaryRep
*/
void convertOctal(char octalChar, char binaryRep[E)
*binaryRep = 0;
/* MSB of octal value
= 0;
*(binaryRep+2) = 0;
if ((octalChar == '1') 1 (octalChar ==
*(binaryRep+2) = 1;
if ((octalChar == '2') 1 (octalChar ==
*(binaryRep+l) = 1;
*/
*(binaryRep+l)
if
}
/*
((octalChar == '4')
*binaryRep = 1;
convertOctal
1 (octalChar ==
/*
LSB of octal value
(octalChar == '5') I
(octalChar ==
'7'))
'3')
(octalChar ==
(
'6')
(octalChar ==
'7'))
'5')
(octalChar ==
'6')
(octalChar ==
'7'))
'3')
|
*/
*/
function: convertString
This function converts the string representation of a generator
polynomial into a char array.
char polyString]
char coeffArray]
Input
Output
Modify :
- string representation of polynomial
- array of polynomial coefficients, O's and
l's
coeffArray
*/
void convertString(char polyString[E,
char coeffArray[],
int v)
int i, length;
char* temp;
length = strlen(polyString) ;
temp
=
(char*)
calloc
(3*length,
for (i=0; ialength; i++)
convertOctal(polyString[i],
for (i=0; i<(v+l); i++)
/*
sizeof(char));
&(temp[3*i]));
number of octal digits
*/
alloc ate max number of binary digits
/*
/*
conver t
each octal digit,
*/
store in temp[]
155
SIMULATION CODE
156
coeffArray[i) = temp[i+(3*length-(v+l))];
}
/* transfer last (v+l) values to coeffArray
/* free up memory used by temp[]
free(temp);
convertString
/
V
/
function: getDegree
This function finds the degree of a generator polynomial.
The degree of the polynomial is its highest exponent value.
char polyString{) - generator polynomial string
- degree of the polynomial
(tempDeg-1)
Input
Output
Modify
*/
int getDegree(char polyString[I)
int length, tempDeg;
char* temp = (char*) calloc(3, sizeof(char));
/*
temporary variable to hold 3 binary values
/* number of octal characters in string */
/* all octal characters except first have 3 bits
/* convert first octal char into binary *
length = strlen(polyString);
tempDeg = 3* (length-1);
convertOctal(polyString[O], temp);
if (temp[0) == 1)
tempDeg += 3;
else if (temp[l] == 1)
tempDeg += 2;
else if (temp)2] == 1)
tempDeg++;
/*
first octal char has no leading zeros
/* first octal char has 1 leading zero
/*
first octal char has 2 leading zeros
/
*
*
free(temp);
/* tempDeg = v+l.
return (tempDeg-1);
/*
Return
(tempDeg-1) = v
*
*/
getDegree
function: setFeedbackG
This function converts the string representation of the feedback
generator polynomial into char array.
Input
char polyString]
char feedbackCoefficient[]
int v
Output
Modify
- feedback polynomial string
- array holding binary coefficients
- degree of polynomial
feedbackCoefficient
*/
void setFeedbackG(char polyString[],
char feedbackCoefficient[], int v)
convertString(polyString,&feedbackCoefficient[0],
S
/* show conversion results
int i, length;
v);
/
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 generator
polynomial into charean and calculates the degree of the polynomial.
Input
: int
parityNum
int
inputNum
char
polyString]
char*** forwCoefficient
int
v
Output :
Modify : forwCoefficient
- indicate which parity bit the polynomial is for
- indicate which input bit the polynomial is for
- the polynomial string
- array holding binary coefficients
- degree of polynomail
*
*
conv.c
void setFeedforwG(int parityNum,
int inputNum,
char polyString[]
char*** forwCoefficient,
convertString(polyString, &forwCoefficient [parityNum-1] [inputNum-1
S
/* show conversion results
int i, length;
[0],
int v)
v)
*/
length = strlen(polyString);
printf("parity bit %d, input bit %d, G%d%d -- " parityNum, inputNum, 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
/
TRELLIS
--------- */
FUNCTIONS --------
function: ratekklSetBranch
This function takes in k input bits and an encoder state and
finds 1 parity bit and the next state. The first delay
register corresponds to state[0] and the last state register
corresponds to state[v-1.
Input
:
Output :
Modify :
branch*
char***
char*
int
int
br
ffCoeff
fbCoeff
v
k
-
pointer to a Trellis branch
the feed-forward generator polynomials
the feedback generator polynomial
degree
number of input bits
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 (i=(V-1); i>O; i--)
{
state[i] = state[i-1] ^ (y & feedbackCoefficient[v-i]);
for
1;
(numInputs=0; numInputs < k; numInputs++)
state[i] = state[i]
^ (forwCoefficient [0]
[numInputs] [v-i]
+ sum (all inputs with generator value
& 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 =
(*br).p =
charArrayToInt(state, v);
Oxl && y;
free(state);
free(inputBits);
} //
ratekklSetBranch
function:
ratelnSetBranch
157
158
SIMULATION CODE
This function takes in
1 input
bit and an encoder state and
The first delay
finds (n-1) parity bits and the next state.
and
register
corresponds to state[0]
corresponds to state[v-1].
br anch* br
ch ar*
ffCoeff
fbCoeff
ch ar*
in t
int
r
:
Input
v
Output
Modify
state
the last
register
pointer to a Trellis branch
the feed-forward generator polynomials
the feedback generator polynomial
degree
number of parity bits
br
char*** ffCoeff,
void ratelnSetBranch(branch* br,
int i,
char* fbCoeff,
int v, int r)
numOutputs;
/* temporarily hold statel value;
char stateiTemp;
*
char* state = (char*) calloc (v, sizeof(char));
char* feedbackCoefficient = fbCoeff;
char-*- forwCoefficient = ffCoeff;
char
input;
char* y;
y
=
(char*) calloc(r,
'* y[]
sizeof(char));
- hold r parity bit values
*/
intToCharArray((*br).S1, state, v);
input = ((*br).d == 0) ? 0 : 1;
state =
/* first
(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++)
= statelTemp & forwCoefficient[numOutputs] [0] [0]
(i=l; i<(v+l); i++)
y[numOutputs] = y[numOutputs] ^ (state[i-1] &&forwCoefficient[numOutputs]
/
y[numOutputs]
for
[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,
(*br).p = charArrayToInt(y, r);
*
v);
free(state);
/* ratelnsetBranch
*
function: nextState
This function trans itions a convolutional encoder to the next
state. It takes in put bit(s) from the encoder input, transitions
the encoder, and re turns the parity bit generated by the transition.
s* encoder
point to encoder struct
pointer to element with input bits
listElemen t* inputEl
parity bit from state transition
encoder.st ate
encodervar
Input
Output
Modify
int nextState(encoderVars* encoder, listElement* inputEl)
int
/a
S,d;
branch:
S
input
= d,
---------- > S2
parity = p
/
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) ;
return (*encoder).trellis[S] [d].p;
/*
nextState
*/
/* update encoder state
puncture.h
puncture.h
/*
file:
puncture.h
This header file contains variable and function definitions of
puncturing objects.
/*
type definitions *
typedef struct punctureVarsStruct
int
numInputs;
int
punctureLength;
int
currIndex;
char** puncturePattern;
linkList**
linkList*
input;
output;
} puncturevars;
typedef
struct unPunctureVarsStruct
int
numOutputs;
int
int
punctureLength;
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,
void threePunctureInitVars(punctureVars*
char patternl)],
puncturer,
char pattern2[]);
char patternl[],
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)
char pattern2[],
char pattern3[]);
159
160
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. The
puncture pattern is stored in the puncturer struct. This
function is called from the main simulation program.
:
Input
punctureVars* puncturer
- pointer to puncturer struct
Output
Modify : output linked list
void punctureBlock(punctureVars* puncturer)
char result;
int i, j, len;
listElement **inputEl, *currEl;
(*puncturer).currIndex = 0;
= (*puncturer).output->head;
inputEl = (listElement**) calloc((*puncturer).numInputs, sizeof(listElement*));
for (j=O; j < (*puncturer).numInputs; j++)
currEl
=
inputEl[j}
(*puncturer).input[j]->head;
len = getNumElements((*puncturer).input[});
for (i=0; i < len; i++)
result = punctureBits(puncturer,
/*
inputEl);
result > 1 means that all bits were punctured */
if
(result <= 1)
(currEL == NULL)
addLLbits((*puncturer).output,
it
&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 into
multiple output linked lists. The unpuncture pattern is
the same as the puncture pattern and is stored in the
unpuncturer struct. This function is called from the main
program.
Input
:
unPunctureVars* unpuncturer
Output
Modify : output linked lists
161
puncture.c
void unpunctureBlock (unPunctureVars* unpuncturer)
int
i;
twoDSignalPoint
LLR,
puncturedLLR;
listElement **outputEl, *currEl;
char done;
outputEl = (listElement**) calloc((*unpuncturer)
(i=0; i
outputEl[i]
for
currEl =
numOutputs,
(*unpuncturer).numOutputs; i++)
= (&(*unpuncturer) output [i])->head;
<
sizeof(listElement*)
(*unpuncturer).input->head;
puncturedLLR.i = 0;
puncturedLLR.q = 0;
(*unpuncturer).currIndex =
/*
The puncture
0;
structure could be:
currIndex
0123
1000
0010
When currIndex
=
3 and
(*unpuncturer)
input is
empty,
we still
unpuncturer the last LLR, which will be 0 for both bits.
loop condition must take this case into account.
alternatively
currIndex
012
If blockSize=1024,
index=1 when
100
010
001
The condition to end is
the input list
if
requesting an input element.
need to
So the while
we will be at
(*unpuncturer).input
runs out of elements.
is
already empty and we are
still
*/
done
while
=
0;
(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
=
(*currEl).signal[0];
currEl = (*currEl).next;
LLR
};
if
(done ==
if
0)
(outputElti] == NULL)
addLLsignal(&(*unpuncturer).output[ii,
&LLR);
else
*(outputEl[i]->signal)
outputEl[i] =
1;
}; /*
currIndex
); /*
/*
if
= LLR;
outputEl[i]->next;
*/
for */
(*unpuncturer) .currIndex
*/
=
((*unpuncturer) .currIndex
+ 1)
% (*unpuncturer) .punctureLength;
while */
free(outputEl);
} /*
unpunctureBlock
-------------------------
function:
*/
INIT/DEALLOCATE FUNCTION
------------
------
*/
twoPunctureInitVars
Initializes class variables and sets up puncturing pattern for
two input linked lists.
Input
: punctureVars* puncturer
char
patternl[]
char
pattern2[]
- pointer to puncture struct
- string specifying first
pu ncture pattern
- string specifying second p uncture pattern
/*
update
SIMULATION CODE
162
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) .punctureLength)
(*puncturer) .puncturePattern[1] = stringTochar(pattern2,
(*puncturer).input = (linkList**) calloc(2, sizeof(linkList*));
(*puncturer).output = (linkList*) calloc(l,
llistInitVars((*puncturer).output, 1);
} /*
twoPunctureInitVars
function:
sizeof(linkList));
*/
twoPunctureInitVars
Initializes class variables and sets up puncturing pattern for
two input linked lists.
: punctureVars*
char
char
char
Output :
Modify : puncturer
Input
puncturer
patterni[]
pattern2[l]
pattern3[]
-
pointer to puncture struct
string specifying first puncture pattern
string specifying second puncture pattern
string specifying third puncture pattern
*/
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*));
stringTochar(patternl,
stringTochar(pattern2,
(*puncturer) .punctureLength)
(*puncturer) .punctureLength)
(*puncturer) .puncturePattern[2] = stringTochar(pattern3,
(*puncturer) .punctureLength)
(*puncturer) .puncturePattern[0] =
(*puncturer) puncturePatternl] =
(*puncturer).input =
(linkList**) calloc(3,
(*puncturer).output = (linkList*) calloc(l,
llistInitVars((*puncturer).output, 1);
/*
sizeof(linkList*));
sizeof(linkList));
threePunctureInitVars */
function: freePunctureInitVars
Deallocates memory for puncture struct variables.
: punctureVars* puncturer - pointer to puncture struct
Input
Output
Modify : 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 variable
values in puncture struct.
puncture.c
Input
Output
Modify
unPunctureVars* unpunc
-
pointer to unpuncturer struct
punctureVars*
-
pointer to puncturer struct
punc
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,
(*unpunc) .puncturePatternfi]
= (*punc) .puncturePattern[i]
llistInitVars(&(*unpunc).outputti],
sizeof (char));
1);
};
/*
unPunctureInitVars
*/
/*
function:
freeUnpunctureInitVars
Deallocates memory for
unpuncturer
unPunctureVars*
Input
Output
Modify
struct
-
unpuncturer
variables.
pointer
to unpuncturer
struct
unpuncturer
void freeUnpunctureVars(unPunctureVars* unpuncturer)
int i;
/*
this routine causes problems
for
(i=0; i <
-- don't use
(*unpuncturer).numOutputs; i++)
for now */
free((*unpuncturer).puncturePattern[i]);
freeList(&(*unpuncturer).output[ii);
};
free((*unpuncturer).puncturePattern);
/*
freeUnpunctureVars */
* --------
----------
-----
OTHER FUNCTIONS
-----------------------
/
/*
function:
stringTochar
Moves a string of
punctureLength.
Input
O's
and
int
into a char array of size
- input puncture pattern string
char theString[]
Output
Modify
punctureLength -
array containing
*/
char* stringTochar(char
O's
size of array
and l's
theString[H,
char* charPtr = (char*)
int
l's
int
punctureLength)
calloc(punctureLength,
for (i=O; i<punctureLength; i++)
charPtr[i] = (theStringi] == '0')
return charPtr;
/*
sizeof (char));
i;
stringTochar
I function:
*/
punctureBits
? 0 : 1;
/*
decide if the character is a 0
*/
163
SIMULATION CODE
164
Performs bit puncturing according to specified pattern.
Input
punctureVars* puncturer - pointer to puncturer struct
- pointers to input elements
listElement** inputEl
Output
Modify
value of the puncturing operation
(0 or 1)
*/
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 =
if
(*puncturer).puncturePattern[0][index];
(i=1; i <
for
(*puncturer).numInputs; i++)
temp = temp II (*puncturer) .puncturePattern[i] [index];
/* not all of the bits are punctured */
(temp)
pout = *(inputEl[0]->value) * (*puncturer).puncturePattern[0][index];
for (i=1; i < (*puncturer).numInputs; i++)
(* (inputEl[i) ->value) * (*puncturer) .puncturePattern[i[ [index]);
pout = pout
else
pout
=
2;
return pout;
/* punctureBits
*/
/*
update currIndex
mapper.h
mapper.h
file:
mapper.h
This header file contains variable and function definitions
for 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 oneDsymbolMapVarsStruct
int M;
double* symbols;
char** code;
double Eav;
} oneDsymbolMapVars;
typedef struct twoDsymbolMapVarsStruct
int M;
twoDSignalPoint* symbols;
char** code;
double Eav;
} twoDsymbolMapVars;
typedef struct twoDsignalMapVarsStruct
bitMapVars 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);
165
SIMULATION CODE
166
mapper.c
file:
This
mapper.c
source file contains code for the signal mapper.
#include
#include
#include
#include
"general.h"
"linkedlist.h"
"source.h"
"mapper.h"
#include
#include
#include
#include
<stdlib.h>
<stdio.h>
<string.h>
<math.h>
SELECTION FUNCTION
function:
selectBitMapper
This function is called from the main simulation program to
select a bit map pattern for uncoded simulations.
Input
: bitMapVars* map - pointer to bit mapper
Output
Modify
map
void selectBitMapper(bitMapVars* map)
int selection;
char error;
char *pattern;
printf("
printf("\n");
.-----------------
printf("|
1
printf("I
2
printf("I
printf("I
ss
ssss
3
4
ssssss
ssssssss
----- \n");
-------------
4-pt uncodecd simulation\n");
16-pt\n");
64-pt\n");
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 <= 4))
I
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 */
mapper.c
function: selectSignalMapper
This function is called from the main simulation program to
select a signal mapping.
Input
: twoDsignalMapVars* map
Output
Modify
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
printf(" j 2
printf("
3
--------------------
\n"
normal bit labeling (00, 01, 1 0, ll)\n");
full gray labeling in each dime nsion (00, 01, 11, 10)\n");
concatenated gray labeling in each dimension\n");
printf
("\n");
printf("------------------------------------error = 1;
while (error)
printf("I Select labeling scheme\n"
printf(I
>>
");
scanf("%d", &selection);
if
((selection
>=
& (selection
1)
<=
3))
{
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(" -----------------------------------------\n");
printf("| * number of upper bits in each dimension must be <= %d **",
printf("I
printf(I
\n");
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\ n", Igc2)
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\ n", Qgc2);
/*
Igcl, Qgc2 must each be <= half
/
if (Igcl > half)
printf("I ** I parameters invalid: Il > %d
\n", half);
error = 1;
};
if (Qgcl > half)
{
printf("I
** Q parameters invalid:
error = 1;
Ql > %d **\n", half);
};
if (error == 0)
QAMgcSignalMapInitVars(map,
Igcl,
printf("\n");
break;.
};
/*
else
};
};
/* switch selection
if input ok /
printf("
/* while error *
/
invalid selection **\n");
} /* selectSignalmapper *
SIMULATION COMMAND FUNCTION
Igc2,
Qgcl,
Qgc2);
half);
167
SIMULATION CODE
168
mapslock
function:
The function is called from the main simulation program to
map a block of bits to two-D symbols.
twoDsignalMapVars* signalMapper
Input
Output
Modify
signalMapper output linked list
void mapBlock(twoDsignalMapVars* signalMapper)
twoDSignalPoint symbol;
listElement *currEl, *Uhead, *Shead, *Phead;
function formTwoDsymbol() changes the I ead pointer of each input linked list,
so we temporarily store the real ones Iere */
Shead = (*signalMapper).inputS->head;
/* no trellis coded modulation *
if ((*signalMapper).inputU != NULL)
Uhead = (*signalMapper).inputU->head;
/*
if
((*signalMapper).inputP
!=
NULL)
Phead = (*signalMapper).inputP->head;
uncoded simulation
no parity bits */
currEl = (*signalMapper).output->head;
while ((*signalMapper).inputS->head 1= NULL)
symbol = formTwoDsymbol(signalMapper);
if (currEl == NULL)
addLLsignal((*signalMapper).output,
else
&symbol);
(*currEl).signal[0] = symbol;
currEl = (*currEl).next;
};
/*
function formTwoDsymbol()
changes the
head
pointer of each input linked list,
so we restore the real ones here */
(*signalMapper).inputS->head = Shead;
if
((*signalMapper).inputU
if
((*signalMapper).inputP
!=
NULL)
(*signalMapper).inputU->head = Uhead;
!=NULL)
(*signalMapper).inputP->head = Phead;
}; /* mapBlock
*
INIT/DEALLOCATE FUNCTIONS
function: bitM apInitVars
Initialize bit mapper variables.
Input
:
DitMa
char
pvars* DitMapper - pointer to nit mapper struct
pattern[] - array containing bit map pattern
Output
Modify
:
bitMa pper
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 -
Output
Modify
bitMap
pointer to bit mapper struct
mapper.c
void
freeBitMapVars(bitMapVars* bitMap)
free((*bitMap).pattern);
free((*bitMap).symbolBits);
/*
freeBitMapVars */
function: freeTwoDsymbolMapVars
Deallocates memory for symbol mapper struct variables
Input
Output
Modify
twoDsymbolMapVars* map - pointer to symbol mapper struct
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* signalMapper
pointer to symbol mapper struct
Output
Modify : map
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,
llistInitVars((*signalMapper).output, 1);
sizeof(linkList));
} /* normalMappingInitVars */
/*
function: QAMgcSignalMapInitVars
This function initializes the signal mapper by using
concatenated gray labels with a square-QAM signal set.
: twoDsignalMapVars*
int
int
int
int
Output :
Modify : signalMapper
Input
signalMapper
InumGB1
InumGB2
QnumGB1
QnumGB2
-
pointer to
upper gray
lower gray
upper gray
lower gray
signal mapper struct
bits in I channel
bits in I channel
bits in Q channel
bits in Q channel
169
SIMULATION CODE
170
I
void QAMgcSignalMapInitVars(twoDsignalMapVars* signalMapper, int InumGB1, int InumGB2, int QnumGB,
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.
twoDsignalMapVars* signalMap
Input
Output
Modify : signalMap
*/-.
void freeTwoDsignalMapVars(twoDsignalMapVars* signalMap)
freeBitMapVars(&(*signalMap).bitMapper);
freeTwoDsymbolMapVars(&(*signalMap).symbolMapper);
freeList((*signalMap).output);
/*
---------------------
function:
DISPLAY/DEBUG FUNCTIONS
----------------------
showOneDmapping
Shows points and labels for one-dimensional signal sets.
: oneDsymbolMapVars* mapper - pointer to signal mapper struct
Input
Output
Modify
*/
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. If
fp is NULL, then prints to screen. Otherwise prints to file fp.
Input
: twoDsymbolMapVars* mapper - pointer to symbol mapper struct
FILE*
fp
- pointer to output file
Output
Modify : contents of file fp
void showTwoDmapping(twoDsymbolMapVars* mapper, FILE* fp)
int i,
j, b;
*
int
QnumGB2)
171
mapper.c
b = (int) (logl0((*mapper).M)/log10(2));
if (fp
NULL)
!=
fprintf(fp, "[point, label]
for (i=0; i < (*mapper).M; i++)
fprintf(fp,
"[(%gg), ",
(j=0; j
b; j++)
fprintf(fp,
"%d", (int)
fprintf(fp, "
"
(*mapper) .symbols[i] .i, (*mapper) .symbols[i] .q);
for
(*mapper)
code [i] [j]);
};
fprintf (fp, "\n");
else
printf(" [point, label]
for
(i=0;
i <
(*mapper).M; i++)
printf("
[(%g,%g) , ", (*mapper) .symbols[i .i, (*mapper)
for (j=0; j < b; j++)
printf("%d", (int)
(*mapper) .code[i [i);
printf("]
symbols[i
.q)
};
("\n")
printf
}; /*
/*
/
showTwoDmapping
-------
---
function:
getNumBits
----
BIT MAPPER
FUNCTIONS
----------------------
/
Find the number of uncoded, systematic, and parity bits per
symbol.
Input
bitMapVars* bitMap
Output
Modify
*bitMap
- pointer
to bit
mapper
struct
*/
void getNumBits(bitMapVars* bitMap)
int i;
(*bitMap).numParity = 0;
(*bitMap).numSys = 0;
(*bitMap).numUncoded = 0;
for
(i=0; i < (*bitMap).b; i++)
if ((*bitMap).pattern[i] ==
/*
'u')
(*bitMap).numUncoded += 1;
else if ((*bitMap).pattern[i] == 's')
(*bitMap).numSys += 1;
else
(*bitMap).numParity +=
1;
/*
/*
getNumBits
---
initialize symbolPattern[]
/* count number of systematic bits
1;
SYMBOL MAPPER FUNCTIONS
----------------------
function: PAMgcSignalSet
Forms a one-dimensional signal set with odd-valued points
centered evenly about zero.
Input
oneDsymbolMapVars* PAMmapper
- pointer to symbol map struct
int
numGrayBitsl - upper gray bits for labels
int
numGrayBits2 - lower gray bits for labels
Output
Modify
*PAMmapper
*/
void PAMgcSignalSet(oneDsymbolMapVars* PAMmapper, int numGrayBitsl, int numGrayBits2)
(*PAMmapper)
(*PAMmapper)
.M =
(int)pow(2, (numCrayBitsl + numGrayBits2));
symbols = createPAMlevels( (*PAMmapper) M);
*/
*/
/* count number of parity bits per symbol
*/
--------
*/
/* count number of uncoded bits per symbol
*/
172
SIMULATION CODE
code = createGrayCode(numGrayBitsl,
(*PAMmapper)
/* PAMgcSignalSet
numGrayBits2,
(*PAMmapper)
.M)
*/
function: QAMSignalSet
Forms a two-dimensional square signal set with odd-valued points
centered evenly about zero in each direction.
Input
twoDsymbolMapVars* symbolMapper - pointer to symbol map struct
oneDsymbolMapVars tempI
- 1-D signal set for I channel
- 1-D signal set for Q channel
oneDsymbolMapVars tempQ
Output
Modify
*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 +=
pos
=
(sqr(tempI.symbols[i}) + sqr(tempQ.symbols[j]));
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++]
};
(*symbolMapper).Eav /=
/*
=
tempQ.code[j] [ki;
};
QAMSignalSet
function:
(*symbolMapper).M;
*/
findOneDsymbol
Finds the signal point in a one-D signal set with bit label
matching the input bits.
bits[]
: char
oneDsymbolMapVars* map
Output : one-dimensional point
Modify
Input
- array containing input bits
- signal set points and labels
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
/* keep on looking for the match
(!done)
*/
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
*/
*/
mapper.c
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[]
twoDsymbolMapVars* map
Output
-
input bit array
two-D points and labels
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)
i++;
tempElement
bitsEqual =
=
(*map).code[i];
1;
for (j=O; j<componentBits;
bitsEqual
= bitsEqual
/*
j++)
*/
keep on looking for the match
get next
Gray code element
/* check each bit for the match
&& (tempElement[j]
*
== bits[j});
done = bitsEqual;
return
(*map).symbols[i];
} /* findTwoDsymbol
function:
/*
return
*/
the matched PAM level
*/
createPAMlevels
Creates an array of odd-valued points centered evenly about
zero.
Input
int M - number of total points
Output
double PAMlevels[]
-
array
Modify
*/
double* createPAMlevels(int M)
{
int
i;
double *PAMlevels = (double*) calloc(M, sizeof(double));
levels */
for
(i=O;
i<(M/2);
* allocate memory to hold PAM
/
i++)
generate
the M
PAM levels
*/
{
PAMlevels[i) = (double) (-l*(M-1) + 2*i)
PAMlevels[M-1-i] = -l*PAMlevels[i];
/*
the
/* the negative (M/2) PAM levels
po sitive (M/2) PAM levels */
};
return PAMlevels;
};
/*
createPAMlevels
*/
function: formTwoDsymbol
Takes bits from the input linked lists and maps them to a
signal point.
Input
Output
Modify
twoDsignalMapVars* signalMapper - pointer to signal mapper
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]
(*map) .symbolBits[i]
(*signalMapper)
==
s')
= (*signalMapper) .inputS->head->value [0];
inputS->head
=
(*signalMapper) .inputS->head->next;
*
173
174
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 codes
can be formed by a recursive algorithm starting with the 1-bit code
0,1.
In general, a n-bit gray code can be formed from the (n-l)-bit
code by prepending a '0' to the (n-l)-bit code, followed by prepending
a 'l' to the (n-l)-bit code in reverse order.
0,1
-- > 0 +
(0,I)
and 1 + (1,0)
= 00,01,11,10
00,01,11,10 -- > 0 + (00,01,11,10) and 1 + (10,11,01,00)
= 000,001,011,010,110,111,101,100
and so on...
int numBits - number of bits in the full gray code.
*theList - the linked list of gray codes
Input
Output
Modify
*/
linkList* makeNbitGC(int numBits)
linkList
=
*theList
(linkList*)
calloc(1,
sizeof(linkList));
/*
linkList *tempList;
listElement *tempElement;
char *tempchar;
int
/*
temporary variables
allocate memory for the gray code
*/
i;
llistInitVars(theList, numBits);
if
(numBits ==
/* base case of recursive algorithm
1)
*/
tempchar = (char*) calloc(l, sizeof(char));
*tempchar = 0;
/* make a 2 element linked list with just
/* 0 and 1 */
addLLbits(theList, tempchar);
*
= 1;
*tempchar
addLLbits(theList, tempchar);
free(tempchar);
} /* numBits = 1 */
else
tempList
= makeNbitGC(numBits-1);
/*
recurse --
first
make a
tempcnar = (cnar-) caliocnumBits, sizeot(cnar));
tempElement = getElement(tempList, 1); /* now prepend the 0 to the
tempchar[0] = 0;
/* the prepended 0 */
while (tempElement != NULL)
(n-l)-bit gray code
(n-l)-bit gray code
*/
*/
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 -tempElement
= getElement(tempList,
tempchar[O] = 1;
while
(tempElement !=
now prepend the 1
*/
(int)pow(2, (*tempList) .valueLength));
/* the prepended 1
*/
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);
}; /*
return
/*
numBits >1
theList;
makeNbitGC
*/
*
/*
free up temporary memory allocations
*/
*/
*/
mapper.c
175
function: concatCodes
Concatenate two separate codes contained in separate linked lists
The elements of the second code are appended to each element of
the 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 as
a 3-bit full gray code.
linkList *MSBlist - the first list of codes
linkList *LSBlist - the second list of codes
Output :theList - the list for the concatenated code
Modify
Input
*/
linkList* concatCodes(linkList *MSBlist, linkList *LSBlist)
linkList *theList =
(linkList*) calloc(l,
* allocate memory for concat. list
sizeof(linkList));
/* temporary variables
int
b = (*MSBlist) .valueLength+(*LSBlist) valuE
?Length;
char *tempchar =
(char*) calloc(b, sizeof(char
int j;
listElement *tempEll, *tempEl2;
llistInitVars(theList, b);
tempEll = getElement(MSBlist, 1);
while
(tempEll
!=
/*
NULL)
(j=0; j<(*MSBlist) .valueLength; j++)
tempchar~j] = (*tempEll).value[j];
for
tempEl2 = getElement(LSBlist,
while (tempEl2 != NULL)
1);
get first element of first list */
/* continue concat until thru first list
/* get bits from first
-
*/
code
go through entire second code
/
*/
*/
(j=0; j<(*LSBlist).valueLength; j++)
/* get bits from second code */
tempchar[(*MSBlist).valueLength + j] = (*tempEl2).value[j];
addLLbits(theList, tempchar);
/* add the new code to the final
tempEl2 = (*tempEl2).next;
for
};
go through LSB gray code list
/*
*/
tempEll = (*tempEll).next;
}; /*
go through MSB gray code list
go to next element in first code
*/
deleteList(MSBlist);
deleteList(LSBlist);
return theList;
} /*
concatCodes
*/
function: createGrayCode
Determine whether to create a full gray code (numMSB=O or numLSB=O) or
a 2-level concatenated Gray code.
The final Gray code is stored in a
linked list
int numMSB - number of bits in the upper level of the 2-level gray code
int numLSB - number of bits in the lower level of the 2-level gray code
Output : two-D array containing the gray code
Modify
Input
*/
char** createGrayCode(int numMSB, int numLSB, int M)
linkList *MSBGC, *LSBGC, *finalGC;
char** retArray = (char**) calloc(M,
listElement *element;
int i=O, j;
if (numMSB == 0)
finalGC = makeNbitGC(numLSB);
else if (numLSB == 0)
finalGC = makeNbitGC(numMSB);
else
sizeof(char*))
/* make a full (b/2)-bit gray code
*/
/* make a full
*/
(b/2)-bit gray code
/* gray code for upper bits */
MSBGC = makeNbitGC(numMSB);
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,
for (j=O; j < (*finalGC) .valueLength; j++)
retArray[i]
[j]
=
(*element) .value[j];
sizeof(char))
*/
list
176
SIMULATION CODE
i++;
element =
(*element).next;
1;
return retArray;
S/* createGrayCode
/*
*/
return the
final gray code
*
channel.h
channel.h
file:
channel.h
This header file contains definitions for simulation functions
related to sending signals through channels, including
AWGN 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*);
/*
177
178
SIMULATION CODE
channel.c
file:
channel.c
This source file contains code for simulation functions
related to sending signals through channels, including
AWGN 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 channel
output list. This function is called from the main simulation
program
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, sizeof(linkList));
llistInitVars((*channel).output, 1);
S/* channelInitVars
*/
function: freechannelVars
This function deallocates channel variable memory.
channel.c
void freeChannelVars(channelVars* channel)
freeList((*channel).output);
/*
freeChannelvars */
OTHER FUNCTIONS ---
function: sendAWGNpoint
This function takes a 2D signal point from the channel input,
sends it through an AWGN channel, and adds it to the channel
output list.
*/
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 random variables.
32 bit arithmetic.
Assumes
*/
void Gauss32(double *x, double *y)
f
long temp;
double ul,u2,r,theta,PI=3.1415;
temp = rand();
/*
rand)
gen an integer
temp = temp % RAND MAX;
between
0
and RANDMAX
'/
/* modulus operation to make sure value of TEMP is less than
Ox7fffffff - which is the greatest value of a LONG data type
ul = (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)
r = sqrt(-2.0 * log(l.0-ul)); /*
/*
theta = u2 * 2 .0 * PI;
/*
*x = or * cos(theta));
*y =
}/*
or * sin(theta));
Gauss32
*/
'
takes a double as an argument t */
0 <= r < sqrt(-2*ln(l/RAND M AX))
*/
with
0 < (1-ul) <= 1
(no zero) */
0 <= theta < 2pi */
179
180
SIMULATION CODE
demod.h
file:
demod.h
This header file contains definitions for functions that generate
soft-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)
demod.c
demod.c
file:
demod.c
This source file contains code for generating soft-values from
received signal points for input to the MAP decoder.
#include
#include
#include
#include
"general.h"
"linkedlist.h"
"mapper.h"
"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.
dem
demodulatorVars*
twoDsignalMapVars* mapper
Input
double
Output
Modify
noise var
- pointer to demodulator struct
- pointer to signal mapper
- channel noise variance
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]
if (outP == NULL)
==
'p')
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
181
182
SIMULATION CODE
for the QAM bit error rate. It chooses the constellation point
nearest to the received symbol as the point that was sent.
There is no struct associated with this operation.
decodedLL -
linkList*
Input
Output
Modify
list where decoded bits will be
stored
- pointer to signal mapper
- list of symbol at output of channel
twoDsignalMapVars* mapper
points
linkList*
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)
deleteFirstElement(points);
[0];
min = 0;
minD = sqrt(sqr(signal.i
for
- (*mapper).symbolMapper.symbols[0) .i) +
sqr(signal.q - (*mapper).symbolMapper.symbols [0].q))
(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
Output
demodulatorVars* dem - pointer to demodulator struct
Modify
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 sturct
Output
Modify
*dem
void freeDemodulatorVars(demodulatorVars* dem)
freeList((*dem).outputP);
freeList((*dem).outputS);
/* freeDemodulatorVars */
*
demod.c
----
OTHER FUNCTIONS
--------
function: calcBitLLR
This function calculates the log-likehood ratio for a bit in
a received symbol.
:
Input
Output
Modify
twoDSignalPoint
point
pos
int
twoDsymbolMapVars symbolMapper
double
noise var
LLR for the specified bit
received point
- bit to calculate LLR for
- symbol mapper struct
- channel noise variance
-
double calcBitLLR(twoDSignalPoint point, int pos,
int i,
double
double
double
twoDsymbolMapVars symbolMapper, double noise var)
half;
metricl=0, metricl=O;
maxlog = 40;
result;
half = (int)floor(loglO(symbolMapper.M)/logl1(2) /2);
for (i=0; i < symbolMapper.M; i++)
if (symbolMapper.code[i] [pos] == 0)
/*
number of bits per dimension in QAM */
(pos < half)
metricO += exp(-1.0/(2*noisevar) * sqr~point.i - symbolMapper.symbols[i].i));
if
else
metricO +=
exp(-l.0/(2*noise var) * sqr(point.q - symbolMapper.symbols[i].q));
else
(pos < half)
metricl += exp(-1.0/(2*noisevar) * sqr(point.i - symbolMapper.symbols[i].i));
if
else
metricl += exp(-l.O/(2*noise var) * sqr(point.q - symbolMapper.symbols[i}.q));
limit magnitude of LLR so it won't cause computational errors
if (fabs(metricl) < exp(-l*maxlog))
metricO = exp(-l * maxlog);
if (fabs(metricl) < exp(-l*maxlog))
metricl = exp(-l * max_log);
result = log(metricl/metric);
if (fabs(result) > maxlog)
result =
return result;
}
/*
calcBitLLR
*/
(result/fabs(result)) * maxlog;
later on *
183
184
SIMULATION CODE
decoder.h
file:
/*
decoder.h
type definitions
*/
typedef struct MAPdecoderVarsStruct
int 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);
decoder.c
185
decoder.c
/*
file:
decoder.c
This source file contains code for turbo decoding,
and the log variants of MAP decoding.
MAP decoding,
*/
#include
#include
#include
#include
#include
#include
#include
"general.h"
"linkedlist.h"
"interleave.h"
"conv.h"
"mapper.h"
"demod.h"
"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
encoderVars*
convCode
int
blockSize
twoDsymbolMapVars* symbolMapper
- pointer to MAP struct
- convolutional code to decode
- number of k-bit inputs
- pointer to symbol mapper struct
Output :
Modify : *decoder
*/
void MAPdecoderInitVars(MAPdecoderVars*
decoder,
encoderVars* convCode,
int blockSize,
twoDsymbolMapVars*
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,
/*
betaEkE [m]
beta[0] Em] not used
beta[l... blockSize] [m] hold decoding info
beta[blockSize] [m] holds initialization info
/*
alpha~k] [m]
alpha[E] [m] hold initialization info
alpha[l... blockSize] [m] hold decoding info
(*decoder)
beta
(double**)
=
calloc (blockSize+1,
sizeof (double**))
sizeof (double*));
*/
(*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]
for
(i=;
i
<
=
(double") calloc((*decoder)
(*decoder)
numInputs; i++)
il = (double*)
numInputs,
sizeof (double*));
(*decoder) gamma[k]
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 integer
for k=2:
E0] [
El] []
[2] [
=
00
=
=
01
10
symbolMapper)
SIMULATION CODE
186
[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 use
doFastRl2decodeBlockO, which uses bit LLR's. Thus, we only need
the 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, we
*
need the MAP module output list to have valueLength = 2^
? 1 : (*decoder).numInputs;
= ((*convCode).k == 1)
(*decoder).output_Dprob = (linkList*) calloc (1, sizeof(linkList));
llistInitVars((*decoder).output_Dprob, k);
k
(*decoder).output-extrinsic = (linkList*) calloc
llistInitVars((*decoder).output_extrinsic, k);
/* MAPdecoderInitVars
function:
(1, sizeof(linkList));
*/
freeMAPDecoderVars
Deallocates memory for decoder struct variables
Input
Output
Modify
MAPdecodervars* decoder
*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 and
calculates the percentage of values that are different.
Input
Output
Modify
- list of original bits
: linkList* origBits
linkList* decodedBits - list of decoded bits
% of values that are different
*/
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;
/
decoder.c
(i=0; i < num; i++)
for
if (* (*currEll) value = (*currEl2)
per++;
currEll = (*currEll).next;
currE12 = (*currE12).next;
value)
};
(per /
return
/*
/*
(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 those
values to Pr(b=O) = 1/(1 + exp(LLR)),
and Pr(b=1) =
exp(LLR)
/
(1
+ exp(LLR)) .
The
LLR value is
held in an input
element's signal[].i variable. After Pr(b=O) is calculated
it is stored in signal[] .i, and Pr(b=l) is stored in signal[] .q
LLR is limited to -40 and 40, so probabilities range from
1 / (1 + e^40) = e^(-40) to about 1.
Input
Output
Modify
MAPdecoderVars* decoder - pointer to decoder struct
*decoder
void calc_probS(MAPdecoderVars* decoder)
int
k,
i, num;
double expval;
listElement*
currS;
currS = (*decoder).inputS->head;
num = getNumElements((*decoder)
for (k=0; k , num; k++)
for
(i=0; i <
expval
(*currS)
(*currS)
inputS);
(*(*decoder).inputS).valueLength;
= exp((*currS).signal[i].i);
signal [i].i = 1.0
signal [i].q = exp
i++)
/ (1 + exp val);
val * (*currS) .signal [ii.i;
};
currS
} /* calc_probS
function:
I
I
I
I
I
=(*currS).next;
*/
calcgamma
This function calculates part of the gamma parameter used in MAP
decoding. gamma][][1 is a three dimensional array.
The
first index is the time index k, the second index is the
input bits integer value i, and the third index is the parity
bit p. If Ak is the LLR associated with the input (systematic)
bits, and Bk is the LLR for the parity bit, then
S(k-1)
input i
---------- > S(k)
gamma [k] [i] [p]
= Pr(Ak) * Pr(Bk)
parity p
In the
actual BCJR algorithm, gamma = Pr(AkI...)
Pr(Bkj ...)
Pr(dk=i) is "a priori" information supplied by the other MAP
module, and is the only probability in gamma that changes with
each iteration. Thus, the part of gamma calculated here is the
part that does not change between iterations.
Input
Output
Modify
:
MAPdecoderVars* decoder
*/
void calcgamma(MAPdecoderVars* decoder)
k
int k,
i,
b,
bits;
Pr(dk=i).
/
187
SIMULATION CODE
188
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);
/* pk = 0 */
probP.i = 1.0 / (1 + exp_val);
/* pk = 1 */
probP.q = probP.i * exp val;
/* ranges from e^(-40) to
/* ranges from e^(-40) to
1 */
1 */
for (i=0; i < (*decoder).numInputs; i++)
(*decoder).gamma[k][i] [0]
(*decoder).gamma[k] [i] [1]
=
=
probPi;
probP.q;
for (b=0; b < bits; b++)
/*
in currElementS, there are valueLength LLR values
signal[o] corresponds to the MSB LLR, and
signal[valueLenght-1] corresponds to the LSB LLR
This ordering is consistent with ordering used by intToCharArray,
(*currElementS).signal[b].i
corresponds to
so bitValue[i] [b]
(*decoder).gamma[k][i][0]
(*currElementS).signal[b.q;
(*decoder).gamma1k][i][1] *=
((*decoder).bitValue[i][b] == 0) ? (*currElementS).signal[b].i
d
((* ecoder).bitValue[i][bi
==
0) ? (*currElementS).signal[b].i
(*currElemenmtS) signal[b].q;
((*decoder).gamma[k][i][01 < (exp(-l* (*decoder).exp_limit)
(*decoder).gamma[k] [i] [0] = exp(-l* (*decoder).exp_limit);
((*decoder).gamma[k [i][1} < (exp(-l* (*decoder).exp_ limit)))
(*decoder).gamma[k] [i [1] = exp(-l* (*decoder).exp_ limit)
if
if
};
currElementS =
currElementP =
};
/*
/*
(*currElementS).next;
(*currElementP).next;
for k */
calc-gamma s/
function:
init_probA
This function initializes an empty "a priori" linked list
by filling it with equiprobable values if we're decoding
rate-k/(k+l), and with O's if we're decoding rate-1/2.
The former uses actual "a priori" probabilities, and the
latter uses bit log-likehood ratios.
Input
:
MAPdecoderVars* decoder - pointer to decoder struct
factor - determines if using "a priori" or LLR
int
Output
Modify : 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 uses
probabilities (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++)
decoder.c
(*currEl) signal[i] .i = equiprob[i] .i;
currEl = currEl->next;
};
free(equiprob);
4 /*
initprobA */
function: calcalpha
This function calculates all the alpha parameters needed in
MAP decoding.
Input
MAPdecoderVars* decoder - pointer to decoder struct
Output
Modify
decoder->alpha
*/
void calc alpha()MAPdecoderVars* decoder)
7* alpha indices -- alpha[k] [Sk)
summation indices */
int k, dk, Sk;
int Skprev;
/*
int pk;
double sum;
listElement* probA;
*/
probA = (*decoder).inputA->head;
for (k-l; k
-
(*decoder).blockSize;
k++)
(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++)
for
Sk =
(*decoder).trellis[Sk_prev] [dk].S2;
pk =
(*decoder)
trellis
(*decoder) .alpha[k] [Sk]
(*decoder).alpha[k-l1] [Sk prev;
}; /* for Sk-prev *
/*
[Sk prev] [dk].p;
+= (*decoder) gamma
Sk-l -- >
(k] [dk] [pk
* (*probA) .signal [dk].i *
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 final
calculation of L(dk).
However, this means that alpha will accumulate
faster with each k, so it'll need to be normalized */
0;
for (Sk=0; Sk < (*decoder) .numStates;
sum +=
for (Sk=0;
Sk++)
(*decoder).alpha[k][Sk];
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 =
} /*
for k
calcalpha
function:
(*probA).next;
*/
*/
calc_beta
This function calculates all the beta values used in MAP
decoding
Input
Output
Modify
Sk,
/* branch:
sum =
}; /*
*/
MAPdecoderVars* decoder - pointer to MAP decoder struct
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;
input dk
*/
189
SIMULATION CODE
190
probA =
for (k =
(* (*decoder).inputA).tail;
((*decoder).blockSize - 1); k >= 1; k--)
f
for (Sk = 0; Sk < (*decoder).numStates; Sk++)
(*decoder).beta[k] [Sk] = 0;
each trellis[Sk-1] [dk] is a branch */
/*
loop through branches:
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]
(*decoder).beta[k+l][Skfuture];
}; /* for dk+l
(*probA) .signal dk future] .i
*/
sum = 0;
for (Sk=O; Sk < (*decoder).numStates; Sk++)
sum += (*decoder).beta]k]]Sk];
for (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.
: MAPdecoderVars* decoder - pointer to decoder struct
Input
Output
Modify
*decoder
void doMAPdecoding(MAPdecoderVars* decoder)
{
int k, Skprev, Sk, dk;
int pk, b, bits;
double *lambda;
double probS, sum;
twoDSignalPoint *prob;
listElement *currElementA, *currElementS, *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, but
bits = (int) (logoO((-decoder).numonputs) / logiu(2));
does.
bits = (int) (logl0((*decoder).numInputs) / logiO(2));
calcalpha(decoder);
if ((*decoder).beta[(*decoder).blockSize][0] != 1) /* trellis is not terminated */
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++)
Sk = (*decoder).trellis[Skprev] [dk].S2;
pk = (*decoder).trellis[Skprev] [dk].p;
lambda[dk] += (*decoder). gamma[k] [dk [pk]
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++)
* (*currElementA) .signal[dk] .i * (*decoder). alpha[k-
decoder.c
prob[dk].i = lambda[dk] / sum;
/* limit magnitude of probability. prob < 1, so log(prob) <
if (fabs(log(prob[dk .i)) > (*decoder) .exp_limit)
prob[dk.i = exp(-l
(*decoder).explimit);
0
};
if (currOutD == NULL)
addLLsignal((*decoder).outputDprob, prob);
if currOut is NULL, it will remain NULL throughout this MAP
decoding round, and bit probabilities will be added to the
*/
output 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]
(*currElementS).signal[b}.q;
prob[dkl.i /= probS;
==
0)
?
(*currElementS).signal[b].i :
};
sum = 0;
for (dk=; dk < (*decoder).numInputs; dk++)
sum += prob[dk].i;
for (dk=0; dk < (*decoder).numInputs; dk++)
prob[dk].i /= sum;
/* limit magnitude of probability.
if
prob < 1, so log(prob)
(fabs(log(prob[dk].i)) > (*decoder).exp_limit)
prob[dk].i = exp(-l * (*decoder).explimit);
if
(currOutA
!=
<0
/
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 used in MAP decoding.
- pointer to MAP decoder vars
: MAPdecoderVars* decoder
char
terminated - whether trellis is terminated
Input
Output
Modify
decoder.alpha, decoder.beta
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]
for
(m = 1;
m
<
=
(*decoder).numStates; m++)
(terminated)
? 1 : equiprob;
(*decoder) .beta[(*decoder) .blockSize] [m] = (terminated)
/*
initAB
*/
/*
Ifunction:
initB usingA
? 0 : equiprob;
191
SIMULATION CODE
192
Initializes beta parameters in the case that the trellis is
not terminated.
MAPdecoderVars* decoder - pointer to decoder
Input
Output
Modify
(*decoder).beta
*/
void initBusingA(MAPdecoderVars* decoder)
int m;
for (m=O; m < (*decoder).numStates; m++)
(*decoder) .beta[(*decoder) .blockSize] [m]
/*
=
(*decoder) .alpha[(*decoder) .blockSize
initB_usingA *
/*,
function:
probDecision
Choose maximum a posteriori probability.
linkList* input - list of the a posteriori probabilities
linkList* output - list of the decoded bits
Input
Output
Modify
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 for
output 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 >>
if
(bits-1 - j))
(currOut ==
&
Oxl;
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 struct
Output
Modify
*decoder
void doFastRl2MAPdecoding(MAPdecoderVars* decoder)
int k, Skprev, Sk;
int pk;
*/
[m];
decoder.c
double lambdal, lambdao;
double Ls, La;
twoDSignalPoint LLR, Z;
const double infinite = le308;
double probA[2];
listElement
*currElementA, *currElementS,
calcalphaRl2(decoder);
if ((*decoder) .beta[(*decoder)
initB usingA(decoder);
calcbetaRi2(decoder);
*currOutA, *currOutD;
blockSize] [0]
!=
1)
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++)
/
+ exp((*currElementA)
probA[0]
= 1.0
probA[1]
= exp((*currElementA).signal[0].i)
(1
[0}.i));
* probA[0];
signal
0;
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).alpha[k-l] [Sk_prev *
(*decoder).beta[k] [Ski;
if (lambdaO > infinite)
pk = 0;
Sk = (*decoder) trellis
[Sk_prev] [1}.S2;
[Sk_prev] [1].p;
pk = (*decoder) trellis
lambdal i= (*decoder) gamma[k] [1] [pk] * probA[l]
( decoder).alpha[k-i] [Sk_prcv] *
(*decoder).beta[k][Sk];
if (lambdal > infinite)
pk = 0;
lambdal =
lambdaO =
};
LLR.i = log(lambdal/lambda0);
LLR.q = LLR.i;
/* set q = i
if
in case accidentally use the q part
*/
(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 the
/*
output 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 the
bit is a 1 or 0, respectively. There's no need to further increase or
decrease the extrinsic LLR because at this point, we are already certain what
the bit is. This is a non-linear operation, but it should not affect the
correction power of the turbo code or the performance.
*/
if (fabs(Z.i) > (*decoder).explimit)
Z.i =
Z.q = Z.i;
if
(Z.i)/fabs(Z.i)
*
(*decoder) .exp
limit;
(currOutA == NULL)
addLLsignal((*decoder) .output extrinsic, &Z);
else
I
(*currOutA).signal[O] = Z;
currOutA = (*currOutA).next;
};
} /* doFastRl2MAPdecoding
function:
*/
calcgammaR12
Calculates the gamma parameter used in MAP decoding.
Input
Output
Modify
MAPdecoderVars* decoder
193
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 *
/* pk = 1 *
probP.q = probP.i * exp_val;
expval = exp((*currElementS).signal[0].i);
probS.i = 1.0 / (1 + exp_val);
probS.q = probS.i * exp_val;
(*decoder).gamma[k][0] [0]
(*decoder).gamma[k][0][1]
(*decoder).gamma[k} [1][0]
(*decoder).gamma[k} [1][1]
for
=
=
=
=
probS.i
probS.i
probS.q
probS.q
*
*
*
*
probP.i;
probP.q;
probPi;
probP.q;
(a=0; a<2; a++)
for (b=0; b<2; b++)
if
(* decoder) .gamma[k] [a] [b]
(*decoder)
gamma[k] [a] [b]
<
(exp(-1* (*decoder) .explimit)))
=
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 in
MAP decoding.
Input
Output
Modify
void calc alphaRl2(MAPdecoderVars* decoder)
int k, dk, Sk;
int Skprev;
int pk;
double sum;
/*
/* alpha indices -- alpha[k] [dk] [Sk]
summation indices */
*
listElement* currA;
double probA[2[;
currA =
tor
(*decoder).inputA->head;
k
k=1;
-= (*decoder).blockSize; k++)
probA[0] = 1.0 / (1 + exp((*currA).signal[0].i));
probA[1] = exp((*currA).signal[0[.i) * probA[0];
1]
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[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 final
calculation of L(dk).
However, this means that alpha will accumulate
faster with each k, so it'll
need to be normalized
*/
0;
for (Sk=0; Sk < (*decoder).numStates; Sk++)
sum += (*decoder).alpha[k[ [Sk];
for (Sk=0; Sk < (*decoder).numStates; Sk++)
sum =
(*decoder).alpha[k][Sk] /= sum;
if ((*decoder) .alpha[k] [Sk] < exp(-l* (*decoder) .exp_limit))
(*decoder) .alpha [k] [Sk] = exp(-1* (*decoder) .exp_limit);
/*
*/
};
decoder.c
};
currA = (*currA).next;
for k
/
/
S/* calcalphaR12
function:
*
calc_betaRl2
This function calculates all the beta values used in
decoding
MAP
Input
Output
Modify
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
(*decoder).beta[k+l][Skfuture];
}; /*
for dk+l
*/
sum = 0;
for (Sk=0; Sk < (*decoder).numStates;
SUM += (*decoder).beta[k] [Sk];
for (Sk=0; Sk < (*decoder).numStates;
Sk++)
Sk++)
{
(*decoder).beta[k] [Sk] /= sum;
if ((*decoder) .beta[k] [Sk] < exp(-l* (*decoder)
(*decoder) beta [k] [Sk] = exp(-l*(*decoder)
};
currA = (*currA).prev;
};
*
/* for k
} /* calc_betaR12
function:
*/
signDecision
Performs a sign decision on LLR's used in MAP decoding to
generate the decoded bits.
Input
Output
Modify
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;
b =
i
a numEl;
i++)
((*currEl).signal[0].i >= 0);
explimit))
exp-limit);
probA[dk future]
195
196
SIMULATION CODE
if
(currOut == NULL)
addLLbits(output, &b);
else
(*currOut).value[O] = b;
currOut =
(*currOut).next;
}1;
currEl = (*currEl).next;
};
} /* signoecision
*/
REFERENCES
[1]
P. Melsa, "Application of Programmable DSPs for DMT and ADSL", in DSP
World Spring Design Conference, April 1998.
[2]
C. Berrou, A. Glavieux, and P. Thitimajshima, "Near shannon limit error-correcting
coding 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 Digital
Communications,Fall 2000.
[4]
P. Robertson, "Illuminating the structure of code and decoder of parallel
concatenated recursive systematic (Turbo) codes", in Proc. GLOBECOM '94, pp.
1298-1303, December 1994.
[5]
Stanford University, "Chapter 11: Code Concatenation and Low-Density Parity
Check Codes", in EE379B - Digital CommunicationH1: Coding, Spring 2001.
[6]
S. Le Goff, A. Glavieux, and C. Berrou, "Turbo-codes and high spectral efficiency
modulation", in Proc.ICC '94, pp. 645-649, May 1994.
[7]
P. Robertson and T. W6rz, "A novel bandwidth efficient coding scheme employing
Turbo codes", in Proc.ICC '96, pp. 962-967, June 1996.
[8]
S. Le Goff and F. 0. Al-Ayyan, "Design of bit-interleaved turbo-coded
modulations", Electronic Letters, vol. 37, no. 16, pp. 1030-1031, August 2001.
[9]
S. Benedetto, D. Divsalar, G. Montorsi, and F. Pollara, "Bandwidth efficient
parallel concatenated coding schemes", Electronic Letters, vol. 31, no. 24, pp.
2067-2069, November 1995.
[10] S. Benedetto and Guido Montorsi, "Design of parallel concatenated convolutional
codes", 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 for
minimizing symbol error rate", IEEE Trans. On Information Theory, vol. IT-20, pp.
284-287, March 1974.
-
197
-
198
REFERENCES
[12] P. Robertson and T. W6rz, "Bandwidth efficient Turbo Trellis-coded modulation
using 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 the
same 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: New
proposal of Turbo codes for ADSL modems", ITU standardcontributionBA-020R1
at Antwerp, Belgium, 19-23 June 2000.
[15] S. A. Barbulescu, J. A. Torres, F. Hirzel, and V. Demjanenko, (VOCAL
Technologies Ltd), "G.gen: G.vdsl: G.dmt.bis: G.lite.bis: : Text to include a Turbo
encoder as mandatory in the transmitter for G.922.1.bis and G.992.2.bis following
the proposal given in BA-020R1 and HC-037", ITU standardcontribution CF-037
at 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 constellations
with independent I&Q for Receiver soft-Decision Decoding Techniques", ITU
standardcontribution CF-038 at Clearwater, Florida, 8-12 January 2001
[17] W. Farrell, (iCODING Technology), "G.gen : G.dmt.bis : G.lite.bis : Low
complexity Turbo coding for the ADSL DMT channel", ITU standard contribution
CF-072 at Clearwater, Florida, 8-12 January 2001.
[18] D. V. Bruyssel, (Alcatel), "G.gen: G.dmt.bis: G.lite.bis: Multilevel Turbo SCCC
code: proposal, performance and complexity", ITU standardcontributionRN-079 at
Red Bank, New Jersey, 21-25 May 2001.
[19] B. I in and A
Deczky, (Catena Networks Inc), "G.gen: G.dmt.bis: (.lite his
Proposing 'Multi-level" Turbo TCM concatenated with Reed-Solomon codes as the
advanced coding method for G.dmt.bis and G.lite.bis", ITU standardcontribution
IC-024 at Irvine, California, 9-13 April 2001.
[20] H. Sadjadpour, (AT&T), "G.gen: G.dmt.bis: G.lite.bis: : Encoder structure of Multitone Turbo Trellis coded modulation proposal", ITU standardcontribution RN-027
at Redbank, New Nersey, 21-25 May 2001.
[21] H. Sadjadpour, (AT&T), "G.gen: G.dmt.bis: G.lite.bis: : Interleaver design for
multi-tone Turbo Trellis coded modulation scheme for G.dmt.bis and G.lite.bis",
ITU standardcontributionRN-029 at Redbank, New Jersey, 21-25 May 2001.
Download