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