UN'"l:k::i/fY OF HAWAII U8RARY CHANNEL CODING FOR THE RELAY CHANNEL A THESIS SUBMl'I"IED TO THE GRADUATE DIVISION OF THE UNIVERSITY OF HAW AI'I IN THE PARTIAL FULFILLMENT OF THE MASTER OF SCIENCE IN ELECTRICAL ENGINEERING May 2006 By DannyYee Thesis Committee Anders Hllst-Madsen, Chair N. Thomas Gaarder Marc Fossorier
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
UN'"l:k::i/fY OF HAWAII U8RARY
CHANNEL CODING FOR THE RELAY CHANNEL
A THESIS SUBMl'I"IED TO THE GRADUATE DIVISION OF THE
UNIVERSITY OF HAW AI'I IN THE PARTIAL FULFILLMENT OF THE
REQ~TSFORTHEDEGREEOF
MASTER OF SCIENCE
IN
ELECTRICAL ENGINEERING
May 2006
By DannyYee
Thesis Committee
Anders Hllst-Madsen, Chair N. Thomas Gaarder
Marc Fossorier
We certify that we have read this thesis and that, in our opinion. it is satisfactory in scope
and quality as a thesis for the degree of Master of Science in Electrical Engineering.
Chair
ii
ffA Qll1 .H3
no. 4075
Acknowledgement
I would like to thank my advisor Dr. Anders H~st-Madsen for always helping me
with whatever questions I had, as well as giving me a subject matter for my thesis. I
would especially like to thank Yige Wang for the LOpe decoder and generator matrices
and helping me with all of the questions I had about the code. I would also like to thank
Dr. Marc Fossorier for help with erasure codes, irregular codes, and serial concatenation.
Finally, I would like to thank Dr. N. Thomas Gaarder for help with some theoretical
issues as well as other miscellaneous questions.
iii
Abstract
The relay channel consists of an input, a relay, and a destination. The source
transmits XII. A relay, which receives that as Y2, will decode it and transmitx2 as a
function of Xu. Finally, the destination receives Xu, XI2, and X2 as)'3, which it decodes. If
done correctly, XI2 and X2 will sum coherently and the resulting)'3 will be superior to
simply sending the message straight from source to destination at 2x the power.
In this thesis, two cases are considered. The cases are full duplex relaying and
half duplex relaying. Full duplex relaying is where the relay can send and receive at the
same time. This is implemented using backward decoding, a form of superposition block
Markov encoding, as well as QPSK signaling.
The half duplex case is where the relay cannot send and receive on the same
channel at the same time. This is implemented using TDO. Code shortening is used to
achieve the relaying objective.
iv
List of Figures
Figure
Figure 1: A diagram of a relay channel.. ............................................................................. 2
Figure 2: The two cuts that are used to prove equation (4) ................................................. 7
I I I I I ___ ! _______ J ________ L _______ L. ______ J____ _ _______ _ _ _ ! _______ J _______ .1. _______ L _______ J _ _ _ ___ .'. ______ _
_____ .! _______ J ________ L _______ L _______ J ______ ~ _______ _ , , , , . , ------- ------~--------~-------~-------1 ------4--------_______ 1 __ ____ J ________ , ________ L _______________ , _______ _ I , I I I
------_£_--- -~--------~-------~------ ~-------~--------I I I I _______ l _______ J ________ L_______ ___ __J _______ J _______ _ I I I 1 1 I 1 I I 1 I I _______ ~ _______ J ________ L _______ L _______ J _______ ~ _______ _
I I I I I 1 I 1 I 1 I 1 I I 1 1 _______ ~ _______ J ________ L _______ L _______ J _______ ~ _______ _
I I I I I 1 I I I I , , , , , , ..
to o.oL:-8---:c0-:'.065c:c:-----:O-':.r11=---O::-.076~---0::-.':::08:-----::0-:'.085':::-----:O:-'.09:::---::-:0.a!5
FIgure 7: BER vs. p, TryiDg to find the best value
The first point at the far left of the graph is the theoretical value of p.
The experiment was repeated with a different value for en. The parameters below were
tried:
e21 = 0.8, e31 = 0.2, e32 = 0.6
Then p was varied, simulated, and the BER was found. These are the results:
-----~----~-----1-----t-----~-----~----~-----~-----+-----_____ 1. ____ J. ____ J _____ 1.. ____ L ____ .1. _____ , _____ J. ____ L ____ _
I I I , I I I I I I , , , I I , I I
-----l-----'-----l-----T-----r-----~----~-----'-----r-----I I I I I I I I I _____ ~ ____ J _____ J _____ 1 _____ L _____ ~ ____ J _____ J _____ ! ____ _ t I I I I I I I I 1 I I I I I I I I I I 1 I I I I I I I I I I I I
-----~----l-----'-----r-----r-----~----~-----,--- -y-----I I I I I
-----~ ---~-----1-----.-----~-----~---- -----1-----~-----_____ 1 ____ J _____ J _____ ! _____ L _____ L ___ J _____ J _____ 1 ____ _ I 1 , I I I I 1 ____ t _____ ~ _____ 4 _____ ~ _____ ~ _____ t ____ ~ _____ ~ _____ ~ ____ _
I 1 I I t I I I 1 ____ L ____ J _____ J _____ ! _____ L _________ J _____ J _____ ! ____ _ I 1 1 I I 1 1 1 I 1 1 I I I I 1 1 I ____ L ____ J _____ .J _____ 1. _____ L ____ 1 _____ J _____ J _____ 1 ____ _
1 1 I 1 I I 1 I I ....,.--- I I 1 1 I I I 1
I 1 1 1 1 I 1 ____ 4 _____ 1 ____ L _____ I _____ J ____ .J _____ 1 ____ _
1 1 I I 1 1 I 1 I I I I I 1
I I I I I 1 I I 1 I 1 I 1 I , "
FIgure 8: Another graph trying to find the optimum value of Ii
Again, at the far left is the theoretical value of p. According to both of these graphs, the
actual p is very close to, but not quite equal to the theoretical value. Since the BER of a
given code is a function of the received SNR, if a small, but constant bit of power was
added to the destination side of equation (6) before solving for p, then the actual value of
pmay be solved for. In other words, a constant, J, will be declared and used in equation
(6) as follows:
Thus, the new equation for pwill be
31
(26)
Using the graphs of pvs. BER, the estimated value of (j - 0.02 to 0.03. There is some
evidence that (j is a function of some of the rest of the variables, and is more than just a
constant. However, fmding an actual formula for the best value of (j will be a very time
consuming task.
The simulations have not been performed to fmd the formula for the exact value
of (j for this case. However, it is not critical for the simulation, due to the fact shown in
the above graphs that the theoretical value of P is very close to the experimentally
determined optimum value of p. So, the non-optimum results obtained in the graphs
above should not change a great deal from the ideal results.
3.4 Summary
In the process of implementing the full duplex relay, the method of Superposition
Block Markov Encoding is used, which has been shown to achieve capacity in various
papers [6]. By using 5MBE and a QPSK signaling scheme, what the capacity theory says
should be the received power at each node is mirrored exactly. While the relay node
decodes the 5MBE in the forward direction, the destination decodes its 5MBE in the
backward direction. In addition, before the destination decodes a block, it should rotate
the received QPSK signal by a phase angle with the direction of the angle determined by
the previous block. Thus, it turns the QPSK signal into a BPSK signal.
Three situations that use the full duplex channel are simulated and graphed. In
the first situation, the relay is the limiting receiver, and so it is possible to reduce the
32
power to the destination from the relay and still get reliable transmission. Within the
graph, there is also a comparison to a 1,4 rate code transmitted using QPSK. This is the
closest comparison that could be simulated that involved direct transmission. In this
graph, the relay channel fared very poorly to the direct transmission case.
Another situation is a typical situation where the path from source to destination
is very poor. This case is also compared with the 1,4 rate direct transmission QPSK. In
addition, it is also compared with what is known as multihop. Multihop is the traditional
form of relaying, where a message is sent from source to relay, and then from the relay to
the destination. It is similar to a cascade of two direct transmission channels. In this case
multihop was actually a bit better than the relay channel implementation. This is
unfortunate, because ideally, the relay channel should be better than multihop.
The third situation is one where the relay channel is better than the other two
methods. This is the situation where the source and relay are close together, and far from
the destination. In this case, the two transmitting nodes act like an antenna array for the
part of the signal that they have in common. The relay implementation is about 1.5 dB
better than the next closest method, direct transmission. Direct transmission is better than
multihop because multihop must deal with interfering signals from the source ~
destination path.
Finally, it was noted that the pthat was being using to simulate blocks was not
necessarily the best performing p. However. in the process of simulation. it was
determined that the actual value was very close to the theoretical value. Thus, the values
that were recorded were allowed to stand, because they were close enough.
33
4. Half Duplex Relaying Implementation
4.1 Basic Idea
For the TOO version of the relay, one must return to the idea behind the relay
channel. The idea was that the source would broadcast a message that both the relay and
the destination would receive. Assuming that the channel gain between source ~ relay is
better than the channel gain between source ~ destination, the message would be sent at
a rate that would be high enough for the relay to decode, but too low for the destination to
decode. The relay and source would then cooperate to send resolution information
coherently to the destination. The destination would receive this resolution information
and combine it with the originally received information to decode the message. For the
TOO implementation, an approach that mirrors this basic idea will be used.
Two possible methods will be described that can achieve the TOO
implementation. Each of them has their positives and negatives, which will be described.
In the end, the one that seemed less likely to have major problems in its implementation
was chosen.
4.1.1 Serial concatenation at the encoder
The first method better elucidates the ideas of the relay, but was ultimately not
implemented because of a lack of knowledge and inability to analytically determine
which method would prove to be better and ease of implementation. This method was a
serial concatenation of block codes. It involved using two codes in series, with the output
34
of one coder put into the input of another coder. An interleaver was placed between the
decoders to improve the performance of the overall decoder [12].
The idea was to broadcast the output of the first encoder from the source to the
relay and the destination. The rate and power of the signal would be such that the relay
would be able to decode it, but the destination wouldn't. Then. since the relay now has
the original message, have the relay and source generate the additional parity checks that
come from the second encoder. Finally, the relay and source cooperate to send the
secondary parity checks coherently. The idea is that the combination of the two block
codes and the interleaver is roughly equivalent to a larger code of lower rate. In other
words. a message that is encoded with a rate 'h code and then another rate 'h code is like
a message encoded with an overa1l code of rate IA.
Message I First Parity Bits Second Parity Bits
~ ~ ,.0 Ii - Outer 1t Inner -
Figure 9: Example of serial concatenation
To d88tlnatlon (parity bits only)
To dastlnatlon and mlay
The idea is simple enough, and has a certain appeal to it. The source sends an
encoded message that the relay would be able to decode. but the destination wouldn't.
Then the source and relay cooperate to send additional resolution information in the form
of parity bits to the destination. The destination would then use the information sent
35
during the relay received period along with the resolution information sent during the
relay transmit period to decode the message.
The problem with this idea came at the decoder. In order to do soft-decision
decoding, a dual soft input soft output decoder with interleavers and feedback would need
to be implemented [12]. A program to do the decoding would have to be written from
scratch. In addition, there was no guarantee that no unforeseen errors with this method
would come up or that this method would even work as planned. Given these facts, and
that the decoder for the other method was already written, it was decided to go with the
other method.
'Mu :'#
5150 ~ ::rc'! ;0) nat used
1.1) Inner Ni;o
1t"1 .:..
1t
'J..(cll;I}
51S0 ").(uo ./
r-- Outer
zero
- 'J..(c ll ;
NUll :
0)
0)
decl ilion
FIgure 10: The theoretical decoder that could not be Implemented dne to time construlnts
4.1.2 Code Shortening
The next method, which is the one that is implemented in this thesis, is called
code shortening. The idea behind code shortening (which is also known as the method of
punctured codes) is to take a code of a given rate and erase a certain number of bits to
make it a new code with a new rate. For instance, in the simulations, a rate \4 (10000,
2500) code is taken and only ~ of the bits are transmitted. In effect, it becomes a rate ~
36
code (5000, 2500). It is important to note, however, that this new shortened rete ~ code
will not perform as well as a code that was genereted from the start to be a rete ~ code.
The method to decode these codewords is to take the transmitted bits and place them in
their respective positions in the original codeword, then stuff 0' s where no signal was
transmitted, and use the original ~ rate parity check. matrix to decode the entire
codeword. How this is used in the relay channel is as follows:
The source produces a codeword from the message. Then, the source takes ~ of
the bits of the codeword and broadcasts them to both the relay and the destination. If the
bits were transmitted with sufficient power, then the relay will be able to decode the
message. but the destination will not be able to. Then the relay and the source cooperate
to coherently send the other ~ of the bits to the destination. Using the bits from the
previous transmission, plus the bits from the current transmission, the destination is able
to treat it as a single codeword of rate ~, and assuming sufficient power was used in the
transmission, should be able to decode it.
This method has the advantage that the decoders written for the full duplex
method may be reused in this case. This is in contrast to the case of serial concatenation,
where the decoder would have to be wrinen from scmtch. From an analytical point of
view, it is difficult to determine which of these methods has an advantage over the other
one. Therefore, it makes sense to choose the one that is easier to implement. Thus, the
code shortening method was chosen.
37
4.2 Implementation Details
4.2.1 The Problem
There are many ways of implementing the idea of code shortening. Within the
scope of this thesis, one of the problems inherent in the relay channel will be solved by
the methods that are explained here. This problem comes up in the situation when the
source ~ destination path is much worse than the source ~ relay and relay ~
destination paths (a common occurrence in rea1life). Using a puncturing method similar
to the serial concatenation case, after encoding a message, the first block. i.e. the first nl
bits, would be sent to the relay and the destination. Then the source and relay both send
the second block, the last n2 bits (n2 = n - nl), to the destination.
n2
For the code given, it was discovered that if the n I bits were sent first, then a very
high SNR would be needed in order for the relay to decode. It seems that the code that
was in use had to be punctured in a very specific manner to retain good performance. At
this point, an attempt was made to send the n2 bits first. It was discovered that this gave
much better performance than the first nl bits at the relay. However, for the case given
above, where the source ~ destination path is very poor, this proved to not work. The
problem is that in this case, the source ~ relay path is sort of a "mirror image" of the
relay + source ~ destination. When the source broadcasts its n. bits to the relay and
destination, the destination receives that particular set of bits on a very poor path, then
when it receives the other ny bits. it receives it on a very good path. This mirrors the
relay, which receives the n. bits on a very good path from the source, but doesn't receive
38
any of the ny bits at all, which is equivalent to transmitting on the worst possible path
with channel gain = O.
4.2.2 An Attempted Solution
One solution tried in order to solve this problem was to use irregular LOpe codes.
Irregular LOpe codes are codes where the columus in the parity check matrix (H matrix)
have very different weights. This means that some of the bits are better protected from
error than other bits. In general, columus in the H matrix that have higher weight will
better protect their corresponding bits. Also, irregular LOPC codes can have better
performance than regular LOpe codes [11]. When an irregular code was tried in place of
the original code while still keeping the nl and n2 block format, it was found that it didn't
make much of a difference. However, in the process of trying irregular codes, a code was
discovered that performed better in direct transmission than the 1,4 rete regular code given
on MacKay's website [8], the decision was made to use this irregular code in the
simulations. This irregular code proved to perform better in the case of relaying than the
regular code as well.
39
• ••
22222222233 ••• 10 10
Figure 11: An example of an irregular code.
The numbers at the bottom represent the colnmn weights.
4.2.3 A Solution That Worked
Another solution thought out for this problem was to divide the code into two
halves in such a way that were approximately equal in performance. Of course, there are
a great many ways to divide the code into two halves. One method tried was a sort of
"sliding window". A ''window'' of Yz of all the bits would be selected, and designated as
the first half, and the rest of the bits would be the second half. The best division of the
bits into two halves would be one where they are approximately equal in terms of error
correcting performance, and out of the entire set of divisions that have equal performance,
the best one would require the least power.
It was realized that it was not necessary for the bits to be clumped together in
blocks, and that perhaps it would be better for them not to be together. So, other methods
to split up the codeword were tried. One novel idea was that if every other column of the
parity check matrix were taken, and combined into a new matrix, then it would appear to
40
be normal parity check matrix. So, the message was divided into two separate bits by
taking all of the odd numbered bits as one half of the codeword, and all the even
numbered bits as the other half of the codeword. After some trial simulations, it was
found that the two halves of the parity check matrix were indeed approximately equal in
their error correcting ability. In addition, each halves' overall performance as a V2 rate
code was fairly good, but not quite as good as a ''true'' 'h rate code. However, they were
good enough to use in simulations.
Figure 12: Taking every other column of a parity check matrix
leads to two matrices of approximately equaJ performance.
4.2.4 Recalculating K
Much like in the full duplex case, the Kthat the equation (14) gave to divide the
power at the source was not optimum. However, unlike in the full duplex case, in this
case the difference in the theoretical Kand the actual KWas quite large. The source of
this difference comes from the point stated earlier, that "It is important to note, however,
that this new shortened rate 'h code will not perform as well as a code that was generated
from the start to be a rate 'h code." In other words, the shortened code will need more
power than a good rate 'h code to decode the same message. In contrast, the destination
does not need any more power to decode what it receives, because it is an original1A rate
41
code with good perfonnance. So, equation (14) needs to be modified to include a
1************************** Gaussian elimination***************************1 /I Return the rank of the matrix. /I nnn: the length of the code; rrr: the number of rows in H matrix /I int **H_matrix = (int **) malloc(sizeof(int*)*rr); /I H_matrix rr*nn int Gaussillll.-elimination(unsigned char *H_matrix[],unsigned short int nnn,unsigned short int rrr) {
unsigned short int firsCcheck_row, operating",column, independenccol, target_row; unsigned short int i, j; unsigned char * temp_row = (unsigned char *)malloc(sizeof(char)*nnn); unsigned short int * independent_pos = (unsigned short int *) ma1loc(sizeof(short
1* printf("Current frrst check row is %d\n", frrsCcheck_row); *1
}
free(temp_row); free(independenCpos);
return independenccol; }
1************Reduced row echelon form **********************1 1* If there is no 1 on the diagonal, then we swap columns until there is one *1 1* The returned int c is the number of swapped columns. *1
short int reduced_row_echelon_form(unsigned short int *swap_cols, const short int N, const short int M, const short int rank, unsigned char **HH) {
short int iJ,d,temp,c=O;
64
for (i=O; kM; i++) swap_cols[i] = 0;
for (d=1; d < rank; d++) { if (HH[d][d] != 1) {
j=d; while «(HH[d][j] != 1) && (j<N» j++; if (j != N) {
/* For every row above the diagonal, starting at one, if find a one in the column d in that row, we xor row d with that row */
if (HH[i][d] = 1) for (j=d; j<N; j++ )
HH[i][j] = HH[i][j]I\HH[dJU];
/* printf("Processedrow %d.\n", d+1); */
}
return c;
}
int main(int argc, char *argv[]) {
65
FILE *in, *out, *0ut2; short int iJ,c; unsigned short int d,mwcrow_weight,max_coLweight; unsigned short int temp.rank.M,N,K; unsigned char **HH; unsigned char **G; unsigned short int *G_row_weight; unsigned short int *G30Lweight; unsigned short int *swap_cols;
unsigned short int **row_entries; unsigned short int **col_entries;
1* We use short int and char to reduce the memory requirements. *1
'* The following two lines in the file are not necessary to reconstruct the matrix *1 1* Dump the numbers into temp and don't use them. *1
for (i=O; kM+N; i++) fscanf(in, "%d", &temp);
1* Now read in the H matrix. *1
for (j=O;j<N; j++) for (i=O; kmlllccoCweight; i++) {
}
fscanf(in, "%d", &temp); if (temp != 0)
HH[temp-I]U1 = I;
fc1ose(in);
printf("Read the H matrix.\n");
1* Perform gaussian elimination on HH to put it in row echelon form *1 rank = Gaussian_elimination(HH, N, M);
printf("Put H matrix in row echelon form. Rank = %d\n", rank);
1* Now that the HH matrix is in row echelon form *1 1* we have to put it in reduced row echelon form *1 1* If there is no 1 on the diagonal, then we swap columns until there is one *1
printf("Put H matrix in reduced row echelon form.\n");
67
if ((out2=fopen("swapped_columns.txt","w+"» NULL) {
}
printf("cannot open the output file.\n"); exit(O);
for (i=O; i<c; i+=2) fprintf(out2, "%d %d\n", swap_cols[i]+l, swap_cols[i+I]+I);
fc1ose(out2);
1* Now we change the matrix from H to G using the fact that H=[I IA] and G= [A' II]
*1
for (i=O; i<M; i++) for G=M; j<N; j++)
G[j-M][i] = HH[i][j];
for (i=O; i<K; i++) for G=O; j<K; j++) if(i=j)
G[i][j+M] = I; else
G[i][j+M] = 0;
printf("Converted H matrix to G matrix.\n");
1* Now we have to output the resulting matrix. *1 1* Output in Alist format *1 1* First we need some statistics about the array *1
for (i=O; i<M; i++) G_row_weight[i]=O; for G=O; j<N; j++) G_coC weight[j]=O;
for (i=O; i<K; i++) for G=O; j<N; j++)
if (G[i][j] = I) {
G_row _ weight[i]++; G_coCweight[j]++;
I
68
for (j=I; j<N;j++) if (G_coLweightfj] > max_col_weight)
max_col_ weight=G_coL weightfj];
for (i=l; kK; i++) if (G_row_weight[i] > max_raw_weight)
max_row_weight=G_raw_weight[il;
1* Now we write to the fIle *1
if«out=fopen("Gmatrix.txt","w+"»-NULL) {
}
printf("cannot open the output fIle\n"); exit(O);
fprintf(out, "%d %d\n", N, K); fprintf(out, "%d %d\n", max_coLweight, max_raw_weight);
for (j=O; j<N; j++) {
fprintf(out, "%d ", G_coLweightU]); col_entriesfj] = (unsigned short int >!C)ma1loc(max_coLweight*sizeof(short int»;
}
fprintf(out, "\nO);
for (i=O; kK; i++) {
fprintf(out, "%d ", G_row_weight[i]); row_entries[i] = (unsigned short int *)malloc(max_fow_weight*sizeof(short int»;
}
fprintf( out, "\n h);
for (i=O; i<K; i++) for (j=O; j<max_row _weight; j++)
raw_entries[i]Ul = 0;
for (j=O; j<N; j++) for (i=O; i<max_coLweight; i++)
% Procedure file ful1duplexrelay.m % Self explanatory from the title, it simulates the full duplex relay channel. % It uses the algorithm described by Dr. Host-Madsen %
%Ioad G4OOOx8000 % this is the G (Generator) matrix
% I have taken out the G matrix because the method that I have used (using % all zeros), means that I don't need to mulitply anything by G.
% E_sl and E_s2 are the received powers (or energies, since P=FJt) they % should be approximately equal when beta is not equal to O. This is just % a sanity check. It is not used in the code.
format compact;
kk=4ooo; nn=8ooo;
% message block length % codeword length
% Genemte the sequence to be transmitted % We assume that the discrete input has already been source % coded (compressed) so that it is uniformly distributed.
M = 10000; % number of blocks (MUST be a factor of N) N= 100; bllcerrors = 0;
%%%%%%%%%%%% Tmnsmit all zeros %%%%%%%%%%%%%%%
% Instead of randomly generating blocks, use the all zero block.. That way % we speed things up and negate the necessity of the G matrix.
% Source transmit over the noisy channel Y2 = c21 *Xl(l:N,:) + wgn(N, nn, N_02l2, 1inear', 'complex'); % The wgn is linear because I am using linear units for my % calculations.
C_hat = mod(curnsum(Cdelta),2); % Since Wdelta is the xor ofW_hat[i-l] and W_hat[i], we have to sum % the Wdelta[i] with the previous W _hat[i-l] to get W _hat[i]. curnsum % is a quick way to get that for all of the codewords. Also note that % C(W _hat[i-l] xor W _hat[iD = C(W _hat[i-lD xor C(W _hat[iD
% Destination decode sprintf('Destination decoding') tic W _hat2 = fullduplex_desCdecode(Y3, N_03/21sqrt{E_s2), theta); toe clearY3; % The destination needs to have theta as an input so that it can rotate % the signals by theta before decoding.
bllcerrors = blk_errors + length(find(sum(W _hat2,2») clear W _hat2;
clear M N i Xl; format;
74
1* File LDPC_decode.c Original version written by Jinghu Chen
This file does belief propagation decoding with a Matlab interface to variables. *1
I*******************update right tanbbZ[][] according to Bit xx ****************1
void update_right tanbZZ(int xx, double *ZZ[], int *row _distribution_index[], int *column_distribution_index[],double *right tanbZZ[]) H to update the matrix of right tanhZZ[][] according to BIT xx H uu is the weight of each column and hh is the weight of each row. (
1* This is the primary function that does all of the work. It takes the constants nO, mrows, and the received signal matrix yy and decodes them using the BP functions above. *1
1/ read in the II_index if «inl=fopen("New _row _ weighcdistribution.txt" ,"r"» NUll.) {
mexErrMsgTxt("cannot open the input filel"); I
if «in2=fopen("New _col_ weighcdistribution.txt", Or"»~ NUll) {
mexErrMsgTxt("cannot open the input file2"); I
1* The II matrix in these two files is in a special form. It is very similar to MacKay's alist format for his II matrices, but instead of one file, there are two files, one for row and one for column. The fIrSt entry of each line represents the number of l's in the rowlcolumn. The rest of the line tells us where in the rowlcolumn the l's are. Note that the first columnlrow in the II matrix is numbered starting from 0 as in all C arrays, while in MacKay's alist format, all indices in the II matrix start from 1.
*1
80
for(i=O;i<=(rr-l);i++) {
fscanf(inl,"%d", &temp_weight);
if « row_distributioD_index[i] = (int *) mxMalloc«temp_weight+l)*sizeof(int))) = NULL)
1* Here I make use of the way that Matlab stores a matrix. 1n short, Matlab stores a 2-D array, like the one we are using here, as a I-D array of very long length. It stores the array column-wise. 1n other words, the first entry in the yy array is the first entry of the fllSt row of the original Matlab matrix. The second entry in yy is the first entry in the second column of the Matlab matrix. This continues until all of the Matlab matrix is done. If you would like a
82
better description, I suggest you go use Matlab's help facilities. They have a very descriptive picture.
for (i=O;i<=(rr-l);i++) /I rr is the number of checks (
for (j=O~<=(row_distribution_index[i][O]-l)~++) { /I Use the received sequence to initialize
tem=y[(row_distribution..index[ilU+l])]*(4/nO);
I I
*(y[i]+j)=tem;
*(Z[i]+j)=tem;
iteration=l;
syndrom=l;
1* If the syndrome is 1. then the codeword has errors. Thus. we continue to decode. However. sometimes. we cannot decode. so we use a maximum iteration to ensure that we do not continue forever.
*1 while«syndrom=I)&&(iteration<=IMAX) {
for (i=(nn-l); i>=O; i--)
83
for (i=O; i<=(nn-l); i++)
for (i=O; k=(nn-l); i++)
update_Ebsilong...Matrix(i,row_distribution_index,column_distribution_index,lefCtanhZ. right tanbZ,Ebsilong...Matrix);
for (i=O; k=(nn-l); i++) update_Ebsilong(i, row_distribution_index, column_distribution_index,
Ebsilong...Matrix, Ebsilong);
for (i=O; k=(nn-l); i++) update_EE(i,row _distribution_index,colllIIlILdistribution_index,Ebsilong,
Ebsilong...Matrix,E);
for (i=O; k=(nn-l); i++) update_ZZ(i,row _distribution_index,column_distribution_index, Y ,E,z);
1* I don't return the decoded_message variable because in this case the codeword is more valuable to me. I can use it and avoid doing another encoding later. So, I don't bother with this variable.
*1
I**.**.**********check whether z*H is 0******************1
for (k=O; k<nn; k++) mxFree(column_distribution_index[k]);
mxFree( column_distribution_index);
mxFree(Ebsilong);
mxFree(z);
for (k=O; k<rr; k++) mxFree(righuanhZ[k]);
mxFree(righUanhZ); for (k=O; k<rr; k++)
mxFree(lefUanhZ[k]); mxFree(lefUanhZ);
/I mxFree(decoded_message);
mxFree(y); I
1* The mex function The inputs should be nO and the received message Y Since NO and sqrt(Es) are used as a ratio throughout the code, we incorporate sqrt(Es) into NO and use that scalar instead. In other words, nO is actually NO/sqrt(Es). The output is the decoded message W _hat.
W _hat = LDPC_decode(Y, nO); *1
1* If you would like to understand all of these declarations, then you will have to read the Matlab help files on mex functions.
double nO; double'" yy; double'" W _hat; int ij,mrows;
86
1* Check for proper number of arguments. *1 if(mhs!= 2)
mexErrMsgTxt("Two inputs required. ");
1* Check that the second input is a scalar *1 if (!mxIsDouble(prhs[l]) II mxIsComplex(prhs[l]) II
mxGetN(prhs[l])*mxGetM(prhs[l]) != 1 ) mexErrMsgTxt("Input nO must be a scalar. ");
}
if (mxGetN(prhs[O]) != nn) mexErrMsgTxt("Y does not have the correct code length.");
nO = mxGetScalar(prhs[l]);
1* mrows is the number of blocks being simulated for this particular instance.
*1 mrows = mxGetM(prhs[O]);
yy = mxGetPr(prhs[O]);
1* Create a matrix for the return argument. *1 plhs[O] = mxCreateDoubleMatrix(mrows, nn. mxREAL);
W _hat = mxGetPr(plhs[O]);
Idpc_decode(nO, yy, W Jutt, mrows);
87
1* File desCdecode.c Based on LDPC_decode.c Based on ldpc.cpp written by Jinghu Chen
This file is for the destination decoding of the full duplex method this means that it uses phase angle rotation by theta and previous codeword to decode the next codeword.
*1
The functions to do BP decoding are the same as in the WPC decode.c file. so I left them out. Also. everything else is almost. but not quite the same. so I only highlight the differences in bold.
/* This is the primary function that does all of the work. It takes the constants nO, mrows, the received signal matrices yr (real part) and yi (imaginary), and the constant theta and decodes them using the BP functions above.
*/
void desCdecode(const double nO, const double *yr, const double *yi, double *W _hat, const int mrows, const int theta) {
FILE *in! *in2;/* *Generator f'... " _&1"
int ** Generator_matrix = (int **) mxMaIIoc(sizeof(int*)*un); */
1* I no longer need the Generator matrix, since I am using the whole output of the decoder instead of just the message, and then re-encoding.
*/
double *y;
I************items used in BP Decoding***********************1
.... somecode ....
if «in2=fopen("New _coL weighcdistribution.txt ..... r .. »-NULL) mexErrMsgTxt("cannot open the input file2");
88
" if «Generator_fp=fopen("Generator_matrix.txt", "r"»=NULL) " mexErrMsgTxt{"cannot open the Generator_matrix");
1* The H matrix in these two files is in a special form. It is very
.... somecode ....
fc\ose(in2);
1* for(I=O; l<nn; i++) {
fscanf(Generator_fp," %d", &temp_ weight);
if « Generator_matrix[l] = (int *) mxMalloc«temp_welght+l)*sIzeof(int))) = NULL)
Matlah's help facilities. They have a very descriptive picture. *1
if (n-mrows-l) for (1=0; i<nn; i++)
y[l] = yr[i*mrows + n];
1* In this if ... else statement, we see that if the block is the last block to be received, then It does not need to be rotated by theta. If It is not the last block, then it does need to be rotated, with
89
the direction of rotation determined by the previous block. This comes from the paper.
} I*end of BP iteratation III whlle«syndrom=l)&&(iteration<=IMAX)*******1
1* This for loop uses the same princple as the yy array. It is stored In MatIab's Internal format. However, unlike at the relay, the maximum length of each block is Hmited to kk.
*1 for (1=0; i<kk; i++)
W _hat[i*{mrows.l) + n • 1] = decodetLmessage(i];
} IIfor (n=mrows-1; n>=1; n--)
.... somecode ....
mxFree(y); 1*
for (k=O; k<nn; k++) mxFree(Generator_matrix[k]);
mxFree(Generator_matrix); */ }
1* The mex function The Inputs should be NO and the received message Y and the constant theta The output is the decoded message W _hat
W _hat = desCdecode(Y, nO, theta); *1
1* If you would like to understand all of these declarations, then you will have to read the Matlab help fIles on mex functions.
double nO, theta; double * yr, * yi; double * W _hat; int ij ,mrows;
1* Check for proper number of arguments. *1 if(nrhs != 3)
mexErrMsgTxt(nThree Inputs required. n);
91
1* Check that the second and third inputs are scalar *1 if (!mxlsDouble(prhs[1]) II mxIsComplex(prhs[1]) II
mxGetN(prhs[l])*mxGetM(prhs[1]) != 1 ) mexErrMsgTxt("lnput nO must be a scalar. "); if (!mxlsDouble(prhs[2]) II mxIsComplex(prhs[2]) II
mxGetN(prhs[2])*mxGetM(prhs[2) != 1 ) mexErrMsgTxt("lnput theta must be a scalar. ");
if (rnxGetN(prhs[O)) != 00) mexErrMsgTxt("Y does not have the correct code length. H);
nO = rnxGetScalar(prhs[l));
1* theta is the constant that was calculated earlier in the Matlab script *1
theta = mxGetScalar(prhs[2]);
mrows = rnxGetM(prhs[O));
1* Real part of the received signal. *1 yr = mxGetPr(prhs[O);
1* Imaginuy part of the received signal. *1 yi = mxGetPi(prhs[O]);
1* Create a matrix for the return argnment. *1 plbs[O) = mxCreateDoubleMatrix(mrows·l, kk, mxREAL);
W _hat = rnxGetPr(plhs[O]);
desCdecode(nO, yr, yi, W _hat, mrows, theta);
}
92
% Procedure File er_tlCrelaY3hannel.m % Is a procedure to simulate the TOD relay channel with Erasure bits %
%load G250OxlOOOO % The use of all zeros for the message as well as a lack of need for % re-encoding means that the Generator matrix (G) is no longer needed.
% This is the value of delta that I got through trial and error.
a = -c3l"4"'Pl"2; b = -2*c3l"3"'c32"'Pl "'sqrt(pl *P2); c = c3l"4*Pl"2 - c3l"2*c32"2"'PI *P2 + c21"2*PI; d = 2"'c3l "'c32*sqrt(pl "'P2) + 2"'c31"3*c32*PI *sqrt(Pl "'P2); e = c31"2*PI + c32"2*P2 + c31"2"'c32"2"'PI "'P2 - c21"2*PI + delta;
sqrtKappa = very long equation deleted due to pointlessness
% I got this formula for sqrt(kappa) by using the symbolic math functions % within matIab. Of course, I had to use abc d e variables because if I % had used the regular PI P2 c31 c32 c2l variables, then the equation % length would have overflowed the equation buffer and would not be % reproducible here. The method to get sqrtKappa is as follows: % %symsabcdex % X=s0Ive('a"'xl 4+b"'xI 3+c"'x"2+d*x+e=Q'); % % Then you have to try out values for the four solutions to get the right one.
% cap1 and cap2 are the overall received powers at the relay and the % destination. cap1 represents the power received by the relay during the % relay transmit period. cap2 represents the power received by the % destination during the relay receive and relay transmit periods. These aren't really % necessary, they are just a way to check my values.
format compact;
kk=2500; nn=10000;
sqrtE_s1 = c31 *sqrt(PC1); sqrtE_s2 = c31 *sqrt(PC2) + c32*sqrt(P2); % sqrtE_s1 is the received power at the destination during the relay % receive period % sqrtE_s2 is the received power at the destination during the relay % transmit period
% Generate the sequence to be transmitted % We assume that the discrete input has already been source % coded (compressed) so that it is uniformly distributed. M = 10000; % number of blocks (MUST be a factor of b) b = 100;
% Here we use ceil so that the number of bits is always a whole number.
94
%%%%%%%%% We transmit all zeros to speed up the process %%%%%%%%%%%
% As with the full duplex method, we transmit all zeros so that the G % matrix becomes unnecessary and the encoding is faster.
% Now we send the other half of the bits coherently with the Xl_2 of % the source (ifXC2 exists)
% C_hat = mod(W _hat*G(:,2:2:nn),2); % clear W _hat;
% Modulate the codeword X2 = sqrt(P2)*(-1)."C_hat(:,2:2:nn); clear C_hat;
95
% This is the part where we decide if we are really going to forward % the message. Since we are only going to forward if there is no % detectable error, we save a little bit of power and possibly improve % the decoding probability. S = find(err); for d = 1 :length(S),
% Y3_l is the bits received during the relay receive period % Y3_2 is the bits received during the relay transmit period Y3(:,l:2:nn) = Y3_1; Y3(:,2:2:nn) = Y3_2; clear Y3_1 Y3_2;
% In order to do decoding of blocks where half of them have one SNR and % the other have another SNR, we need the received power at each % period. Thus, the destination decoder uses sqrtE_sl and sqrtE_s2. sprintfCDestination decoding') tic W _hat2 = ir_desCdecode(Y3, N_03, sqrtE_sl, sqrtE_s2); toc clearY3;
1* This is the primary function that does all of the work. It takes the constants nO, mrows, the received signal matrix yy and decodes them using the BP functions above. Then it stores the codewords in C_hat and says whether there is an error or not in err.
*1
void ldpc_decode(const double nO, const double *yy, double *C_hat, const int mrows, double >!Ierr) {
.... some code ....
} I"'end of BP iteratation 1/1 while«(syndrom=l)&&(iteration<=!MAX»*******1
97
err[n] = (double)syndrom;
1* This for loop uses the same princple as the yy array. It is stored in MatJab's internal format.
*1
.... some code ....
1* The mex function The inputs should be the noise variance No and the received message Y The output is the decoded message C_hat
[C_hat, err] = ir]elay_decode(Y, nO); *1
1* If you would like to understand all of these declarations, then you will have to read the Matlab help fIles on mex functions.
1* err corresponds to the block errors that the decoding algorithm detected. A 1 in position X of the array corresponds to an error detected in row X of the blocks.
*1 err = mxGetPr(plbs[1»;
Idpc_decode(nO, yy, C_hat, mrows, err);
98
1* File icdescdecode.c Based on LDPC_decode.c Based on ldpc.cpp written by Jinghu Chen
This file is for the destination decoding of the half duplex method this means that it needs to know the received powers of each half of the received codeword, hence sqrtEsl and sqrtEs2.
*1
All ofthe functions to do belief propagation decoding are the same for this file as for the previous files. so I cut them out.
1* This is the primary function that does all of the work. It takes the constants nO, mrows, the received signal matrix yy, and the received powers at the destination sqrtEsl and sqrt Esl and decodes them using the BP functions above. *1
void ldpc_decode(const double nO, const double *yy, double *W _hat, const int mrows, const double sqrtEsl, const double sqrtEs2) {
1* This is the first place where we need to apply the received energy at the destination. The ML ratio for Gaussian channels requires that we multiply 4*sqrt(Es)INO. Since the two halves are received with different energy, we have to mUltiply each of them by a different sqrt(Es).
*1
1* Note that sqrtEsl corresponds to the half of the code that is all of the odd numbered columns, i.e. column 1,3,5. It Is important that if you were to somehow change the division that you change it here and in the next place.
*1 for (i=O; i<1lJl; i+=2)
rO[i)=(4*sqrtEsllnO)*y[i);
99
f* sqrtEs2 corresponds to the even numbered columns, i.e. column 2,4,6. If you change the way you divide the codeword, you need to change it here and the place below this.
*1 for (i=1; i<un; i+=2)
rO[i)=(4*sqrtEs2InO)*y[i);
for (i=O;i<=(rr-1);i++) /I rr is the number of rows and bh is the weight of rows {
}
for G=O;j<=(row _distribution_index[i][Oj-1 );j++) { /I Use the received sequence to initialize
1* Here is the next place where you need to change the way the sqrt(Es) is used if you change it in the codeword outside of this source code. I'm sure you can figure out which is which.
1* This for loop uses the same priucple as the yy array. It is stored in Matlab's internal format. However, unlike at the relay, the maximum length of each block is limited to kk because that is the message length.
*1 for (h=O; h<kk; h++)
W _hat[b*mrows + n) = (double)decoded_message[b);
} /lfor (n=O; n<mrows; n++)
.... somecode ....
100
1* The mex function The inputs should be the noise variance No and the received message Y and the received energies sqrtEsl and sqrtEs2 The output is the decoded message W _hat
W _hat = unbalancecCLDPC_decode(y, nO, sqrtEsl, sqrtEs2); *1
1* If you would like to understand all of these declarations, then you will have to read the Matlab help files on mex functions.