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 // ofdmframe data, methods common to both generator/synchronizer
25 // objects
26 // - physical layer convergence procedure (PLCP)
27 //
28
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <math.h>
32
33 #include "liquid.internal.h"
34
35 // generate short sequence symbols
36 // _p : subcarrier allocation array
37 // _M : total number of subcarriers
38 // _S0 : output symbol (freq)
39 // _s0 : output symbol (time)
40 // _M_S0 : total number of enabled subcarriers in S0
ofdmframe_init_S0(unsigned char * _p,unsigned int _M,float complex * _S0,float complex * _s0,unsigned int * _M_S0)41 void ofdmframe_init_S0(unsigned char * _p,
42 unsigned int _M,
43 float complex * _S0,
44 float complex * _s0,
45 unsigned int * _M_S0)
46 {
47 unsigned int i;
48
49 // compute m-sequence length
50 unsigned int m = liquid_nextpow2(_M);
51 if (m < 4) m = 4;
52 else if (m > 8) m = 8;
53
54 // generate m-sequence generator object
55 msequence ms = msequence_create_default(m);
56
57 unsigned int s;
58 unsigned int M_S0 = 0;
59
60 // short sequence
61 for (i=0; i<_M; i++) {
62 // generate symbol
63 //s = msequence_generate_symbol(ms,1);
64 s = msequence_generate_symbol(ms,3) & 0x01;
65
66 if (_p[i] == OFDMFRAME_SCTYPE_NULL) {
67 // NULL subcarrier
68 _S0[i] = 0.0f;
69 } else {
70 if ( (i%2) == 0 ) {
71 // even subcarrer
72 _S0[i] = s ? 1.0f : -1.0f;
73 M_S0++;
74 } else {
75 // odd subcarrer (ignore)
76 _S0[i] = 0.0f;
77 }
78 }
79 }
80
81 // destroy objects
82 msequence_destroy(ms);
83
84 // ensure at least one subcarrier was enabled
85 if (M_S0 == 0) {
86 fprintf(stderr,"error: ofdmframe_init_S0(), no subcarriers enabled; check allocation\n");
87 exit(1);
88 }
89
90 // set return value(s)
91 *_M_S0 = M_S0;
92
93 // run inverse fft to get time-domain sequence
94 fft_run(_M, _S0, _s0, LIQUID_FFT_BACKWARD, 0);
95
96 // normalize time-domain sequence level
97 float g = 1.0f / sqrtf(M_S0);
98 for (i=0; i<_M; i++)
99 _s0[i] *= g;
100 }
101
102
103 // generate long sequence symbols
104 // _p : subcarrier allocation array
105 // _M : total number of subcarriers
106 // _S1 : output symbol (freq)
107 // _s1 : output symbol (time)
108 // _M_S1 : total number of enabled subcarriers in S1
ofdmframe_init_S1(unsigned char * _p,unsigned int _M,float complex * _S1,float complex * _s1,unsigned int * _M_S1)109 void ofdmframe_init_S1(unsigned char * _p,
110 unsigned int _M,
111 float complex * _S1,
112 float complex * _s1,
113 unsigned int * _M_S1)
114 {
115 unsigned int i;
116
117 // compute m-sequence length
118 unsigned int m = liquid_nextpow2(_M);
119 if (m < 4) m = 4;
120 else if (m > 8) m = 8;
121
122 // increase m such that the resulting S1 sequence will
123 // differ significantly from S0 with the same subcarrier
124 // allocation array
125 m++;
126
127 // generate m-sequence generator object
128 msequence ms = msequence_create_default(m);
129
130 unsigned int s;
131 unsigned int M_S1 = 0;
132
133 // long sequence
134 for (i=0; i<_M; i++) {
135 // generate symbol
136 //s = msequence_generate_symbol(ms,1);
137 s = msequence_generate_symbol(ms,3) & 0x01;
138
139 if (_p[i] == OFDMFRAME_SCTYPE_NULL) {
140 // NULL subcarrier
141 _S1[i] = 0.0f;
142 } else {
143 _S1[i] = s ? 1.0f : -1.0f;
144 M_S1++;
145 }
146 }
147
148 // destroy objects
149 msequence_destroy(ms);
150
151 // ensure at least one subcarrier was enabled
152 if (M_S1 == 0) {
153 fprintf(stderr,"error: ofdmframe_init_S1(), no subcarriers enabled; check allocation\n");
154 exit(1);
155 }
156
157 // set return value(s)
158 *_M_S1 = M_S1;
159
160 // run inverse fft to get time-domain sequence
161 fft_run(_M, _S1, _s1, LIQUID_FFT_BACKWARD, 0);
162
163 // normalize time-domain sequence level
164 float g = 1.0f / sqrtf(M_S1);
165 for (i=0; i<_M; i++)
166 _s1[i] *= g;
167 }
168
169 // initialize default subcarrier allocation
170 // _M : number of subcarriers
171 // _p : output subcarrier allocation array, [size: _M x 1]
172 //
173 // key: '.' (null), 'P' (pilot), '+' (data)
174 // .+++P+++++++P.........P+++++++P+++
175 //
ofdmframe_init_default_sctype(unsigned int _M,unsigned char * _p)176 void ofdmframe_init_default_sctype(unsigned int _M,
177 unsigned char * _p)
178 {
179 // validate input
180 if (_M < 6) {
181 fprintf(stderr,"warning: ofdmframe_init_default_sctype(), less than 6 subcarriers\n");
182 }
183
184 unsigned int i;
185 unsigned int M2 = _M/2;
186
187 // compute guard band
188 unsigned int G = _M / 10;
189 if (G < 2) G = 2;
190
191 // designate pilot spacing
192 unsigned int P = (_M > 34) ? 8 : 4;
193 unsigned int P2 = P/2;
194
195 // initialize as NULL
196 for (i=0; i<_M; i++)
197 _p[i] = OFDMFRAME_SCTYPE_NULL;
198
199 // upper band
200 for (i=1; i<M2-G; i++) {
201 if ( ((i+P2)%P) == 0 )
202 _p[i] = OFDMFRAME_SCTYPE_PILOT;
203 else
204 _p[i] = OFDMFRAME_SCTYPE_DATA;
205 }
206
207 // lower band
208 for (i=1; i<M2-G; i++) {
209 unsigned int k = _M - i;
210 if ( ((i+P2)%P) == 0 )
211 _p[k] = OFDMFRAME_SCTYPE_PILOT;
212 else
213 _p[k] = OFDMFRAME_SCTYPE_DATA;
214 }
215 }
216
217 // initialize default subcarrier allocation
218 // _M : number of subcarriers
219 // _f0 : lower frequency band, _f0 in [-0.5,0.5]
220 // _f1 : upper frequency band, _f1 in [-0.5,0.5]
221 // _p : output subcarrier allocation array, [size: _M x 1]
ofdmframe_init_sctype_range(unsigned int _M,float _f0,float _f1,unsigned char * _p)222 void ofdmframe_init_sctype_range(unsigned int _M,
223 float _f0,
224 float _f1,
225 unsigned char * _p)
226 {
227 // validate input
228 if (_M < 6) {
229 fprintf(stderr,"warning: ofdmframe_init_sctype_range(), less than 6 subcarriers\n");
230 } else if (_f0 < -0.5f || _f0 > 0.5f) {
231 fprintf(stderr,"error: ofdmframe_init_sctype_range(), lower frequency edge must be in [-0.5,0.5]\n");
232 exit(1);
233 } else if (_f1 < -0.5f || _f1 > 0.5f) {
234 fprintf(stderr,"error: ofdmframe_init_sctype_range(), upper frequency edge must be in [-0.5,0.5]\n");
235 exit(1);
236 } else if (_f0 >= _f1) {
237 fprintf(stderr,"error: ofdmframe_init_sctype_range(), lower frequency edge must be below upper edge\n");
238 exit(1);
239 }
240
241 // get relative edges
242 int M0 = (int)((_f0 + 0.5f) * _M); // lower subcarrier index
243 int M1 = (int)((_f1 + 0.5f) * _M); // upper subcarrier index
244 int Mp = M1 - M0;
245 if (Mp > (int)_M) {
246 Mp = (int)_M;
247 } else if (Mp < 6) {
248 fprintf(stderr,"warning: ofdmframe_init_sctype_range(), less than 6 subcarriers (effectively)\n");
249 exit(1);
250 }
251
252 // designate pilot spacing
253 unsigned int P = (Mp > 34) ? 8 : 4;
254
255 // upper band
256 int i;
257 for (i=0; i<(int)_M; i++) {
258 // shift
259 unsigned int k = ((unsigned int)i + _M/2) % _M;
260 if (i < M0 || i > M1) {
261 // guard band
262 _p[k] = OFDMFRAME_SCTYPE_NULL;
263 } else if ( (k%P)==0 ) {
264 _p[k] = OFDMFRAME_SCTYPE_PILOT;
265 } else {
266 _p[k] = OFDMFRAME_SCTYPE_DATA;
267 }
268 }
269 }
270
271 // validate subcarrier type (count number of null, pilot, and data
272 // subcarriers in the allocation)
273 // _p : subcarrier allocation array, [size: _M x 1]
274 // _M : number of subcarriers
275 // _M_null : output number of null subcarriers
276 // _M_pilot : output number of pilot subcarriers
277 // _M_data : output number of data subcarriers
ofdmframe_validate_sctype(unsigned char * _p,unsigned int _M,unsigned int * _M_null,unsigned int * _M_pilot,unsigned int * _M_data)278 void ofdmframe_validate_sctype(unsigned char * _p,
279 unsigned int _M,
280 unsigned int * _M_null,
281 unsigned int * _M_pilot,
282 unsigned int * _M_data)
283 {
284 // clear counters
285 unsigned int M_null = 0;
286 unsigned int M_pilot = 0;
287 unsigned int M_data = 0;
288
289 unsigned int i;
290 for (i=0; i<_M; i++) {
291 // update appropriate counters
292 if (_p[i] == OFDMFRAME_SCTYPE_NULL)
293 M_null++;
294 else if (_p[i] == OFDMFRAME_SCTYPE_PILOT)
295 M_pilot++;
296 else if (_p[i] == OFDMFRAME_SCTYPE_DATA)
297 M_data++;
298 else {
299 fprintf(stderr,"error: ofdmframe_validate_sctype(), invalid subcarrier type (%u)\n", _p[i]);
300 exit(1);
301 }
302 }
303
304 // set outputs
305 *_M_null = M_null;
306 *_M_pilot = M_pilot;
307 *_M_data = M_data;
308 }
309
310 // print subcarrier allocation to screen
311 //
312 // key: '.' (null), 'P' (pilot), '+' (data)
313 // .+++P+++++++P.........P+++++++P+++
314 //
ofdmframe_print_sctype(unsigned char * _p,unsigned int _M)315 void ofdmframe_print_sctype(unsigned char * _p,
316 unsigned int _M)
317 {
318 unsigned int i;
319
320 printf("[");
321 for (i=0; i<_M; i++) {
322 unsigned int k = (i + _M/2) % _M;
323
324 switch (_p[k]) {
325 case OFDMFRAME_SCTYPE_NULL: printf("."); break;
326 case OFDMFRAME_SCTYPE_PILOT: printf("|"); break;
327 case OFDMFRAME_SCTYPE_DATA: printf("+"); break;
328 default:
329 fprintf(stderr,"error: ofdmframe_print_default_sctype(), invalid subcarrier type\n");
330 exit(1);
331 }
332 }
333
334 printf("]\n");
335 }
336
337