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