3 # Copyright 2004 Free Software Foundation, Inc.
5 # This file is part of GNU Radio
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)
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.
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.
31 from gnuradio import trellis
35 ######################################################################
36 # Decimal to any base conversion.
37 # Convert 'num' to a list of 'l' numbers representing 'num'
38 # to base 'base' (most significant symbol first).
39 ######################################################################
40 def dec2base(num,base,l):
47 print 'Number ', num, ' requires more than ', l, 'digits.'
51 ######################################################################
52 # Conversion from any base to decimal.
53 # Convert a list 's' of symbols to a decimal number
54 # (most significant symbol first)
55 ######################################################################
58 for i in range(len(s)):
65 ######################################################################
66 # Automatically generate the lookup table that maps the FSM outputs
67 # to channel inputs corresponding to a channel 'channel' and a modulation
68 # 'mod'. Optional normalization of channel to unit energy.
69 # This table is used by the 'metrics' block to translate
70 # channel outputs to metrics for use with the Viterbi algorithm.
71 # Limitations: currently supports only one-dimensional modulations.
72 ######################################################################
73 def make_isi_lookup(mod,channel,normalize):
75 constellation = mod[1]
79 for i in range(len(channel)):
81 for i in range(len(channel)):
82 channel[i] = channel[i]/math.sqrt(p)
84 lookup=range(len(constellation)**len(channel))
85 for o in range(len(constellation)**len(channel)):
86 ss=dec2base(o,len(constellation),len(channel))
88 for i in range(len(channel)):
89 ll=ll+constellation[ss[i]]*channel[i]
98 ######################################################################
99 # Automatically generate the signals appropriate for CPM
101 # This decomposition is based on the paper by B. Rimoldi
102 # "A decomposition approach to CPM", IEEE Trans. Info Theory, March 1988
103 # See also my own notes at http://www.eecs.umich.edu/~anastas/docs/cpm.pdf
104 ######################################################################
105 def make_cpm_signals(K,P,M,L,q,frac):
110 dt=0.0; # maybe start at t=0.5
111 t=(dt+numpy.arange(0,Q))/Q
115 w=math.pi*h*(M-1)*t-2*math.pi*h*(M-1)*qq+math.pi*h*(L-1)*(M-1)
118 PSI=numpy.empty((X,Q))
121 xv=numpy.append(xv, x%P)
124 qq1=qq1+xv[m]*q[m*Q:m*Q+Q]
125 psi=2*math.pi*h*xv[-1]+4*math.pi*h*qq1+w
128 PSI = numpy.transpose(PSI)
129 SS=numpy.exp(1j*PSI) # contains all signals as columns
133 # Now we need to orthogonalize the signals
134 F = scipy.linalg.orth(SS) # find an orthonormal basis for SS
135 #print numpy.dot(numpy.transpose(F.conjugate()),F) # check for orthonormality
136 S = numpy.dot(numpy.transpose(F.conjugate()),SS)
140 # We only want to keep those dimensions that contain most
141 # of the energy of the overall constellation (eg, frac=0.9 ==> 90%)
142 # evaluate mean energy in each dimension
143 E=numpy.sum(numpy.absolute(S)**2,axis=1)/Q
147 Esi = numpy.argsort(-E)
150 Ecum=numpy.cumsum(Es)
152 v0=numpy.searchsorted(Ecum,frac)
156 Ff=numpy.transpose(numpy.transpose(F)[Esi[0:v0+1]])
162 return (f0,SS,S,F,Sf,Ff,N)
168 ######################################################################
169 # A list of common modulations.
170 # Format: (dimensionality,constellation)
171 ######################################################################
173 pam4 = (1,[-3, -1, 3, 1]) # includes Gray mapping
174 pam8 = (1,[-7, -5, -3, -1, 1, 3, 5, 7])
179 -1, 0]) # includes Gray mapping
180 psk8=(2,[math.cos(2*math.pi*0/8), math.sin(2*math.pi*0/8), \
181 math.cos(2*math.pi*1/8), math.sin(2*math.pi*1/8), \
182 math.cos(2*math.pi*2/8), math.sin(2*math.pi*2/8), \
183 math.cos(2*math.pi*3/8), math.sin(2*math.pi*3/8), \
184 math.cos(2*math.pi*4/8), math.sin(2*math.pi*4/8), \
185 math.cos(2*math.pi*5/8), math.sin(2*math.pi*5/8), \
186 math.cos(2*math.pi*6/8), math.sin(2*math.pi*6/8), \
187 math.cos(2*math.pi*7/8), math.sin(2*math.pi*7/8)])
191 orth4=(4,[1, 0, 0, 0, \
196 ######################################################################
197 # A list of channels to be tested
198 ######################################################################
200 # C test channel (J. Proakis, Digital Communications, McGraw-Hill Inc., 2001)
201 c_channel = [0.227, 0.460, 0.688, 0.460, 0.227]
212 if __name__ == '__main__':
213 f1=trellis.fsm('fsm_files/awgn1o2_4.fsm')
214 #f2=trellis.fsm('fsm_files/awgn2o3_4.fsm')
215 #print f1.I(), f1.S(), f1.O()
218 #print f2.I(), f2.S(), f2.O()
221 ##f1.write_trellis_svg('f1.svg',4)
222 #f2.write_trellis_svg('f2.svg',4)
223 #f=fsm_concatenate(f1,f2)
226 #print "----------\n"
227 #print f.I(), f.S(), f.O()
230 #f.write_trellis_svg('f.svg',4)
232 q=numpy.arange(0,8)/(2.0*8)
233 (f0,SS,S,F,Sf,Ff,N) = make_cpm_signals(1,2,2,1,q,0.99)