1 /*
2  * Copyright (c) 2007 - 2015 Joseph Gaeddert
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), to deal
6  * in the Software without restriction, including without limitation the rights
7  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8  * copies of the Software, and to permit persons to whom the Software is
9  * furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20  * THE SOFTWARE.
21  */
22 
23 //
24 // m-sequence
25 //
26 
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <math.h>
31 
32 #include "liquid.internal.h"
33 
34 #define LIQUID_MIN_MSEQUENCE_M  2
35 #define LIQUID_MAX_MSEQUENCE_M  15
36 
37 // msequence structure
38 //  Note that 'g' is stored as the default polynomial shifted to the
39 //  right by one bit; this bit is implied and not actually used in
40 //  the shift register's feedback bit computation.
41 struct msequence_s msequence_default[16] = {
42 //   m,     g,      a,      n,      v,      b
43     {0,     0,      1,      0,      1,      0}, // dummy placeholder
44     {0,     0,      1,      0,      1,      0}, // dummy placeholder
45     {2,     0x0003, 0x0002, 3,      0x0002, 0},
46     {3,     0x0005, 0x0004, 7,      0x0004, 0},
47     {4,     0x0009, 0x0008, 15,     0x0008, 0},
48     {5,     0x0012, 0x0010, 31,     0x0010, 0},
49     {6,     0x0021, 0x0020, 63,     0x0020, 0},
50     {7,     0x0044, 0x0040, 127,    0x0040, 0},
51     {8,     0x008E, 0x0080, 255,    0x0080, 0},
52     {9,     0x0108, 0x0100, 511,    0x0100, 0},
53     {10,    0x0204, 0x0200, 1023,   0x0200, 0},
54     {11,    0x0402, 0x0400, 2047,   0x0400, 0},
55     {12,    0x0829, 0x0800, 4095,   0x0800, 0},
56     {13,    0x100d, 0x1000, 8191,   0x1000, 0},
57     {14,    0x2015, 0x2000, 16383,  0x2000, 0},
58     {15,    0x4001, 0x4000, 32767,  0x4000, 0}
59 };
60 
61 // create a maximal-length sequence (m-sequence) object with
62 // an internal shift register length of _m bits.
63 //  _m      :   generator polynomial length, sequence length is (2^m)-1
64 //  _g      :   generator polynomial, starting with most-significant bit
65 //  _a      :   initial shift register state, default: 000...001
msequence_create(unsigned int _m,unsigned int _g,unsigned int _a)66 msequence msequence_create(unsigned int _m,
67                            unsigned int _g,
68                            unsigned int _a)
69 {
70     // validate input
71     if (_m > LIQUID_MAX_MSEQUENCE_M || _m < LIQUID_MIN_MSEQUENCE_M) {
72         fprintf(stderr,"error: msequence_create(), m not in range\n");
73         exit(1);
74     }
75 
76     // allocate memory for msequence object
77     msequence ms = (msequence) malloc(sizeof(struct msequence_s));
78 
79     // set internal values
80     ms->m = _m;         // generator polynomial length
81     ms->g = _g >> 1;    // generator polynomial (clip off most significant bit)
82 
83     // initialize state register, reversing order
84     // 0001 -> 1000
85     unsigned int i;
86     ms->a = 0;
87     for (i=0; i<ms->m; i++) {
88         ms->a <<= 1;
89         ms->a |= (_a & 0x01);
90         _a >>= 1;
91     }
92 
93     ms->n = (1<<_m)-1;  // sequence length, (2^m)-1
94     ms->v = ms->a;      // shift register
95     ms->b = 0;          // return bit
96 
97     return ms;
98 }
99 
100 
101 // create a maximal-length sequence (m-sequence) object from a generator polynomial
msequence_create_genpoly(unsigned int _g)102 msequence msequence_create_genpoly(unsigned int _g)
103 {
104     unsigned int t = liquid_msb_index(_g);
105 
106     // validate input
107     if (t < 2) {
108         fprintf(stderr,"error: msequence_create_genpoly(), invalid generator polynomial: 0x%x\n", _g);
109         exit(1);
110     }
111 
112     // compute derived values
113     unsigned int m = t - 1; // m-sequence shift register length
114     unsigned int a = 1;     // m-sequence initial state
115 
116     // generate object and return
117     return msequence_create(m,_g,a);
118 }
119 
120 // creates a default maximal-length sequence
msequence_create_default(unsigned int _m)121 msequence msequence_create_default(unsigned int _m)
122 {
123     // validate input
124     if (_m > LIQUID_MAX_MSEQUENCE_M || _m < LIQUID_MIN_MSEQUENCE_M) {
125         fprintf(stderr,"error: msequence_create(), m not in range\n");
126         exit(1);
127     }
128 
129     // allocate memory for msequence object
130     msequence ms = (msequence) malloc(sizeof(struct msequence_s));
131 
132     // copy default sequence
133     memmove(ms, &msequence_default[_m], sizeof(struct msequence_s));
134 
135     // return
136     return ms;
137 }
138 
139 // destroy an msequence object, freeing all internal memory
msequence_destroy(msequence _ms)140 void msequence_destroy(msequence _ms)
141 {
142     free(_ms);
143 }
144 
145 // prints the sequence's internal state to the screen
msequence_print(msequence _m)146 void msequence_print(msequence _m)
147 {
148     unsigned int i;
149 
150     printf("msequence: m=%u (n=%u):\n", _m->m, _m->n);
151 
152     // print shift register
153     printf("    shift register: ");
154     for (i=0; i<_m->m; i++)
155         printf("%c", ((_m->v) >> (_m->m-i-1)) & 0x01 ? '1' : '0');
156     printf("\n");
157 
158     // print generator polynomial
159     printf("    generator poly: ");
160     for (i=0; i<_m->m; i++)
161         printf("%c", ((_m->g) >> (_m->m-i-1)) & 0x01 ? '1' : '0');
162     printf("\n");
163 }
164 
165 // advance msequence on shift register, returning output bit
msequence_advance(msequence _ms)166 unsigned int msequence_advance(msequence _ms)
167 {
168     // compute return bit as binary dot product between the
169     // internal shift register and the generator polynomial
170     _ms->b = liquid_bdotprod( _ms->v, _ms->g );
171 
172     _ms->v <<= 1;       // shift internal register
173     _ms->v |= _ms->b;   // push bit onto register
174     _ms->v &= _ms->n;   // apply mask to register
175 
176     return _ms->b;      // return result
177 }
178 
179 
180 // generate pseudo-random symbol from shift register
181 //  _ms     :   m-sequence object
182 //  _bps    :   bits per symbol of output
msequence_generate_symbol(msequence _ms,unsigned int _bps)183 unsigned int msequence_generate_symbol(msequence _ms,
184                                        unsigned int _bps)
185 {
186     unsigned int i;
187     unsigned int s = 0;
188     for (i=0; i<_bps; i++) {
189         s <<= 1;
190         s |= msequence_advance(_ms);
191     }
192     return s;
193 }
194 
195 // reset msequence shift register to original state, typically '1'
msequence_reset(msequence _ms)196 void msequence_reset(msequence _ms)
197 {
198     _ms->v = _ms->a;
199 }
200 
201 // initialize a bsequence object on an msequence object
202 //  _bs     :   bsequence object
203 //  _ms     :   msequence object
bsequence_init_msequence(bsequence _bs,msequence _ms)204 void bsequence_init_msequence(bsequence _bs,
205                               msequence _ms)
206 {
207 #if 0
208     if (_ms->n > LIQUID_MAX_MSEQUENCE_LENGTH) {
209         fprintf(stderr,"error: bsequence_init_msequence(), msequence length exceeds maximum\n");
210         exit(1);
211     }
212 #endif
213 
214     // clear binary sequence
215     bsequence_reset(_bs);
216 
217     unsigned int i;
218     for (i=0; i<(_ms->n); i++)
219         bsequence_push(_bs, msequence_advance(_ms));
220 }
221 
222 // get the length of the sequence
msequence_get_length(msequence _ms)223 unsigned int msequence_get_length(msequence _ms)
224 {
225     return _ms->n;
226 }
227 
228 // get the internal state of the sequence
msequence_get_state(msequence _ms)229 unsigned int msequence_get_state(msequence _ms)
230 {
231     return _ms->v;
232 }
233 
234 // set the internal state of the sequence
msequence_set_state(msequence _ms,unsigned int _a)235 void msequence_set_state(msequence    _ms,
236                          unsigned int _a)
237 {
238     // set internal state
239     // NOTE: if state is set to zero, this will lock the sequence generator,
240     //       but let the user set this value if they wish
241     _ms->v = _a;
242 }
243 
244