diff options
author | anastas | 2006-08-16 20:07:36 +0000 |
---|---|---|
committer | anastas | 2006-08-16 20:07:36 +0000 |
commit | d5c192f9e3cde58589845b7b51057afc45d3bc79 (patch) | |
tree | 04dc746388bb19f66bae93d110e4f2a5ca14c64b /gnuradio-examples/python | |
parent | 1f0a124c68a40b2eee063267d4f7aeba4ed87619 (diff) | |
download | gnuradio-d5c192f9e3cde58589845b7b51057afc45d3bc79.tar.gz gnuradio-d5c192f9e3cde58589845b7b51057afc45d3bc79.tar.bz2 gnuradio-d5c192f9e3cde58589845b7b51057afc45d3bc79.zip |
Several enhancements to gr-trellis and gnuradio-examples/python/channel-coding:
-Added fsm constructor for generating FSM directly from the
generator matrix of binary convolutional codes.
-Added functionality to fsm class to compute the best way to
go from any state to any other state (useful for termination)
-Added soft-in-soft-out (SISO) block for turbo processing
-Added turbo decoding examples
git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@3322 221aa14e-8319-0410-a670-987f0aec2ac5
Diffstat (limited to 'gnuradio-examples/python')
22 files changed, 616 insertions, 245 deletions
diff --git a/gnuradio-examples/python/channel-coding/README b/gnuradio-examples/python/channel-coding/README index abfceb429..2be8c6ba1 100644 --- a/gnuradio-examples/python/channel-coding/README +++ b/gnuradio-examples/python/channel-coding/README @@ -8,26 +8,39 @@ fsm_files is a directory with some FSM definitions If you just want to see what these programs do, run each of the following: -./test_tcm.py fsm_files/awgn1o2_4.fsm 10.0 1000 -./test_tcm1.py fsm_files/awgn1o2_4.fsm 10.0 1000 -./test_tcm_combined.py fsm_files/awgn1o2_4.fsm 10.0 1000 -./test_tcm_parallel.py fsm_files/awgn1o2_4.fsm 10.0 1000 -./test_sccc_hard.py fsm_files/awgn1o2_4.fsm fsm_files/awgn1o2_4.fsm 10.0 1000 +./test_tcm.py fsm_files/awgn1o2_4.fsm 6.0 1000 +./test_tcm1.py fsm_files/awgn1o2_4.fsm 6.0 1000 +./test_tcm2.py 6.0 1000 +./test_tcm_combined.py fsm_files/awgn1o2_4.fsm 6.0 1000 +./test_tcm_parallel.py fsm_files/awgn1o2_4.fsm 6.0 1000 + +./test_sccc_hard.py fsm_files/awgn1o2_4.fsm fsm_files/awgn1o2_4_msb.fsm 10.0 100 +./test_sccc_soft.py fsm_files/awgn1o2_4.fsm fsm_files/awgn1o2_4_msb.fsm 8.0 100 +./test_sccc_turbo.py fsm_files/awgn1o2_4.fsm fsm_files/awgn1o2_4_msb.fsm 5.0 100 In your terminal you will see something like this: -[anastas@ernesto channel-coding]$ ./test_tcm.py fsm_files/awgn1o2_4.fsm 6.0 1000 -100 1024 1 103424 10 9.668936e-05 -200 1024 1 205824 21 1.020289e-04 -300 1024 0 308224 40 1.297757e-04 -400 1024 0 410624 1074 2.615531e-03 -500 1024 0 513024 1081 2.107114e-03 -600 1024 0 615424 1090 1.771137e-03 -700 1024 0 717824 1097 1.528230e-03 -800 1024 0 820224 1107 1.349631e-03 -900 1024 0 922624 1120 1.213929e-03 -1024000 1129 1.102539e-03 - -1.102539e-03 is the error rate estimates by sending 1000 packets of -1024x16 bits each using an 1/2 4-state convolutional code and QPSK +$ ./test_tcm.py fsm_files/awgn1o2_4.fsm 6.0 1000 +100 98 9.80e-01 102400 9 8.79e-05 +200 198 9.90e-01 204800 20 9.77e-05 +300 298 9.93e-01 307200 40 1.30e-04 +400 398 9.95e-01 409600 1074 2.62e-03 +500 498 9.96e-01 512000 1081 2.11e-03 +600 598 9.97e-01 614400 1090 1.77e-03 +700 698 9.97e-01 716800 1097 1.53e-03 +800 798 9.98e-01 819200 1107 1.35e-03 +900 898 9.98e-01 921600 1120 1.22e-03 +1000 998 9.98e-01 1024000 1129 1.10e-03 +1000 998 9.98e-01 1024000 1129 1.10e-03 + +which gives you information about the: +number of transmitted packets +number of packets in error +iestimated packet error rate +number of transmitted shorts +number of shorts in error +estimated (short) error rate + +1.10e-03 is the error rate estimate by sending 1000 packets of +1024 shorts each, using an 1/2 4-state convolutional code and QPSK modulation through an AWGN with Es/N0 = 6.0 dB diff --git a/gnuradio-examples/python/channel-coding/fsm_files/awgn1o2_128.fsm b/gnuradio-examples/python/channel-coding/fsm_files/awgn1o2_128.fsm index 9c14d82f3..bb79c59da 100644 --- a/gnuradio-examples/python/channel-coding/fsm_files/awgn1o2_128.fsm +++ b/gnuradio-examples/python/channel-coding/fsm_files/awgn1o2_128.fsm @@ -260,5 +260,6 @@ -GM1o2_128=[1+D^3+D^4+D^5+D^6+D^7 1+D+D^2+D^5+D^7] - =[249 167] +GM1o2_128=[1+D+D^2+D^5+D^7 1+D^3+D^4+D^5+D^6+D^7] + =[11100101 10011111] + =[229 159] diff --git a/gnuradio-examples/python/channel-coding/fsm_files/awgn1o2_16.fsm b/gnuradio-examples/python/channel-coding/fsm_files/awgn1o2_16.fsm index 2b000da69..cdab41359 100644 --- a/gnuradio-examples/python/channel-coding/fsm_files/awgn1o2_16.fsm +++ b/gnuradio-examples/python/channel-coding/fsm_files/awgn1o2_16.fsm @@ -36,4 +36,4 @@ -GM1o2_16=[1+D^2+D^3+D^4 1+D+D^4]; +GM1o2_16=[1+D+D^4 1+D^2+D^3+D^4 ] = [25,23] (decimal) diff --git a/gnuradio-examples/python/channel-coding/fsm_files/awgn1o2_4.fsm b/gnuradio-examples/python/channel-coding/fsm_files/awgn1o2_4.fsm index 33e5ee315..fb316b5ef 100644 --- a/gnuradio-examples/python/channel-coding/fsm_files/awgn1o2_4.fsm +++ b/gnuradio-examples/python/channel-coding/fsm_files/awgn1o2_4.fsm @@ -11,7 +11,4 @@ 2 1 AWGN CC from Proakis-Salehi pg 779 -GM1o2_4=[1+D+D^2 1+D^2]; - - - +GM1o2_4=[1+D^2, 1+D+D^2] = [5, 7] (in decimal); diff --git a/gnuradio-examples/python/channel-coding/fsm_files/awgn1o2_8.fsm b/gnuradio-examples/python/channel-coding/fsm_files/awgn1o2_8.fsm index dd63b1ef5..604bac6c2 100644 --- a/gnuradio-examples/python/channel-coding/fsm_files/awgn1o2_8.fsm +++ b/gnuradio-examples/python/channel-coding/fsm_files/awgn1o2_8.fsm @@ -21,4 +21,4 @@ 1/2 8-state code (Proakis pg. 493) -GM1o2_8=[ 1+D+D^2+D^3 1+D+D^3]; +GM1o2_8=[ 1+D+D^3 1+D+D^2+D^3] =[13 , 15] (decimal) diff --git a/gnuradio-examples/python/channel-coding/fsm_files/awgn2o3_4.fsm b/gnuradio-examples/python/channel-coding/fsm_files/awgn2o3_4.fsm index 567948e78..3ac57be18 100644 --- a/gnuradio-examples/python/channel-coding/fsm_files/awgn2o3_4.fsm +++ b/gnuradio-examples/python/channel-coding/fsm_files/awgn2o3_4.fsm @@ -1,44 +1,15 @@ 4 4 8 -0 2 1 3 -0 2 1 3 -0 2 1 3 -0 2 1 3 - -0 3 5 6 -4 7 1 2 -7 4 2 1 -3 0 6 5 - - -This is generated by the 1/2 AWGN code (5 7) by puncturing the first (MSB) bit. ---> d_free=3 - -before puncturing: - -00 03 31 32 -30 33 01 02 -13 10 22 21 -23 20 12 11 - -or in decimal representation: - - 0 3 13 14 -12 15 1 2 - 7 4 10 9 -11 8 6 5 - -by punturing the MSB you get (dmin=3) - -0 3 5 6 -4 7 1 2 -7 4 2 1 -3 0 6 5 - -and by puncturing the LSB (something is wrong with this code) - -0 1 6 7 -6 7 0 1 -3 2 5 4 -5 4 3 2 - +0 1 2 3 +0 1 2 3 +0 1 2 3 +0 1 2 3 + +0 7 4 3 +3 4 7 0 +5 2 1 6 +6 1 2 5 + +I don't remeber how I generated this one... +it is a bit better than awgn2o3_4_msb and worse +than awgn2o3_4_msbG. diff --git a/gnuradio-examples/python/channel-coding/fsm_files/awgn2o3_4_1.fsm b/gnuradio-examples/python/channel-coding/fsm_files/awgn2o3_4_1.fsm deleted file mode 100644 index c5aee6983..000000000 --- a/gnuradio-examples/python/channel-coding/fsm_files/awgn2o3_4_1.fsm +++ /dev/null @@ -1,42 +0,0 @@ -4 4 8 - -0 1 2 3 -0 1 2 3 -0 1 2 3 -0 1 2 3 - -0 7 4 3 -3 4 7 0 -5 2 1 6 -6 1 2 5 - - - -This is generated by the 1/2 AWGN code (5 7) by puncturing the first (MSB) bit. ---> d_free=3 - -before puncturing: - - -or in decimal representation: - -0 7 12 11 -3 4 15 8 -13 10 1 6 -14 9 2 5 - -by punturing the MSB you get (dmin=3) - -0 7 4 3 -3 4 7 0 -5 2 1 6 -6 1 2 5 - - -and by puncturing the LSB (something is wrong with this code) - -0 3 6 5 -1 2 7 4 -6 5 0 3 -7 4 1 2 - diff --git a/gnuradio-examples/python/channel-coding/fsm_files/awgn2o3_4_msb.fsm b/gnuradio-examples/python/channel-coding/fsm_files/awgn2o3_4_msb.fsm new file mode 100644 index 000000000..551b71101 --- /dev/null +++ b/gnuradio-examples/python/channel-coding/fsm_files/awgn2o3_4_msb.fsm @@ -0,0 +1,46 @@ +4 4 8 + +0 1 2 3 +0 1 2 3 +0 1 2 3 +0 1 2 3 + +0 5 3 6 +4 1 7 2 +7 2 4 1 +3 6 0 5 + + +This is generated by the 1/2 AWGN code (5 7) operated twice, ie, +(xk+1 xki) [xk-1 xk-2] -> [xk+1 xki]. +We also puncture the first (MSB) bit. +This code is worse than awgn2o3_4_msbG and slightly worse than +awgn2o3_4, BUT seems to be a good innner code for sctcm (with 8PSK natural). + +intermediate states: + +00 21 02 23 +00 21 02 23 +10 31 12 33 +10 31 12 33 + +output before puncturing: + +00 31 03 32 +30 01 33 02 +13 22 10 21 +23 12 20 11 + +output after punturing the MSB: + +00 11 03 12 +10 01 13 02 +13 02 10 01 +03 12 00 11 + +and in decimal: + +0 5 3 6 +4 1 7 2 +7 2 4 1 +3 6 0 5 diff --git a/gnuradio-examples/python/channel-coding/fsm_files/awgn2o3_4_msbG.fsm b/gnuradio-examples/python/channel-coding/fsm_files/awgn2o3_4_msbG.fsm new file mode 100644 index 000000000..8956c53da --- /dev/null +++ b/gnuradio-examples/python/channel-coding/fsm_files/awgn2o3_4_msbG.fsm @@ -0,0 +1,60 @@ +4 4 8 + +0 1 2 3 +0 1 2 3 +0 1 2 3 +0 1 2 3 + +0 4 2 6 +5 1 3 7 +3 7 5 1 + + +This is generated by the 1/2 AWGN code (5 7) operated twice, ie, +(xk+1 xki) [xk-1 xk-2] -> [xk+1 xki]. +We also puncture the first (MSB) bit and Gray map the symbols. + +intermediate states: + +00 21 02 23 +00 21 02 23 +10 31 12 33 +10 31 12 33 + +output before puncturing: + +00 31 03 32 +30 01 33 02 +13 22 10 21 +23 12 20 11 + +output after punturing the MSB: + +00 11 03 12 +10 01 13 02 +13 02 10 01 +03 12 00 11 + +and in decimal: + +0 5 3 6 +4 1 7 2 +7 2 4 1 +3 6 0 5 + +After Gray mapping: +label -> phase +0 -> 0 +1 -> 0 +2 -> 7 +3 -> 2 +4 -> 5 +5 -> 4 +6 -> 6 +7 -> 3 + +0 4 2 6 +5 1 3 7 +3 7 5 1 +2 6 0 4 + diff --git a/gnuradio-examples/python/channel-coding/fsm_files/awgn2o4_4.fsm b/gnuradio-examples/python/channel-coding/fsm_files/awgn2o4_4.fsm index 793d419c5..a895be896 100644 --- a/gnuradio-examples/python/channel-coding/fsm_files/awgn2o4_4.fsm +++ b/gnuradio-examples/python/channel-coding/fsm_files/awgn2o4_4.fsm @@ -1,14 +1,36 @@ -4 4 16 +4 4 16 -0 2 1 3 -0 2 1 3 -0 2 1 3 -0 2 1 3 +0 1 2 3 +0 1 2 3 +0 1 2 3 +0 1 2 3 - 0 3 13 14 -12 15 1 2 - 7 4 10 9 -11 8 6 5 + 0 13 3 14 +12 1 15 2 + 7 10 4 9 +11 6 8 5 -generated by the awgn1o2_4.fsm code -(two steps of the 1o2 code) + +This is generated by the 1/2 AWGN code (5 7) operated twice, ie, +(xk+1 xki) [xk-1 xk-2] -> [xk+1 xki]. + +intermediate states: + +00 21 02 23 +00 21 02 23 +10 31 12 33 +10 31 12 33 + +output: + +00 31 03 32 +30 01 33 02 +13 22 10 21 +23 12 20 11 + +and in decimal: + + 0 13 3 14 +12 1 15 2 + 7 10 4 9 +11 6 8 5 diff --git a/gnuradio-examples/python/channel-coding/fsm_files/disconnected.fsm b/gnuradio-examples/python/channel-coding/fsm_files/disconnected.fsm new file mode 100644 index 000000000..847963e7b --- /dev/null +++ b/gnuradio-examples/python/channel-coding/fsm_files/disconnected.fsm @@ -0,0 +1,11 @@ +1 4 1 + +1 +0 +3 +2 + +0 +0 +0 +0 diff --git a/gnuradio-examples/python/channel-coding/fsm_files/rep3.fsm b/gnuradio-examples/python/channel-coding/fsm_files/rep3.fsm index 1930523b3..ef1bd1f02 100644 --- a/gnuradio-examples/python/channel-coding/fsm_files/rep3.fsm +++ b/gnuradio-examples/python/channel-coding/fsm_files/rep3.fsm @@ -4,4 +4,5 @@ 0 7 -1/3 repetition code (with binary input) +1/3 repetition code (with binary input). +There is only one state, since this is essentially a memoryless system. diff --git a/gnuradio-examples/python/channel-coding/fsm_files/simple.fsm b/gnuradio-examples/python/channel-coding/fsm_files/simple.fsm new file mode 100644 index 000000000..07fb0852f --- /dev/null +++ b/gnuradio-examples/python/channel-coding/fsm_files/simple.fsm @@ -0,0 +1,13 @@ +1 4 1 + +1 +2 +3 +0 + +0 +0 +0 +0 + +essentially this fsm has no inputs and no outputs; it ijust cycles through all 4 states. diff --git a/gnuradio-examples/python/channel-coding/fsm_utils.py b/gnuradio-examples/python/channel-coding/fsm_utils.py index dc5ee79f1..fe9f4f3b8 100755 --- a/gnuradio-examples/python/channel-coding/fsm_utils.py +++ b/gnuradio-examples/python/channel-coding/fsm_utils.py @@ -60,101 +60,6 @@ def base2dec(s,base): - - -###################################################################### -# Automaticaly generate the FSM structure for a binary feed-forward -# convolutional code. -# Input: k x n generator matrix (decimal representation) -###################################################################### -def make_fsm_bin_cc_ff(k,n,GM): - mem=[[]]*k - max_mem_x=[-1]*k - max_mem = -1 - for i in range(k): - memr=[0]*n - for j in range(n): - if GM[i][j]==0: - memr[j]=-1 - else: - memr[j]=int(math.log(GM[i][j],2)) - if memr[j]>max_mem_x[i]: - max_mem_x[i]=memr[j] - if memr[j]>max_mem: - max_mem=memr[j] - mem[i]=memr - - sum_max_mem = 0 - for i in range(k): - sum_max_mem = sum_max_mem+max_mem_x[i] - - - #print mem - #print max_mem_x - #print max_mem - #print sum_max_mem - - I=2**k - S=2**sum_max_mem - O=2**n - - #print I, S, O - - NS=[0]*S*I; - OS=[0]*S*I; - for s in range(S): - for i in range(I): - ss=dec2base(s,2,sum_max_mem) - ind=0 - ss_r=[] - for kk in range(k): - ss1 = [0]*max_mem - ss1[0:max_mem_x[kk]] = ss[ind:ind+max_mem_x[kk]] - ss_r.append(ss1) - ind=ind+max_mem_x[kk] - ii=dec2base(i,2,k) - - tt_r = ss_r - for kk in range(k): - tt_r[kk].insert(0,ii[kk]) - #print tt_r - - ns_r = [] - for kk in range(k): - ns_r.append(tt_r[kk][0:max_mem]) - - ns=[] - for kk in range(k): - ns = ns + ns_r[kk][0:max_mem_x[kk]] - NS[s*I+i]=base2dec(ns,2); - - out_r=[0]*n - for nn in range(n): - out=0; - for kk in range(k): - c=[0]*max_mem - gm = dec2base(GM[kk][nn],2,max_mem_x[kk]+1) - gm.reverse() - c[0:len(gm)] = gm - sy = 0 - for m in range(len(c)): - sy = sy + c[m]*tt_r[kk][m]; - out=operator.mod(out+sy,2); - out_r[nn]=out; - out_r.reverse() - OS[s*I+i] = base2dec(out_r,2); - - #O=max(max(OS))+1; - print I, S, O - print NS - print OS - - return (I,S,O,NS,OS) - - - - - ###################################################################### # Automatically generate the lookup table that maps the FSM outputs # to channel inputs corresponding to a channel 'channel' and a modulation diff --git a/gnuradio-examples/python/channel-coding/test_sccc_hard.py b/gnuradio-examples/python/channel-coding/test_sccc_hard.py index a869e91e1..d634282fe 100755 --- a/gnuradio-examples/python/channel-coding/test_sccc_hard.py +++ b/gnuradio-examples/python/channel-coding/test_sccc_hard.py @@ -18,7 +18,7 @@ def run_test (fo,fi,interleaver,Kb,bitspersymbol,K,dimensionality,constellation, src_head = gr.head (gr.sizeof_short,Kb/16) # packet size in shorts s2fsmi = gr.packed_to_unpacked_ss(bitspersymbol,gr.GR_MSB_FIRST) # unpack shorts to symbols compatible with the outer FSM input cardinality enc_out = trellis.encoder_ss(fo,0) # initial state = 0 - inter = trellis.permutation(interleaver.K(),interleaver.INTER(),gr.sizeof_short) + inter = trellis.permutation(interleaver.K(),interleaver.INTER(),1,gr.sizeof_short) enc_in = trellis.encoder_ss(fi,0) # initial state = 0 mod = gr.chunks_to_symbols_sf(constellation,dimensionality) @@ -29,7 +29,7 @@ def run_test (fo,fi,interleaver,Kb,bitspersymbol,K,dimensionality,constellation, # RX metrics_in = trellis.metrics_f(fi.O(),dimensionality,constellation,trellis.TRELLIS_EUCLIDEAN) # data preprocessing to generate metrics for innner Viterbi va_in = trellis.viterbi_s(fi,K,0,-1) # Put -1 if the Initial/Final states are not set. - deinter = trellis.permutation(interleaver.K(),interleaver.DEINTER(),gr.sizeof_short) + deinter = trellis.permutation(interleaver.K(),interleaver.DEINTER(),1,gr.sizeof_short) metrics_out = trellis.metrics_s(fo.O(),1,[0,1,2,3],trellis.TRELLIS_HARD_SYMBOL) # data preprocessing to generate metrics for outer Viterbi (hard decisions) va_out = trellis.viterbi_s(fo,K,0,-1) # Put -1 if the Initial/Final states are not set. fsmi2s = gr.unpacked_to_packed_ss(bitspersymbol,gr.GR_MSB_FIRST) # pack FSM input symbols to shorts @@ -85,14 +85,16 @@ def main(args): tot_s=0 # total number of transmitted shorts terr_s=0 # total number of shorts in error + terr_p=0 # total number of packets in error for i in range(rep): (s,e)=run_test(fo,fi,interleaver,Kb,bitspersymbol,K,dimensionality,constellation,N0,-long(666+i)) # run experiment with different seed to get different noise realizations tot_s=tot_s+s terr_s=terr_s+e - if (i%100==0) & (i>0): # display progress - print i,s,e,tot_s,terr_s, '%e' % ((1.0*terr_s)/tot_s) + terr_p=terr_p+(terr_s!=0) + if ((i+1)%100==0) : # display progress + print i+1,terr_p, '%.2e' % ((1.0*terr_p)/(i+1)),tot_s,terr_s, '%.2e' % ((1.0*terr_s)/tot_s) # estimate of the (short or bit) error rate - print tot_s,terr_s, '%e' % ((1.0*terr_s)/tot_s) + print rep,terr_p, '%.2e' % ((1.0*terr_p)/(i+1)),tot_s,terr_s, '%.2e' % ((1.0*terr_s)/tot_s) if __name__ == '__main__': diff --git a/gnuradio-examples/python/channel-coding/test_sccc_soft.py b/gnuradio-examples/python/channel-coding/test_sccc_soft.py new file mode 100755 index 000000000..23e6553ca --- /dev/null +++ b/gnuradio-examples/python/channel-coding/test_sccc_soft.py @@ -0,0 +1,108 @@ +#!/usr/bin/env python + +from gnuradio import gr +from gnuradio import audio +from gnuradio import trellis +from gnuradio import eng_notation +import math +import sys +import random +import fsm_utils + + + + +def run_test (fo,fi,interleaver,Kb,bitspersymbol,K,dimensionality,constellation,N0,seed): + fg = gr.flow_graph () + + + # TX + src = gr.lfsr_32k_source_s() + src_head = gr.head (gr.sizeof_short,Kb/16) # packet size in shorts + s2fsmi = gr.packed_to_unpacked_ss(bitspersymbol,gr.GR_MSB_FIRST) # unpack shorts to symbols compatible with the outer FSM input cardinality + enc_out = trellis.encoder_ss(fo,0) # initial state = 0 + inter = trellis.permutation(interleaver.K(),interleaver.INTER(),1,gr.sizeof_short) + enc_in = trellis.encoder_ss(fi,0) # initial state = 0 + mod = gr.chunks_to_symbols_sf(constellation,dimensionality) + + # CHANNEL + add = gr.add_ff() + noise = gr.noise_source_f(gr.GR_GAUSSIAN,math.sqrt(N0/2),seed) + + # RX + metrics_in = trellis.metrics_f(fi.O(),dimensionality,constellation,trellis.TRELLIS_EUCLIDEAN) # data preprocessing to generate metrics for innner Viterbi + gnd = gr.vector_source_f([0],True); + siso_in = trellis.siso_f(fi,K,0,-1,True,False,trellis.TRELLIS_MIN_SUM) # Put -1 if the Initial/Final states are not set. + deinter = trellis.permutation(interleaver.K(),interleaver.DEINTER(),fi.I(),gr.sizeof_float) + va_out = trellis.viterbi_s(fo,K,0,-1) # Put -1 if the Initial/Final states are not set. + fsmi2s = gr.unpacked_to_packed_ss(bitspersymbol,gr.GR_MSB_FIRST) # pack FSM input symbols to shorts + dst = gr.check_lfsr_32k_s() + + fg.connect (src,src_head,s2fsmi,enc_out,inter,enc_in,mod) + fg.connect (mod,(add,0)) + fg.connect (noise,(add,1)) + fg.connect (add,metrics_in) + fg.connect (gnd,(siso_in,0)) + fg.connect (metrics_in,(siso_in,1)) + fg.connect (siso_in,deinter,va_out,fsmi2s,dst) + + fg.run() + + ntotal = dst.ntotal () + nright = dst.nright () + runlength = dst.runlength () + return (ntotal,ntotal-nright) + + +def main(args): + nargs = len (args) + if nargs == 4: + fname_out=args[0] + fname_in=args[1] + esn0_db=float(args[2]) # Es/No in dB + rep=int(args[3]) # number of times the experiment is run to collect enough errors + else: + sys.stderr.write ('usage: test_tcm.py fsm_name_out fsm_fname_in Es/No_db repetitions\n') + sys.exit (1) + + # system parameters + Kb=1024*16 # packet size in bits (make it multiple of 16 so it can be packed in a short) + fo=trellis.fsm(fname_out) # get the outer FSM specification from a file + fi=trellis.fsm(fname_in) # get the innner FSM specification from a file + bitspersymbol = int(round(math.log(fo.I())/math.log(2))) # bits per FSM input symbol + if fo.O() != fi.I(): + sys.stderr.write ('Incompatible cardinality between outer and inner FSM.\n') + sys.exit (1) + K=Kb/bitspersymbol # packet size in trellis steps + interleaver=trellis.interleaver(K,666) # construct a random interleaver + modulation = fsm_utils.psk8 # see fsm_utlis.py for available predefined modulations + dimensionality = modulation[0] + constellation = modulation[1] + if len(constellation)/dimensionality != fi.O(): + sys.stderr.write ('Incompatible FSM output cardinality and modulation size.\n') + sys.exit (1) + # calculate average symbol energy + Es = 0 + for i in range(len(constellation)): + Es = Es + constellation[i]**2 + Es = Es / (len(constellation)/dimensionality) + N0=Es/pow(10.0,esn0_db/10.0); # calculate noise variance + + + tot_s=0 # total number of transmitted shorts + terr_s=0 # total number of shorts in error + terr_p=0 # total number of packets in error + for i in range(rep): + (s,e)=run_test(fo,fi,interleaver,Kb,bitspersymbol,K,dimensionality,constellation,N0,-long(666+i)) # run experiment with different seed to get different noise realizations + tot_s=tot_s+s + terr_s=terr_s+e + terr_p=terr_p+(terr_s!=0) + if ((i+1)%100==0) : # display progress + print i+1,terr_p, '%.2e' % ((1.0*terr_p)/(i+1)),tot_s,terr_s, '%.2e' % ((1.0*terr_s)/tot_s) + # estimate of the (short or bit) error rate + print rep,terr_p, '%.2e' % ((1.0*terr_p)/(i+1)),tot_s,terr_s, '%.2e' % ((1.0*terr_s)/tot_s) + + + +if __name__ == '__main__': + main (sys.argv[1:]) diff --git a/gnuradio-examples/python/channel-coding/test_sccc_turbo.py b/gnuradio-examples/python/channel-coding/test_sccc_turbo.py new file mode 100755 index 000000000..cdd1ad8b0 --- /dev/null +++ b/gnuradio-examples/python/channel-coding/test_sccc_turbo.py @@ -0,0 +1,139 @@ +#!/usr/bin/env python + +from gnuradio import gr +from gnuradio import audio +from gnuradio import trellis +from gnuradio import eng_notation +import math +import sys +import random +import fsm_utils + + + +def make_rx(fg,fo,fi,dimensionality,constellation,K,interleaver,IT,Es,N0,type): + metrics_in = trellis.metrics_f(fi.O(),dimensionality,constellation,trellis.TRELLIS_EUCLIDEAN) # data preprocessing to generate metrics for innner Viterbi + scale = gr.multiply_const_ff(1.0/N0) + gnd = gr.vector_source_f([0],True); + + inter=[] + deinter=[] + siso_in=[] + siso_out=[] + + for it in range(IT-1): + inter.append( trellis.permutation(interleaver.K(),interleaver.INTER(),fi.I(),gr.sizeof_float) ) + siso_in.append( trellis.siso_f(fi,K,0,3,True,False,type) ) + deinter.append( trellis.permutation(interleaver.K(),interleaver.DEINTER(),fi.I(),gr.sizeof_float) ) + siso_out.append( trellis.siso_f(fo,K,0,3,False,True,type) ) + fg.connect (inter[it],(siso_in[it],0)) + fg.connect (gnd,(siso_out[it],0)) + fg.connect (siso_in[it],deinter[it],(siso_out[it],1)) + + inter.append( trellis.permutation(interleaver.K(),interleaver.INTER(),fi.I(),gr.sizeof_float) ) + siso_in.append( trellis.siso_f(fi,K,0,-1,True,False,type) ) + deinter.append( trellis.permutation(interleaver.K(),interleaver.DEINTER(),fi.I(),gr.sizeof_float) ) + siso_out.append( trellis.viterbi_s(fo,K,0,-1) ) + fg.connect (inter[IT-1],(siso_in[IT-1],0)) + fg.connect (siso_in[IT-1],deinter[IT-1],siso_out[IT-1]) + + # connect first stage + fg.connect (gnd,inter[0]) + fg.connect (metrics_in,scale) + fg.connect (scale,(siso_in[0],1)) + for it in range(IT-1): + fg.connect (siso_out[it],inter[it+1]) + fg.connect (metrics_in,(siso_in[it+1],1)) + return (metrics_in,siso_out[IT-1]) + + +def run_test (fo,fi,interleaver,Kb,bitspersymbol,K,dimensionality,constellation,Es,N0,IT,seed): + fg = gr.flow_graph () + + + # TX + src = gr.lfsr_32k_source_s() + src_head = gr.head (gr.sizeof_short,Kb/16) # packet size in shorts + s2fsmi = gr.packed_to_unpacked_ss(bitspersymbol,gr.GR_MSB_FIRST) # unpack shorts to symbols compatible with the outer FSM input cardinality + enc_out = trellis.encoder_ss(fo,0) # initial state = 0 + inter = trellis.permutation(interleaver.K(),interleaver.INTER(),1,gr.sizeof_short) + enc_in = trellis.encoder_ss(fi,0) # initial state = 0 + mod = gr.chunks_to_symbols_sf(constellation,dimensionality) + + # CHANNEL + add = gr.add_ff() + noise = gr.noise_source_f(gr.GR_GAUSSIAN,math.sqrt(N0/2),seed) + + # RX + (head,tail) = make_rx(fg,fo,fi,dimensionality,constellation,K,interleaver,IT,Es,N0,trellis.TRELLIS_MIN_SUM) + #(head,tail) = make_rx(fg,fo,fi,dimensionality,constellation,K,interleaver,IT,Es,N0,trellis.TRELLIS_SUM_PRODUCT) + fsmi2s = gr.unpacked_to_packed_ss(bitspersymbol,gr.GR_MSB_FIRST) # pack FSM input symbols to shorts + dst = gr.check_lfsr_32k_s() + + fg.connect (src,src_head,s2fsmi,enc_out,inter,enc_in,mod) + fg.connect (mod,(add,0)) + fg.connect (noise,(add,1)) + fg.connect (add,head) + fg.connect (tail,fsmi2s,dst) + + fg.run() + + #print enc_out.ST(), enc_in.ST() + + ntotal = dst.ntotal () + nright = dst.nright () + runlength = dst.runlength () + return (ntotal,ntotal-nright) + + +def main(args): + nargs = len (args) + if nargs == 4: + fname_out=args[0] + fname_in=args[1] + esn0_db=float(args[2]) # Es/No in dB + rep=int(args[3]) # number of times the experiment is run to collect enough errors + else: + sys.stderr.write ('usage: test_tcm.py fsm_name_out fsm_fname_in Es/No_db repetitions\n') + sys.exit (1) + + # system parameters + Kb=1024*16 # packet size in bits (make it multiple of 16 so it can be packed in a short) + fo=trellis.fsm(fname_out) # get the outer FSM specification from a file + fi=trellis.fsm(fname_in) # get the innner FSM specification from a file + bitspersymbol = int(round(math.log(fo.I())/math.log(2))) # bits per FSM input symbol + if fo.O() != fi.I(): + sys.stderr.write ('Incompatible cardinality between outer and inner FSM.\n') + sys.exit (1) + K=Kb/bitspersymbol # packet size in trellis steps + interleaver=trellis.interleaver(K,666) # construct a random interleaver + modulation = fsm_utils.psk8 # see fsm_utlis.py for available predefined modulations + dimensionality = modulation[0] + constellation = modulation[1] + if len(constellation)/dimensionality != fi.O(): + sys.stderr.write ('Incompatible FSM output cardinality and modulation size.\n') + sys.exit (1) + # calculate average symbol energy + Es = 0 + for i in range(len(constellation)): + Es = Es + constellation[i]**2 + Es = Es / (len(constellation)/dimensionality) + N0=Es/pow(10.0,esn0_db/10.0); # calculate noise variance + IT = 3 # number of turbo iterations + + tot_s=0 # total number of transmitted shorts + terr_s=0 # total number of shorts in error + terr_p=0 # total number of packets in error + for i in range(rep): + (s,e)=run_test(fo,fi,interleaver,Kb,bitspersymbol,K,dimensionality,constellation,Es,N0,IT,-long(666+i)) # run experiment with different seed to get different noise realizations + tot_s=tot_s+s + terr_s=terr_s+e + terr_p=terr_p+(terr_s!=0) + if ((i+1)%10==0): # display progress + print i+1,terr_p, '%.2e' % ((1.0*terr_p)/(i+1)),tot_s,terr_s, '%.2e' % ((1.0*terr_s)/tot_s) + # estimate of the (short or bit) error rate + print rep,terr_p, '%.2e' % ((1.0*terr_p)/(i+1)),tot_s,terr_s, '%.2e' % ((1.0*terr_s)/tot_s) + + +if __name__ == '__main__': + main (sys.argv[1:]) diff --git a/gnuradio-examples/python/channel-coding/test_tcm.py b/gnuradio-examples/python/channel-coding/test_tcm.py index 1f892ef99..f22501558 100755 --- a/gnuradio-examples/python/channel-coding/test_tcm.py +++ b/gnuradio-examples/python/channel-coding/test_tcm.py @@ -101,14 +101,17 @@ def main(args): tot_s=0 # total number of transmitted shorts terr_s=0 # total number of shorts in error + terr_p=0 # total number of packets in error for i in range(rep): (s,e)=run_test(f,Kb,bitspersymbol,K,dimensionality,constellation,N0,-long(666+i)) # run experiment with different seed to get different noise realizations tot_s=tot_s+s terr_s=terr_s+e - if (i%100==0) & (i>0): # display progress - print i,s,e,tot_s,terr_s, '%e' % ((1.0*terr_s)/tot_s) + terr_p=terr_p+(terr_s!=0) + if ((i+1)%100==0) : # display progress + print i+1,terr_p, '%.2e' % ((1.0*terr_p)/(i+1)),tot_s,terr_s, '%.2e' % ((1.0*terr_s)/tot_s) # estimate of the (short or bit) error rate - print tot_s,terr_s, '%e' % ((1.0*terr_s)/tot_s) + print rep,terr_p, '%.2e' % ((1.0*terr_p)/(i+1)),tot_s,terr_s, '%.2e' % ((1.0*terr_s)/tot_s) + if __name__ == '__main__': diff --git a/gnuradio-examples/python/channel-coding/test_tcm1.py b/gnuradio-examples/python/channel-coding/test_tcm1.py index e4f88d0b5..66d7131e3 100755 --- a/gnuradio-examples/python/channel-coding/test_tcm1.py +++ b/gnuradio-examples/python/channel-coding/test_tcm1.py @@ -102,17 +102,19 @@ def main(args): Es = Es / (len(constellation)/dimensionality) N0=Es/pow(10.0,esn0_db/10.0); # noise variance - - tot_s=0 - terr_s=0 + tot_s=0 # total number of transmitted shorts + terr_s=0 # total number of shorts in error + terr_p=0 # total number of packets in error for i in range(rep): (s,e)=run_test(f,Kb,bitspersymbol,K,dimensionality,constellation,N0,-long(666+i)) # run experiment with different seed to get different noise realizations tot_s=tot_s+s terr_s=terr_s+e - if (i%1==0) & (i>0): - print i,s,e,tot_s,terr_s, '%e' % ((1.0*terr_s)/tot_s) + terr_p=terr_p+(terr_s!=0) + if ((i+1)%1==0) : # display progress + print i+1,terr_p, '%.2e' % ((1.0*terr_p)/(i+1)),tot_s,terr_s, '%.2e' % ((1.0*terr_s)/tot_s) # estimate of the (short or bit) error rate - print tot_s,terr_s, '%e' % ((1.0*terr_s)/tot_s) + print rep,terr_p, '%.2e' % ((1.0*terr_p)/(i+1)),tot_s,terr_s, '%.2e' % ((1.0*terr_s)/tot_s) + if __name__ == '__main__': diff --git a/gnuradio-examples/python/channel-coding/test_tcm2.py b/gnuradio-examples/python/channel-coding/test_tcm2.py new file mode 100755 index 000000000..9680909ea --- /dev/null +++ b/gnuradio-examples/python/channel-coding/test_tcm2.py @@ -0,0 +1,116 @@ +#!/usr/bin/env python + +from gnuradio import gr +from gnuradio import audio +from gnuradio import trellis +from gnuradio import eng_notation +import math +import sys +import random +import fsm_utils + +def run_test (f,Kb,bitspersymbol,K,dimensionality,constellation,N0,seed): + fg = gr.flow_graph () + + + # TX + #packet = [0]*Kb + #for i in range(Kb-1*16): # last 16 bits = 0 to drive the final state to 0 + #packet[i] = random.randint(0, 1) # random 0s and 1s + #src = gr.vector_source_s(packet,False) + src = gr.lfsr_32k_source_s() + src_head = gr.head (gr.sizeof_short,Kb/16) # packet size in shorts + #b2s = gr.unpacked_to_packed_ss(1,gr.GR_MSB_FIRST) # pack bits in shorts + s2fsmi = gr.packed_to_unpacked_ss(bitspersymbol,gr.GR_MSB_FIRST) # unpack shorts to symbols compatible with the FSM input cardinality + enc = trellis.encoder_ss(f,0) # initial state = 0 + mod = gr.chunks_to_symbols_sf(constellation,dimensionality) + + # CHANNEL + add = gr.add_ff() + noise = gr.noise_source_f(gr.GR_GAUSSIAN,math.sqrt(N0/2),seed) + + # RX + metrics = trellis.metrics_f(f.O(),dimensionality,constellation,trellis.TRELLIS_EUCLIDEAN) # data preprocessing to generate metrics for Viterbi + va = trellis.viterbi_s(f,K,0,-1) # Put -1 if the Initial/Final states are not set. + fsmi2s = gr.unpacked_to_packed_ss(bitspersymbol,gr.GR_MSB_FIRST) # pack FSM input symbols to shorts + #s2b = gr.packed_to_unpacked_ss(1,gr.GR_MSB_FIRST) # unpack shorts to bits + #dst = gr.vector_sink_s(); + dst = gr.check_lfsr_32k_s() + + + fg.connect (src,src_head,s2fsmi,enc,mod) + #fg.connect (src,b2s,s2fsmi,enc,mod) + fg.connect (mod,(add,0)) + fg.connect (noise,(add,1)) + fg.connect (add,metrics) + fg.connect (metrics,va,fsmi2s,dst) + #fg.connect (metrics,va,fsmi2s,s2b,dst) + + + fg.run() + + # A bit of cheating: run the program once and print the + # final encoder state.. + # Then put it as the last argument in the viterbi block + #print "final state = " , enc.ST() + + ntotal = dst.ntotal () + nright = dst.nright () + runlength = dst.runlength () + #ntotal = len(packet) + #if len(dst.data()) != ntotal: + #print "Error: not enough data\n" + #nright = 0; + #for i in range(ntotal): + #if packet[i]==dst.data()[i]: + #nright=nright+1 + #else: + #print "Error in ", i + return (ntotal,ntotal-nright) + + + + +def main(args): + nargs = len (args) + if nargs == 2: + esn0_db=float(args[0]) # Es/No in dB + rep=int(args[1]) # number of times the experiment is run to collect enough errors + else: + sys.stderr.write ('usage: test_tcm2.py Es/No_db repetitions\n') + sys.exit (1) + + # system parameters + f=trellis.fsm(1,2,[5,7]) # generate FSM specification from the generator matrix + Kb=1024*16 # packet size in bits (make it multiple of 16 so it can be packed in a short) + bitspersymbol = int(round(math.log(f.I())/math.log(2))) # bits per FSM input symbol + K=Kb/bitspersymbol # packet size in trellis steps + modulation = fsm_utils.psk4 # see fsm_utlis.py for available predefined modulations + dimensionality = modulation[0] + constellation = modulation[1] + if len(constellation)/dimensionality != f.O(): + sys.stderr.write ('Incompatible FSM output cardinality and modulation size.\n') + sys.exit (1) + # calculate average symbol energy + Es = 0 + for i in range(len(constellation)): + Es = Es + constellation[i]**2 + Es = Es / (len(constellation)/dimensionality) + N0=Es/pow(10.0,esn0_db/10.0); # calculate noise variance + + tot_s=0 # total number of transmitted shorts + terr_s=0 # total number of shorts in error + terr_p=0 # total number of packets in error + for i in range(rep): + (s,e)=run_test(f,Kb,bitspersymbol,K,dimensionality,constellation,N0,-long(666+i)) # run experiment with different seed to get different noise realizations + tot_s=tot_s+s + terr_s=terr_s+e + terr_p=terr_p+(terr_s!=0) + if ((i+1)%100==0) : # display progress + print i+1,terr_p, '%.2e' % ((1.0*terr_p)/(i+1)),tot_s,terr_s, '%.2e' % ((1.0*terr_s)/tot_s) + # estimate of the (short or bit) error rate + print rep,terr_p, '%.2e' % ((1.0*terr_p)/(i+1)),tot_s,terr_s, '%.2e' % ((1.0*terr_s)/tot_s) + + +if __name__ == '__main__': + main (sys.argv[1:]) diff --git a/gnuradio-examples/python/channel-coding/test_tcm_combined.py b/gnuradio-examples/python/channel-coding/test_tcm_combined.py index ce0863183..37f38ef1a 100755 --- a/gnuradio-examples/python/channel-coding/test_tcm_combined.py +++ b/gnuradio-examples/python/channel-coding/test_tcm_combined.py @@ -80,17 +80,19 @@ def main(args): Es = Es / (len(constellation)/dimensionality) N0=Es/pow(10.0,esn0_db/10.0); # noise variance - - tot_s=0 - terr_s=0 + tot_s=0 # total number of transmitted shorts + terr_s=0 # total number of shorts in error + terr_p=0 # total number of packets in error for i in range(rep): (s,e)=run_test(f,Kb,bitspersymbol,K,dimensionality,constellation,N0,-long(666+i)) # run experiment with different seed to get different noise realizations tot_s=tot_s+s terr_s=terr_s+e - if (i%100==0) & (i>0): - print i,s,e,tot_s,terr_s, '%e' % ((1.0*terr_s)/tot_s) - # estimate of the (short) error rate - print tot_s,terr_s, '%e' % ((1.0*terr_s)/tot_s) + terr_p=terr_p+(terr_s!=0) + if ((i+1)%100==0) : # display progress + print i+1,terr_p, '%.2e' % ((1.0*terr_p)/(i+1)),tot_s,terr_s, '%.2e' % ((1.0*terr_s)/tot_s) + # estimate of the (short or bit) error rate + print rep,terr_p, '%.2e' % ((1.0*terr_p)/(i+1)),tot_s,terr_s, '%.2e' % ((1.0*terr_s)/tot_s) + if __name__ == '__main__': diff --git a/gnuradio-examples/python/channel-coding/test_tcm_parallel.py b/gnuradio-examples/python/channel-coding/test_tcm_parallel.py index 230bf4b98..f9dcb5852 100755 --- a/gnuradio-examples/python/channel-coding/test_tcm_parallel.py +++ b/gnuradio-examples/python/channel-coding/test_tcm_parallel.py @@ -15,7 +15,7 @@ def run_test (f,Kb,bitspersymbol,K,dimensionality,constellation,N0,seed,P): src = gr.lfsr_32k_source_s() src_head = gr.head (gr.sizeof_short,Kb/16*P) # packet size in shorts s2fsmi=gr.packed_to_unpacked_ss(bitspersymbol,gr.GR_MSB_FIRST) # unpack shorts to symbols compatible with the FSM input cardinality - s2p = gr.stream_to_streams(2,P) # serial to parallel + s2p = gr.stream_to_streams(gr.sizeof_short,P) # serial to parallel enc = trellis.encoder_ss(f,0) # initiali state = 0 mod = gr.chunks_to_symbols_sf(constellation,dimensionality) @@ -26,11 +26,10 @@ def run_test (f,Kb,bitspersymbol,K,dimensionality,constellation,N0,seed,P): add.append(gr.add_ff()) noise.append(gr.noise_source_f(gr.GR_GAUSSIAN,math.sqrt(N0/2),seed)) - # RX metrics = trellis.metrics_f(f.O(),dimensionality,constellation,trellis.TRELLIS_EUCLIDEAN) # data preprocessing to generate metrics for Viterbi va = trellis.viterbi_s(f,K,0,-1) # Put -1 if the Initial/Final states are not set. - p2s = gr.streams_to_stream(2,P) # parallel to serial + p2s = gr.streams_to_stream(gr.sizeof_short,P) # parallel to serial fsmi2s=gr.unpacked_to_packed_ss(bitspersymbol,gr.GR_MSB_FIRST) # pack FSM input symbols to shorts dst = gr.check_lfsr_32k_s() @@ -90,14 +89,16 @@ def main(args): tot_s=0 # total number of transmitted shorts terr_s=0 # total number of shorts in error + terr_p=0 # total number of packets in error for i in range(rep): (s,e)=run_test(f,Kb,bitspersymbol,K,dimensionality,constellation,N0,-long(666+i),P) # run experiment with different seed to get different noise realizations tot_s=tot_s+s terr_s=terr_s+e - if (i%10==0) & (i>0): # display progress - print i,s,e,tot_s,terr_s, '%e' % ((1.0*terr_s)/tot_s) + terr_p=terr_p+(terr_s!=0) + if ((i+1)%100==0) : # display progress + print i+1,terr_p, '%.2e' % ((1.0*terr_p)/(i+1)),tot_s,terr_s, '%.2e' % ((1.0*terr_s)/tot_s) # estimate of the (short or bit) error rate - print tot_s,terr_s, '%e' % ((1.0*terr_s)/tot_s) + print rep,terr_p, '%.2e' % ((1.0*terr_p)/(i+1)),tot_s,terr_s, '%.2e' % ((1.0*terr_s)/tot_s) if __name__ == '__main__': |