root / gr-trellis / src / python / qa_trellis.py @ 765c9f6e
History | View | Annotate | Download (4.8 kB)
| 1 | #!/usr/bin/env python
|
|---|---|
| 2 | #
|
| 3 | # Copyright 2004,2010 Free Software Foundation, Inc.
|
| 4 | #
|
| 5 | # This file is part of GNU Radio
|
| 6 | #
|
| 7 | # GNU Radio is free software; you can redistribute it and/or modify
|
| 8 | # it under the terms of the GNU General Public License as published by
|
| 9 | # the Free Software Foundation; either version 3, or (at your option)
|
| 10 | # any later version.
|
| 11 | #
|
| 12 | # GNU Radio is distributed in the hope that it will be useful,
|
| 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 15 | # GNU General Public License for more details.
|
| 16 | #
|
| 17 | # You should have received a copy of the GNU General Public License
|
| 18 | # along with GNU Radio; see the file COPYING. If not, write to
|
| 19 | # the Free Software Foundation, Inc., 51 Franklin Street,
|
| 20 | # Boston, MA 02110-1301, USA.
|
| 21 | #
|
| 22 | |
| 23 | import math |
| 24 | |
| 25 | |
| 26 | from gnuradio import gr, gr_unittest, blks2 |
| 27 | # It's pretty ugly that we can't import trellis from gnuradio in this test
|
| 28 | # but because it runs on the non-installed python code it's all a mess.
|
| 29 | import trellis |
| 30 | |
| 31 | fsm_args = {"awgn1o2_4": (2, 4, 4,
|
| 32 | (0, 2, 0, 2, 1, 3, 1, 3), |
| 33 | (0, 3, 3, 0, 1, 2, 2, 1), |
| 34 | ), |
| 35 | "rep2": (2, 1, 4, (0, 0), (0, 3)), |
| 36 | "nothing": (2, 1, 2, (0, 0), (0, 1)), |
| 37 | } |
| 38 | |
| 39 | constells = {2: blks2.bpsk_constellation(),
|
| 40 | 4: blks2.qpsk_constellation(),
|
| 41 | } |
| 42 | |
| 43 | class test_trellis (gr_unittest.TestCase): |
| 44 | |
| 45 | def test_001_fsm (self): |
| 46 | f = trellis.fsm(*fsm_args["awgn1o2_4"])
|
| 47 | self.assertEqual(fsm_args["awgn1o2_4"],(f.I(),f.S(),f.O(),f.NS(),f.OS())) |
| 48 | |
| 49 | def test_002_fsm (self): |
| 50 | f = trellis.fsm(*fsm_args["awgn1o2_4"])
|
| 51 | g = trellis.fsm(f) |
| 52 | self.assertEqual((g.I(),g.S(),g.O(),g.NS(),g.OS()),(f.I(),f.S(),f.O(),f.NS(),f.OS()))
|
| 53 | |
| 54 | def test_003_fsm (self): |
| 55 | f = trellis.fsm("awgn1o2_4.fsm")
|
| 56 | self.assertEqual(fsm_args["awgn1o2_4"],(f.I(),f.S(),f.O(),f.NS(),f.OS())) |
| 57 | |
| 58 | def test_004_fsm(self): |
| 59 | """ Test to make sure fsm works with a single state fsm."""
|
| 60 | # Just checking that it initializes properly.
|
| 61 | f = trellis.fsm(*fsm_args["rep2"])
|
| 62 | |
| 63 | def test_001_interleaver (self): |
| 64 | K = 5
|
| 65 | IN = (1,2,3,4,0) |
| 66 | DIN = (4,0,1,2,3) |
| 67 | i = trellis.interleaver(K,IN) |
| 68 | self.assertEqual((K,IN,DIN),(i.K(),i.INTER(),i.DEINTER()))
|
| 69 | |
| 70 | def test_001_viterbi(self): |
| 71 | """
|
| 72 | Runs some coding/decoding tests with a few different FSM
|
| 73 | specs.
|
| 74 | """ |
| 75 | for name, args in fsm_args.items(): |
| 76 | constellation = constells[args[2]]
|
| 77 | fsms = trellis.fsm(*args) |
| 78 | noise = 0.1
|
| 79 | tb = trellis_tb(constellation, fsms, noise) |
| 80 | tb.run() |
| 81 | # Make sure all packets succesfully transmitted.
|
| 82 | self.assertEqual(tb.dst.ntotal(), tb.dst.nright())
|
| 83 | |
| 84 | |
| 85 | class trellis_tb(gr.top_block): |
| 86 | """
|
| 87 | A simple top block for use testing gr-trellis.
|
| 88 | """ |
| 89 | def __init__(self, constellation, f, N0=0.25, seed=-666L): |
| 90 | """
|
| 91 | constellation - a constellation object used for modulation.
|
| 92 | f - a finite state machine specification used for coding.
|
| 93 | N0 - noise level
|
| 94 | seed - random seed
|
| 95 | """ |
| 96 | super(trellis_tb, self).__init__() |
| 97 | # packet size in bits (make it multiple of 16 so it can be packed in a short)
|
| 98 | packet_size = 1024*16 |
| 99 | # bits per FSM input symbol
|
| 100 | bitspersymbol = int(round(math.log(f.I())/math.log(2))) # bits per FSM input symbol |
| 101 | # packet size in trellis steps
|
| 102 | K = packet_size/bitspersymbol |
| 103 | |
| 104 | # TX
|
| 105 | src = gr.lfsr_32k_source_s() |
| 106 | # packet size in shorts
|
| 107 | src_head = gr.head (gr.sizeof_short, packet_size/16)
|
| 108 | # unpack shorts to symbols compatible with the FSM input cardinality
|
| 109 | s2fsmi = gr.packed_to_unpacked_ss(bitspersymbol, gr.GR_MSB_FIRST) |
| 110 | # initial FSM state = 0
|
| 111 | enc = trellis.encoder_ss(f, 0)
|
| 112 | mod = gr.chunks_to_symbols_sc(constellation.points(), 1)
|
| 113 | |
| 114 | # CHANNEL
|
| 115 | add = gr.add_cc() |
| 116 | noise = gr.noise_source_c(gr.GR_GAUSSIAN,math.sqrt(N0/2),seed)
|
| 117 | |
| 118 | # RX
|
| 119 | # data preprocessing to generate metrics for Viterbi
|
| 120 | metrics = trellis.constellation_metrics_cf(constellation.base(), trellis.TRELLIS_EUCLIDEAN) |
| 121 | # Put -1 if the Initial/Final states are not set.
|
| 122 | va = trellis.viterbi_s(f, K, 0, -1) |
| 123 | # pack FSM input symbols to shorts
|
| 124 | fsmi2s = gr.unpacked_to_packed_ss(bitspersymbol, gr.GR_MSB_FIRST) |
| 125 | # check the output
|
| 126 | self.dst = gr.check_lfsr_32k_s()
|
| 127 | |
| 128 | self.connect (src, src_head, s2fsmi, enc, mod)
|
| 129 | self.connect (mod, (add, 0)) |
| 130 | self.connect (noise, (add, 1)) |
| 131 | self.connect (add, metrics, va, fsmi2s, self.dst) |
| 132 | |
| 133 | |
| 134 | if __name__ == '__main__': |
| 135 | gr_unittest.run(test_trellis, "test_trellis.xml")
|