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 // modem_utilities.c : common utilities not specific to precision
25 //
26
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <string.h>
30
31 #include "liquid.internal.h"
32
33 // full modulation type descriptor
34 const struct modulation_type_s modulation_types[LIQUID_MODEM_NUM_SCHEMES] = {
35 // name fullname scheme bps
36
37 // unknown
38 {"unknown", "unkown", LIQUID_MODEM_UNKNOWN, 0},
39
40 // phase-shift keying
41 {"psk2", "phase-shift keying (2)", LIQUID_MODEM_PSK2, 1},
42 {"psk4", "phase-shift keying (4)", LIQUID_MODEM_PSK4, 2},
43 {"psk8", "phase-shift keying (8)", LIQUID_MODEM_PSK8, 3},
44 {"psk16", "phase-shift keying (16)", LIQUID_MODEM_PSK16, 4},
45 {"psk32", "phase-shift keying (32)", LIQUID_MODEM_PSK32, 5},
46 {"psk64", "phase-shift keying (64)", LIQUID_MODEM_PSK64, 6},
47 {"psk128", "phase-shift keying (128)", LIQUID_MODEM_PSK128, 7},
48 {"psk256", "phase-shift keying (256)", LIQUID_MODEM_PSK256, 8},
49
50 // differential phase-shift keying
51 {"dpsk2", "differential phase-shift keying (2)", LIQUID_MODEM_DPSK2, 1},
52 {"dpsk4", "differential phase-shift keying (4)", LIQUID_MODEM_DPSK4, 2},
53 {"dpsk8", "differential phase-shift keying (8)", LIQUID_MODEM_DPSK8, 3},
54 {"dpsk16", "differential phase-shift keying (16)", LIQUID_MODEM_DPSK16, 4},
55 {"dpsk32", "differential phase-shift keying (32)", LIQUID_MODEM_DPSK32, 5},
56 {"dpsk64", "differential phase-shift keying (64)", LIQUID_MODEM_DPSK64, 6},
57 {"dpsk128", "differential phase-shift keying (128)", LIQUID_MODEM_DPSK128, 7},
58 {"dpsk256", "differential phase-shift keying (256)", LIQUID_MODEM_DPSK256, 8},
59
60 // amplitude-shift keying
61 {"ask2", "amplitude-shift keying (2)", LIQUID_MODEM_ASK2, 1},
62 {"ask4", "amplitude-shift keying (4)", LIQUID_MODEM_ASK4, 2},
63 {"ask8", "amplitude-shift keying (8)", LIQUID_MODEM_ASK8, 3},
64 {"ask16", "amplitude-shift keying (16)", LIQUID_MODEM_ASK16, 4},
65 {"ask32", "amplitude-shift keying (32)", LIQUID_MODEM_ASK32, 5},
66 {"ask64", "amplitude-shift keying (64)", LIQUID_MODEM_ASK64, 6},
67 {"ask128", "amplitude-shift keying (128)", LIQUID_MODEM_ASK128, 7},
68 {"ask256", "amplitude-shift keying (256)", LIQUID_MODEM_ASK256, 8},
69
70 // quadrature amplitude-shift keying
71 {"qam4", "quadrature amplitude-shift keying (4)", LIQUID_MODEM_QAM4, 2},
72 {"qam8", "quadrature amplitude-shift keying (8)", LIQUID_MODEM_QAM8, 3},
73 {"qam16", "quadrature amplitude-shift keying (16)", LIQUID_MODEM_QAM16, 4},
74 {"qam32", "quadrature amplitude-shift keying (32)", LIQUID_MODEM_QAM32, 5},
75 {"qam64", "quadrature amplitude-shift keying (64)", LIQUID_MODEM_QAM64, 6},
76 {"qam128", "quadrature amplitude-shift keying (128)", LIQUID_MODEM_QAM128, 7},
77 {"qam256", "quadrature amplitude-shift keying (256)", LIQUID_MODEM_QAM256, 8},
78
79 // amplitude/phase-shift keying
80 {"apsk4", "amplitude/phase-shift keying (4)", LIQUID_MODEM_APSK4, 2},
81 {"apsk8", "amplitude/phase-shift keying (8)", LIQUID_MODEM_APSK8, 3},
82 {"apsk16", "amplitude/phase-shift keying (16)", LIQUID_MODEM_APSK16, 4},
83 {"apsk32", "amplitude/phase-shift keying (32)", LIQUID_MODEM_APSK32, 5},
84 {"apsk64", "amplitude/phase-shift keying (64)", LIQUID_MODEM_APSK64, 6},
85 {"apsk128", "amplitude/phase-shift keying (128)", LIQUID_MODEM_APSK128, 7},
86 {"apsk256", "amplitude/phase-shift keying (256)", LIQUID_MODEM_APSK256, 8},
87
88 // specific modem types
89 {"bpsk", "binary phase-shift keying", LIQUID_MODEM_BPSK, 1},
90 {"qpsk", "quaternary phase-shift keying", LIQUID_MODEM_QPSK, 2},
91 {"ook", "ook (on/off keying)", LIQUID_MODEM_OOK, 1},
92 {"sqam32", "'square' 32-QAM", LIQUID_MODEM_SQAM32, 5},
93 {"sqam128", "'square' 128-QAM", LIQUID_MODEM_SQAM128, 7},
94 {"V29", "V.29", LIQUID_MODEM_V29, 4},
95 {"arb16opt", "arb16opt (optimal 16-qam)", LIQUID_MODEM_ARB16OPT, 4},
96 {"arb32opt", "arb32opt (optimal 32-qam)", LIQUID_MODEM_ARB32OPT, 5},
97 {"arb64opt", "arb64opt (optimal 64-qam)", LIQUID_MODEM_ARB64OPT, 6},
98 {"arb128opt", "arb128opt (optimal 128-qam)", LIQUID_MODEM_ARB128OPT, 7},
99 {"arb256opt", "arb256opt (optimal 256-qam)", LIQUID_MODEM_ARB256OPT, 8},
100 {"arb64vt", "arb64vt (64-qam vt logo)", LIQUID_MODEM_ARB64VT, 6},
101
102 // arbitrary modem type
103 {"arb", "arbitrary constellation", LIQUID_MODEM_ARB, 0},
104 };
105
106
107
liquid_getopt_str2mod(const char * _str)108 modulation_scheme liquid_getopt_str2mod(const char * _str)
109 {
110 // compare each string to short name
111 unsigned int i;
112 for (i=0; i<LIQUID_MODEM_NUM_SCHEMES; i++) {
113 if (strcmp(_str,modulation_types[i].name)==0)
114 return i;
115 }
116 fprintf(stderr,"warning: liquid_getopt_str2mod(), unknown/unsupported mod scheme : %s\n", _str);
117 return LIQUID_MODEM_UNKNOWN;
118 }
119
120 // Print compact list of existing and available modulation schemes
liquid_print_modulation_schemes()121 void liquid_print_modulation_schemes()
122 {
123 unsigned int i;
124 unsigned int len = 10;
125
126 // print all available modem schemes
127 printf(" ");
128 for (i=1; i<LIQUID_MODEM_NUM_SCHEMES; i++) {
129 printf("%s", modulation_types[i].name);
130
131 if (i != LIQUID_MODEM_NUM_SCHEMES-1)
132 printf(", ");
133
134 len += strlen(modulation_types[i].name);
135 if (len > 48 && i != LIQUID_MODEM_NUM_SCHEMES-1) {
136 len = 10;
137 printf("\n ");
138 }
139 }
140 printf("\n");
141 }
142
143 // query basic modulation types
liquid_modem_is_psk(modulation_scheme _ms)144 int liquid_modem_is_psk(modulation_scheme _ms)
145 {
146 switch (_ms) {
147 // Phase-shift keying (PSK)
148 case LIQUID_MODEM_PSK2:
149 case LIQUID_MODEM_PSK4:
150 case LIQUID_MODEM_PSK8:
151 case LIQUID_MODEM_PSK16:
152 case LIQUID_MODEM_PSK32:
153 case LIQUID_MODEM_PSK64:
154 case LIQUID_MODEM_PSK128:
155 case LIQUID_MODEM_PSK256:
156 return 1;
157 default:
158 return 0;
159 }
160
161 return 0;
162 }
163
liquid_modem_is_dpsk(modulation_scheme _ms)164 int liquid_modem_is_dpsk(modulation_scheme _ms)
165 {
166 switch (_ms) {
167 // Differential phase-shift keying (DPSK)
168 case LIQUID_MODEM_DPSK2:
169 case LIQUID_MODEM_DPSK4:
170 case LIQUID_MODEM_DPSK8:
171 case LIQUID_MODEM_DPSK16:
172 case LIQUID_MODEM_DPSK32:
173 case LIQUID_MODEM_DPSK64:
174 case LIQUID_MODEM_DPSK128:
175 case LIQUID_MODEM_DPSK256:
176 return 1;
177 default:
178 return 0;
179 }
180
181 return 0;
182 }
183
liquid_modem_is_ask(modulation_scheme _ms)184 int liquid_modem_is_ask(modulation_scheme _ms)
185 {
186 switch (_ms) {
187 // amplitude-shift keying (ASK)
188 case LIQUID_MODEM_ASK2:
189 case LIQUID_MODEM_ASK4:
190 case LIQUID_MODEM_ASK8:
191 case LIQUID_MODEM_ASK16:
192 case LIQUID_MODEM_ASK32:
193 case LIQUID_MODEM_ASK64:
194 case LIQUID_MODEM_ASK128:
195 case LIQUID_MODEM_ASK256:
196 return 1;
197 default:
198 return 0;
199 }
200
201 return 0;
202 }
203
liquid_modem_is_qam(modulation_scheme _ms)204 int liquid_modem_is_qam(modulation_scheme _ms)
205 {
206 switch (_ms) {
207 // rectangular quadrature amplitude-shift keying (QAM)
208 case LIQUID_MODEM_QAM4:
209 case LIQUID_MODEM_QAM8:
210 case LIQUID_MODEM_QAM16:
211 case LIQUID_MODEM_QAM32:
212 case LIQUID_MODEM_QAM64:
213 case LIQUID_MODEM_QAM128:
214 case LIQUID_MODEM_QAM256:
215 return 1;
216 default:
217 return 0;
218 }
219
220 return 0;
221 }
222
liquid_modem_is_apsk(modulation_scheme _ms)223 int liquid_modem_is_apsk(modulation_scheme _ms)
224 {
225 switch (_ms) {
226 // amplitude phase-shift keying (APSK)
227 case LIQUID_MODEM_APSK4:
228 case LIQUID_MODEM_APSK8:
229 case LIQUID_MODEM_APSK16:
230 case LIQUID_MODEM_APSK32:
231 case LIQUID_MODEM_APSK64:
232 case LIQUID_MODEM_APSK128:
233 case LIQUID_MODEM_APSK256:
234 return 1;
235 default:
236 return 0;
237 }
238
239 return 0;
240 }
241
242
243 // gray encoding
gray_encode(unsigned int symbol_in)244 unsigned int gray_encode(unsigned int symbol_in)
245 {
246 return symbol_in ^ (symbol_in >> 1);
247 }
248
249 // gray decoding
gray_decode(unsigned int symbol_in)250 unsigned int gray_decode(unsigned int symbol_in)
251 {
252 unsigned int mask = symbol_in;
253 unsigned int symbol_out = symbol_in;
254 unsigned int i;
255
256 // Run loop in blocks of 4 to reduce number of comparisons. Running
257 // loop more times than MAX_MOD_BITS_PER_SYMBOL will not result in
258 // decoding errors.
259 for (i=0; i<MAX_MOD_BITS_PER_SYMBOL; i+=4) {
260 symbol_out ^= (mask >> 1);
261 symbol_out ^= (mask >> 2);
262 symbol_out ^= (mask >> 3);
263 symbol_out ^= (mask >> 4);
264 mask >>= 4;
265 }
266
267 return symbol_out;
268 }
269
270 // pack soft bits into symbol
271 // _soft_bits : soft input bits [size: _bps x 1]
272 // _bps : bits per symbol
273 // _sym_out : output symbol, value in [0,2^_bps)
liquid_pack_soft_bits(unsigned char * _soft_bits,unsigned int _bps,unsigned int * _sym_out)274 void liquid_pack_soft_bits(unsigned char * _soft_bits,
275 unsigned int _bps,
276 unsigned int * _sym_out)
277 {
278 // validate input
279 if (_bps > MAX_MOD_BITS_PER_SYMBOL) {
280 fprintf(stderr,"error: liquid_unpack_soft_bits(), bits/symbol exceeds maximum (%u)\n", MAX_MOD_BITS_PER_SYMBOL);
281 exit(1);
282 }
283
284 unsigned int i;
285 unsigned int s=0;
286 for (i=0; i<_bps; i++) {
287 s <<= 1;
288 s |= _soft_bits[i] > LIQUID_SOFTBIT_ERASURE ? 1 : 0;
289 }
290 *_sym_out = s;
291 }
292
293 // unpack soft bits into symbol
294 // _sym_in : input symbol, value in [0,2^_bps)
295 // _bps : bits per symbol
296 // _soft_bits : soft output bits [size: _bps x 1]
liquid_unpack_soft_bits(unsigned int _sym_in,unsigned int _bps,unsigned char * _soft_bits)297 void liquid_unpack_soft_bits(unsigned int _sym_in,
298 unsigned int _bps,
299 unsigned char * _soft_bits)
300 {
301 // validate input
302 if (_bps > MAX_MOD_BITS_PER_SYMBOL) {
303 fprintf(stderr,"error: liquid_unpack_soft_bits(), bits/symbol exceeds maximum (%u)\n", MAX_MOD_BITS_PER_SYMBOL);
304 exit(1);
305 }
306
307 unsigned int i;
308 for (i=0; i<_bps; i++)
309 _soft_bits[i] = ((_sym_in >> (_bps-i-1)) & 0x0001) ? LIQUID_SOFTBIT_1 : LIQUID_SOFTBIT_0;
310 }
311
312
313