summaryrefslogtreecommitdiff
path: root/gr-fec/python
diff options
context:
space:
mode:
authorTom Rondeau <tom@trondeau.com>2015-06-15 14:29:11 -0400
committerTom Rondeau <tom@trondeau.com>2015-10-15 10:40:24 -0400
commit4bafcfc25404be0e1f2ed5cb4836494f6ccae4b5 (patch)
treed31eb53671b65af4a8598bd3fa6d4d1f527b5c43 /gr-fec/python
parent7c0ff8a410528ca3eed769c595d91e2b89f30a0f (diff)
fec: LDPC: massive code clean up and change.
Squashed a number of commits to get to this point. Separated the H and G matrix concepts, make two different encoders and two different decoders. Removed gsl from API; now only an internal dep that we can replace more easily later. Working examples.
Diffstat (limited to 'gr-fec/python')
-rw-r--r--gr-fec/python/fec/CMakeLists.txt10
-rw-r--r--gr-fec/python/fec/LDPC/CMakeLists.txt11
-rw-r--r--gr-fec/python/fec/LDPC/Generate_LDPC_matrix.py16
-rw-r--r--gr-fec/python/fec/LDPC/Generate_LDPC_matrix_functions.py343
-rw-r--r--gr-fec/python/fec/LDPC/__init__.py22
-rw-r--r--gr-fec/python/fec/qa_fecapi_ldpc.py111
6 files changed, 286 insertions, 227 deletions
diff --git a/gr-fec/python/fec/CMakeLists.txt b/gr-fec/python/fec/CMakeLists.txt
index d5bebd7638..1b20004e6e 100644
--- a/gr-fec/python/fec/CMakeLists.txt
+++ b/gr-fec/python/fec/CMakeLists.txt
@@ -57,8 +57,18 @@ list(APPEND GR_TEST_TARGET_DEPS gnuradio-fec)
include(GrTest)
file(GLOB py_qa_test_files "qa_*.py")
+
+# Without GSL, we don't build some of the LDPC work, so we can't test
+# it here.
+if(NOT GSL_FOUND)
+ list(REMOVE_ITEM py_qa_test_files
+ ${CMAKE_CURRENT_SOURCE_DIR}/qa_fecapi_ldpc.py
+ )
+endif(NOT GSL_FOUND)
+
foreach(py_qa_test_file ${py_qa_test_files})
get_filename_component(py_qa_test_name ${py_qa_test_file} NAME_WE)
GR_ADD_TEST(${py_qa_test_name} ${QA_PYTHON_EXECUTABLE} ${PYTHON_DASH_B} ${py_qa_test_file})
endforeach(py_qa_test_file)
+
endif(ENABLE_TESTING)
diff --git a/gr-fec/python/fec/LDPC/CMakeLists.txt b/gr-fec/python/fec/LDPC/CMakeLists.txt
index 94848882f8..3e56ef3975 100644
--- a/gr-fec/python/fec/LDPC/CMakeLists.txt
+++ b/gr-fec/python/fec/LDPC/CMakeLists.txt
@@ -1,17 +1,17 @@
-# Copyright 2012 Free Software Foundation, Inc.
-#
+# Copyright 2015 Free Software Foundation, Inc.
+#
# This file is part of GNU Radio
-#
+#
# GNU Radio is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3, or (at your option)
# any later version.
-#
+#
# GNU Radio is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
-#
+#
# You should have received a copy of the GNU General Public License
# along with GNU Radio; see the file COPYING. If not, write to
# the Free Software Foundation, Inc., 51 Franklin Street,
@@ -22,6 +22,7 @@ include(GrPython)
GR_PYTHON_INSTALL(
FILES
+ __init__.py
Generate_LDPC_matrix_functions.py
Generate_LDPC_matrix.py
DESTINATION ${GR_PYTHON_DIR}/gnuradio/fec/LDPC
diff --git a/gr-fec/python/fec/LDPC/Generate_LDPC_matrix.py b/gr-fec/python/fec/LDPC/Generate_LDPC_matrix.py
index a984b3b796..696d957604 100644
--- a/gr-fec/python/fec/LDPC/Generate_LDPC_matrix.py
+++ b/gr-fec/python/fec/LDPC/Generate_LDPC_matrix.py
@@ -26,7 +26,7 @@ from Generate_LDPC_matrix_functions import *
# use with the LDPC Richardson Urbanke encoder. A significant amount
# of matrix manipulation is required, so this process should be done
# before using the encoder at run-time. This process can take quite
-# a while, with more time required for larger matrices.
+# a while, with more time required for larger matrices.
# Not all attempts to create a parity check matrix will be
# successful. The script will terminate and output error messages
@@ -35,8 +35,8 @@ from Generate_LDPC_matrix_functions import *
# Because random number generation and
# shuffling methods are used, it is not possible to predict what
-# starting conditions will result in success. It requires a bit of
-# trial and error.
+# starting conditions will result in success. It requires a bit of
+# trial and error.
# ----------------------------------------------------------------- #
@@ -49,9 +49,9 @@ q = 5 # row weight
parity_check_matrix = LDPC_matrix(n_p_q = [n,p,q])
# Richardson and Urbanke's preprocessing method requires a full rank
-# matrix to start. The matrices generated by the
+# matrix to start. The matrices generated by the
# regular_LDPC_code_contructor function will never be full rank. So,
-# use the get_full_rank_H_matrix function.
+# use the get_full_rank_H_matrix function.
newH = get_full_rank_H_matrix(parity_check_matrix.H)
# At this point, the matrix is no longer regular. (The row/column
@@ -62,7 +62,7 @@ newH = get_full_rank_H_matrix(parity_check_matrix.H)
# can take a while...
[bestH,g] = get_best_matrix(newH,100)
-# Print out some of the resulting properties.
+# Print out some of the resulting properties.
n = bestH.shape[1]
k = n - bestH.shape[0]
print "Parity check matrix properties:"
@@ -73,7 +73,7 @@ print "\tn :", n, " (codeword length)"
print "\tk :", k, " (info word length)"
print "\tgap : %i" % g
-# Save the matrix to an alist file for future use:
+# Save the matrix to an alist file for future use:
alist_filename = "n_%04i_k_%04i_gap_%02i.alist" % (n,k,g)
parity_check_matrix.write_alist_file(alist_filename,bestH)
-print '\nMatrix saved to alist file:', alist_filename, "\n" \ No newline at end of file
+print '\nMatrix saved to alist file:', alist_filename, "\n"
diff --git a/gr-fec/python/fec/LDPC/Generate_LDPC_matrix_functions.py b/gr-fec/python/fec/LDPC/Generate_LDPC_matrix_functions.py
index ac702243a8..28eb5d1b7b 100644
--- a/gr-fec/python/fec/LDPC/Generate_LDPC_matrix_functions.py
+++ b/gr-fec/python/fec/LDPC/Generate_LDPC_matrix_functions.py
@@ -20,18 +20,106 @@
# Boston, MA 02110-1301, USA.
#
-import string
+import string, sys
from numpy import *
from numpy.random import shuffle, randint
from numpy.linalg import inv, det
# 0 gives no debug output, 1 gives a little, 2 gives a lot
-verbose = 1 #######################################################
+#verbose = 1 #######################################################
+
+def read_alist_file(filename):
+ """
+ This function reads in an alist file and creates the
+ corresponding parity check matrix H. The format of alist
+ files is described at:
+ http://www.inference.phy.cam.ac.uk/mackay/codes/alist.html
+ """
+
+ myfile = open(filename,'r')
+ data = myfile.readlines()
+ size = string.split(data[0])
+ numCols = int(size[0])
+ numRows = int(size[1])
+ H = zeros((numRows,numCols))
+ for lineNumber in arange(4,4+numCols):
+ indices = string.split(data[lineNumber])
+ for index in indices:
+ H[int(index)-1,lineNumber-4] = 1
+ # The subsequent lines in the file list the indices for where
+ # the 1s are in the rows, but this is redundant
+ # information.
+
+ return H
+
+def write_alist_file(filename, H, verbose=0):
+ """
+ This function writes an alist file for the parity check
+ matrix. The format of alist files is desribed at:
+ http://www.inference.phy.cam.ac.uk/mackay/codes/alist.html
+ """
+
+ try:
+ myfile = open(filename,'w')
+ except:
+ sys.stderr.write("Could not open output file '{0}'".format(filename))
+ sys.exit(1)
+
+ numRows = H.shape[0]
+ numCols = H.shape[1]
+
+ tempstring = `numCols` + ' ' + `numRows` + '\n'
+ myfile.write(tempstring)
+
+ tempstring1 = ''
+ tempstring2 = ''
+ maxRowWeight = 0
+ for rowNum in arange(numRows):
+ nonzeros = array(H[rowNum,:].nonzero())
+ rowWeight = nonzeros.shape[1]
+ if rowWeight > maxRowWeight:
+ maxRowWeight = rowWeight
+ tempstring1 = tempstring1 + `rowWeight` + ' '
+ for tempArray in nonzeros:
+ for index in tempArray:
+ tempstring2 = tempstring2 + `index+1` + ' '
+ tempstring2 = tempstring2 + '\n'
+ tempstring1 = tempstring1 + '\n'
+
+ tempstring3 = ''
+ tempstring4 = ''
+ maxColWeight = 0
+ for colNum in arange(numCols):
+ nonzeros = array(H[:,colNum].nonzero())
+ colWeight = nonzeros.shape[1]
+ if colWeight > maxColWeight:
+ maxColWeight = colWeight
+ tempstring3 = tempstring3 + `colWeight` + ' '
+ for tempArray in nonzeros:
+ for index in tempArray:
+ tempstring4 = tempstring4 + `index+1` + ' '
+ tempstring4 = tempstring4 + '\n'
+ tempstring3 = tempstring3 + '\n'
+
+ tempstring = `maxColWeight` + ' ' + `maxRowWeight` + '\n'
+ # write out max column and row weights
+ myfile.write(tempstring)
+ # write out all of the column weights
+ myfile.write(tempstring3)
+ # write out all of the row weights
+ myfile.write(tempstring1)
+ # write out the nonzero indices for each column
+ myfile.write(tempstring4)
+ # write out the nonzero indices for each row
+ myfile.write(tempstring2)
+ # close the file
+ myfile.close()
+
class LDPC_matrix:
""" Class for a LDPC parity check matrix """
- def __init__(self, alist_filename = None,
- n_p_q = None,
+ def __init__(self, alist_filename = None,
+ n_p_q = None,
H_matrix = None):
if (alist_filename != None):
self.H = self.read_alist_file(alist_filename)
@@ -40,7 +128,7 @@ class LDPC_matrix:
elif (H_matrix != None):
self.H = H_matrix
else:
- print 'Error: provide either an alist filename,',
+ print 'Error: provide either an alist filename,',
print 'parameters for constructing regular LDPC parity',
print 'check matrix, or a numpy array.'
@@ -49,99 +137,16 @@ class LDPC_matrix:
self.n = self.H.shape[1]
self.k = self.n -self.numRows
- def read_alist_file(self,filename):
- """
- This function reads in an alist file and creates the
- corresponding parity check matrix H. The format of alist
- files is described at:
- http://www.inference.phy.cam.ac.uk/mackay/codes/alist.html
- """
-
- myfile = open(filename,'r')
- data = myfile.readlines()
- size = string.split(data[0])
- numCols = int(size[0])
- numRows = int(size[1])
- H = zeros((numRows,numCols))
- for lineNumber in arange(4,4+numCols):
- indices = string.split(data[lineNumber])
- for index in indices:
- H[int(index)-1,lineNumber-4] = 1
- # The subsequent lines in the file list the indices for where
- # the 1s are in the rows, but this is redundant
- # information.
-
- return H
-
- def write_alist_file(self,filename,H,verbose=0):
- """
- This function writes an alist file for the parity check
- matrix. The format of alist files is desribed at:
- http://www.inference.phy.cam.ac.uk/mackay/codes/alist.html
- """
-
- myfile = open(filename,'w')
-
- numRows = H.shape[0]
- numCols = H.shape[1]
-
- tempstring = `numCols` + ' ' + `numRows` + '\n'
- myfile.write(tempstring)
-
- tempstring1 = ''
- tempstring2 = ''
- maxRowWeight = 0
- for rowNum in arange(numRows):
- nonzeros = array(H[rowNum,:].nonzero())
- rowWeight = nonzeros.shape[1]
- if rowWeight > maxRowWeight:
- maxRowWeight = rowWeight
- tempstring1 = tempstring1 + `rowWeight` + ' '
- for tempArray in nonzeros:
- for index in tempArray:
- tempstring2 = tempstring2 + `index+1` + ' '
- tempstring2 = tempstring2 + '\n'
- tempstring1 = tempstring1 + '\n'
-
- tempstring3 = ''
- tempstring4 = ''
- maxColWeight = 0
- for colNum in arange(numCols):
- nonzeros = array(H[:,colNum].nonzero())
- colWeight = nonzeros.shape[1]
- if colWeight > maxColWeight:
- maxColWeight = colWeight
- tempstring3 = tempstring3 + `colWeight` + ' '
- for tempArray in nonzeros:
- for index in tempArray:
- tempstring4 = tempstring4 + `index+1` + ' '
- tempstring4 = tempstring4 + '\n'
- tempstring3 = tempstring3 + '\n'
-
- tempstring = `maxColWeight` + ' ' + `maxRowWeight` + '\n'
- # write out max column and row weights
- myfile.write(tempstring)
- # write out all of the column weights
- myfile.write(tempstring3)
- # write out all of the row weights
- myfile.write(tempstring1)
- # write out the nonzero indices for each column
- myfile.write(tempstring4)
- # write out the nonzero indices for each row
- myfile.write(tempstring2)
- # close the file
- myfile.close()
-
def regular_LDPC_code_contructor(self,n_p_q):
"""
This function constructs a LDPC parity check matrix
- H. The algorithm follows Gallager's approach where we create
- p submatrices and stack them together. Reference: Turbo
+ H. The algorithm follows Gallager's approach where we create
+ p submatrices and stack them together. Reference: Turbo
Coding for Satellite and Wireless Communications, section
9,3.
Note: the matrices computed from this algorithm will never
- have full rank. (Reference Gallager's Dissertation.) They
+ have full rank. (Reference Gallager's Dissertation.) They
will have rank = (number of rows - p + 1). To convert it
to full rank, use the function get_full_rank_H_matrix
"""
@@ -160,12 +165,12 @@ class LDPC_matrix:
print 'ratio of inputs n/q must be a whole number.\n'
return
- # First submatrix first:
+ # First submatrix first:
m = (n*p)/q # number of rows in H matrix
- submatrix1 = zeros((m/p,n))
+ submatrix1 = zeros((m/p,n))
for row in arange(m/p):
range1 = row*q
- range2 = (row+1)*q
+ range2 = (row+1)*q
submatrix1[row,range1:range2] = 1
H = submatrix1
@@ -181,7 +186,7 @@ class LDPC_matrix:
submatrix1[:,newColumnOrder[columnNum]]
H = vstack((H,submatrix))
- submatrixNum = submatrixNum + 1
+ submatrixNum = submatrixNum + 1
# Double check the row weight and column weights.
size = H.shape
@@ -204,11 +209,11 @@ class LDPC_matrix:
return H
-def greedy_upper_triangulation(H):
+def greedy_upper_triangulation(H, verbose=0):
"""
This function performs row/column permutations to bring
- H into approximate upper triangular form via greedy
- upper triangulation method outlined in Modern Coding
+ H into approximate upper triangular form via greedy
+ upper triangulation method outlined in Modern Coding
Theory Appendix 1, Section A.2
"""
H_t = H.copy()
@@ -216,7 +221,7 @@ def greedy_upper_triangulation(H):
# Per email from Dr. Urbanke, author of this textbook, this
# algorithm requires H to be full rank
if linalg.matrix_rank(H_t) != H_t.shape[0]:
- print 'Rank of H:',linalg.matrix_rank(tempArray)
+ print 'Rank of H:', linalg.matrix_rank(tempArray)
print 'H has', H_t.shape[0], 'rows'
print 'Error: H must be full rank.'
return
@@ -240,8 +245,8 @@ def greedy_upper_triangulation(H):
# Find the minimum nonzero residual degree
nonZeroElementIndices = minResidualDegrees.nonzero()
- nonZeroElements=minResidualDegrees[nonZeroElementIndices[0],\
- nonZeroElementIndices[1]]
+ nonZeroElements = minResidualDegrees[nonZeroElementIndices[0],
+ nonZeroElementIndices[1]]
minimumResidualDegree = nonZeroElements.min()
# Get indices of all of the columns in H_t that have degree
@@ -260,16 +265,15 @@ def greedy_upper_triangulation(H):
if minimumResidualDegree == 1:
# This is the 'extend' case
- rowThatContainsNonZero = H_residual[:,columnC-t]\
- .nonzero()[0][0]
-
- # Swap column c with column t. (Book says t+1 but we
+ rowThatContainsNonZero = H_residual[:,columnC-t].nonzero()[0][0]
+
+ # Swap column c with column t. (Book says t+1 but we
# index from 0, not 1.)
Htemp[:,columnC] = H_t[:,t]
Htemp[:,t] = H_t[:,columnC]
H_t = Htemp.copy()
Htemp = H_t.copy()
- # Swap row r with row t. (Book says t+1 but we index from
+ # Swap row r with row t. (Book says t+1 but we index from
# 0, not 1.)
Htemp[rowThatContainsNonZero + t,:] = H_t[t,:]
Htemp[t,:] = H_t[rowThatContainsNonZero + t,:]
@@ -279,8 +283,8 @@ def greedy_upper_triangulation(H):
# This is the 'choose' case.
rowsThatContainNonZeros = H_residual[:,columnC-t]\
.nonzero()[0]
-
- # Swap column c with column t. (Book says t+1 but we
+
+ # Swap column c with column t. (Book says t+1 but we
# index from 0, not 1.)
Htemp[:,columnC] = H_t[:,t]
Htemp[:,t] = H_t[:,columnC]
@@ -296,16 +300,16 @@ def greedy_upper_triangulation(H):
Htemp = H_t.copy()
# Move the other rows that contain nonZero entries to the
- # bottom of the matrix. We can't just swap them,
- # otherwise we will be pulling up rows that we pushed
+ # bottom of the matrix. We can't just swap them,
+ # otherwise we will be pulling up rows that we pushed
# down before. So, use a rotation method.
for index in arange (1,numRowsLeft+1):
rowInH_residual = rowsThatContainNonZeros[index]
rowInH_t = rowInH_residual + t - index +1
m = n-k
- # Move the row with the nonzero element to the
+ # Move the row with the nonzero element to the
# bottom; don't update H_t.
- Htemp[m-1,:] = H_t[rowInH_t,:]
+ Htemp[m-1,:] = H_t[rowInH_t,:]
# Now rotate the bottom rows up.
sub_index = 1
while sub_index < (m - rowInH_t):
@@ -322,7 +326,8 @@ def greedy_upper_triangulation(H):
t = t + 1
if g == 0:
- if verbose: print 'Error: gap is 0.'
+ if verbose:
+ print 'Error: gap is 0.'
return
# We need to ensure phi is nonsingular.
@@ -330,7 +335,7 @@ def greedy_upper_triangulation(H):
E = H_t[t:t+g,0:t]
A = H_t[0:t,t:t+g]
C = H_t[t:t+g,t:t+g]
- D = H_t[t:t+g,t+g:n]
+ D = H_t[t:t+g,t+g:n]
invTmod2array = inv_mod2(T)
temp1 = dot(E,invTmod2array) % 2
@@ -342,18 +347,21 @@ def greedy_upper_triangulation(H):
invPhi = inv_mod2(phi)
except linalg.linalg.LinAlgError:
# Phi is singular
- if verbose > 1: print 'Initial phi is singular'
+ if verbose > 1:
+ print 'Initial phi is singular'
else:
# Phi is nonsingular, so we need to use this version of H.
- if verbose > 1: print 'Initial phi is nonsingular'
+ if verbose > 1:
+ print 'Initial phi is nonsingular'
return [H_t, g, t]
else:
- if verbose: print 'Initial phi is all zeros:\n', phi
+ if verbose:
+ print 'Initial phi is all zeros:\n', phi
# If the C and D submatrices are all zeros, there is no point in
# shuffling them around in an attempt to find a good phi.
if not (C.any() or D.any()):
- if verbose:
+ if verbose:
print 'C and D are all zeros. There is no hope in',
print 'finding a nonsingular phi matrix. '
return
@@ -361,15 +369,16 @@ def greedy_upper_triangulation(H):
# We can't look at every row/column permutation possibility
# because there would be (n-t)! column shuffles and g! row
# shuffles. g has gotten up to 12 in tests, so 12! would still
- # take quite some time. Instead, we will just pick an arbitrary
+ # take quite some time. Instead, we will just pick an arbitrary
# number of max iterations to perform, then break.
maxIterations = 300
iterationCount = 0
- columnsToShuffle = arange(t,n)
+ columnsToShuffle = arange(t,n)
rowsToShuffle = arange(t,t+g)
while iterationCount < maxIterations:
- if verbose > 1: print 'iterationCount:', iterationCount
+ if verbose > 1:
+ print 'iterationCount:', iterationCount
tempH = H_t.copy()
shuffle(columnsToShuffle)
@@ -387,7 +396,7 @@ def greedy_upper_triangulation(H):
oldRowNumber = rowsToShuffle[index]
tempH[newDesinationRowNumber,:] = tempH2[oldRowNumber,:]
index +=1
-
+
# Now test this new H matrix.
H_t = tempH.copy()
T = H_t[0:t, 0:t]
@@ -404,21 +413,24 @@ def greedy_upper_triangulation(H):
invPhi = inv_mod2(phi)
except linalg.linalg.LinAlgError:
# Phi is singular
- if verbose > 1: print 'Phi is still singular'
+ if verbose > 1:
+ print 'Phi is still singular'
else:
# Phi is nonsingular, so we're done.
- if verbose:
+ if verbose:
print 'Found a nonsingular phi on',
print 'iterationCount = ', iterationCount
return [H_t, g, t]
else:
- if verbose > 1: print 'phi is all zeros'
+ if verbose > 1:
+ print 'phi is all zeros'
iterationCount +=1
# If we've reached this point, then we haven't found a
# version of H that has a nonsingular phi.
- if verbose: print '--- Error: nonsingular phi matrix not found.'
+ if verbose:
+ print '--- Error: nonsingular phi matrix not found.'
def inv_mod2(squareMatrix):
"""
@@ -448,14 +460,14 @@ def inv_mod2(squareMatrix):
# this is a 1
tempTest[rowNum,colNum] = 1
elif (abs(2-value)) < 0.01:
- # there shouldn't be any 2s after B % 2, but I'm
+ # there shouldn't be any 2s after B % 2, but I'm
# seeing them!
tempTest[rowNum,colNum] = 0
elif (abs(0-value)) < 0.01:
# this is a 0
tempTest[rowNum,colNum] = 0
- else:
- if verbose > 1:
+ else:
+ if verbose > 1:
print 'In inv_mod2. Rounding error on this',
print 'value? Mod 2 has already been done.',
print 'value:', value
@@ -483,9 +495,9 @@ def move_row_to_bottom(i,arrayIn):
""""
Moves a specified row (just one) to the bottom of the matrix,
then rotates the rows at the bottom up.
-
+
For example, if we had a matrix with 5 rows, and we wanted to
- push row 2 to the bottom, then the resulting row order would be:
+ push row 2 to the bottom, then the resulting row order would be:
1,3,4,5,2
"""
arrayOut = arrayIn.copy()
@@ -499,19 +511,20 @@ def move_row_to_bottom(i,arrayIn):
index = index + 1
return arrayOut
-def get_full_rank_H_matrix(H):
+def get_full_rank_H_matrix(H, verbose=False):
"""
This function accepts a parity check matrix H and, if it is not
- already full rank, will determine which rows are dependent and
+ already full rank, will determine which rows are dependent and
remove them. The updated matrix will be returned.
"""
tempArray = H.copy()
if linalg.matrix_rank(tempArray) == tempArray.shape[0]:
- if verbose > 1: print 'Returning H; it is already full rank.'
+ if verbose:
+ print 'Returning H; it is already full rank.'
return tempArray
-
+
numRows = tempArray.shape[0]
- numColumns = tempArray.shape[1]
+ numColumns = tempArray.shape[1]
limit = numRows
rank = 0
i = 0
@@ -523,38 +536,39 @@ def get_full_rank_H_matrix(H):
# this to know which dependent rows to delete.
rowOrder = arange(numRows).reshape(numRows,1)
- while i < limit:
- if verbose > 1: print 'In get_full_rank_H_matrix; i:', i
+ while i < limit:
+ if verbose:
+ print 'In get_full_rank_H_matrix; i:', i
# Flag indicating that the row contains a non-zero entry
found = False
for j in arange(i, numColumns):
- if tempArray[i, j] == 1:
+ if tempArray[i, j] == 1:
# Encountered a non-zero entry at (i, j)
- found = True
+ found = True
# Increment rank by 1
- rank = rank + 1
- # Make the entry at (i,i) be 1
- tempArray = swap_columns(j,i,tempArray)
+ rank = rank + 1
+ # Make the entry at (i,i) be 1
+ tempArray = swap_columns(j,i,tempArray)
# Keep track of the column swapping
columnOrder = swap_columns(j,i,columnOrder)
break
if found == True:
- for k in arange(0,numRows):
+ for k in arange(0,numRows):
if k == i: continue
- # Checking for 1's
+ # Checking for 1's
if tempArray[k, i] == 1:
# Add row i to row k
tempArray[k,:] = tempArray[k,:] + tempArray[i,:]
# Addition is mod2
- tempArray = tempArray.copy() % 2
- # All the entries above & below (i, i) are now 0
+ tempArray = tempArray.copy() % 2
+ # All the entries above & below (i, i) are now 0
i = i + 1
if found == False:
# Push the row of 0s to the bottom, and move the bottom
# rows up (sort of a rotation thing).
tempArray = move_row_to_bottom(i,tempArray)
# Decrease limit since we just found a row of 0s
- limit -= 1
+ limit -= 1
# Keep track of row swapping
rowOrder = move_row_to_bottom(i,rowOrder)
@@ -579,26 +593,32 @@ def get_full_rank_H_matrix(H):
return newH
-def get_best_matrix(H,numIterations=100):
+def get_best_matrix(H, numIterations=100, verbose=False):
"""
This function will run the Greedy Upper Triangulation algorithm
- for numIterations times, looking for the lowest possible gap.
+ for numIterations times, looking for the lowest possible gap.
The submatrices returned are those needed for real-time encoding.
"""
hadFirstJoy = 0
index = 1
while index <= numIterations:
- if verbose:
- print '--- In get_best_matrix, index:', index
+ if verbose:
+ print '--- In get_best_matrix, iteration:', index
+ index += 1
try:
- [betterH, gap, t] = greedy_upper_triangulation(H)
- except:
- if verbose > 1:
- print 'greedy_upper_triangulation must have had error'
+ ret = greedy_upper_triangulation(H, verbose)
+ except ValueError, e:
+ if verbose > 1:
+ print 'greedy_upper_triangulation error: ', e
else:
- if not hadFirstJoy:
- hadFirstJoy = 1
+ if ret:
+ [betterH, gap, t]
+ else:
+ continue
+
+ if not hadFirstJoy:
+ hadFirstJoy = 1
bestGap = gap
bestH = betterH.copy()
bestT = t
@@ -607,12 +627,11 @@ def get_best_matrix(H,numIterations=100):
bestH = betterH.copy()
bestT = t
- index += 1
if hadFirstJoy:
- return [bestH,bestGap]
+ return [bestH, bestGap]
else:
- if verbose:
+ if verbose:
print 'Error: Could not find appropriate H form',
print 'for encoding.'
return
@@ -661,4 +680,4 @@ def getSystematicGmatrix(H):
limit -= 1
# the rows below i are the dependent rows, which we discard
G = tempArray[0:i,:]
- return G \ No newline at end of file
+ return G
diff --git a/gr-fec/python/fec/LDPC/__init__.py b/gr-fec/python/fec/LDPC/__init__.py
new file mode 100644
index 0000000000..173171a24f
--- /dev/null
+++ b/gr-fec/python/fec/LDPC/__init__.py
@@ -0,0 +1,22 @@
+#
+# Copyright 2015 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
+
+from Generate_LDPC_matrix_functions import *
diff --git a/gr-fec/python/fec/qa_fecapi_ldpc.py b/gr-fec/python/fec/qa_fecapi_ldpc.py
index 08c7a836b7..b4eae82cda 100644
--- a/gr-fec/python/fec/qa_fecapi_ldpc.py
+++ b/gr-fec/python/fec/qa_fecapi_ldpc.py
@@ -27,6 +27,13 @@ from _qa_helper import _qa_helper
from extended_encoder import extended_encoder
from extended_decoder import extended_decoder
+import os
+
+# Get location of the alist files. If run in 'ctest' or 'make test',
+# the shell script sets srcdir. Otherwise, we assume we're running
+# from the current directory and know where to go.
+LDPC_ALIST_DIR = os.getenv('srcdir', '.') + "/../../ldpc_alist/"
+
class test_fecapi_ldpc(gr_unittest.TestCase):
def setUp(self):
@@ -36,199 +43,199 @@ class test_fecapi_ldpc(gr_unittest.TestCase):
self.tb = None
def test_parallelism0_00(self):
- filename = "LDPC/n_0100_k_0027_gap_04.alist"
+ filename = LDPC_ALIST_DIR + "n_0100_k_0027_gap_04.alist"
gap = 4
- LDPC_matrix_object = fec.ldpc_R_U_mtrx(filename, gap)
+ LDPC_matrix_object = fec.ldpc_H_matrix(filename, gap)
k = LDPC_matrix_object.k()
- enc = fec.ldpc_R_U_encoder_make(LDPC_matrix_object)
+ enc = fec.ldpc_encoder_make(LDPC_matrix_object)
dec = fec.ldpc_bit_flip_decoder.make(LDPC_matrix_object)
threading = None
self.test = _qa_helper(10*k, enc, dec, threading)
self.tb.connect(self.test)
self.tb.run()
-
+
data_in = self.test.snk_input.data()
data_out =self.test.snk_output.data()
self.assertEqual(data_in, data_out)
def test_parallelism0_01(self):
- filename = "LDPC/n_0100_k_0027_gap_04.alist"
+ filename = LDPC_ALIST_DIR + "n_0100_k_0027_gap_04.alist"
gap = 4
- LDPC_matrix_object = fec.ldpc_R_U_mtrx(filename, gap)
+ LDPC_matrix_object = fec.ldpc_H_matrix(filename, gap)
k = LDPC_matrix_object.k()
- enc = fec.ldpc_R_U_encoder_make(LDPC_matrix_object)
+ enc = fec.ldpc_encoder_make(LDPC_matrix_object)
dec = fec.ldpc_bit_flip_decoder.make(LDPC_matrix_object)
threading = 'ordinary'
self.test = _qa_helper(10*k, enc, dec, threading)
self.tb.connect(self.test)
self.tb.run()
-
+
data_in = self.test.snk_input.data()
data_out =self.test.snk_output.data()
self.assertEqual(data_in, data_out)
def test_parallelism0_02(self):
- filename = "LDPC/n_0100_k_0027_gap_04.alist"
+ filename = LDPC_ALIST_DIR + "n_0100_k_0027_gap_04.alist"
gap = 4
- LDPC_matrix_object = fec.ldpc_R_U_mtrx(filename, gap)
+ LDPC_matrix_object = fec.ldpc_H_matrix(filename, gap)
k = LDPC_matrix_object.k()
- enc = fec.ldpc_R_U_encoder_make(LDPC_matrix_object)
+ enc = fec.ldpc_H_encoder_make(LDPC_matrix_object)
dec = fec.ldpc_bit_flip_decoder.make(LDPC_matrix_object)
threading = 'capillary'
self.test = _qa_helper(10*k, enc, dec, threading)
self.tb.connect(self.test)
self.tb.run()
-
+
data_in = self.test.snk_input.data()
data_out =self.test.snk_output.data()
self.assertEqual(data_in, data_out)
def test_parallelism1_00(self):
- filename = "LDPC/n_0100_k_0027_gap_04.alist"
+ filename = LDPC_ALIST_DIR + "n_0100_k_0027_gap_04.alist"
gap = 4
- LDPC_matrix_object = fec.ldpc_R_U_mtrx(filename, gap)
+ LDPC_matrix_object = fec.ldpc_H_matrix(filename, gap)
k = LDPC_matrix_object.k()
- enc = map((lambda a: fec.ldpc_R_U_encoder_make(LDPC_matrix_object)), range(0,1))
+ enc = map((lambda a: fec.ldpc_encoder_make(LDPC_matrix_object)), range(0,1))
dec = map((lambda a: fec.ldpc_bit_flip_decoder.make(LDPC_matrix_object)), range(0,1))
threading = None
self.test = _qa_helper(10*k, enc, dec, threading)
self.tb.connect(self.test)
self.tb.run()
-
+
data_in = self.test.snk_input.data()
data_out =self.test.snk_output.data()
self.assertEqual(data_in, data_out)
def test_parallelism1_01(self):
- filename = "LDPC/n_0100_k_0027_gap_04.alist"
+ filename = LDPC_ALIST_DIR + "n_0100_k_0027_gap_04.alist"
gap = 4
- LDPC_matrix_object = fec.ldpc_R_U_mtrx(filename, gap)
+ LDPC_matrix_object = fec.ldpc_H_matrix(filename, gap)
k = LDPC_matrix_object.k()
- enc = map((lambda a: fec.ldpc_R_U_encoder_make(LDPC_matrix_object)), range(0,1))
+ enc = map((lambda a: fec.ldpc_encoder_make(LDPC_matrix_object)), range(0,1))
dec = map((lambda a: fec.ldpc_bit_flip_decoder.make(LDPC_matrix_object)), range(0,1))
threading = 'ordinary'
self.test = _qa_helper(10*k, enc, dec, threading)
self.tb.connect(self.test)
self.tb.run()
-
+
data_in = self.test.snk_input.data()
data_out =self.test.snk_output.data()
self.assertEqual(data_in, data_out)
def test_parallelism1_02(self):
- filename = "LDPC/n_0100_k_0027_gap_04.alist"
+ filename = LDPC_ALIST_DIR + "n_0100_k_0027_gap_04.alist"
gap = 4
- LDPC_matrix_object = fec.ldpc_R_U_mtrx(filename, gap)
+ LDPC_matrix_object = fec.ldpc_H_matrix(filename, gap)
k = LDPC_matrix_object.k()
- enc = map((lambda a: fec.ldpc_R_U_encoder_make(LDPC_matrix_object)), range(0,1))
+ enc = map((lambda a: fec.ldpc_encoder_make(LDPC_matrix_object)), range(0,1))
dec = map((lambda a: fec.ldpc_bit_flip_decoder.make(LDPC_matrix_object)), range(0,1))
threading = 'capillary'
self.test = _qa_helper(10*k, enc, dec, threading)
self.tb.connect(self.test)
self.tb.run()
-
+
data_in = self.test.snk_input.data()
data_out =self.test.snk_output.data()
self.assertEqual(data_in, data_out)
def test_parallelism1_03(self):
- filename = "LDPC/n_0100_k_0027_gap_04.alist"
+ filename = LDPC_ALIST_DIR + "n_0100_k_0027_gap_04.alist"
gap = 4
dims = 10
- LDPC_matrix_object = fec.ldpc_R_U_mtrx(filename, gap)
+ LDPC_matrix_object = fec.ldpc_H_matrix(filename, gap)
k = LDPC_matrix_object.k()
- enc = map((lambda a: fec.ldpc_R_U_encoder_make(LDPC_matrix_object)), range(0,dims))
+ enc = map((lambda a: fec.ldpc_encoder_make(LDPC_matrix_object)), range(0,dims))
dec = map((lambda a: fec.ldpc_bit_flip_decoder.make(LDPC_matrix_object)), range(0,dims))
threading = 'ordinary'
self.test = _qa_helper(dims*k, enc, dec, threading)
self.tb.connect(self.test)
self.tb.run()
-
+
data_in = self.test.snk_input.data()
data_out =self.test.snk_output.data()
self.assertEqual(data_in, data_out)
def test_parallelism1_04(self):
- filename = "LDPC/n_0100_k_0027_gap_04.alist"
+ filename = LDPC_ALIST_DIR + "n_0100_k_0027_gap_04.alist"
gap = 4
dims = 16
- LDPC_matrix_object = fec.ldpc_R_U_mtrx(filename, gap)
+ LDPC_matrix_object = fec.ldpc_H_matrix(filename, gap)
k = LDPC_matrix_object.k()
- enc = map((lambda a: fec.ldpc_R_U_encoder_make(LDPC_matrix_object)), range(0,dims))
+ enc = map((lambda a: fec.ldpc_encoder_make(LDPC_matrix_object)), range(0,dims))
dec = map((lambda a: fec.ldpc_bit_flip_decoder.make(LDPC_matrix_object)), range(0,dims))
threading = 'capillary'
self.test = _qa_helper(dims*k, enc, dec, threading)
self.tb.connect(self.test)
self.tb.run()
-
+
data_in = self.test.snk_input.data()
data_out =self.test.snk_output.data()
self.assertEqual(data_in, data_out)
def test_parallelism1_05(self):
- filename = "LDPC/n_0100_k_0027_gap_04.alist"
+ filename = LDPC_ALIST_DIR + "n_0100_k_0027_gap_04.alist"
gap = 4
dims = 5
- LDPC_matrix_object = fec.ldpc_R_U_mtrx(filename, gap)
+ LDPC_matrix_object = fec.ldpc_H_matrix(filename, gap)
k = LDPC_matrix_object.k()
- enc = map((lambda a: fec.ldpc_R_U_encoder_make(LDPC_matrix_object)), range(0,dims))
+ enc = map((lambda a: fec.ldpc_encoder_make(LDPC_matrix_object)), range(0,dims))
# dec = map((lambda a: fec.ldpc_bit_flip_decoder.make(LDPC_matrix_object)), range(0,dims))
threading = 'capillary'
self.assertRaises(AttributeError, lambda: extended_encoder(enc, threading=threading, puncpat="11"))
def test_parallelism1_06(self):
- filename = "LDPC/n_0100_k_0027_gap_04.alist"
+ filename = LDPC_ALIST_DIR + "n_0100_k_0027_gap_04.alist"
gap = 4
dims = 5
- LDPC_matrix_object = fec.ldpc_R_U_mtrx(filename, gap)
+ LDPC_matrix_object = fec.ldpc_H_matrix(filename, gap)
k = LDPC_matrix_object.k()
- # enc = map((lambda a: fec.ldpc_R_U_encoder_make(LDPC_matrix_object)), range(0,dims))
+ # enc = map((lambda a: fec.ldpc_encoder_make(LDPC_matrix_object)), range(0,dims))
dec = map((lambda a: fec.ldpc_bit_flip_decoder.make(LDPC_matrix_object)), range(0,dims))
threading = 'capillary'
self.assertRaises(AttributeError, lambda: extended_decoder(dec, threading=threading, puncpat="11"))
def test_parallelism2_00(self):
- filename = "LDPC/n_0100_k_0027_gap_04.alist"
+ filename = LDPC_ALIST_DIR + "n_0100_k_0027_gap_04.alist"
gap = 4
dims = 5
- LDPC_matrix_object = fec.ldpc_R_U_mtrx(filename, gap)
- k = LDPC_matrix_object.k()
+ LDPC_matrix_object = fec.ldpc_H_matrix(filename, gap)
+ k = LDPC_matrix_object.k()
dims1 = 16
- dims2 = 16
- enc = map((lambda b: map((lambda a: fec.ldpc_R_U_encoder_make(LDPC_matrix_object)), range(0,dims1))), range(0,dims2))
+ dims2 = 16
+ enc = map((lambda b: map((lambda a: fec.ldpc_encoder_make(LDPC_matrix_object)), range(0,dims1))), range(0,dims2))
threading = 'capillary'
self.assertRaises(AttributeError, lambda: extended_encoder(enc, threading=threading, puncpat="11"))
def test_parallelism2_00(self):
- filename = "LDPC/n_0100_k_0027_gap_04.alist"
+ filename = LDPC_ALIST_DIR + "n_0100_k_0027_gap_04.alist"
gap = 4
dims = 5
- LDPC_matrix_object = fec.ldpc_R_U_mtrx(filename, gap)
- k = LDPC_matrix_object.k()
+ LDPC_matrix_object = fec.ldpc_H_matrix(filename, gap)
+ k = LDPC_matrix_object.k()
dims1 = 16
- dims2 = 16
- enc = map((lambda b: map((lambda a: fec.ldpc_R_U_encoder_make(LDPC_matrix_object)), range(0,dims1))), range(0,dims2))
+ dims2 = 16
+ enc = map((lambda b: map((lambda a: fec.ldpc_encoder_make(LDPC_matrix_object)), range(0,dims1))), range(0,dims2))
threading = 'capillary'
self.assertRaises(AttributeError, lambda: extended_encoder(enc, threading=threading, puncpat="11"))
def test_parallelism2_01(self):
- filename = "LDPC/n_0100_k_0027_gap_04.alist"
+ filename = LDPC_ALIST_DIR + "n_0100_k_0027_gap_04.alist"
gap = 4
dims = 5
- LDPC_matrix_object = fec.ldpc_R_U_mtrx(filename, gap)
- k = LDPC_matrix_object.k()
+ LDPC_matrix_object = fec.ldpc_H_matrix(filename, gap)
+ k = LDPC_matrix_object.k()
dims1 = 16
- dims2 = 16
+ dims2 = 16
dec = map((lambda b: map((lambda a: fec.ldpc_bit_flip_decoder_make(LDPC_matrix_object)), range(0,dims1))), range(0,dims2))
threading = 'capillary'