summaryrefslogtreecommitdiff
path: root/gr-fec/python
diff options
context:
space:
mode:
authorJohannes Demel <ufcsy@student.kit.edu>2015-05-28 12:39:36 +0200
committerJohannes Demel <ufcsy@student.kit.edu>2015-09-21 10:45:12 +0200
commit8ac5a86f98d5a545cf65dda77c960cf273ee7aca (patch)
treece89f793a584e39842a13dedcd700a79f5f9aeed /gr-fec/python
parenta03893d51553eb74ac348ee88d4dd879b0a253c8 (diff)
polar: Python test code for polar codes
Diffstat (limited to 'gr-fec/python')
-rw-r--r--gr-fec/python/fec/polar/README.md4
-rw-r--r--gr-fec/python/fec/polar/bit_reversed_polar_encoding_scheme.svg1160
-rw-r--r--gr-fec/python/fec/polar/channel_construction_bec.py110
-rwxr-xr-xgr-fec/python/fec/polar/channel_construction_bsc.py206
-rw-r--r--gr-fec/python/fec/polar/common.py69
-rw-r--r--gr-fec/python/fec/polar/decoder.py278
-rw-r--r--gr-fec/python/fec/polar/encoder.py135
-rw-r--r--gr-fec/python/fec/polar/helper_functions.py84
-rw-r--r--gr-fec/python/fec/polar/polar_code.py493
-rwxr-xr-xgr-fec/python/fec/polar/testbed.py143
10 files changed, 2682 insertions, 0 deletions
diff --git a/gr-fec/python/fec/polar/README.md b/gr-fec/python/fec/polar/README.md
new file mode 100644
index 0000000000..2bd00dc3de
--- /dev/null
+++ b/gr-fec/python/fec/polar/README.md
@@ -0,0 +1,4 @@
+POLAR Code Python test functions module
+===========
+
+This folder contains all the necessary files for POLAR code testcode. It shall serve as a reference later on. \ No newline at end of file
diff --git a/gr-fec/python/fec/polar/bit_reversed_polar_encoding_scheme.svg b/gr-fec/python/fec/polar/bit_reversed_polar_encoding_scheme.svg
new file mode 100644
index 0000000000..84849c994e
--- /dev/null
+++ b/gr-fec/python/fec/polar/bit_reversed_polar_encoding_scheme.svg
@@ -0,0 +1,1160 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="744.09448819"
+ height="1052.3622047"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="bit_reversed_polar_encoding_scheme.svg">
+ <defs
+ id="defs4" />
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="0.94"
+ inkscape:cx="186.70213"
+ inkscape:cy="520"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="false"
+ inkscape:window-width="1920"
+ inkscape:window-height="1056"
+ inkscape:window-x="1920"
+ inkscape:window-y="24"
+ inkscape:window-maximized="1" />
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1">
+ <flowRoot
+ xml:space="preserve"
+ id="flowRoot3755"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"><flowRegion
+ id="flowRegion3757"><rect
+ id="rect3759"
+ width="190.42554"
+ height="154.25533"
+ x="75.531914"
+ y="201.29836" /></flowRegion><flowPara
+ id="flowPara3761">000sfdgkzhlbx000000</flowPara></flowRoot> <g
+ id="g4231"
+ transform="translate(-11.702127,-12.23403)">
+ <g
+ transform="translate(-77.659574,-114.89362)"
+ id="g3767">
+ <rect
+ id="rect2985"
+ width="42.553192"
+ height="41.489372"
+ x="136.17021"
+ y="258.74515"
+ style="fill:none;stroke:#000000;stroke-opacity:1" />
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ x="144.68085"
+ y="293.85156"
+ id="text3763"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan3765"
+ x="144.68085"
+ y="293.85156">0</tspan></text>
+ </g>
+ </g>
+ <g
+ id="g4225"
+ transform="translate(-5.319148,-34.650486)">
+ <g
+ transform="translate(-84.042553,-23.936162)"
+ id="g3767-0">
+ <rect
+ id="rect2985-6"
+ width="42.553192"
+ height="41.489372"
+ x="136.17021"
+ y="258.74515"
+ style="fill:none;stroke:#000000;stroke-opacity:1" />
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ x="144.68085"
+ y="293.85156"
+ id="text3763-6"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan3765-8"
+ x="144.68085"
+ y="293.85156">4</tspan></text>
+ </g>
+ </g>
+ <g
+ id="g4219"
+ transform="translate(-10.638297,-24.62003)">
+ <g
+ transform="translate(-78.723404,34.574476)"
+ id="g3767-8">
+ <rect
+ id="rect2985-8"
+ width="42.553192"
+ height="41.489372"
+ x="136.17021"
+ y="258.74515"
+ style="fill:none;stroke:#000000;stroke-opacity:1" />
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ x="144.68085"
+ y="293.85156"
+ id="text3763-62"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan3765-7"
+ x="144.68085"
+ y="293.85156">2</tspan></text>
+ </g>
+ </g>
+ <g
+ id="g4213"
+ transform="translate(-7.446808,-9.270503)">
+ <g
+ transform="translate(-81.914893,87.765966)"
+ id="g3767-5">
+ <rect
+ id="rect2985-3"
+ width="42.553192"
+ height="41.489372"
+ x="136.17021"
+ y="258.74515"
+ style="fill:none;stroke:#000000;stroke-opacity:1" />
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ x="144.68085"
+ y="293.85156"
+ id="text3763-7"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan3765-81"
+ x="144.68085"
+ y="293.85156">6</tspan></text>
+ </g>
+ </g>
+ <g
+ id="g4207"
+ transform="translate(-5.319148,-12.00608)">
+ <g
+ transform="translate(-84.042553,159.04256)"
+ id="g3767-1">
+ <rect
+ id="rect2985-5"
+ width="42.553192"
+ height="41.489372"
+ x="136.17021"
+ y="258.74515"
+ style="fill:none;stroke:#000000;stroke-opacity:1" />
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ x="144.68085"
+ y="293.85156"
+ id="text3763-3"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan3765-87"
+ x="144.68085"
+ y="293.85156">1</tspan></text>
+ </g>
+ </g>
+ <g
+ id="g4201"
+ transform="translate(-11.702127,0.15198)">
+ <g
+ transform="translate(-77.659574,215.42554)"
+ id="g3767-54">
+ <rect
+ id="rect2985-4"
+ width="42.553192"
+ height="41.489372"
+ x="136.17021"
+ y="258.74515"
+ style="fill:none;stroke:#000000;stroke-opacity:1" />
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ x="144.68085"
+ y="293.85156"
+ id="text3763-4"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan3765-6"
+ x="144.68085"
+ y="293.85156">5</tspan></text>
+ </g>
+ </g>
+ <g
+ id="g4195"
+ transform="translate(-3.191489,-1.51975)">
+ <g
+ transform="translate(-86.170212,285.63831)"
+ id="g3767-9">
+ <rect
+ id="rect2985-7"
+ width="42.553192"
+ height="41.489372"
+ x="136.17021"
+ y="258.74515"
+ style="fill:none;stroke:#000000;stroke-opacity:1" />
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ x="144.68085"
+ y="293.85156"
+ id="text3763-8"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan3765-0"
+ x="144.68085"
+ y="293.85156">3</tspan></text>
+ </g>
+ </g>
+ <g
+ id="g4189"
+ transform="translate(0,-2.12766)">
+ <g
+ transform="translate(-89.361701,354.78724)"
+ id="g3767-6">
+ <rect
+ id="rect2985-73"
+ width="42.553192"
+ height="41.489372"
+ x="136.17021"
+ y="258.74515"
+ style="fill:none;stroke:#000000;stroke-opacity:1" />
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ x="144.68085"
+ y="293.85156"
+ id="text3763-64"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan3765-07"
+ x="144.68085"
+ y="293.85156">7</tspan></text>
+ </g>
+ </g>
+ <g
+ id="g3767-4"
+ transform="translate(188.08511,-127.12765)">
+ <rect
+ style="fill:none;stroke:#000000;stroke-opacity:1"
+ y="258.74515"
+ x="136.17021"
+ height="41.489372"
+ width="42.553192"
+ id="rect2985-0" />
+ <text
+ sodipodi:linespacing="125%"
+ id="text3763-38"
+ y="293.85156"
+ x="144.68085"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ xml:space="preserve"><tspan
+ y="293.85156"
+ x="144.68085"
+ id="tspan3765-9"
+ sodipodi:role="line">0</tspan></text>
+ </g>
+ <g
+ id="g3767-01"
+ transform="translate(188.08511,-58.586648)">
+ <rect
+ style="fill:none;stroke:#000000;stroke-opacity:1"
+ y="258.74515"
+ x="136.17021"
+ height="41.489372"
+ width="42.553192"
+ id="rect2985-68" />
+ <text
+ sodipodi:linespacing="125%"
+ id="text3763-40"
+ y="293.85156"
+ x="144.68085"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ xml:space="preserve"><tspan
+ y="293.85156"
+ x="144.68085"
+ id="tspan3765-69"
+ sodipodi:role="line">1</tspan></text>
+ </g>
+ <g
+ id="g3767-83"
+ transform="translate(188.08511,9.9544464)">
+ <rect
+ style="fill:none;stroke:#000000;stroke-opacity:1"
+ y="258.74515"
+ x="136.17021"
+ height="41.489372"
+ width="42.553192"
+ id="rect2985-44" />
+ <text
+ sodipodi:linespacing="125%"
+ id="text3763-9"
+ y="293.85156"
+ x="144.68085"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ xml:space="preserve"><tspan
+ y="293.85156"
+ x="144.68085"
+ id="tspan3765-1"
+ sodipodi:role="line">2</tspan></text>
+ </g>
+ <g
+ id="g3767-010"
+ transform="translate(188.08511,78.495463)">
+ <rect
+ style="fill:none;stroke:#000000;stroke-opacity:1"
+ y="258.74515"
+ x="136.17021"
+ height="41.489372"
+ width="42.553192"
+ id="rect2985-9" />
+ <text
+ sodipodi:linespacing="125%"
+ id="text3763-1"
+ y="293.85156"
+ x="144.68085"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ xml:space="preserve"><tspan
+ y="293.85156"
+ x="144.68085"
+ id="tspan3765-68"
+ sodipodi:role="line">3</tspan></text>
+ </g>
+ <g
+ id="g3767-7"
+ transform="translate(188.08511,147.03648)">
+ <rect
+ style="fill:none;stroke:#000000;stroke-opacity:1"
+ y="258.74515"
+ x="136.17021"
+ height="41.489372"
+ width="42.553192"
+ id="rect2985-42" />
+ <text
+ sodipodi:linespacing="125%"
+ id="text3763-93"
+ y="293.85156"
+ x="144.68085"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ xml:space="preserve"><tspan
+ y="293.85156"
+ x="144.68085"
+ id="tspan3765-89"
+ sodipodi:role="line">4</tspan></text>
+ </g>
+ <g
+ id="g3767-87"
+ transform="translate(188.08511,215.57752)">
+ <rect
+ style="fill:none;stroke:#000000;stroke-opacity:1"
+ y="258.74515"
+ x="136.17021"
+ height="41.489372"
+ width="42.553192"
+ id="rect2985-1" />
+ <text
+ sodipodi:linespacing="125%"
+ id="text3763-90"
+ y="293.85156"
+ x="144.68085"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ xml:space="preserve"><tspan
+ y="293.85156"
+ x="144.68085"
+ id="tspan3765-97"
+ sodipodi:role="line">5</tspan></text>
+ </g>
+ <g
+ id="g3767-79"
+ transform="translate(188.08511,284.11856)">
+ <rect
+ style="fill:none;stroke:#000000;stroke-opacity:1"
+ y="258.74515"
+ x="136.17021"
+ height="41.489372"
+ width="42.553192"
+ id="rect2985-36" />
+ <text
+ sodipodi:linespacing="125%"
+ id="text3763-99"
+ y="293.85156"
+ x="144.68085"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ xml:space="preserve"><tspan
+ y="293.85156"
+ x="144.68085"
+ id="tspan3765-3"
+ sodipodi:role="line">6</tspan></text>
+ </g>
+ <g
+ id="g3767-40"
+ transform="translate(188.08511,352.65958)">
+ <rect
+ style="fill:none;stroke:#000000;stroke-opacity:1"
+ y="258.74515"
+ x="136.17021"
+ height="41.489372"
+ width="42.553192"
+ id="rect2985-66" />
+ <text
+ sodipodi:linespacing="125%"
+ id="text3763-16"
+ y="293.85156"
+ x="144.68085"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ xml:space="preserve"><tspan
+ y="293.85156"
+ x="144.68085"
+ id="tspan3765-5"
+ sodipodi:role="line">7</tspan></text>
+ </g>
+ <g
+ id="g3767-544"
+ transform="translate(344.97872,-127.12765)">
+ <rect
+ style="fill:none;stroke:#000000;stroke-opacity:1"
+ y="258.74515"
+ x="136.17021"
+ height="41.489372"
+ width="42.553192"
+ id="rect2985-2" />
+ <text
+ sodipodi:linespacing="125%"
+ id="text3763-88"
+ y="293.85156"
+ x="144.68085"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ xml:space="preserve"><tspan
+ y="293.85156"
+ x="144.68085"
+ id="tspan3765-32"
+ sodipodi:role="line">0</tspan></text>
+ </g>
+ <g
+ id="g3767-94"
+ transform="translate(344.97872,-58.586648)">
+ <rect
+ style="fill:none;stroke:#000000;stroke-opacity:1"
+ y="258.74515"
+ x="136.17021"
+ height="41.489372"
+ width="42.553192"
+ id="rect2985-08" />
+ <text
+ sodipodi:linespacing="125%"
+ id="text3763-5"
+ y="293.85156"
+ x="144.68085"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ xml:space="preserve"><tspan
+ y="293.85156"
+ x="144.68085"
+ id="tspan3765-10"
+ sodipodi:role="line">1</tspan></text>
+ </g>
+ <g
+ id="g3767-59"
+ transform="translate(344.97872,9.9544464)">
+ <rect
+ style="fill:none;stroke:#000000;stroke-opacity:1"
+ y="258.74515"
+ x="136.17021"
+ height="41.489372"
+ width="42.553192"
+ id="rect2985-76" />
+ <text
+ sodipodi:linespacing="125%"
+ id="text3763-46"
+ y="293.85156"
+ x="144.68085"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ xml:space="preserve"><tspan
+ y="293.85156"
+ x="144.68085"
+ id="tspan3765-65"
+ sodipodi:role="line">2</tspan></text>
+ </g>
+ <g
+ id="g3767-12"
+ transform="translate(344.97872,78.495463)">
+ <rect
+ style="fill:none;stroke:#000000;stroke-opacity:1"
+ y="258.74515"
+ x="136.17021"
+ height="41.489372"
+ width="42.553192"
+ id="rect2985-67" />
+ <text
+ sodipodi:linespacing="125%"
+ id="text3763-87"
+ y="293.85156"
+ x="144.68085"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ xml:space="preserve"><tspan
+ y="293.85156"
+ x="144.68085"
+ id="tspan3765-56"
+ sodipodi:role="line">3</tspan></text>
+ </g>
+ <g
+ id="g3767-2"
+ transform="translate(344.97872,147.03648)">
+ <rect
+ style="fill:none;stroke:#000000;stroke-opacity:1"
+ y="258.74515"
+ x="136.17021"
+ height="41.489372"
+ width="42.553192"
+ id="rect2985-92" />
+ <text
+ sodipodi:linespacing="125%"
+ id="text3763-47"
+ y="293.85156"
+ x="144.68085"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ xml:space="preserve"><tspan
+ y="293.85156"
+ x="144.68085"
+ id="tspan3765-09"
+ sodipodi:role="line">4</tspan></text>
+ </g>
+ <g
+ id="g3767-11"
+ transform="translate(344.97872,215.57752)">
+ <rect
+ style="fill:none;stroke:#000000;stroke-opacity:1"
+ y="258.74515"
+ x="136.17021"
+ height="41.489372"
+ width="42.553192"
+ id="rect2985-449" />
+ <text
+ sodipodi:linespacing="125%"
+ id="text3763-95"
+ y="293.85156"
+ x="144.68085"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ xml:space="preserve"><tspan
+ y="293.85156"
+ x="144.68085"
+ id="tspan3765-06"
+ sodipodi:role="line">5</tspan></text>
+ </g>
+ <g
+ id="g3767-69"
+ transform="translate(344.97872,284.11856)">
+ <rect
+ style="fill:none;stroke:#000000;stroke-opacity:1"
+ y="258.74515"
+ x="136.17021"
+ height="41.489372"
+ width="42.553192"
+ id="rect2985-31" />
+ <text
+ sodipodi:linespacing="125%"
+ id="text3763-51"
+ y="293.85156"
+ x="144.68085"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ xml:space="preserve"><tspan
+ y="293.85156"
+ x="144.68085"
+ id="tspan3765-683"
+ sodipodi:role="line">6</tspan></text>
+ </g>
+ <g
+ id="g3767-47"
+ transform="translate(344.97872,352.65958)">
+ <rect
+ style="fill:none;stroke:#000000;stroke-opacity:1"
+ y="258.74515"
+ x="136.17021"
+ height="41.489372"
+ width="42.553192"
+ id="rect2985-32" />
+ <text
+ sodipodi:linespacing="125%"
+ id="text3763-2"
+ y="293.85156"
+ x="144.68085"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ xml:space="preserve"><tspan
+ y="293.85156"
+ x="144.68085"
+ id="tspan3765-94"
+ sodipodi:role="line">7</tspan></text>
+ </g>
+ <g
+ id="g3767-111"
+ transform="translate(502,-127.12765)">
+ <rect
+ style="fill:none;stroke:#000000;stroke-opacity:1"
+ y="258.74515"
+ x="136.17021"
+ height="41.489372"
+ width="42.553192"
+ id="rect2985-14" />
+ <text
+ sodipodi:linespacing="125%"
+ id="text3763-0"
+ y="293.85156"
+ x="144.68085"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ xml:space="preserve"><tspan
+ y="293.85156"
+ x="144.68085"
+ id="tspan3765-4"
+ sodipodi:role="line">0</tspan></text>
+ </g>
+ <g
+ id="g3767-56"
+ transform="translate(502,-58.586648)">
+ <rect
+ style="fill:none;stroke:#000000;stroke-opacity:1"
+ y="258.74515"
+ x="136.17021"
+ height="41.489372"
+ width="42.553192"
+ id="rect2985-85" />
+ <text
+ sodipodi:linespacing="125%"
+ id="text3763-66"
+ y="293.85156"
+ x="144.68085"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ xml:space="preserve"><tspan
+ y="293.85156"
+ x="144.68085"
+ id="tspan3765-74"
+ sodipodi:role="line">1</tspan></text>
+ </g>
+ <g
+ id="g3767-46"
+ transform="translate(502,9.9544464)">
+ <rect
+ style="fill:none;stroke:#000000;stroke-opacity:1"
+ y="258.74515"
+ x="136.17021"
+ height="41.489372"
+ width="42.553192"
+ id="rect2985-75" />
+ <text
+ sodipodi:linespacing="125%"
+ id="text3763-48"
+ y="293.85156"
+ x="144.68085"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ xml:space="preserve"><tspan
+ y="293.85156"
+ x="144.68085"
+ id="tspan3765-42"
+ sodipodi:role="line">2</tspan></text>
+ </g>
+ <g
+ id="g3767-18"
+ transform="translate(502,78.495463)">
+ <rect
+ style="fill:none;stroke:#000000;stroke-opacity:1"
+ y="258.74515"
+ x="136.17021"
+ height="41.489372"
+ width="42.553192"
+ id="rect2985-27" />
+ <text
+ sodipodi:linespacing="125%"
+ id="text3763-24"
+ y="293.85156"
+ x="144.68085"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ xml:space="preserve"><tspan
+ y="293.85156"
+ x="144.68085"
+ id="tspan3765-67"
+ sodipodi:role="line">3</tspan></text>
+ </g>
+ <g
+ id="g3767-80"
+ transform="translate(502,147.03648)">
+ <rect
+ style="fill:none;stroke:#000000;stroke-opacity:1"
+ y="258.74515"
+ x="136.17021"
+ height="41.489372"
+ width="42.553192"
+ id="rect2985-89" />
+ <text
+ sodipodi:linespacing="125%"
+ id="text3763-405"
+ y="293.85156"
+ x="144.68085"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ xml:space="preserve"><tspan
+ y="293.85156"
+ x="144.68085"
+ id="tspan3765-17"
+ sodipodi:role="line">4</tspan></text>
+ </g>
+ <g
+ id="g3767-66"
+ transform="translate(502,215.57752)">
+ <rect
+ style="fill:none;stroke:#000000;stroke-opacity:1"
+ y="258.74515"
+ x="136.17021"
+ height="41.489372"
+ width="42.553192"
+ id="rect2985-52" />
+ <text
+ sodipodi:linespacing="125%"
+ id="text3763-39"
+ y="293.85156"
+ x="144.68085"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ xml:space="preserve"><tspan
+ y="293.85156"
+ x="144.68085"
+ id="tspan3765-82"
+ sodipodi:role="line">5</tspan></text>
+ </g>
+ <g
+ id="g3767-946"
+ transform="translate(502,284.11856)">
+ <rect
+ style="fill:none;stroke:#000000;stroke-opacity:1"
+ y="258.74515"
+ x="136.17021"
+ height="41.489372"
+ width="42.553192"
+ id="rect2985-70" />
+ <text
+ sodipodi:linespacing="125%"
+ id="text3763-01"
+ y="293.85156"
+ x="144.68085"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ xml:space="preserve"><tspan
+ y="293.85156"
+ x="144.68085"
+ id="tspan3765-02"
+ sodipodi:role="line">6</tspan></text>
+ </g>
+ <g
+ id="g3767-837"
+ transform="translate(502,352.65958)">
+ <rect
+ style="fill:none;stroke:#000000;stroke-opacity:1"
+ y="258.74515"
+ x="136.17021"
+ height="41.489372"
+ width="42.553192"
+ id="rect2985-60" />
+ <text
+ sodipodi:linespacing="125%"
+ id="text3763-76"
+ y="293.85156"
+ x="144.68085"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ xml:space="preserve"><tspan
+ y="293.85156"
+ x="144.68085"
+ id="tspan3765-08"
+ sodipodi:role="line">7</tspan></text>
+ </g>
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 89.361703,152.36218 234.893617,0"
+ id="path4237"
+ inkscape:connector-type="polyline"
+ inkscape:connector-curvature="0"
+ inkscape:connection-start="#g4231"
+ inkscape:connection-start-point="d4"
+ inkscape:connection-end="#g3767-4"
+ inkscape:connection-end-point="d4" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 366.80851,152.36218 114.34042,0"
+ id="path4239"
+ inkscape:connector-type="polyline"
+ inkscape:connector-curvature="0"
+ inkscape:connection-start="#g3767-4"
+ inkscape:connection-start-point="d4"
+ inkscape:connection-end="#g3767-544"
+ inkscape:connection-end-point="d4" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 523.70212,152.36218 114.46809,0"
+ id="path4241"
+ inkscape:connector-type="polyline"
+ inkscape:connector-curvature="0"
+ inkscape:connection-start="#g3767-544"
+ inkscape:connection-start-point="d4"
+ inkscape:connection-end="#g3767-111"
+ inkscape:connection-end-point="d4" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 89.361703,220.90319 234.893617,0"
+ id="path4243"
+ inkscape:connector-type="polyline"
+ inkscape:connector-curvature="0"
+ inkscape:connection-start="#g4225"
+ inkscape:connection-start-point="d4"
+ inkscape:connection-end="#g3767-01"
+ inkscape:connection-end-point="d4" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 366.80851,220.90319 114.34042,0"
+ id="path4245"
+ inkscape:connector-type="polyline"
+ inkscape:connector-curvature="0"
+ inkscape:connection-start="#g3767-01"
+ inkscape:connection-start-point="d4"
+ inkscape:connection-end="#g3767-94"
+ inkscape:connection-end-point="d4" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 523.70212,220.90319 114.46809,0"
+ id="path4247"
+ inkscape:connector-type="polyline"
+ inkscape:connector-curvature="0"
+ inkscape:connection-start="#g3767-94"
+ inkscape:connection-start-point="d4"
+ inkscape:connection-end="#g3767-56"
+ inkscape:connection-end-point="d4" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 89.361703,289.44428 234.893617,0"
+ id="path4249"
+ inkscape:connector-type="polyline"
+ inkscape:connector-curvature="0"
+ inkscape:connection-start="#g4219"
+ inkscape:connection-start-point="d4"
+ inkscape:connection-end="#g3767-83"
+ inkscape:connection-end-point="d4" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 366.80851,289.44428 114.34042,0"
+ id="path4251"
+ inkscape:connector-type="polyline"
+ inkscape:connector-curvature="0"
+ inkscape:connection-start="#g3767-83"
+ inkscape:connection-start-point="d4"
+ inkscape:connection-end="#g3767-59"
+ inkscape:connection-end-point="d4" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 523.70212,289.44428 114.46809,0"
+ id="path4253"
+ inkscape:connector-type="polyline"
+ inkscape:connector-curvature="0"
+ inkscape:connection-start="#g3767-59"
+ inkscape:connection-start-point="d4"
+ inkscape:connection-end="#g3767-46"
+ inkscape:connection-end-point="d4" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 89.361703,357.9853 234.893617,0"
+ id="path4255"
+ inkscape:connector-type="polyline"
+ inkscape:connector-curvature="0"
+ inkscape:connection-start="#g4213"
+ inkscape:connection-start-point="d4"
+ inkscape:connection-end="#g3767-010"
+ inkscape:connection-end-point="d4" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 366.80851,357.9853 114.34042,0"
+ id="path4257"
+ inkscape:connector-type="polyline"
+ inkscape:connector-curvature="0"
+ inkscape:connection-start="#g3767-010"
+ inkscape:connection-start-point="d4"
+ inkscape:connection-end="#g3767-12"
+ inkscape:connection-end-point="d4" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 523.70212,357.9853 114.46809,0"
+ id="path4259"
+ inkscape:connector-type="polyline"
+ inkscape:connector-curvature="0"
+ inkscape:connection-start="#g3767-12"
+ inkscape:connection-start-point="d4"
+ inkscape:connection-end="#g3767-18"
+ inkscape:connection-end-point="d4" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 89.361703,426.52631 234.893617,0"
+ id="path4261"
+ inkscape:connector-type="polyline"
+ inkscape:connector-curvature="0"
+ inkscape:connection-start="#g4207"
+ inkscape:connection-start-point="d4"
+ inkscape:connection-end="#g3767-7"
+ inkscape:connection-end-point="d4" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 366.80851,426.52631 114.34042,0"
+ id="path4263"
+ inkscape:connector-type="polyline"
+ inkscape:connector-curvature="0"
+ inkscape:connection-start="#g3767-7"
+ inkscape:connection-start-point="d4"
+ inkscape:connection-end="#g3767-2"
+ inkscape:connection-end-point="d4" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 523.70212,426.52631 114.46809,0"
+ id="path4265"
+ inkscape:connector-type="polyline"
+ inkscape:connector-curvature="0"
+ inkscape:connection-start="#g3767-2"
+ inkscape:connection-start-point="d4"
+ inkscape:connection-end="#g3767-80"
+ inkscape:connection-end-point="d4" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 89.361703,495.06735 234.893617,0"
+ id="path4267"
+ inkscape:connector-type="polyline"
+ inkscape:connector-curvature="0"
+ inkscape:connection-start="#g4201"
+ inkscape:connection-start-point="d4"
+ inkscape:connection-end="#g3767-87"
+ inkscape:connection-end-point="d4" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 366.80851,495.06735 114.34042,0"
+ id="path4269"
+ inkscape:connector-type="polyline"
+ inkscape:connector-curvature="0"
+ inkscape:connection-start="#g3767-87"
+ inkscape:connection-start-point="d4"
+ inkscape:connection-end="#g3767-11"
+ inkscape:connection-end-point="d4" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 523.70212,495.06735 114.46809,0"
+ id="path4271"
+ inkscape:connector-type="polyline"
+ inkscape:connector-curvature="0"
+ inkscape:connection-start="#g3767-11"
+ inkscape:connection-start-point="d4"
+ inkscape:connection-end="#g3767-66"
+ inkscape:connection-end-point="d4" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 366.80851,563.60839 114.34042,0"
+ id="path4275"
+ inkscape:connector-type="polyline"
+ inkscape:connector-curvature="0"
+ inkscape:connection-start="#g3767-79"
+ inkscape:connection-start-point="d4"
+ inkscape:connection-end="#g3767-69"
+ inkscape:connection-end-point="d4" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 523.70212,563.60839 114.46809,0"
+ id="path4277"
+ inkscape:connector-type="polyline"
+ inkscape:connector-curvature="0"
+ inkscape:connection-start="#g3767-69"
+ inkscape:connection-start-point="d4"
+ inkscape:connection-end="#g3767-946"
+ inkscape:connection-end-point="d4" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 366.80851,632.14941 114.34042,0"
+ id="path4285"
+ inkscape:connector-type="polyline"
+ inkscape:connector-curvature="0"
+ inkscape:connection-start="#g3767-40"
+ inkscape:connection-start-point="d4"
+ inkscape:connection-end="#g3767-47"
+ inkscape:connection-end-point="d4" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 523.70212,632.14941 114.46809,0"
+ id="path4287"
+ inkscape:connector-type="polyline"
+ inkscape:connector-curvature="0"
+ inkscape:connection-start="#g3767-47"
+ inkscape:connection-start-point="d4"
+ inkscape:connection-end="#g3767-837"
+ inkscape:connection-end-point="d4" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 89.361703,563.60839 234.893617,0"
+ id="path4289"
+ inkscape:connector-type="polyline"
+ inkscape:connector-curvature="0"
+ inkscape:connection-start="#g4195"
+ inkscape:connection-start-point="d4"
+ inkscape:connection-end="#g3767-79"
+ inkscape:connection-end-point="d4" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 89.361703,632.14941 234.893617,0"
+ id="path4291"
+ inkscape:connector-type="polyline"
+ inkscape:connector-curvature="0"
+ inkscape:connection-start="#g4189"
+ inkscape:connection-start-point="d4"
+ inkscape:connection-end="#g3767-40"
+ inkscape:connection-end-point="d4" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="M 523.70212,211.61579 638.17021,161.64958"
+ id="path4293"
+ inkscape:connector-type="polyline"
+ inkscape:connector-curvature="0"
+ inkscape:connection-start="#g3767-94"
+ inkscape:connection-start-point="d4"
+ inkscape:connection-end="#g3767-111"
+ inkscape:connection-end-point="d4" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="M 523.70212,348.6979 638.17021,298.73168"
+ id="path4295"
+ inkscape:connector-type="polyline"
+ inkscape:connector-curvature="0"
+ inkscape:connection-start="#g3767-12"
+ inkscape:connection-start-point="d4"
+ inkscape:connection-end="#g3767-46"
+ inkscape:connection-end-point="d4" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="M 523.70212,485.77995 638.17021,435.81372"
+ id="path4297"
+ inkscape:connector-type="polyline"
+ inkscape:connector-curvature="0"
+ inkscape:connection-start="#g3767-11"
+ inkscape:connection-start-point="d4"
+ inkscape:connection-end="#g3767-80"
+ inkscape:connection-end-point="d4" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="M 523.70212,622.86201 638.17021,572.89579"
+ id="path4299"
+ inkscape:connector-type="polyline"
+ inkscape:connector-curvature="0"
+ inkscape:connection-start="#g3767-47"
+ inkscape:connection-start-point="d4"
+ inkscape:connection-end="#g3767-946"
+ inkscape:connection-end-point="d4" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="M 366.80851,545.01847 481.14893,445.11624"
+ id="path4301"
+ inkscape:connector-type="polyline"
+ inkscape:connector-curvature="0"
+ inkscape:connection-start="#g3767-79"
+ inkscape:connection-start-point="d4"
+ inkscape:connection-end="#g3767-2"
+ inkscape:connection-end-point="d4" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="M 366.80851,613.55949 481.14893,513.65727"
+ id="path4303"
+ inkscape:connector-type="polyline"
+ inkscape:connector-curvature="0"
+ inkscape:connection-start="#g3767-40"
+ inkscape:connection-start-point="d4"
+ inkscape:connection-end="#g3767-11"
+ inkscape:connection-end-point="d4" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="M 366.80851,270.85436 481.14893,170.95211"
+ id="path4305"
+ inkscape:connector-type="polyline"
+ inkscape:connector-curvature="0"
+ inkscape:connection-start="#g3767-83"
+ inkscape:connection-start-point="d4"
+ inkscape:connection-end="#g3767-544"
+ inkscape:connection-end-point="d4" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="M 366.80851,339.39537 481.14893,239.49311"
+ id="path4307"
+ inkscape:connector-type="polyline"
+ inkscape:connector-curvature="0"
+ inkscape:connection-start="#g3767-010"
+ inkscape:connection-start-point="d4"
+ inkscape:connection-end="#g3767-94"
+ inkscape:connection-end-point="d4" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="M 89.078178,405.78163 324.53885,173.10687"
+ id="path4309"
+ inkscape:connector-type="polyline"
+ inkscape:connector-curvature="0"
+ inkscape:connection-start="#g4207"
+ inkscape:connection-start-point="d4"
+ inkscape:connection-end="#g3767-4"
+ inkscape:connection-end-point="d4" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="M 89.078175,474.32267 324.53885,241.64787"
+ id="path4311"
+ inkscape:connector-type="polyline"
+ inkscape:connector-curvature="0"
+ inkscape:connection-start="#g4201"
+ inkscape:connection-start-point="d4"
+ inkscape:connection-end="#g3767-01"
+ inkscape:connection-end-point="d4" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="M 89.078179,542.86371 324.53885,310.18897"
+ id="path4313"
+ inkscape:connector-type="polyline"
+ inkscape:connector-curvature="0"
+ inkscape:connection-start="#g4195"
+ inkscape:connection-start-point="d4"
+ inkscape:connection-end="#g3767-83"
+ inkscape:connection-end-point="d4" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="M 89.078179,611.40473 324.53885,378.72998"
+ id="path4315"
+ inkscape:connector-type="polyline"
+ inkscape:connector-curvature="0"
+ inkscape:connection-start="#g4189"
+ inkscape:connection-start-point="d4"
+ inkscape:connection-end="#g3767-010"
+ inkscape:connection-end-point="d4" />
+ </g>
+</svg>
diff --git a/gr-fec/python/fec/polar/channel_construction_bec.py b/gr-fec/python/fec/polar/channel_construction_bec.py
new file mode 100644
index 0000000000..cd61f463f6
--- /dev/null
+++ b/gr-fec/python/fec/polar/channel_construction_bec.py
@@ -0,0 +1,110 @@
+#!/usr/bin/env python
+#
+# Copyright 2015 Free Software Foundation, Inc.
+#
+# 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.
+#
+
+import numpy as np
+import matplotlib.pyplot as plt
+
+def bsc_channel(p):
+ '''
+ binary symmetric channel (BSC)
+ output alphabet Y = {0, 1} and
+ W(0|0) = W(1|1) and W(1|0) = W(0|1)
+
+ this function returns a prob's vector for a BSC
+ p denotes an erroneous transistion
+ '''
+ if not (p >= 0.0 and p <= 1.0):
+ print "given p is out of range!"
+ return np.array([], dtype=float)
+
+ # 0 -> 0, 0 -> 1, 1 -> 0, 1 -> 1
+ W = np.array([[1 - p, p], [p, 1 - p]], dtype=float)
+ return W
+
+
+def bec_channel(eta):
+ '''
+ binary erasure channel (BEC)
+ for each y e Y
+ W(y|0) * W(y|1) = 0 or W(y|0) = W(y|1)
+ transistions are 1 -> 1 or 0 -> 0 or {0, 1} -> ? (erased symbol)
+ '''
+
+ # looks like BSC but should be interpreted differently.
+ W = np.array((1 - eta, eta, 1 - eta), dtype=float)
+ return W
+
+
+def odd_rec(iwn):
+ return iwn ** 2
+
+
+def even_rec(iwn):
+ return 2 * iwn - iwn ** 2
+
+
+def calc_one_recursion(iw0):
+ iw1 = np.zeros(2 * len(iw0)) # double values
+ for i in range(len(iw0)):
+ # careful indices screw you because paper is '1' based :(
+ iw1[2 * i] = odd_rec(iw0[i])
+ iw1[2 * i + 1] = even_rec(iw0[i])
+ return iw1
+
+
+def calculate_bec_channel_capacities(eta, n):
+ iw = 1 - eta # holds for BEC as stated in paper
+ iw = np.array([iw, ], dtype=float)
+ lw = int(np.log2(n))
+ for i in range(lw):
+ iw = calc_one_recursion(iw)
+ return iw
+
+
+def get_frozen_bit_indices_from_capacities(chan_caps, nfrozen):
+ indexes = np.array([], dtype=int)
+ while indexes.size < nfrozen:
+ index = np.argmin(chan_caps)
+ indexes = np.append(indexes, index)
+ chan_caps[index] = 1.0
+ return np.sort(indexes)
+
+
+def bec_channel_contruction_tests():
+ n = 2 ** 10
+ k = n // 2
+ eta = 0.3
+ bec_capacities = calculate_bec_channel_capacities(eta, n)
+ print(bec_capacities)
+
+ frozenbits_position = get_frozen_bit_indices_from_capacities(bec_capacities, k)
+
+ print('frozenbit_positions:')
+ print(frozenbits_position)
+ print('frozenbit_num:', frozenbits_position.size)
+
+
+def main():
+ print 'channel construction main'
+ bec_channel_contruction_tests()
+
+
+if __name__ == '__main__':
+ main()
diff --git a/gr-fec/python/fec/polar/channel_construction_bsc.py b/gr-fec/python/fec/polar/channel_construction_bsc.py
new file mode 100755
index 0000000000..8cee7ceac5
--- /dev/null
+++ b/gr-fec/python/fec/polar/channel_construction_bsc.py
@@ -0,0 +1,206 @@
+#!/usr/bin/env python
+#
+# Copyright 2015 Free Software Foundation, Inc.
+#
+# 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.
+#
+
+import numpy as np
+from helper_functions import *
+import matplotlib.pyplot as plt
+
+
+# def bit_reverse(value, n):
+# # is this really missing in NumPy???
+# bits = np.zeros(n, type(value))
+# for index in range(n):
+# mask = 1
+# mask = np.left_shift(mask, index)
+# bit = np.bitwise_and(value, mask)
+# bit = np.right_shift(bit, index)
+# bits[index] = bit
+# bits = bits[::-1]
+# result = 0
+# for index, bit in enumerate(bits):
+# bit = np.left_shift(bit, index)
+# result += bit
+# return result
+
+
+def get_Bn(n):
+ # this is a bit reversal matrix.
+ lw = int(np.log2(n)) # number of used bits
+ indexes = [bit_reverse(i, lw) for i in range(n)]
+ Bn = np.zeros((n, n), type(n))
+ for i, index in enumerate(indexes):
+ Bn[i][index] = 1
+ return Bn
+
+
+def get_Fn(n):
+ # this matrix defines the actual channel combining.
+ if n == 1:
+ return np.array([1, ])
+ F2 = np.array([[1, 0], [1, 1]], np.int)
+ nump = int(np.log2(n)) - 1 # number of Kronecker products to calculate
+ Fn = F2
+ for i in range(nump):
+ Fn = np.kron(Fn, F2)
+ return Fn
+
+def get_Gn(n):
+ # this matrix is called generator matrix
+ if not is_power_of_two(n):
+ print "invalid input"
+ return None
+ if n == 1:
+ return np.array([1, ])
+ Bn = get_Bn(n)
+ Fn = get_Fn(n)
+ Gn = np.dot(Bn, Fn)
+ return Gn
+
+
+def mutual_information(w):
+ '''
+ calculate mutual information I(W)
+ I(W) = sum over y e Y ( sum over x e X ( ... ) )
+ .5 W(y|x) log frac { W(y|x) }{ .5 W(y|0) + .5 W(y|1) }
+ '''
+ ydim, xdim = np.shape(w)
+ i = 0.0
+ for y in range(ydim):
+ for x in range(xdim):
+ v = w[y][x] * np.log2(w[y][x] / (0.5 * w[y][0] + 0.5 * w[y][1]))
+ i += v
+ i /= 2.0
+ return i
+
+
+def bhattacharyya_parameter(w):
+ '''bhattacharyya parameter is a measure of similarity between two prob. distributions'''
+ # sum over all y e Y for sqrt( W(y|0) * W(y|1) )
+ dim = np.shape(w)
+ ydim = dim[0]
+ xdim = dim[1]
+ z = 0.0
+ for y in range(ydim):
+ z += np.sqrt(w[y][0] * w[y][1])
+ # need all
+ return z
+
+
+def w_transition_prob(y, u, p):
+ return p[y == u]
+ # return 1 - p if y == u else p
+
+# @profile
+def calculate_joint_transition_probability(N, y, x, transition_probs):
+ single_ws = np.empty(N)
+ single_ws[y == x] = transition_probs[True]
+ single_ws[y != x] = transition_probs[False]
+ return np.prod(single_ws)
+
+
+# @profile
+def w_split_prob(y, u, G, transition_probs):
+ ''' Calculate channel splitting probabilities. '''
+ N = len(y) # number of combined channels
+ df = N - len(u) # degrees of freedom.
+ prob = 0.0
+ for uf in range(2 ** df):
+ utemp = unpack_byte(np.array([uf, ]), df)
+ ub = np.concatenate((u, utemp))
+ x = np.dot(ub, G) % 2
+ true_num = np.sum(y == x)
+ false_num = N - true_num
+ w = (transition_probs[True] ** true_num) * (transition_probs[False] ** false_num)
+ # w = calculate_joint_transition_probability(N, y, x, transition_probs)
+ prob += w
+ divider = 1.0 / (2 ** (N - 1))
+ return divider * prob
+
+# @profile
+def wn_split_channel(N, p):
+ G = get_Gn(N)
+ y = np.zeros((N, ), dtype=np.uint8)
+ n = 1
+ u = np.zeros((n + 1, ), dtype=np.uint8)
+ transition_probs = np.array([p, 1 - p], dtype=float)
+
+ z_params = []
+ c_params = []
+ for w in range(N):
+ nentries = (2 ** N) * (2 ** w)
+ print "for w=", w, " nentries=", nentries
+ w_probs = np.zeros((nentries, 2), dtype=float)
+ for y in range(2 ** N):
+ yb = unpack_byte(np.array([y, ]), N)
+ for u in range(2 ** (w + 1)):
+ ub = unpack_byte(np.array([u, ]), w + 1)
+ wp = w_split_prob(yb, ub, G, transition_probs)
+ ufixed = ub[0:-1]
+ yindex = y * (2 ** w) + pack_byte(ufixed)
+ uindex = ub[-1]
+ w_probs[yindex][uindex] = wp
+
+ z = bhattacharyya_parameter(w_probs)
+ z_params.append(z)
+ c = mutual_information(w_probs)
+ c_params.append(c)
+ print "W=", w, "Z=", z, "capacity=", c
+
+ return z_params, c_params
+
+
+def calculate_z_param(x):
+ # variables etc taken from paper bei Ido Tal et al.
+ # name there is f(x)
+ # x is the cross over probability of a BSC.
+ return 2 * np.sqrt(x * (1 - x))
+
+
+def calculate_capacity(x):
+ # in paper it is called g(x)
+ return -1. * x * np.log(x) - (1 - x) * np.log(1 - x)
+
+
+def splitting_masses_algorithm(n, k):
+ m = 2 ** n
+ p0 = 1.0 / m
+ mass_vec
+
+
+def main():
+ print 'channel construction BSC main'
+ n = 3
+ m = 2 ** n
+ k = m // 2
+ eta = 0.3
+ p = 0.1
+ # z, c = wn_split_channel(m, p)
+ # print(z)
+ # print(c)
+
+ u = np.zeros(m, dtype=bool)
+ G = get_Gn(m).astype(dtype=bool)
+ print G
+ print np.dot(u, G)
+
+
+
+if __name__ == '__main__':
+ main()
diff --git a/gr-fec/python/fec/polar/common.py b/gr-fec/python/fec/polar/common.py
new file mode 100644
index 0000000000..b4b152de61
--- /dev/null
+++ b/gr-fec/python/fec/polar/common.py
@@ -0,0 +1,69 @@
+#!/usr/bin/env python
+#
+# Copyright 2015 Free Software Foundation, Inc.
+#
+# 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.
+#
+
+
+import numpy as np
+from helper_functions import *
+
+'''
+PolarCommon holds value checks and common initializer code for both Encoder and Decoder.
+'''
+
+
+class PolarCommon:
+ def __init__(self, n, k, frozen_bit_position, frozenbits=None):
+ if not is_power_of_two(n):
+ raise ValueError("n={0} is not a power of 2!".format(n))
+ if frozenbits is None:
+ frozenbits = np.zeros(n - k, dtype=np.int)
+ if not len(frozenbits) == n - k:
+ raise ValueError("len(frozenbits)={0} is not equal to n-k={1}!".format(len(frozenbits), n - k))
+ if not frozenbits.dtype == np.int:
+ frozenbits = frozenbits.astype(dtype=int)
+ if not len(frozen_bit_position) == (n - k):
+ raise ValueError("len(frozen_bit_position)={0} is not equal to n-k={1}!".format(len(frozen_bit_position), n - k))
+ if not frozen_bit_position.dtype == np.int:
+ frozen_bit_position = frozen_bit_position.astype(dtype=int)
+
+ self.bit_reverse_positions = self._vector_bit_reversed(np.arange(n, dtype=int), int(np.log2(n)))
+ self.N = n
+ self.power = int(np.log2(self.N))
+ self.K = k
+ self.frozenbits = frozenbits
+ self.frozen_bit_position = frozen_bit_position
+ self.info_bit_position = np.delete(np.arange(self.N), self.frozen_bit_position)
+
+ def _insert_frozen_bits(self, u):
+ prototype = np.empty(self.N, dtype=int)
+ prototype[self.frozen_bit_position] = self.frozenbits
+ prototype[self.info_bit_position] = u
+ return prototype
+
+ def _extract_info_bits(self, y):
+ return y[self.info_bit_position]
+
+ def _reverse_bits(self, vec):
+ return vec[self.bit_reverse_positions]
+
+ def _vector_bit_reversed(self, vec, n):
+ return bit_reverse_vector(vec, n)
+
+ def info_print(self):
+ print "POLAR code ({0}, {1})".format(self.N, self.K)
diff --git a/gr-fec/python/fec/polar/decoder.py b/gr-fec/python/fec/polar/decoder.py
new file mode 100644
index 0000000000..d74f1f9e1a
--- /dev/null
+++ b/gr-fec/python/fec/polar/decoder.py
@@ -0,0 +1,278 @@
+#!/usr/bin/env python
+#
+# Copyright 2015 Free Software Foundation, Inc.
+#
+# 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.
+#
+
+import numpy as np
+from common import PolarCommon
+
+# for dev
+from encoder import PolarEncoder
+from matplotlib import pyplot as plt
+
+
+class PolarDecoder(PolarCommon):
+ def __init__(self, n, k, frozen_bit_position, frozenbits=None):
+ PolarCommon.__init__(self, n, k, frozen_bit_position, frozenbits)
+
+ self.error_probability = 0.1 # this is kind of a dummy value. usually chosen individually.
+ self.bsc_lr = ((1 - self.error_probability) / self.error_probability, self.error_probability / (1 - self.error_probability))
+ self.bsc_llrs = np.log(self.bsc_lr)
+
+ def _llr_bit(self, bit):
+ return self.bsc_llrs[bit]
+
+ def _llr_odd(self, la, lb):
+ # this functions uses the min-sum approximation
+ # exact formula: np.log((np.exp(la + lb) + 1) / (np.exp(la) + np.exp(lb)))
+ return np.sign(la) * np.sign(lb) * np.minimum(np.abs(la), np.abs(lb))
+
+ _f_vals = np.array((1.0, -1.0), dtype=float)
+
+ def _llr_even(self, la, lb, f):
+ return (la * self._f_vals[f]) + lb
+
+ def _llr_bit_decision(self, llr):
+ if llr < 0.0:
+ ui = int(1)
+ else:
+ ui = int(0)
+ return ui
+
+ def _retrieve_bit_from_llr(self, lr, pos):
+ f_index = np.where(self.frozen_bit_position == pos)[0]
+ if not f_index.size == 0:
+ ui = self.frozenbits[f_index][0]
+ else:
+ ui = self._llr_bit_decision(lr)
+ return ui
+
+ def _lr_bit(self, bit):
+ return self.bsc_lr[bit]
+
+ def _lr_odd(self, la, lb):
+ # la is upper branch and lb is lower branch
+ return (la * lb + 1) / (la + lb)
+
+ def _lr_even(self, la, lb, f):
+ # la is upper branch and lb is lower branch, f is last decoded bit.
+ return (la ** (1 - (2 * f))) * lb
+
+ def _lr_bit_decision(self, lr):
+ if lr < 1:
+ return int(1)
+ return int(0)
+
+ def _get_even_indices_values(self, u_hat):
+ # looks like overkill for some indexing, but zero and one based indexing mix-up gives you haedaches.
+ return u_hat[1::2]
+
+ def _get_odd_indices_values(self, u_hat):
+ return u_hat[0::2]
+
+ def _calculate_lrs(self, y, u):
+ ue = self._get_even_indices_values(u)
+ uo = self._get_odd_indices_values(u)
+ ya = y[0:y.size//2]
+ yb = y[(y.size//2):]
+ la = self._lr_decision_element(ya, (ue + uo) % 2)
+ lb = self._lr_decision_element(yb, ue)
+ return la, lb
+
+ def _lr_decision_element(self, y, u):
+ if y.size == 1:
+ return self._llr_bit(y[0])
+ if u.size % 2 == 0: # use odd branch formula
+ la, lb = self._calculate_lrs(y, u)
+ return self._llr_odd(la, lb)
+ else:
+ ui = u[-1]
+ la, lb = self._calculate_lrs(y, u[0:-1])
+ return self._llr_even(la, lb, ui)
+
+ def _retrieve_bit_from_lr(self, lr, pos):
+ f_index = np.where(self.frozen_bit_position == pos)[0]
+ if not f_index.size == 0:
+ ui = self.frozenbits[f_index][0]
+ else:
+ ui = self._lr_bit_decision(lr)
+ return ui
+
+ def _lr_sc_decoder(self, y):
+ # this is the standard SC decoder as derived from the formulas. It sticks to natural bit order.
+ u = np.array([], dtype=int)
+ for i in range(y.size):
+ lr = self._lr_decision_element(y, u)
+ ui = self._retrieve_bit_from_llr(lr, i)
+ u = np.append(u, ui)
+ return u
+
+ def _butterfly_decode_bits(self, pos, graph, u):
+ llr = graph[pos][0]
+ ui = self._llr_bit_decision(llr)
+ u = np.append(u, ui)
+ lower_right = pos + (self.N // 2)
+ la = graph[pos][1]
+ lb = graph[lower_right][1]
+ graph[lower_right][0] = self._llr_even(la, lb, ui)
+ llr = graph[lower_right][0]
+ ui = self._llr_bit_decision(llr)
+ u = np.append(u, ui)
+ return graph, u
+
+ def _lr_sc_decoder_efficient(self, y):
+ graph = np.full((self.N, self.power + 1), np.NaN, dtype=float)
+ for i in range(self.N):
+ graph[i][self.power] = self._llr_bit(y[i])
+ decode_order = self._vector_bit_reversed(np.arange(self.N), self.power)
+ decode_order = np.delete(decode_order, np.where(decode_order >= self.N // 2))
+ u = np.array([], dtype=int)
+ for pos in decode_order:
+ graph = self._butterfly(pos, 0, graph, u)
+ graph, u = self._butterfly_decode_bits(pos, graph, u)
+ return u
+
+ def _stop_propagation(self, bf_entry_row, stage):
+ # calculate break condition
+ modulus = 2 ** (self.power - stage)
+ # stage_size = self.N // (2 ** stage)
+ # half_stage_size = stage_size // 2
+ half_stage_size = self.N // (2 ** (stage + 1))
+ stage_pos = bf_entry_row % modulus
+ return stage_pos >= half_stage_size
+
+ def _butterfly(self, bf_entry_row, stage, graph, u):
+ if not self.power > stage:
+ return graph
+
+ if self._stop_propagation(bf_entry_row, stage):
+ upper_right = bf_entry_row - self.N // (2 ** (stage + 1))
+ la = graph[upper_right][stage + 1]
+ lb = graph[bf_entry_row][stage + 1]
+ ui = u[-1]
+ graph[bf_entry_row][stage] = self._llr_even(la, lb, ui)
+ return graph
+
+ # activate right side butterflies
+ u_even = self._get_even_indices_values(u)
+ u_odd = self._get_odd_indices_values(u)
+ graph = self._butterfly(bf_entry_row, stage + 1, graph, (u_even + u_odd) % 2)
+ lower_right = bf_entry_row + self.N // (2 ** (stage + 1))
+ graph = self._butterfly(lower_right, stage + 1, graph, u_even)
+
+ la = graph[bf_entry_row][stage + 1]
+ lb = graph[lower_right][stage + 1]
+ graph[bf_entry_row][stage] = self._llr_odd(la, lb)
+ return graph
+
+ def decode(self, data, is_packed=False):
+ if not len(data) == self.N:
+ raise ValueError("len(data)={0} is not equal to n={1}!".format(len(data), self.N))
+ if is_packed:
+ data = np.unpackbits(data)
+ data = self._lr_sc_decoder_efficient(data)
+ data = self._extract_info_bits(data)
+ if is_packed:
+ data = np.packbits(data)
+ return data
+
+
+def test_reverse_enc_dec():
+ n = 16
+ k = 8
+ frozenbits = np.zeros(n - k)
+ frozenbitposition = np.array((0, 1, 2, 3, 4, 5, 8, 9), dtype=int)
+ bits = np.random.randint(2, size=k)
+ encoder = PolarEncoder(n, k, frozenbitposition, frozenbits)
+ decoder = PolarDecoder(n, k, frozenbitposition, frozenbits)
+ encoded = encoder.encode(bits)
+ print 'encoded:', encoded
+ rx = decoder.decode(encoded)
+ print 'bits:', bits
+ print 'rx :', rx
+ print (bits == rx).all()
+
+
+def compare_decoder_impls():
+ print '\nthis is decoder test'
+ n = 8
+ k = 4
+ frozenbits = np.zeros(n - k)
+ # frozenbitposition = np.array((0, 1, 2, 3, 4, 5, 8, 9), dtype=int)
+ frozenbitposition = np.array((0, 1, 2, 4), dtype=int)
+ # bits = np.ones(k, dtype=int)
+ bits = np.random.randint(2, size=k)
+ # bits = np.array([0, 1, 1, 1])
+ # bits = np.array([0, 1, 1, 0])
+ # bits = np.array([1, 0, 1, 0])
+ print 'bits:', bits
+ encoder = PolarEncoder(n, k, frozenbitposition, frozenbits)
+ decoder = PolarDecoder(n, k, frozenbitposition, frozenbits)
+ encoded = encoder.encode(bits)
+ print 'encoded:', encoded
+ rx_st = decoder._lr_sc_decoder(encoded)
+ rx_eff = decoder._lr_sc_decoder_efficient(encoded)
+ print 'standard :', rx_st
+ print 'efficient:', rx_eff
+ print (rx_st == rx_eff).all()
+
+
+
+def main():
+ power = 3
+ n = 2 ** power
+ k = 4
+ frozenbits = np.zeros(n - k, dtype=int)
+ frozenbitposition = np.array((0, 1, 2, 4), dtype=int)
+ frozenbitposition4 = np.array((0, 1), dtype=int)
+
+
+ encoder = PolarEncoder(n, k, frozenbitposition, frozenbits)
+ decoder = PolarDecoder(n, k, frozenbitposition, frozenbits)
+
+ bits = np.ones(k, dtype=int)
+ # bits = np.array([1, 0, 1, 0], dtype=int)
+ print "bits: ", bits
+ evec = encoder.encode(bits)
+ print "froz: ", encoder._insert_frozen_bits(bits)
+ print "evec: ", evec
+ # dvec = decoder.decode(evec)
+ # print "dec: ", dvec
+
+ # llr = decoder._llr(4, evec, np.array([0, 0, 0]))
+ # print "llr=", llr
+ evec[1] = 0
+ deced = decoder._lr_sc_decoder(evec)
+ print 'SC decoded:', deced
+
+
+
+
+ # test_reverse_enc_dec()
+ compare_decoder_impls()
+
+ # graph_decode()
+
+
+
+
+
+
+
+if __name__ == '__main__':
+ main() \ No newline at end of file
diff --git a/gr-fec/python/fec/polar/encoder.py b/gr-fec/python/fec/polar/encoder.py
new file mode 100644
index 0000000000..6f87a22191
--- /dev/null
+++ b/gr-fec/python/fec/polar/encoder.py
@@ -0,0 +1,135 @@
+#!/usr/bin/env python
+#
+# Copyright 2015 Free Software Foundation, Inc.
+#
+# 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.
+#
+
+import numpy as np
+from common import PolarCommon
+
+
+class PolarEncoder(PolarCommon):
+ def __init__(self, n, k, frozen_bit_position, frozenbits=None):
+ PolarCommon.__init__(self, n, k, frozen_bit_position, frozenbits)
+ self.G = self._gn(n)
+
+ def _gn(self, n):
+ # this matrix is called generator matrix
+ if n == 1:
+ return np.array([1, ])
+ f = self._fn(n)
+ return f
+
+ def _fn(self, n):
+ # this matrix defines the actual channel combining.
+ if n == 1:
+ return np.array([1, ])
+ f2 = np.array([[1, 0], [1, 1]], np.int)
+ nump = int(np.log2(n)) - 1 # number of Kronecker products to calculate
+ fn = f2
+ for i in range(nump):
+ fn = np.kron(fn, f2)
+ return fn
+
+ def get_gn(self):
+ return self.G
+
+ def _prepare_input_data(self, vec):
+ vec = self._insert_frozen_bits(vec)
+ vec = self._reverse_bits(vec)
+ return vec
+
+ def _encode_matrix(self, data):
+ data = np.dot(data, self.G) % 2
+ data = data.astype(dtype=int)
+ return data
+
+ def _encode_efficient(self, vec):
+ nstages = int(np.log2(self.N))
+ pos = np.arange(self.N, dtype=int)
+ for i in range(nstages):
+ splitted = np.reshape(pos, (2 ** (i + 1), -1))
+ upper_branch = splitted[0::2].flatten()
+ lower_branch = splitted[1::2].flatten()
+ vec[upper_branch] = (vec[upper_branch] + vec[lower_branch]) % 2
+ return vec
+
+ def encode(self, data, is_packed=False):
+ if not len(data) == self.K:
+ raise ValueError("len(data)={0} is not equal to k={1}!".format(len(data), self.K))
+ if is_packed:
+ data = np.unpackbits(data)
+ if np.max(data) > 1 or np.min(data) < 0:
+ raise ValueError("can only encode bits!")
+ data = self._prepare_input_data(data)
+ data = self._encode_efficient(data)
+ if is_packed:
+ data = np.packbits(data)
+ return data
+
+
+def compare_results(encoder, ntests, k):
+ for n in range(ntests):
+ bits = np.random.randint(2, size=k)
+ preped = encoder._prepare_input_data(bits)
+ menc = encoder._encode_matrix(preped)
+ fenc = encoder._encode_efficient(preped)
+ if (menc == fenc).all() == False:
+ return False
+ return True
+
+
+def test_pseudo_rate_1_encoder(encoder, ntests, k):
+ for n in range(ntests):
+ bits = np.random.randint(2, size=k)
+ u = encoder._prepare_input_data(bits)
+ fenc = encoder._encode_efficient(u)
+ u_hat = encoder._encode_efficient(fenc)
+ if not (u_hat == u).all():
+ print('rate-1 encoder/decoder failed')
+ print u
+ print u_hat
+ return False
+ return True
+
+
+def test_encoder_impls():
+ print('comparing encoder implementations, matrix vs. efficient')
+ ntests = 1000
+ n = 16
+ k = 8
+ frozenbits = np.zeros(n - k)
+ # frozenbitposition8 = np.array((0, 1, 2, 4), dtype=int) # keep it!
+ frozenbitposition = np.array((0, 1, 2, 3, 4, 5, 8, 9), dtype=int)
+ encoder = PolarEncoder(n, k, frozenbitposition, frozenbits)
+ print 'result:', compare_results(encoder, ntests, k)
+
+ print('Test rate-1 encoder/decoder chain results')
+ r1_test = test_pseudo_rate_1_encoder(encoder, ntests, k)
+ print 'test rate-1 encoder/decoder:', r1_test
+
+
+
+def main():
+ print "main in encoder"
+ test_encoder_impls()
+
+
+
+
+if __name__ == '__main__':
+ main() \ No newline at end of file
diff --git a/gr-fec/python/fec/polar/helper_functions.py b/gr-fec/python/fec/polar/helper_functions.py
new file mode 100644
index 0000000000..1d82457f17
--- /dev/null
+++ b/gr-fec/python/fec/polar/helper_functions.py
@@ -0,0 +1,84 @@
+#!/usr/bin/env python
+#
+# Copyright 2015 Free Software Foundation, Inc.
+#
+# 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.
+#
+
+import numpy as np
+
+
+def is_power_of_two(num):
+ if type(num) != int:
+ return False # make sure we only compute integers.
+ return num != 0 and ((num & (num - 1)) == 0)
+
+
+def bit_reverse(value, n):
+ # is this really missing in NumPy???
+ seq = np.int(value)
+ rev = np.int(0)
+ rmask = np.int(1)
+ lmask = np.int(2 ** (n - 1))
+ for i in range(n // 2):
+ shiftval = n - 1 - (i * 2)
+ rshift = np.left_shift(np.bitwise_and(seq, rmask), shiftval)
+ lshift = np.right_shift(np.bitwise_and(seq, lmask), shiftval)
+ rev = np.bitwise_or(rev, rshift)
+ rev = np.bitwise_or(rev, lshift)
+ rmask = np.left_shift(rmask, 1)
+ lmask = np.right_shift(lmask, 1)
+ if not n % 2 == 0:
+ rev = np.bitwise_or(rev, np.bitwise_and(seq, rmask))
+ return rev
+
+
+def bit_reverse_vector(vec, n):
+ return np.array([bit_reverse(e, n) for e in vec], dtype=vec.dtype)
+
+
+def unpack_byte(byte, nactive):
+ if np.amin(byte) < 0 or np.amax(byte) > 255:
+ return None
+ if not byte.dtype == np.uint8:
+ byte = byte.astype(np.uint8)
+ if nactive == 0:
+ return np.array([], dtype=np.uint8)
+ return np.unpackbits(byte)[-nactive:]
+
+
+def pack_byte(bits):
+ if len(bits) == 0:
+ return 0
+ if np.amin(bits) < 0 or np.amax(bits) > 1: # only '1' and '0' in bits array allowed!
+ return None
+ bits = np.concatenate((np.zeros(8 - len(bits), dtype=np.uint8), bits))
+ res = np.packbits(bits)[0]
+ return res
+
+
+def main():
+ print 'helper functions'
+
+ for i in range(8):
+ print(i, 'is power of 2: ', is_power_of_two(i))
+ n = 2 ** 6
+ k = n // 2
+ eta = 0.3
+
+
+if __name__ == '__main__':
+ main()
diff --git a/gr-fec/python/fec/polar/polar_code.py b/gr-fec/python/fec/polar/polar_code.py
new file mode 100644
index 0000000000..f263c6d056
--- /dev/null
+++ b/gr-fec/python/fec/polar/polar_code.py
@@ -0,0 +1,493 @@
+#!/usr/bin/env python
+
+import numpy as np
+import matplotlib.pyplot as plt
+
+from encoder import PolarEncoder as enc
+
+# input alphabet X is always {0,1}
+# output alphabet is arbitrary
+# transition probabilities are arbitrary W(y|x)
+
+
+def bit_reverse(value, n):
+ # is this really missing in NumPy???
+ bits = np.zeros(n, type(value))
+ for index in range(n):
+ mask = 1
+ mask = np.left_shift(mask, index)
+ bit = np.bitwise_and(value, mask)
+ bit = np.right_shift(bit, index)
+ bits[index] = bit
+ bits = bits[::-1]
+ result = 0
+ for index, bit in enumerate(bits):
+ bit = np.left_shift(bit, index)
+ result += bit
+ return result
+
+
+def get_Bn(n):
+ # this is a bit reversal matrix.
+ lw = int(np.log2(n)) # number of used bits
+ indexes = [bit_reverse(i, lw) for i in range(n)]
+ Bn = np.zeros((n, n), type(n))
+ for i, index in enumerate(indexes):
+ Bn[i][index] = 1
+ return Bn
+
+
+def get_Fn(n):
+ # this matrix defines the actual channel combining.
+ if n == 1:
+ return np.array([1, ])
+ F2 = np.array([[1, 0], [1, 1]], np.int)
+ nump = int(np.log2(n)) - 1 # number of Kronecker products to calculate
+ Fn = F2
+ for i in range(nump):
+ Fn = np.kron(Fn, F2)
+ return Fn
+
+def get_Gn(n):
+ # this matrix is called generator matrix
+ if not is_power_of_2(n):
+ print "invalid input"
+ return None
+ if n == 1:
+ return np.array([1, ])
+ Bn = get_Bn(n)
+ Fn = get_Fn(n)
+ Gn = np.dot(Bn, Fn)
+ return Gn
+
+
+def odd_rec(iwn):
+ return iwn ** 2
+
+
+def even_rec(iwn):
+ return 2 * iwn - iwn ** 2
+
+
+def calc_one_recursion(iw0):
+ iw1 = np.zeros(2 * len(iw0)) # double values
+ for i in range(len(iw0)):
+ # careful indices screw you because paper is '1' based :(
+ iw1[2 * i] = odd_rec(iw0[i])
+ iw1[2 * i + 1] = even_rec(iw0[i])
+ return iw1
+
+
+def calculate_bec_channel_capacities(eta, n):
+ iw = 1 - eta # holds for BEC as stated in paper
+ lw = int(np.log2(n))
+ iw = [iw, ]
+ for i in range(lw):
+ iw = calc_one_recursion(iw)
+ return iw
+
+
+def bsc_channel(p):
+ '''
+ binary symmetric channel (BSC)
+ output alphabet Y = {0, 1} and
+ W(0|0) = W(1|1) and W(1|0) = W(0|1)
+
+ this function returns a prob's vector for a BSC
+ p denotes an erroneous transistion
+ '''
+ if not (p >= 0.0 and p <= 1.0):
+ print "given p is out of range!"
+ return ()
+
+ # 0 -> 0, 0 -> 1, 1 -> 0, 1 -> 1
+ W = np.array([[1 - p, p], [p, 1 - p]])
+ return W
+
+
+def bec_channel(eta):
+ '''
+ binary erasure channel (BEC)
+ for each y e Y
+ W(y|0) * W(y|1) = 0 or W(y|0) = W(y|1)
+ transistions are 1 -> 1 or 0 -> 0 or {0, 1} -> ? (erased symbol)
+ '''
+ print eta
+
+ # looks like BSC but should be interpreted differently.
+ W = (1 - eta, eta, 1 - eta)
+ return W
+
+
+def is_power_of_2(num):
+ if type(num) != int:
+ return False # make sure we only compute integers.
+ return num != 0 and ((num & (num - 1)) == 0)
+
+
+def combine_W2(u):
+ # This function applies the channel combination for W2
+ x1 = (u[0] + u[1]) % 2
+ x2 = (u[1])
+ return np.array([x1, x2], np.int)
+
+
+def combine_W4(u):
+ im = np.concatenate((combine_W2(u[0:2]), combine_W2(u[2:4])))
+ print "combine_W4.im = ", im
+ swappy = im[1]
+ im[1] = im[2]
+ im[2] = swappy
+ print "combine_W4.reverse_shuffled = ", im
+
+ return np.concatenate((combine_W2(im[0:2]), combine_W2(im[2:4])))
+
+
+def combine_Wn(u):
+ '''Combine vector u for encoding. It's described in the "Channel combining" section'''
+ # will throw error if len(u) isn't a power of 2!
+ n = len(u)
+ G = get_Gn(n)
+ return np.dot(u, G) % 2
+
+
+def unpack_byte(byte, nactive):
+ if np.amin(byte) < 0 or np.amax(byte) > 255:
+ return None
+ if not byte.dtype == np.uint8:
+ byte = byte.astype(np.uint8)
+ if nactive == 0:
+ return np.array([], dtype=np.uint8)
+ return np.unpackbits(byte)[-nactive:]
+
+
+def pack_byte(bits):
+ if len(bits) == 0:
+ return 0
+ if np.amin(bits) < 0 or np.amax(bits) > 1: # only '1' and '0' in bits array allowed!
+ return None
+ bits = np.concatenate((np.zeros(8 - len(bits), dtype=np.uint8), bits))
+ res = np.packbits(bits)[0]
+ return res
+
+
+def calculate_conditional_prob(y, u, channel):
+ # y and u same size and 1d!
+ # channel 2 x 2 matrix!
+ x1 = (u[0] + u[1]) % 2
+ s = 0 if y[0] == x1 else 1
+ # print "W(", y[0], "|", u[0], "+", u[1], "=", s, ") =", channel[y[0]][x1]
+ w112 = channel[y[0]][x1]
+ w22 = channel[y[1]][u[1]]
+ return w112 * w22
+
+
+def calculate_w2_probs():
+ w0 = np.array([[0.9, 0.1], [0.1, 0.9]])
+ print w0
+
+ w2 = np.zeros((4, 4), dtype=float)
+
+ print "W(y1|u1+u2)"
+ for y in range(4):
+ ybits = unpack_byte(np.array([y, ]), 2)
+ for u in range(4):
+ ubits = unpack_byte(np.array([u, ]), 2)
+ prob = calculate_conditional_prob(ybits, ubits, w0)
+ w2[y][u] = prob
+ # print "W(y1,y2|u1,u2) =", prob
+ return w2
+
+
+def get_prob(y, u, channel):
+ return channel[y][u]
+
+
+def get_wn_prob(y, u, channel):
+ x = combine_Wn(u)
+ result = 1
+ for i in range(len(x)):
+ result *= get_prob(y[i], x[i], channel)
+ return result
+
+
+def calculate_Wn_probs(n, channel):
+ # print "calculate_wn_probs"
+ ncomb = 2 ** n
+ wn = np.ones((ncomb, ncomb), dtype=float)
+ for y in range(ncomb):
+ ybits = unpack_byte(np.array([y, ]), n)
+ for u in range(ncomb):
+ ubits = unpack_byte(np.array([u, ]), n)
+ xbits = combine_Wn(ubits)
+ wn[y][u] = get_wn_prob(ybits, ubits, channel)
+ return wn
+
+
+def calculate_channel_splitting_probs(wn, n):
+ print wn
+
+ wi = np.zeros((n, 2 ** n, 2 ** n), dtype=float)
+ divider = (1.0 / (2 ** (n - 1)))
+ for i in range(n):
+ for y in range(2 ** n):
+ ybits = unpack_byte(np.array([y, ]), n)
+ print
+ for u in range(2 ** n):
+ ubits = unpack_byte(np.array([u, ]), n)
+ usc = ubits[0:i]
+ u = ubits[i]
+ usum = ubits[i+1:]
+ fixed_pu = np.append(usc, u)
+
+ my_iter = []
+ if len(usum) == 0:
+ my_iter.append(np.append(np.zeros(8 - len(fixed_pu), dtype=np.uint8), fixed_pu))
+ else:
+ uiter = np.arange(2 ** len(usum), dtype=np.uint8)
+ for ui in uiter:
+ element = unpack_byte(ui, len(usum))
+ item = np.append(fixed_pu, element)
+ item = np.append(np.zeros(8 - len(item), dtype=np.uint8), item)
+ my_iter.append(item)
+ my_iter = np.array(my_iter)
+
+ prob_sum = 0
+ for item in my_iter:
+ upos = np.packbits(item)
+ # print "y=", np.binary_repr(y, n), "item=", item, "u=", np.binary_repr(upos, n)
+ wni = wn[y][upos]
+ prob_sum += wni
+ prob_sum *= divider
+
+ print "W[{5}]({0},{1},{2}|{3}) = {4}".format(ybits[0], ybits[1], usc, u, prob_sum, i)
+
+ # print "i=", i, "y=", np.binary_repr(y, n), " fixed=", fixed_pu, "usum=", usum, " WN(i) =", prob_sum
+ wi[i][y][u] = prob_sum
+
+ for i in range(n):
+ print
+ for y in range(2 ** n):
+ ybits = unpack_byte(np.array([y, ]), n)
+ for u in range(2 ** n):
+
+ print "W[{}] ({},{}|{})".format(i, ybits[0], ybits[1], u)
+
+
+
+ return wi
+
+
+
+def mutual_information(w):
+ '''
+ calculate mutual information I(W)
+ I(W) = sum over y e Y ( sum over x e X ( ... ) )
+ .5 W(y|x) log frac { W(y|x) }{ .5 W(y|0) + .5 W(y|1) }
+ '''
+ ydim, xdim = np.shape(w)
+ i = 0.0
+ for y in range(ydim):
+ for x in range(xdim):
+ v = w[y][x] * np.log2(w[y][x] / (0.5 * w[y][0] + 0.5 * w[y][1]))
+ i += v
+ i /= 2.0
+ return i
+
+
+def capacity(w):
+ '''
+ find supremum I(W) of a channel.
+ '''
+ return w
+
+
+def bhattacharyya_parameter(w):
+ '''bhattacharyya parameter is a measure of similarity between two prob. distributions'''
+ # sum over all y e Y for sqrt( W(y|0) * W(y|1) )
+ dim = np.shape(w)
+ ydim = dim[0]
+ xdim = dim[1]
+ z = 0.0
+ for y in range(ydim):
+ z += np.sqrt(w[y][0] * w[y][1])
+ # need all
+ return z
+
+
+def w_transition_prob(y, u, p):
+ return 1 - p if y == u else p
+
+
+def w_split_prob(y, u, G, p):
+ ''' Calculate channel splitting probabilities. '''
+ N = len(y) # number of combined channels
+ df = N - len(u) # degrees of freedom.
+ prob = 0.0
+ for uf in range(2 ** df):
+ utemp = unpack_byte(np.array([uf, ]), df)
+ ub = np.concatenate((u, utemp))
+ # print "y=", y, "\tu=", ub
+ x = np.dot(ub, G) % 2
+ # print "x=", x
+ w = 1.0
+ for i in range(N):
+ w *= w_transition_prob(y[i], x[i], p)
+ # print "for u1=", uf, "prob=", w
+ prob += w
+ divider = 1.0 / (2 ** (N - 1))
+ return divider * prob
+
+
+def wn_split_channel(N, p):
+ G = get_Gn(N)
+ y = np.zeros((N, ), dtype=np.uint8)
+ n = 1
+ u = np.zeros((n + 1, ), dtype=np.uint8)
+
+ pn = w_split_prob(y, u, G, p)
+ # print "pn=", pn
+ z_params = []
+ c_params = []
+ for w in range(N):
+ nentries = (2 ** N) * (2 ** w)
+ print "for w=", w, " nentries=", nentries
+ w_probs = np.zeros((nentries, 2), dtype=float)
+ for y in range(2 ** N):
+ yb = unpack_byte(np.array([y, ]), N)
+ # print "\n\nyb", yb
+ for u in range(2 ** (w + 1)):
+ ub = unpack_byte(np.array([u, ]), w + 1)
+ # print "ub", ub
+ wp = w_split_prob(yb, ub, G, p)
+ ufixed = ub[0:-1]
+ yindex = y * (2 ** w) + pack_byte(ufixed)
+ uindex = ub[-1]
+ # print "y=", y, "ub", u, " prob=", wp, "index=[", yindex, ", ", uindex, "]"
+ w_probs[yindex][uindex] = wp
+ print "\n", np.sum(w_probs, axis=0)
+ z = bhattacharyya_parameter(w_probs)
+ z_params.append(z)
+ c = mutual_information(w_probs)
+ c_params.append(c)
+ print "W=", w, "Z=", z, "capacity=", c
+
+ return z_params, c_params
+
+
+def wminus(y0, y1, u0, p):
+ prob = 0.0
+ for i in range(2):
+ # print y0, y1, u0, i
+ u0u1 = (i + u0) % 2
+ w0 = w_transition_prob(y0, u0u1, p)
+ w1 = w_transition_prob(y1, i, p)
+ # print "w0=", w0, "\tw1=", w1
+ prob += w0 * w1
+ prob *= 0.5
+ return prob
+
+
+def wplus(y0, y1, u0, u1, p):
+ u0u1 = (u0 + u1) % 2
+ w0 = w_transition_prob(y0, u0u1, p)
+ w1 = w_transition_prob(y1, u1, p)
+ return 0.5 * w0 * w1
+
+
+def w2_split_channel(p):
+
+ wm_probs = np.zeros((4, 2), dtype=float)
+ for y0 in range(2):
+ for y1 in range(2):
+ for u0 in range(2):
+ wm = wminus(y0, y1, u0, p)
+ wm_probs[y0 * 2 + y1][u0] = wm
+
+ print wm_probs
+ print "W- Z parameter=", bhattacharyya_parameter(wm_probs)
+ print "I(W-)=", mutual_information(wm_probs)
+
+ chan_prob = 0.0
+ wp_probs = np.zeros((8, 2), dtype=float)
+ for y0 in range(2):
+ for y1 in range(2):
+ for u0 in range(2):
+ for u1 in range(2):
+ wp = wplus(y0, y1, u0, u1, p)
+ wp_probs[4 * y0 + 2 * y1 + u0][u1] = wp
+
+ print wp_probs
+ print "W+ Z parameter=", bhattacharyya_parameter(wp_probs)
+ print "I(W+)=", mutual_information(wp_probs)
+
+
+def plot_channel(probs, p, name):
+ nc = len(probs)
+ plt.plot(probs)
+ plt.grid()
+ plt.xlim((0, nc - 1))
+ plt.ylim((0.0, 1.0))
+ plt.xlabel('channel')
+ plt.ylabel('capacity')
+
+ fname = name, '_', p, '_', nc
+ print fname
+ fname = ''.join(str(n) for n in fname)
+ print fname
+ fname = fname.replace('.', '_')
+ print fname
+ fname = ''.join((fname, '.pdf'))
+ print fname
+ plt.savefig(fname)
+ # plt.show()
+
+
+def main():
+ np.set_printoptions(precision=4, linewidth=150)
+ print "POLAR code!"
+ w2 = calculate_w2_probs()
+ print w2
+
+ p = 0.1
+ n = 2
+ wn = calculate_Wn_probs(n, bsc_channel(p))
+
+ wi = calculate_channel_splitting_probs(wn, n)
+
+ w0 = bsc_channel(p)
+ print w0
+ iw = mutual_information(w0)
+ print "I(W)=", iw
+ print 1 - (p * np.log2(1.0 / p) + (1 - p) * np.log2(1.0 / (1 - p)))
+
+ print "Z param call"
+ bhattacharyya_parameter(w0)
+
+ print "old vs new encoder"
+
+ p = 0.1
+ w2_split_channel(p)
+ z, c = wn_split_channel(4, p)
+
+ eta = 0.3
+ nc = 1024
+ probs = calculate_bec_channel_capacities(eta, nc)
+ # plot_channel(probs, eta, 'bec_capacity')
+ # plot_channel(c, p, 'bsc_capacity')
+
+ nt = 2 ** 5
+
+
+ fG = get_Gn(nt)
+ # print fG
+ encoder = enc(nt, 4, np.arange(nt - 4, dtype=int))
+ # print encoder.get_gn()
+ comp = np.equal(fG, encoder.get_gn())
+
+ print "is equal?", np.all(comp)
+
+
+
+if __name__ == '__main__':
+ main()
diff --git a/gr-fec/python/fec/polar/testbed.py b/gr-fec/python/fec/polar/testbed.py
new file mode 100755
index 0000000000..f34f8a6b96
--- /dev/null
+++ b/gr-fec/python/fec/polar/testbed.py
@@ -0,0 +1,143 @@
+#!/usr/bin/env python
+#
+# Copyright 2015 Free Software Foundation, Inc.
+#
+# 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.
+#
+
+import numpy as np
+from encoder import PolarEncoder
+from decoder import PolarDecoder
+
+import matplotlib.pyplot as plt
+
+
+def get_frozen_bit_position():
+ # frozenbitposition = np.array((0, 1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 16, 17, 18, 20, 24), dtype=int)
+ # frozenbitposition = np.array((0, 1, 2, 3, 4, 5, 8, 9), dtype=int)
+ frozenbitposition = np.load('frozen_bit_positions_n256_k128_p0.11.npy').flatten()
+ print(frozenbitposition)
+ return frozenbitposition
+
+
+def test_enc_dec_chain():
+ ntests = 100
+ n = 256
+ k = n // 2
+ frozenbits = np.zeros(n - k)
+ frozenbitposition = get_frozen_bit_position()
+ for i in range(ntests):
+ bits = np.random.randint(2, size=k)
+ encoder = PolarEncoder(n, k, frozenbitposition, frozenbits)
+ decoder = PolarDecoder(n, k, frozenbitposition, frozenbits)
+ encoded = encoder.encode(bits)
+ rx = decoder.decode(encoded)
+ if not is_equal(bits, rx):
+ raise ValueError('Test #', i, 'failed, input and output differ', bits, '!=', rx)
+ return
+
+
+def is_equal(first, second):
+ if not (first == second).all():
+ result = first == second
+ for i in range(len(result)):
+ print '{0:4}: {1:2} == {2:1} = {3}'.format(i, first[i], second[i], result[i])
+ return False
+ return True
+
+
+def exact_value(la, lb):
+ return np.log((np.exp(la + lb) + 1) / (np.exp(la) + np.exp(lb)))
+
+
+def approx_value(la, lb):
+ return np.sign(la) * np.sign(lb) * np.minimum(np.abs(la), np.abs(lb))
+
+
+def test_1024_rate_1_code():
+ # effectively a Monte-Carlo simulation for channel polarization.
+ ntests = 10000
+ n = 256
+ k = n
+ transition_prob = 0.11
+ num_transitions = int(k * transition_prob)
+ frozenbits = np.zeros(n - k)
+ frozenbitposition = np.array((), dtype=int)
+ encoder = PolarEncoder(n, k, frozenbitposition, frozenbits)
+ decoder = PolarDecoder(n, k, frozenbitposition, frozenbits)
+
+ channel_counter = np.zeros(k)
+ possible_indices = np.arange(n, dtype=int)
+ for i in range(ntests):
+ bits = np.random.randint(2, size=k)
+ tx = encoder.encode(bits)
+ np.random.shuffle(possible_indices)
+ tx[possible_indices[0:num_transitions]] = (tx[possible_indices[0:num_transitions]] + 1) % 2
+ rx = tx
+ recv = decoder.decode(rx)
+ channel_counter += (bits == recv)
+
+ print channel_counter
+ print(np.min(channel_counter), np.max(channel_counter))
+
+ np.save('channel_counter_' + str(ntests) + '.npy', channel_counter)
+
+
+def find_good_indices(res, nindices):
+ channel_counter = np.copy(res)
+ good_indices = np.zeros(channel_counter.size)
+
+ for i in range(nindices):
+ idx = np.argmax(channel_counter)
+ good_indices[idx] = 1
+ channel_counter[idx] = 0
+ return good_indices
+
+
+def channel_analysis():
+ ntests = 10000
+ filename = 'channel_counter_' + str(ntests) + '.npy'
+ channel_counter = np.load(filename)
+ print(np.min(channel_counter), np.max(channel_counter))
+ channel_counter[0] = np.min(channel_counter)
+ good_indices = find_good_indices(channel_counter, channel_counter.size // 2)
+ frozen_bit_positions = np.where(good_indices > 0)
+ print(frozen_bit_positions)
+ np.save('frozen_bit_positions_n256_k128_p0.11.npy', frozen_bit_positions)
+ good_indices *= 2000
+ good_indices += 4000
+
+
+ plt.plot(channel_counter)
+ plt.plot(good_indices)
+ plt.show()
+
+def main():
+ # n = 16
+ # k = 8
+ # frozenbits = np.zeros(n - k)
+ # frozenbitposition8 = np.array((0, 1, 2, 4), dtype=int)
+ # frozenbitposition = np.array((0, 1, 2, 3, 4, 5, 8, 9), dtype=int)
+ # print frozenbitposition
+
+ test_enc_dec_chain()
+
+ # test_1024_rate_1_code()
+
+ # channel_analysis()
+
+if __name__ == '__main__':
+ main() \ No newline at end of file