Mercurial > hg > audiostuff
comparison spandsp-0.0.3/spandsp-0.0.3/src/v27ter_rx.c @ 5:f762bf195c4b
import spandsp-0.0.3
author | Peter Meerwald <pmeerw@cosy.sbg.ac.at> |
---|---|
date | Fri, 25 Jun 2010 16:00:21 +0200 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
4:26cd8f1ef0b1 | 5:f762bf195c4b |
---|---|
1 /* | |
2 * SpanDSP - a series of DSP components for telephony | |
3 * | |
4 * v27ter_rx.c - ITU V.27ter modem receive part | |
5 * | |
6 * Written by Steve Underwood <steveu@coppice.org> | |
7 * | |
8 * Copyright (C) 2003 Steve Underwood | |
9 * | |
10 * All rights reserved. | |
11 * | |
12 * This program is free software; you can redistribute it and/or modify | |
13 * it under the terms of the GNU General Public License version 2, as | |
14 * published by the Free Software Foundation. | |
15 * | |
16 * This program is distributed in the hope that it will be useful, | |
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
19 * GNU General Public License for more details. | |
20 * | |
21 * You should have received a copy of the GNU General Public License | |
22 * along with this program; if not, write to the Free Software | |
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
24 * | |
25 * $Id: v27ter_rx.c,v 1.75 2006/11/28 16:59:57 steveu Exp $ | |
26 */ | |
27 | |
28 /*! \file */ | |
29 | |
30 #ifdef HAVE_CONFIG_H | |
31 #include <config.h> | |
32 #endif | |
33 | |
34 #include <inttypes.h> | |
35 #include <string.h> | |
36 #include <stdio.h> | |
37 #include <stdlib.h> | |
38 #if defined(HAVE_TGMATH_H) | |
39 #include <tgmath.h> | |
40 #endif | |
41 #if defined(HAVE_MATH_H) | |
42 #include <math.h> | |
43 #endif | |
44 | |
45 #include "spandsp/telephony.h" | |
46 #include "spandsp/logging.h" | |
47 #include "spandsp/complex.h" | |
48 #include "spandsp/vector_float.h" | |
49 #include "spandsp/complex_vector_float.h" | |
50 #include "spandsp/async.h" | |
51 #include "spandsp/power_meter.h" | |
52 #include "spandsp/arctan2.h" | |
53 #include "spandsp/dds.h" | |
54 #include "spandsp/complex_filters.h" | |
55 | |
56 #include "spandsp/v29rx.h" | |
57 #include "spandsp/v27ter_rx.h" | |
58 | |
59 /* V.27ter is a DPSK modem, but this code treats it like QAM. It nails down the | |
60 signal to a static constellation, even though dealing with differences is all | |
61 that is necessary. */ | |
62 | |
63 #define CARRIER_NOMINAL_FREQ 1800.0f | |
64 #define EQUALIZER_DELTA 0.25f | |
65 | |
66 /* Segments of the training sequence */ | |
67 /* V.27ter defines a long and a short sequence. FAX doesn't use the | |
68 short sequence, so it is not implemented here. */ | |
69 #define V27TER_TRAINING_SEG_3_LEN 50 | |
70 #define V27TER_TRAINING_SEG_5_LEN 1074 | |
71 #define V27TER_TRAINING_SEG_6_LEN 8 | |
72 | |
73 enum | |
74 { | |
75 TRAINING_STAGE_NORMAL_OPERATION = 0, | |
76 TRAINING_STAGE_SYMBOL_ACQUISITION, | |
77 TRAINING_STAGE_LOG_PHASE, | |
78 TRAINING_STAGE_WAIT_FOR_HOP, | |
79 TRAINING_STAGE_TRAIN_ON_ABAB, | |
80 TRAINING_STAGE_TEST_ONES, | |
81 TRAINING_STAGE_PARKED | |
82 }; | |
83 | |
84 static const complexf_t v27ter_constellation[8] = | |
85 { | |
86 { 1.414f, 0.0f}, /* 0deg */ | |
87 { 1.0f, 1.0f}, /* 45deg */ | |
88 { 0.0f, 1.414f}, /* 90deg */ | |
89 {-1.0f, 1.0f}, /* 135deg */ | |
90 {-1.414f, 0.0f}, /* 180deg */ | |
91 {-1.0f, -1.0f}, /* 225deg */ | |
92 { 0.0f, -1.414f}, /* 270deg */ | |
93 { 1.0f, -1.0f} /* 315deg */ | |
94 }; | |
95 | |
96 /* Raised root cosine pulse shaping filter set; beta 0.5; sample rate 8000; 8 phase steps; | |
97 baud rate 1600; shifted to centre at 1800Hz; complex. */ | |
98 #define PULSESHAPER_4800_GAIN (2.4975f*2.0f) | |
99 #define PULSESHAPER_4800_COEFF_SETS 8 | |
100 static const complexf_t pulseshaper_4800[PULSESHAPER_4800_COEFF_SETS][V27TER_RX_4800_FILTER_STEPS] = | |
101 { | |
102 { | |
103 {-0.0050334423f, -0.0025646669f}, /* Filter 0 */ | |
104 { 0.0001996320f, -0.0006144041f}, | |
105 {-0.0064914716f, -0.0010281481f}, | |
106 {-0.0000000000f, 0.0057152766f}, | |
107 {-0.0060638961f, 0.0009604268f}, | |
108 { 0.0046534477f, 0.0143218395f}, | |
109 {-0.0027026909f, 0.0013770898f}, | |
110 { 0.0114324470f, 0.0157354133f}, | |
111 { 0.0161335660f, -0.0161335660f}, | |
112 { 0.0216170550f, 0.0157057098f}, | |
113 { 0.0523957134f, -0.1028323775f}, | |
114 { 0.1009107956f, 0.0327879051f}, | |
115 { 0.0626681574f, -0.3956711736f}, | |
116 { 1.0309650898f, 0.0000000000f}, | |
117 { 0.1612784723f, 1.0182721987f}, | |
118 {-0.3809963452f, 0.1237932168f}, | |
119 { 0.0481701579f, 0.0945392579f}, | |
120 {-0.0933698449f, 0.0678371631f}, | |
121 { 0.0188939989f, 0.0188939989f}, | |
122 {-0.0134110893f, 0.0184587808f}, | |
123 { 0.0173301130f, 0.0088301336f}, | |
124 { 0.0009373415f, -0.0028848406f}, | |
125 { 0.0148734735f, 0.0023557268f}, | |
126 {-0.0000000000f, -0.0061394833f}, | |
127 { 0.0056449120f, -0.0008940662f}, | |
128 {-0.0020309798f, -0.0062507130f}, | |
129 {-0.0005756104f, 0.0002932882f}, | |
130 }, | |
131 { | |
132 {-0.0018682578f, -0.0009519249f}, /* Filter 1 */ | |
133 {-0.0002684621f, 0.0008262413f}, | |
134 {-0.0059141931f, -0.0009367162f}, | |
135 {-0.0000000000f, 0.0073941285f}, | |
136 {-0.0037772132f, 0.0005982518f}, | |
137 { 0.0050394423f, 0.0155098087f}, | |
138 { 0.0010806327f, -0.0005506098f}, | |
139 { 0.0105277637f, 0.0144902237f}, | |
140 { 0.0209691082f, -0.0209691082f}, | |
141 { 0.0125153543f, 0.0090929371f}, | |
142 { 0.0603186345f, -0.1183819857f}, | |
143 { 0.0675630592f, 0.0219525687f}, | |
144 { 0.0765237582f, -0.4831519944f}, | |
145 { 1.0763458014f, 0.0000000000f}, | |
146 { 0.1524445751f, 0.9624971666f}, | |
147 {-0.2992580667f, 0.0972348401f}, | |
148 { 0.0600222537f, 0.1178003057f}, | |
149 {-0.0774892752f, 0.0562992540f}, | |
150 { 0.0247376160f, 0.0247376159f}, | |
151 {-0.0090916622f, 0.0125135995f}, | |
152 { 0.0175076452f, 0.0089205908f}, | |
153 { 0.0021568809f, -0.0066381970f}, | |
154 { 0.0129897446f, 0.0020573734f}, | |
155 {-0.0000000000f, -0.0079766726f}, | |
156 { 0.0037729191f, -0.0005975717f}, | |
157 {-0.0020837980f, -0.0064132707f}, | |
158 {-0.0018682578f, 0.0009519249f}, | |
159 }, | |
160 { | |
161 {-0.0030355143f, -0.0015466718f}, /* Filter 2 */ | |
162 {-0.0007306011f, 0.0022485590f}, | |
163 {-0.0049435003f, -0.0007829735f}, | |
164 {-0.0000000000f, 0.0087472824f}, | |
165 {-0.0011144870f, 0.0001765174f}, | |
166 { 0.0051901643f, 0.0159736834f}, | |
167 { 0.0049297142f, -0.0025118148f}, | |
168 { 0.0088213528f, 0.0121415505f}, | |
169 { 0.0251126307f, -0.0251126307f}, | |
170 { 0.0011182680f, 0.0008124692f}, | |
171 { 0.0667555589f, -0.1310151612f}, | |
172 { 0.0256033627f, 0.0083190368f}, | |
173 { 0.0905183226f, -0.5715101964f}, | |
174 { 1.1095595360f, 0.0000000000f}, | |
175 { 0.1420835849f, 0.8970804494f}, | |
176 {-0.2215345589f, 0.0719809416f}, | |
177 { 0.0679608493f, 0.1333806768f}, | |
178 {-0.0606982839f, 0.0440998847f}, | |
179 { 0.0284660210f, 0.0284660210f}, | |
180 {-0.0047348689f, 0.0065169880f}, | |
181 { 0.0165731197f, 0.0084444263f}, | |
182 { 0.0032233168f, -0.0099203492f}, | |
183 { 0.0105861265f, 0.0016766777f}, | |
184 {-0.0000000000f, -0.0092685623f}, | |
185 { 0.0018009090f, -0.0002852360f}, | |
186 {-0.0020112222f, -0.0061899056f}, | |
187 {-0.0030355143f, 0.0015466718f}, | |
188 }, | |
189 { | |
190 {-0.0040182937f, -0.0020474229f}, /* Filter 3 */ | |
191 {-0.0011603659f, 0.0035712391f}, | |
192 {-0.0036173562f, -0.0005729329f}, | |
193 {-0.0000000000f, 0.0096778115f}, | |
194 { 0.0018022529f, -0.0002854488f}, | |
195 { 0.0050847711f, 0.0156493164f}, | |
196 { 0.0086257291f, -0.0043950285f}, | |
197 { 0.0063429899f, 0.0087303766f}, | |
198 { 0.0282322904f, -0.0282322904f}, | |
199 {-0.0123306868f, -0.0089587683f}, | |
200 { 0.0712060603f, -0.1397497620f}, | |
201 {-0.0248170325f, -0.0080635427f}, | |
202 { 0.1043647251f, -0.6589329411f}, | |
203 { 1.1298123598f, 0.0000000000f}, | |
204 { 0.1304361227f, 0.8235412673f}, | |
205 {-0.1491678531f, 0.0484675735f}, | |
206 { 0.0722366382f, 0.1417723850f}, | |
207 {-0.0437871917f, 0.0318132570f}, | |
208 { 0.0301678844f, 0.0301678844f}, | |
209 {-0.0005794433f, 0.0007975353f}, | |
210 { 0.0146599874f, 0.0074696367f}, | |
211 { 0.0040878789f, -0.0125811975f}, | |
212 { 0.0078126085f, 0.0012373956f}, | |
213 {-0.0000000000f, -0.0099797659f}, | |
214 {-0.0001576582f, 0.0000249706f}, | |
215 {-0.0018223262f, -0.0056085432f}, | |
216 {-0.0040182937f, 0.0020474229f}, | |
217 }, | |
218 { | |
219 {-0.0047695783f, -0.0024302215f}, /* Filter 4 */ | |
220 {-0.0015320920f, 0.0047152944f}, | |
221 {-0.0019955989f, -0.0003160718f}, | |
222 {-0.0000000000f, 0.0101070339f}, | |
223 { 0.0048302421f, -0.0007650352f}, | |
224 { 0.0047152968f, 0.0145121913f}, | |
225 { 0.0119428503f, -0.0060851862f}, | |
226 { 0.0031686377f, 0.0043612557f}, | |
227 { 0.0300119095f, -0.0300119094f}, | |
228 {-0.0274628457f, -0.0199529254f}, | |
229 { 0.0731841827f, -0.1436320457f}, | |
230 {-0.0832936387f, -0.0270637438f}, | |
231 { 0.1177684882f, -0.7435609707f}, | |
232 { 1.1366178989f, 0.0000000000f}, | |
233 { 0.1177684882f, 0.7435609707f}, | |
234 {-0.0832936387f, 0.0270637438f}, | |
235 { 0.0731841827f, 0.1436320457f}, | |
236 {-0.0274628457f, 0.0199529254f}, | |
237 { 0.0300119095f, 0.0300119094f}, | |
238 { 0.0031686377f, -0.0043612557f}, | |
239 { 0.0119428503f, 0.0060851862f}, | |
240 { 0.0047152968f, -0.0145121913f}, | |
241 { 0.0048302421f, 0.0007650352f}, | |
242 {-0.0000000000f, -0.0101070339f}, | |
243 {-0.0019955989f, 0.0003160718f}, | |
244 {-0.0015320920f, -0.0047152944f}, | |
245 {-0.0047695783f, 0.0024302215f}, | |
246 }, | |
247 { | |
248 {-0.0052564711f, -0.0026783058f}, /* Filter 5 */ | |
249 {-0.0018223262f, 0.0056085432f}, | |
250 {-0.0001576582f, -0.0000249706f}, | |
251 {-0.0000000000f, 0.0099797659f}, | |
252 { 0.0078126085f, -0.0012373956f}, | |
253 { 0.0040878789f, 0.0125811975f}, | |
254 { 0.0146599874f, -0.0074696367f}, | |
255 {-0.0005794433f, -0.0007975353f}, | |
256 { 0.0301678844f, -0.0301678844f}, | |
257 {-0.0437871917f, -0.0318132570f}, | |
258 { 0.0722366382f, -0.1417723850f}, | |
259 {-0.1491678531f, -0.0484675735f}, | |
260 { 0.1304361227f, -0.8235412673f}, | |
261 { 1.1298123598f, 0.0000000000f}, | |
262 { 0.1043647251f, 0.6589329411f}, | |
263 {-0.0248170325f, 0.0080635427f}, | |
264 { 0.0712060603f, 0.1397497620f}, | |
265 {-0.0123306868f, 0.0089587683f}, | |
266 { 0.0282322904f, 0.0282322904f}, | |
267 { 0.0063429899f, -0.0087303766f}, | |
268 { 0.0086257291f, 0.0043950285f}, | |
269 { 0.0050847711f, -0.0156493164f}, | |
270 { 0.0018022529f, 0.0002854488f}, | |
271 {-0.0000000000f, -0.0096778115f}, | |
272 {-0.0036173562f, 0.0005729329f}, | |
273 {-0.0011603659f, -0.0035712391f}, | |
274 {-0.0052564711f, 0.0026783058f}, | |
275 }, | |
276 { | |
277 {-0.0054614245f, -0.0027827348f}, /* Filter 6 */ | |
278 {-0.0020112222f, 0.0061899056f}, | |
279 { 0.0018009090f, 0.0002852360f}, | |
280 {-0.0000000000f, 0.0092685623f}, | |
281 { 0.0105861265f, -0.0016766777f}, | |
282 { 0.0032233168f, 0.0099203492f}, | |
283 { 0.0165731197f, -0.0084444263f}, | |
284 {-0.0047348689f, -0.0065169880f}, | |
285 { 0.0284660210f, -0.0284660210f}, | |
286 {-0.0606982839f, -0.0440998847f}, | |
287 { 0.0679608493f, -0.1333806768f}, | |
288 {-0.2215345589f, -0.0719809416f}, | |
289 { 0.1420835849f, -0.8970804494f}, | |
290 { 1.1095595360f, 0.0000000000f}, | |
291 { 0.0905183226f, 0.5715101964f}, | |
292 { 0.0256033627f, -0.0083190368f}, | |
293 { 0.0667555589f, 0.1310151612f}, | |
294 { 0.0011182680f, -0.0008124692f}, | |
295 { 0.0251126307f, 0.0251126307f}, | |
296 { 0.0088213528f, -0.0121415505f}, | |
297 { 0.0049297142f, 0.0025118148f}, | |
298 { 0.0051901643f, -0.0159736834f}, | |
299 {-0.0011144870f, -0.0001765174f}, | |
300 {-0.0000000000f, -0.0087472824f}, | |
301 {-0.0049435003f, 0.0007829735f}, | |
302 {-0.0007306011f, -0.0022485590f}, | |
303 {-0.0054614245f, 0.0027827348f}, | |
304 }, | |
305 { | |
306 {-0.0053826099f, -0.0027425768f}, /* Filter 7 */ | |
307 {-0.0020837980f, 0.0064132707f}, | |
308 { 0.0037729191f, 0.0005975717f}, | |
309 {-0.0000000000f, 0.0079766726f}, | |
310 { 0.0129897446f, -0.0020573734f}, | |
311 { 0.0021568809f, 0.0066381970f}, | |
312 { 0.0175076452f, -0.0089205908f}, | |
313 {-0.0090916622f, -0.0125135995f}, | |
314 { 0.0247376160f, -0.0247376159f}, | |
315 {-0.0774892752f, -0.0562992540f}, | |
316 { 0.0600222537f, -0.1178003057f}, | |
317 {-0.2992580667f, -0.0972348401f}, | |
318 { 0.1524445751f, -0.9624971666f}, | |
319 { 1.0763458014f, 0.0000000000f}, | |
320 { 0.0765237582f, 0.4831519944f}, | |
321 { 0.0675630592f, -0.0219525687f}, | |
322 { 0.0603186345f, 0.1183819857f}, | |
323 { 0.0125153543f, -0.0090929371f}, | |
324 { 0.0209691082f, 0.0209691082f}, | |
325 { 0.0105277637f, -0.0144902237f}, | |
326 { 0.0010806327f, 0.0005506098f}, | |
327 { 0.0050394423f, -0.0155098087f}, | |
328 {-0.0037772132f, -0.0005982518f}, | |
329 {-0.0000000000f, -0.0073941285f}, | |
330 {-0.0059141931f, 0.0009367162f}, | |
331 {-0.0002684621f, -0.0008262413f}, | |
332 {-0.0053826099f, 0.0027425768f}, | |
333 }, | |
334 }; | |
335 | |
336 /* Raised root cosine pulse shaping filter set; beta 0.5; sample rate 8000; 12 phase steps; | |
337 baud rate 1200; shifted to centre at 1800Hz; complex. */ | |
338 #define PULSESHAPER_2400_GAIN 2.223f | |
339 #define PULSESHAPER_2400_COEFF_SETS 12 | |
340 static const complexf_t pulseshaper_2400[PULSESHAPER_2400_COEFF_SETS][V27TER_RX_2400_FILTER_STEPS] = | |
341 { | |
342 { | |
343 { 0.0036326320f, 0.0018509185f}, /* Filter 0 */ | |
344 { 0.0003793370f, -0.0011674794f}, | |
345 { 0.0048754563f, 0.0007721964f}, | |
346 { 0.0000000000f, -0.0062069190f}, | |
347 {-0.0027810383f, 0.0004404732f}, | |
348 {-0.0021925965f, -0.0067481182f}, | |
349 {-0.0140173459f, 0.0071421944f}, | |
350 { 0.0019772880f, 0.0027215034f}, | |
351 {-0.0092149554f, 0.0092149553f}, | |
352 { 0.0334995425f, 0.0243388423f}, | |
353 { 0.0199195813f, -0.0390943796f}, | |
354 { 0.1477459776f, 0.0480055782f}, | |
355 { 0.0427277333f, -0.2697722907f}, | |
356 { 1.0040582418f, 0.0000000000f}, | |
357 { 0.1570693140f, 0.9916966187f}, | |
358 {-0.2597668560f, 0.0844033680f}, | |
359 { 0.0705271128f, 0.1384172525f}, | |
360 {-0.0354969538f, 0.0257900466f}, | |
361 { 0.0292796738f, 0.0292796738f}, | |
362 { 0.0076599673f, -0.0105430406f}, | |
363 { 0.0029973132f, 0.0015272073f}, | |
364 { 0.0048614662f, -0.0149620544f}, | |
365 {-0.0070080354f, -0.0011099638f}, | |
366 {-0.0000000000f, -0.0028157043f}, | |
367 {-0.0061305015f, 0.0009709761f}, | |
368 { 0.0015253788f, 0.0046946332f}, | |
369 {-0.0010937644f, 0.0005573008f}, | |
370 }, | |
371 { | |
372 {-0.0002819961f, -0.0001436842f}, /* Filter 1 */ | |
373 { 0.0006588563f, -0.0020277512f}, | |
374 { 0.0041797109f, 0.0006620012f}, | |
375 { 0.0000000000f, -0.0065623410f}, | |
376 {-0.0042368606f, 0.0006710528f}, | |
377 {-0.0017245111f, -0.0053074995f}, | |
378 {-0.0146686673f, 0.0074740593f}, | |
379 { 0.0038644283f, 0.0053189292f}, | |
380 {-0.0067358415f, 0.0067358415f}, | |
381 { 0.0345347757f, 0.0250909833f}, | |
382 { 0.0269170677f, -0.0528277198f}, | |
383 { 0.1389398473f, 0.0451442930f}, | |
384 { 0.0525256151f, -0.3316336818f}, | |
385 { 1.0434222221f, 0.0000000000f}, | |
386 { 0.1499906453f, 0.9470036639f}, | |
387 {-0.2028542371f, 0.0659113371f}, | |
388 { 0.0727579142f, 0.1427954467f}, | |
389 {-0.0235379981f, 0.0171013566f}, | |
390 { 0.0275384769f, 0.0275384769f}, | |
391 { 0.0093041035f, -0.0128059998f}, | |
392 { 0.0001136455f, 0.0000579053f}, | |
393 { 0.0045116911f, -0.0138855574f}, | |
394 {-0.0082179267f, -0.0013015917f}, | |
395 {-0.0000000000f, -0.0013177606f}, | |
396 {-0.0055834514f, 0.0008843318f}, | |
397 { 0.0016945064f, 0.0052151545f}, | |
398 {-0.0002819961f, 0.0001436842f}, | |
399 }, | |
400 { | |
401 { 0.0005112062f, 0.0002604726f}, /* Filter 2 */ | |
402 { 0.0009277352f, -0.0028552754f}, | |
403 { 0.0033466091f, 0.0005300508f}, | |
404 { 0.0000000000f, -0.0067017064f}, | |
405 {-0.0056208495f, 0.0008902551f}, | |
406 {-0.0011771217f, -0.0036228080f}, | |
407 {-0.0149285967f, 0.0076064999f}, | |
408 { 0.0056743444f, 0.0078100650f}, | |
409 {-0.0038028170f, 0.0038028170f}, | |
410 { 0.0344837758f, 0.0250539297f}, | |
411 { 0.0340482504f, -0.0668234539f}, | |
412 { 0.1257304818f, 0.0408523100f}, | |
413 { 0.0626620127f, -0.3956323778f}, | |
414 { 1.0763765574f, 0.0000000000f}, | |
415 { 0.1420845360f, 0.8970864542f}, | |
416 {-0.1491315874f, 0.0484557901f}, | |
417 { 0.0731690629f, 0.1436023716f}, | |
418 {-0.0123276338f, 0.0089565502f}, | |
419 { 0.0250869159f, 0.0250869159f}, | |
420 { 0.0105070407f, -0.0144617008f}, | |
421 {-0.0027029676f, -0.0013772308f}, | |
422 { 0.0040530413f, -0.0124739786f}, | |
423 {-0.0091186142f, -0.0014442466f}, | |
424 { 0.0000000000f, 0.0001565015f}, | |
425 {-0.0048632493f, 0.0007702630f}, | |
426 { 0.0018111360f, 0.0055741034f}, | |
427 { 0.0005112062f, -0.0002604726f}, | |
428 }, | |
429 { | |
430 { 0.0012626700f, 0.0006433625f}, /* Filter 3 */ | |
431 { 0.0011774450f, -0.0036238031f}, | |
432 { 0.0023987660f, 0.0003799272f}, | |
433 { 0.0000000000f, -0.0066136620f}, | |
434 {-0.0068852097f, 0.0010905101f}, | |
435 {-0.0005635325f, -0.0017343746f}, | |
436 {-0.0147735044f, 0.0075274764f}, | |
437 { 0.0073440948f, 0.0101082792f}, | |
438 {-0.0004807357f, 0.0004807357f}, | |
439 { 0.0332365955f, 0.0241478001f}, | |
440 { 0.0411429005f, -0.0807474888f}, | |
441 { 0.1079056364f, 0.0350606666f}, | |
442 { 0.0730301872f, -0.4610944549f}, | |
443 { 1.1024802923f, 0.0000000000f}, | |
444 { 0.1334542238f, 0.8425968074f}, | |
445 {-0.0990668329f, 0.0321887653f}, | |
446 { 0.0719339457f, 0.1411783175f}, | |
447 {-0.0020666801f, 0.0015015310f}, | |
448 { 0.0220599213f, 0.0220599213f}, | |
449 { 0.0112587393f, -0.0154963252f}, | |
450 {-0.0053688554f, -0.0027355684f}, | |
451 { 0.0035031104f, -0.0107814651f}, | |
452 {-0.0096971580f, -0.0015358789f}, | |
453 { 0.0000000000f, 0.0015619067f}, | |
454 {-0.0039973434f, 0.0006331170f}, | |
455 { 0.0018730190f, 0.0057645597f}, | |
456 { 0.0012626700f, -0.0006433625f}, | |
457 }, | |
458 { | |
459 { 0.0019511001f, 0.0009941351f}, /* Filter 4 */ | |
460 { 0.0013998188f, -0.0043081992f}, | |
461 { 0.0013630316f, 0.0002158830f}, | |
462 { 0.0000000000f, -0.0062936717f}, | |
463 {-0.0079839961f, 0.0012645408f}, | |
464 { 0.0001005750f, 0.0003095379f}, | |
465 {-0.0141915007f, 0.0072309308f}, | |
466 { 0.0088117029f, 0.0121282686f}, | |
467 { 0.0031486956f, -0.0031486956f}, | |
468 { 0.0307069943f, 0.0223099373f}, | |
469 { 0.0480159027f, -0.0942365150f}, | |
470 { 0.0853178815f, 0.0277214601f}, | |
471 { 0.0835162618f, -0.5273009241f}, | |
472 { 1.1213819981f, 0.0000000000f}, | |
473 { 0.1242110958f, 0.7842379942f}, | |
474 {-0.0530547129f, 0.0172385212f}, | |
475 { 0.0692420091f, 0.1358950944f}, | |
476 { 0.0070828755f, -0.0051460103f}, | |
477 { 0.0185973391f, 0.0185973390f}, | |
478 { 0.0115630893f, -0.0159152271f}, | |
479 {-0.0078088406f, -0.0039788030f}, | |
480 { 0.0028814530f, -0.0088682003f}, | |
481 {-0.0099506630f, -0.0015760302f}, | |
482 { 0.0000000000f, 0.0028570218f}, | |
483 {-0.0030168074f, 0.0004778154f}, | |
484 { 0.0018796273f, 0.0057848981f}, | |
485 { 0.0019511001f, -0.0009941351f}, | |
486 }, | |
487 { | |
488 { 0.0025576725f, 0.0013031992f}, /* Filter 5 */ | |
489 { 0.0015873149f, -0.0048852529f}, | |
490 { 0.0002697804f, 0.0000427290f}, | |
491 { 0.0000000000f, -0.0057443897f}, | |
492 {-0.0088745956f, 0.0014055979f}, | |
493 { 0.0007973152f, 0.0024538838f}, | |
494 {-0.0131833524f, 0.0067172536f}, | |
495 { 0.0100180850f, 0.0137887111f}, | |
496 { 0.0069881240f, -0.0069881240f}, | |
497 { 0.0268364889f, 0.0194978505f}, | |
498 { 0.0544701590f, -0.1069037062f}, | |
499 { 0.0578903347f, 0.0188097100f}, | |
500 { 0.0940009470f, -0.5934986215f}, | |
501 { 1.1328263283f, 0.0000000000f}, | |
502 { 0.1144728051f, 0.7227528464f}, | |
503 {-0.0114127678f, 0.0037082330f}, | |
504 { 0.0652944573f, 0.1281475878f}, | |
505 { 0.0149986858f, -0.0108971831f}, | |
506 { 0.0148400450f, 0.0148400450f}, | |
507 { 0.0114369676f, -0.0157416354f}, | |
508 {-0.0099579979f, -0.0050738534f}, | |
509 { 0.0022089316f, -0.0067983924f}, | |
510 {-0.0098859888f, -0.0015657868f}, | |
511 { 0.0000000000f, 0.0040052626f}, | |
512 {-0.0019552917f, 0.0003096878f}, | |
513 { 0.0018321212f, 0.0056386894f}, | |
514 { 0.0025576725f, -0.0013031992f}, | |
515 }, | |
516 { | |
517 { 0.0030665390f, 0.0015624797f}, /* Filter 6 */ | |
518 { 0.0017332683f, -0.0053344513f}, | |
519 {-0.0008479269f, -0.0001342984f}, | |
520 { 0.0000000000f, -0.0049758209f}, | |
521 {-0.0095191676f, 0.0015076880f}, | |
522 { 0.0015070535f, 0.0046382337f}, | |
523 {-0.0117630486f, 0.0059935726f}, | |
524 { 0.0109089996f, 0.0150149499f}, | |
525 { 0.0109262557f, -0.0109262557f}, | |
526 { 0.0215979519f, 0.0156918306f}, | |
527 { 0.0602999226f, -0.1183452615f}, | |
528 { 0.0256212387f, 0.0083248451f}, | |
529 { 0.1043613218f, -0.6589114533f}, | |
530 { 1.1366584301f, 0.0000000000f}, | |
531 { 0.1043613218f, 0.6589114533f}, | |
532 { 0.0256212387f, -0.0083248451f}, | |
533 { 0.0602999226f, 0.1183452615f}, | |
534 { 0.0215979519f, -0.0156918306f}, | |
535 { 0.0109262557f, 0.0109262557f}, | |
536 { 0.0109089996f, -0.0150149499f}, | |
537 {-0.0117630486f, -0.0059935726f}, | |
538 { 0.0015070535f, -0.0046382337f}, | |
539 {-0.0095191676f, -0.0015076880f}, | |
540 { 0.0000000000f, 0.0049758209f}, | |
541 {-0.0008479269f, 0.0001342984f}, | |
542 { 0.0017332683f, 0.0053344513f}, | |
543 { 0.0030665390f, -0.0015624797f}, | |
544 }, | |
545 { | |
546 { 0.0034652296f, 0.0017656227f}, /* Filter 7 */ | |
547 { 0.0018321212f, -0.0056386894f}, | |
548 {-0.0019552917f, -0.0003096878f}, | |
549 { 0.0000000000f, -0.0040052626f}, | |
550 {-0.0098859888f, 0.0015657868f}, | |
551 { 0.0022089316f, 0.0067983924f}, | |
552 {-0.0099579979f, 0.0050738534f}, | |
553 { 0.0114369676f, 0.0157416354f}, | |
554 { 0.0148400450f, -0.0148400450f}, | |
555 { 0.0149986858f, 0.0108971831f}, | |
556 { 0.0652944573f, -0.1281475878f}, | |
557 {-0.0114127678f, -0.0037082330f}, | |
558 { 0.1144728051f, -0.7227528464f}, | |
559 { 1.1328263283f, 0.0000000000f}, | |
560 { 0.0940009470f, 0.5934986215f}, | |
561 { 0.0578903347f, -0.0188097100f}, | |
562 { 0.0544701590f, 0.1069037062f}, | |
563 { 0.0268364889f, -0.0194978505f}, | |
564 { 0.0069881240f, 0.0069881240f}, | |
565 { 0.0100180850f, -0.0137887111f}, | |
566 {-0.0131833524f, -0.0067172536f}, | |
567 { 0.0007973152f, -0.0024538838f}, | |
568 {-0.0088745956f, -0.0014055979f}, | |
569 { 0.0000000000f, 0.0057443897f}, | |
570 { 0.0002697804f, -0.0000427290f}, | |
571 { 0.0015873149f, 0.0048852529f}, | |
572 { 0.0034652296f, -0.0017656227f}, | |
573 }, | |
574 { | |
575 { 0.0037449420f, 0.0019081433f}, /* Filter 8 */ | |
576 { 0.0018796273f, -0.0057848981f}, | |
577 {-0.0030168074f, -0.0004778154f}, | |
578 { 0.0000000000f, -0.0028570218f}, | |
579 {-0.0099506630f, 0.0015760302f}, | |
580 { 0.0028814530f, 0.0088682003f}, | |
581 {-0.0078088406f, 0.0039788030f}, | |
582 { 0.0115630893f, 0.0159152271f}, | |
583 { 0.0185973391f, -0.0185973390f}, | |
584 { 0.0070828755f, 0.0051460103f}, | |
585 { 0.0692420091f, -0.1358950944f}, | |
586 {-0.0530547129f, -0.0172385212f}, | |
587 { 0.1242110958f, -0.7842379942f}, | |
588 { 1.1213819981f, 0.0000000000f}, | |
589 { 0.0835162618f, 0.5273009241f}, | |
590 { 0.0853178815f, -0.0277214601f}, | |
591 { 0.0480159027f, 0.0942365150f}, | |
592 { 0.0307069943f, -0.0223099373f}, | |
593 { 0.0031486956f, 0.0031486956f}, | |
594 { 0.0088117029f, -0.0121282686f}, | |
595 {-0.0141915007f, -0.0072309308f}, | |
596 { 0.0001005750f, -0.0003095379f}, | |
597 {-0.0079839961f, -0.0012645408f}, | |
598 { 0.0000000000f, 0.0062936717f}, | |
599 { 0.0013630316f, -0.0002158830f}, | |
600 { 0.0013998188f, 0.0043081992f}, | |
601 { 0.0037449420f, -0.0019081433f}, | |
602 }, | |
603 { | |
604 { 0.0039007144f, 0.0019875132f}, /* Filter 9 */ | |
605 { 0.0018730190f, -0.0057645597f}, | |
606 {-0.0039973434f, -0.0006331170f}, | |
607 { 0.0000000000f, -0.0015619067f}, | |
608 {-0.0096971580f, 0.0015358789f}, | |
609 { 0.0035031104f, 0.0107814651f}, | |
610 {-0.0053688554f, 0.0027355684f}, | |
611 { 0.0112587393f, 0.0154963252f}, | |
612 { 0.0220599213f, -0.0220599213f}, | |
613 {-0.0020666801f, -0.0015015310f}, | |
614 { 0.0719339457f, -0.1411783175f}, | |
615 {-0.0990668329f, -0.0321887653f}, | |
616 { 0.1334542238f, -0.8425968074f}, | |
617 { 1.1024802923f, 0.0000000000f}, | |
618 { 0.0730301872f, 0.4610944549f}, | |
619 { 0.1079056364f, -0.0350606666f}, | |
620 { 0.0411429005f, 0.0807474888f}, | |
621 { 0.0332365955f, -0.0241478001f}, | |
622 {-0.0004807357f, -0.0004807357f}, | |
623 { 0.0073440948f, -0.0101082792f}, | |
624 {-0.0147735044f, -0.0075274764f}, | |
625 {-0.0005635325f, 0.0017343746f}, | |
626 {-0.0068852097f, -0.0010905101f}, | |
627 { 0.0000000000f, 0.0066136620f}, | |
628 { 0.0023987660f, -0.0003799272f}, | |
629 { 0.0011774450f, 0.0036238031f}, | |
630 { 0.0039007144f, -0.0019875132f}, | |
631 }, | |
632 { | |
633 { 0.0039314768f, 0.0020031875f}, /* Filter 10 */ | |
634 { 0.0018111360f, -0.0055741034f}, | |
635 {-0.0048632493f, -0.0007702630f}, | |
636 { 0.0000000000f, -0.0001565015f}, | |
637 {-0.0091186142f, 0.0014442466f}, | |
638 { 0.0040530413f, 0.0124739786f}, | |
639 {-0.0027029676f, 0.0013772308f}, | |
640 { 0.0105070407f, 0.0144617008f}, | |
641 { 0.0250869159f, -0.0250869159f}, | |
642 {-0.0123276338f, -0.0089565502f}, | |
643 { 0.0731690629f, -0.1436023716f}, | |
644 {-0.1491315874f, -0.0484557901f}, | |
645 { 0.1420845360f, -0.8970864542f}, | |
646 { 1.0763765574f, 0.0000000000f}, | |
647 { 0.0626620127f, 0.3956323778f}, | |
648 { 0.1257304818f, -0.0408523100f}, | |
649 { 0.0340482504f, 0.0668234539f}, | |
650 { 0.0344837758f, -0.0250539297f}, | |
651 {-0.0038028170f, -0.0038028170f}, | |
652 { 0.0056743444f, -0.0078100650f}, | |
653 {-0.0149285967f, -0.0076064999f}, | |
654 {-0.0011771217f, 0.0036228080f}, | |
655 {-0.0056208495f, -0.0008902551f}, | |
656 { 0.0000000000f, 0.0067017064f}, | |
657 { 0.0033466091f, -0.0005300508f}, | |
658 { 0.0009277352f, 0.0028552754f}, | |
659 { 0.0039314768f, -0.0020031875f}, | |
660 }, | |
661 { | |
662 { 0.0038399827f, 0.0019565689f}, /* Filter 11 */ | |
663 { 0.0016945064f, -0.0052151545f}, | |
664 {-0.0055834514f, -0.0008843318f}, | |
665 {-0.0000000000f, 0.0013177606f}, | |
666 {-0.0082179267f, 0.0013015917f}, | |
667 { 0.0045116911f, 0.0138855574f}, | |
668 { 0.0001136455f, -0.0000579053f}, | |
669 { 0.0093041035f, 0.0128059998f}, | |
670 { 0.0275384769f, -0.0275384769f}, | |
671 {-0.0235379981f, -0.0171013566f}, | |
672 { 0.0727579142f, -0.1427954467f}, | |
673 {-0.2028542371f, -0.0659113371f}, | |
674 { 0.1499906453f, -0.9470036639f}, | |
675 { 1.0434222221f, 0.0000000000f}, | |
676 { 0.0525256151f, 0.3316336818f}, | |
677 { 0.1389398473f, -0.0451442930f}, | |
678 { 0.0269170677f, 0.0528277198f}, | |
679 { 0.0345347757f, -0.0250909833f}, | |
680 {-0.0067358415f, -0.0067358415f}, | |
681 { 0.0038644283f, -0.0053189292f}, | |
682 {-0.0146686673f, -0.0074740593f}, | |
683 {-0.0017245111f, 0.0053074995f}, | |
684 {-0.0042368606f, -0.0006710528f}, | |
685 { 0.0000000000f, 0.0065623410f}, | |
686 { 0.0041797109f, -0.0006620012f}, | |
687 { 0.0006588563f, 0.0020277512f}, | |
688 { 0.0038399827f, -0.0019565689f}, | |
689 }, | |
690 }; | |
691 | |
692 float v27ter_rx_carrier_frequency(v27ter_rx_state_t *s) | |
693 { | |
694 return dds_frequencyf(s->carrier_phase_rate); | |
695 } | |
696 /*- End of function --------------------------------------------------------*/ | |
697 | |
698 float v27ter_rx_symbol_timing_correction(v27ter_rx_state_t *s) | |
699 { | |
700 int steps_per_symbol; | |
701 | |
702 steps_per_symbol = (s->bit_rate == 4800) ? PULSESHAPER_4800_COEFF_SETS*5 : PULSESHAPER_2400_COEFF_SETS*20/3; | |
703 return (float) s->total_baud_timing_correction/(float) steps_per_symbol; | |
704 } | |
705 /*- End of function --------------------------------------------------------*/ | |
706 | |
707 float v27ter_rx_signal_power(v27ter_rx_state_t *s) | |
708 { | |
709 return power_meter_dbm0(&s->power); | |
710 } | |
711 /*- End of function --------------------------------------------------------*/ | |
712 | |
713 void v27ter_rx_signal_cutoff(v27ter_rx_state_t *s, float cutoff) | |
714 { | |
715 /* The 0.4 factor allows for the gain of the DC blocker */ | |
716 s->carrier_on_power = (int32_t) (power_meter_level_dbm0(cutoff + 2.5f)*0.4f); | |
717 s->carrier_off_power = (int32_t) (power_meter_level_dbm0(cutoff - 2.5f)*0.4f); | |
718 } | |
719 /*- End of function --------------------------------------------------------*/ | |
720 | |
721 int v27ter_rx_equalizer_state(v27ter_rx_state_t *s, complexf_t **coeffs) | |
722 { | |
723 *coeffs = s->eq_coeff; | |
724 return V27TER_EQUALIZER_PRE_LEN + 1 + V27TER_EQUALIZER_POST_LEN; | |
725 } | |
726 /*- End of function --------------------------------------------------------*/ | |
727 | |
728 static void equalizer_save(v27ter_rx_state_t *s) | |
729 { | |
730 cvec_copyf(s->eq_coeff_save, s->eq_coeff, V27TER_EQUALIZER_PRE_LEN + 1 + V27TER_EQUALIZER_POST_LEN); | |
731 } | |
732 /*- End of function --------------------------------------------------------*/ | |
733 | |
734 static void equalizer_restore(v27ter_rx_state_t *s) | |
735 { | |
736 cvec_copyf(s->eq_coeff, s->eq_coeff_save, V27TER_EQUALIZER_PRE_LEN + 1 + V27TER_EQUALIZER_POST_LEN); | |
737 cvec_zerof(s->eq_buf, V27TER_EQUALIZER_MASK); | |
738 | |
739 s->eq_put_step = (s->bit_rate == 4800) ? PULSESHAPER_4800_COEFF_SETS*5/2 : PULSESHAPER_2400_COEFF_SETS*20/(3*2); | |
740 s->eq_step = 0; | |
741 s->eq_delta = EQUALIZER_DELTA/(V27TER_EQUALIZER_PRE_LEN + 1 + V27TER_EQUALIZER_POST_LEN); | |
742 } | |
743 /*- End of function --------------------------------------------------------*/ | |
744 | |
745 static void equalizer_reset(v27ter_rx_state_t *s) | |
746 { | |
747 /* Start with an equalizer based on everything being perfect */ | |
748 cvec_zerof(s->eq_coeff, V27TER_EQUALIZER_PRE_LEN + 1 + V27TER_EQUALIZER_POST_LEN); | |
749 s->eq_coeff[V27TER_EQUALIZER_PRE_LEN] = complex_setf(1.414f, 0.0f); | |
750 cvec_zerof(s->eq_buf, V27TER_EQUALIZER_MASK); | |
751 | |
752 s->eq_put_step = (s->bit_rate == 4800) ? PULSESHAPER_4800_COEFF_SETS*5/2 : PULSESHAPER_2400_COEFF_SETS*20/(3*2); | |
753 s->eq_step = 0; | |
754 s->eq_delta = EQUALIZER_DELTA/(V27TER_EQUALIZER_PRE_LEN + 1 + V27TER_EQUALIZER_POST_LEN); | |
755 } | |
756 /*- End of function --------------------------------------------------------*/ | |
757 | |
758 static __inline__ complexf_t equalizer_get(v27ter_rx_state_t *s) | |
759 { | |
760 int i; | |
761 int p; | |
762 complexf_t z; | |
763 complexf_t z1; | |
764 | |
765 /* Get the next equalized value. */ | |
766 z = complex_setf(0.0, 0.0); | |
767 p = s->eq_step - 1; | |
768 for (i = 0; i < V27TER_EQUALIZER_PRE_LEN + 1 + V27TER_EQUALIZER_POST_LEN; i++) | |
769 { | |
770 p = (p - 1) & V27TER_EQUALIZER_MASK; | |
771 z1 = complex_mulf(&s->eq_coeff[i], &s->eq_buf[p]); | |
772 z = complex_addf(&z, &z1); | |
773 } | |
774 return z; | |
775 } | |
776 /*- End of function --------------------------------------------------------*/ | |
777 | |
778 static void tune_equalizer(v27ter_rx_state_t *s, const complexf_t *z, const complexf_t *target) | |
779 { | |
780 int i; | |
781 int p; | |
782 complexf_t ez; | |
783 complexf_t z1; | |
784 | |
785 /* Find the x and y mismatch from the exact constellation position. */ | |
786 ez = complex_subf(target, z); | |
787 ez.re *= s->eq_delta; | |
788 ez.im *= s->eq_delta; | |
789 | |
790 p = s->eq_step - 1; | |
791 for (i = 0; i < V27TER_EQUALIZER_PRE_LEN + 1 + V27TER_EQUALIZER_POST_LEN; i++) | |
792 { | |
793 p = (p - 1) & V27TER_EQUALIZER_MASK; | |
794 z1 = complex_conjf(&s->eq_buf[p]); | |
795 z1 = complex_mulf(&ez, &z1); | |
796 s->eq_coeff[i] = complex_addf(&s->eq_coeff[i], &z1); | |
797 /* Leak a little to tame uncontrolled wandering */ | |
798 s->eq_coeff[i].re *= 0.9999f; | |
799 s->eq_coeff[i].im *= 0.9999f; | |
800 } | |
801 } | |
802 /*- End of function --------------------------------------------------------*/ | |
803 | |
804 static __inline__ void track_carrier(v27ter_rx_state_t *s, const complexf_t *z, const complexf_t *target) | |
805 { | |
806 float error; | |
807 | |
808 /* For small errors the imaginary part of the difference between the actual and the target | |
809 positions is proportional to the phase error, for any particular target. However, the | |
810 different amplitudes of the various target positions scale things. */ | |
811 error = z->im*target->re - z->re*target->im; | |
812 | |
813 s->carrier_phase_rate += (int32_t) (s->carrier_track_i*error); | |
814 s->carrier_phase += (int32_t) (s->carrier_track_p*error); | |
815 //span_log(&s->logging, SPAN_LOG_FLOW, "Im = %15.5f f = %15.5f\n", error, dds_frequencyf(s->carrier_phase_rate)); | |
816 } | |
817 /*- End of function --------------------------------------------------------*/ | |
818 | |
819 static __inline__ int descramble(v27ter_rx_state_t *s, int in_bit) | |
820 { | |
821 int out_bit; | |
822 | |
823 out_bit = (in_bit ^ (s->scramble_reg >> 5) ^ (s->scramble_reg >> 6)) & 1; | |
824 if (s->scrambler_pattern_count >= 33) | |
825 { | |
826 out_bit ^= 1; | |
827 s->scrambler_pattern_count = 0; | |
828 } | |
829 else | |
830 { | |
831 if (s->in_training > TRAINING_STAGE_NORMAL_OPERATION && s->in_training < TRAINING_STAGE_TEST_ONES) | |
832 { | |
833 s->scrambler_pattern_count = 0; | |
834 } | |
835 else | |
836 { | |
837 if ((((s->scramble_reg >> 7) ^ in_bit) & ((s->scramble_reg >> 8) ^ in_bit) & ((s->scramble_reg >> 11) ^ in_bit) & 1)) | |
838 s->scrambler_pattern_count = 0; | |
839 else | |
840 s->scrambler_pattern_count++; | |
841 } | |
842 } | |
843 s->scramble_reg <<= 1; | |
844 if (s->in_training > TRAINING_STAGE_NORMAL_OPERATION && s->in_training < TRAINING_STAGE_TEST_ONES) | |
845 s->scramble_reg |= out_bit; | |
846 else | |
847 s->scramble_reg |= in_bit; | |
848 return out_bit; | |
849 } | |
850 /*- End of function --------------------------------------------------------*/ | |
851 | |
852 static __inline__ void put_bit(v27ter_rx_state_t *s, int bit) | |
853 { | |
854 int out_bit; | |
855 | |
856 bit &= 1; | |
857 | |
858 out_bit = descramble(s, bit); | |
859 | |
860 /* We need to strip the last part of the training before we let data | |
861 go to the application. */ | |
862 if (s->in_training == TRAINING_STAGE_NORMAL_OPERATION) | |
863 { | |
864 s->put_bit(s->user_data, out_bit); | |
865 } | |
866 else | |
867 { | |
868 //span_log(&s->logging, SPAN_LOG_FLOW, "Test bit %d\n", out_bit); | |
869 /* The bits during the final stage of training should be all ones. However, | |
870 buggy modems mean you cannot rely on this. Therefore we don't bother | |
871 testing for ones, but just rely on a constellation mismatch measurement. */ | |
872 } | |
873 } | |
874 /*- End of function --------------------------------------------------------*/ | |
875 | |
876 static __inline__ int find_quadrant(const complexf_t *z) | |
877 { | |
878 int b1; | |
879 int b2; | |
880 | |
881 /* Split the space along the two diagonals. */ | |
882 b1 = (z->im > z->re); | |
883 b2 = (z->im < -z->re); | |
884 return (b2 << 1) | (b1 ^ b2); | |
885 } | |
886 /*- End of function --------------------------------------------------------*/ | |
887 | |
888 static __inline__ int find_octant(complexf_t *z) | |
889 { | |
890 float abs_re; | |
891 float abs_im; | |
892 int b1; | |
893 int b2; | |
894 int bits; | |
895 | |
896 /* Are we near an axis or a diagonal? */ | |
897 abs_re = fabsf(z->re); | |
898 abs_im = fabsf(z->im); | |
899 if (abs_im > abs_re*0.4142136 && abs_im < abs_re*2.4142136) | |
900 { | |
901 /* Split the space along the two axes. */ | |
902 b1 = (z->re < 0.0); | |
903 b2 = (z->im < 0.0); | |
904 bits = (b2 << 2) | ((b1 ^ b2) << 1) | 1; | |
905 } | |
906 else | |
907 { | |
908 /* Split the space along the two diagonals. */ | |
909 b1 = (z->im > z->re); | |
910 b2 = (z->im < -z->re); | |
911 bits = (b2 << 2) | ((b1 ^ b2) << 1); | |
912 } | |
913 return bits; | |
914 } | |
915 /*- End of function --------------------------------------------------------*/ | |
916 | |
917 static void decode_baud(v27ter_rx_state_t *s, complexf_t *z) | |
918 { | |
919 static const uint8_t phase_steps_4800[8] = | |
920 { | |
921 4, 0, 2, 6, 7, 3, 1, 5 | |
922 }; | |
923 static const uint8_t phase_steps_2400[4] = | |
924 { | |
925 0, 2, 3, 1 | |
926 }; | |
927 int nearest; | |
928 int raw_bits; | |
929 | |
930 switch (s->bit_rate) | |
931 { | |
932 case 4800: | |
933 default: | |
934 nearest = find_octant(z); | |
935 raw_bits = phase_steps_4800[(nearest - s->constellation_state) & 7]; | |
936 put_bit(s, raw_bits); | |
937 put_bit(s, raw_bits >> 1); | |
938 put_bit(s, raw_bits >> 2); | |
939 s->constellation_state = nearest; | |
940 break; | |
941 case 2400: | |
942 nearest = find_quadrant(z); | |
943 raw_bits = phase_steps_2400[(nearest - s->constellation_state) & 3]; | |
944 put_bit(s, raw_bits); | |
945 put_bit(s, raw_bits >> 1); | |
946 s->constellation_state = nearest; | |
947 nearest <<= 1; | |
948 break; | |
949 } | |
950 track_carrier(s, z, &v27ter_constellation[nearest]); | |
951 if (--s->eq_skip <= 0) | |
952 { | |
953 /* Once we are in the data the equalization should not need updating. | |
954 However, the line characteristics may slowly drift. We, therefore, | |
955 tune up on the occassional sample, keeping the compute down. */ | |
956 s->eq_skip = 100; | |
957 tune_equalizer(s, z, &v27ter_constellation[nearest]); | |
958 } | |
959 } | |
960 /*- End of function --------------------------------------------------------*/ | |
961 | |
962 static __inline__ void process_half_baud(v27ter_rx_state_t *s, const complexf_t *sample) | |
963 { | |
964 static const int abab_pos[2] = | |
965 { | |
966 0, 4 | |
967 }; | |
968 complexf_t z; | |
969 complexf_t zz; | |
970 float p; | |
971 float q; | |
972 int i; | |
973 int j; | |
974 int32_t angle; | |
975 int32_t ang; | |
976 | |
977 /* Add a sample to the equalizer's circular buffer, but don't calculate anything | |
978 at this time. */ | |
979 s->eq_buf[s->eq_step] = *sample; | |
980 s->eq_step = (s->eq_step + 1) & V27TER_EQUALIZER_MASK; | |
981 | |
982 /* On alternate insertions we have a whole baud, and must process it. */ | |
983 if ((s->baud_phase ^= 1)) | |
984 { | |
985 //span_log(&s->logging, SPAN_LOG_FLOW, "Samp, %f, %f, %f, -1, 0x%X\n", z.re, z.im, sqrt(z.re*z.re + z.im*z.im), s->eq_put_step); | |
986 return; | |
987 } | |
988 //span_log(&s->logging, SPAN_LOG_FLOW, "Samp, %f, %f, %f, 1, 0x%X\n", z.re, z.im, sqrt(z.re*z.re + z.im*z.im), s->eq_put_step); | |
989 | |
990 /* Perform a Gardner test for baud alignment */ | |
991 p = s->eq_buf[(s->eq_step - 3) & V27TER_EQUALIZER_MASK].re | |
992 - s->eq_buf[(s->eq_step - 1) & V27TER_EQUALIZER_MASK].re; | |
993 p *= s->eq_buf[(s->eq_step - 2) & V27TER_EQUALIZER_MASK].re; | |
994 | |
995 q = s->eq_buf[(s->eq_step - 3) & V27TER_EQUALIZER_MASK].im | |
996 - s->eq_buf[(s->eq_step - 1) & V27TER_EQUALIZER_MASK].im; | |
997 q *= s->eq_buf[(s->eq_step - 2) & V27TER_EQUALIZER_MASK].im; | |
998 | |
999 s->gardner_integrate += (p + q > 0.0) ? s->gardner_step : -s->gardner_step; | |
1000 | |
1001 if (abs(s->gardner_integrate) >= 256) | |
1002 { | |
1003 /* This integrate and dump approach avoids rapid changes of the equalizer put step. | |
1004 Rapid changes, without hysteresis, are bad. They degrade the equalizer performance | |
1005 when the true symbol boundary is close to a sample boundary. */ | |
1006 //span_log(&s->logging, SPAN_LOG_FLOW, "Hop %d\n", s->gardner_integrate); | |
1007 s->eq_put_step += (s->gardner_integrate/256); | |
1008 s->total_baud_timing_correction += (s->gardner_integrate/256); | |
1009 if (s->qam_report) | |
1010 s->qam_report(s->qam_user_data, NULL, NULL, s->gardner_integrate); | |
1011 s->gardner_integrate = 0; | |
1012 } | |
1013 //span_log(&s->logging, SPAN_LOG_FLOW, "Gardner=%10.5f 0x%X\n", p, s->eq_put_step); | |
1014 | |
1015 z = equalizer_get(s); | |
1016 | |
1017 //span_log(&s->logging, SPAN_LOG_FLOW, "Equalized symbol - %15.5f %15.5f\n", z.re, z.im); | |
1018 switch (s->in_training) | |
1019 { | |
1020 case TRAINING_STAGE_NORMAL_OPERATION: | |
1021 decode_baud(s, &z); | |
1022 break; | |
1023 case TRAINING_STAGE_SYMBOL_ACQUISITION: | |
1024 /* Allow time for the Gardner algorithm to settle the baud timing */ | |
1025 /* Don't start narrowing the bandwidth of the Gardner algorithm too early. | |
1026 Some modems are a bit wobbly when they start sending the signal. Also, we start | |
1027 this analysis before our filter buffers have completely filled. */ | |
1028 if (++s->training_count >= 30) | |
1029 { | |
1030 s->gardner_step = 32; | |
1031 s->in_training = TRAINING_STAGE_LOG_PHASE; | |
1032 s->angles[0] = | |
1033 s->start_angles[0] = arctan2(z.im, z.re); | |
1034 } | |
1035 break; | |
1036 case TRAINING_STAGE_LOG_PHASE: | |
1037 /* Record the current alternate phase angle */ | |
1038 angle = arctan2(z.im, z.re); | |
1039 s->angles[1] = | |
1040 s->start_angles[1] = angle; | |
1041 s->training_count = 1; | |
1042 s->in_training = TRAINING_STAGE_WAIT_FOR_HOP; | |
1043 break; | |
1044 case TRAINING_STAGE_WAIT_FOR_HOP: | |
1045 angle = arctan2(z.im, z.re); | |
1046 /* Look for the initial ABAB sequence to display a phase reversal, which will | |
1047 signal the start of the scrambled ABAB segment */ | |
1048 ang = angle - s->angles[(s->training_count - 1) & 0xF]; | |
1049 s->angles[(s->training_count + 1) & 0xF] = angle; | |
1050 if ((ang > 0x20000000 || ang < -0x20000000) && s->training_count >= 3) | |
1051 { | |
1052 /* We seem to have a phase reversal */ | |
1053 /* Slam the carrier frequency into line, based on the total phase drift over the last | |
1054 section. Use the shift from the odd bits and the shift from the even bits to get | |
1055 better jitter suppression. We need to scale here, or at the maximum specified | |
1056 frequency deviation we could overflow, and get a silly answer. */ | |
1057 /* Step back a few symbols so we don't get ISI distorting things. */ | |
1058 i = (s->training_count - 8) & ~1; | |
1059 /* Avoid the possibility of a divide by zero */ | |
1060 if (i) | |
1061 { | |
1062 j = i & 0xF; | |
1063 ang = (s->angles[j] - s->start_angles[0])/i | |
1064 + (s->angles[j | 0x1] - s->start_angles[1])/i; | |
1065 if (s->bit_rate == 4800) | |
1066 s->carrier_phase_rate += ang/10; | |
1067 else | |
1068 s->carrier_phase_rate += 3*(ang/40); | |
1069 } | |
1070 span_log(&s->logging, SPAN_LOG_FLOW, "Coarse carrier frequency %7.2f (%d)\n", dds_frequencyf(s->carrier_phase_rate), s->training_count); | |
1071 /* Check if the carrier frequency is plausible */ | |
1072 if (s->carrier_phase_rate < dds_phase_ratef(CARRIER_NOMINAL_FREQ - 20.0f) | |
1073 || | |
1074 s->carrier_phase_rate > dds_phase_ratef(CARRIER_NOMINAL_FREQ + 20.0f)) | |
1075 { | |
1076 span_log(&s->logging, SPAN_LOG_FLOW, "Training failed (sequence failed)\n"); | |
1077 /* Park this modem */ | |
1078 s->in_training = TRAINING_STAGE_PARKED; | |
1079 s->put_bit(s->user_data, PUTBIT_TRAINING_FAILED); | |
1080 break; | |
1081 } | |
1082 | |
1083 /* Make a step shift in the phase, to pull it into line. We need to rotate the equalizer | |
1084 buffer, as well as the carrier phase, for this to play out nicely. */ | |
1085 angle += 0x80000000; | |
1086 p = angle*2.0f*3.14159f/(65536.0f*65536.0f); | |
1087 zz = complex_setf(cosf(p), -sinf(p)); | |
1088 for (i = 0; i <= V27TER_EQUALIZER_MASK; i++) | |
1089 s->eq_buf[i] = complex_mulf(&s->eq_buf[i], &zz); | |
1090 s->carrier_phase += angle; | |
1091 | |
1092 s->gardner_step = 1; | |
1093 /* We have just seen the first element of the scrambled sequence so skip it. */ | |
1094 s->training_bc = 1; | |
1095 s->training_bc ^= descramble(s, 1); | |
1096 descramble(s, 1); | |
1097 descramble(s, 1); | |
1098 s->training_count = 1; | |
1099 s->in_training = TRAINING_STAGE_TRAIN_ON_ABAB; | |
1100 } | |
1101 else if (++s->training_count > V27TER_TRAINING_SEG_3_LEN) | |
1102 { | |
1103 /* This is bogus. There are not this many bits in this section | |
1104 of a real training sequence. */ | |
1105 span_log(&s->logging, SPAN_LOG_FLOW, "Training failed (sequence failed)\n"); | |
1106 /* Park this modem */ | |
1107 s->in_training = TRAINING_STAGE_PARKED; | |
1108 s->put_bit(s->user_data, PUTBIT_TRAINING_FAILED); | |
1109 } | |
1110 break; | |
1111 case TRAINING_STAGE_TRAIN_ON_ABAB: | |
1112 /* Train on the scrambled ABAB section */ | |
1113 s->training_bc ^= descramble(s, 1); | |
1114 descramble(s, 1); | |
1115 descramble(s, 1); | |
1116 s->constellation_state = abab_pos[s->training_bc]; | |
1117 track_carrier(s, &z, &v27ter_constellation[s->constellation_state]); | |
1118 tune_equalizer(s, &z, &v27ter_constellation[s->constellation_state]); | |
1119 | |
1120 if (++s->training_count >= V27TER_TRAINING_SEG_5_LEN) | |
1121 { | |
1122 s->constellation_state = (s->bit_rate == 4800) ? 4 : 2; | |
1123 s->training_count = 0; | |
1124 s->in_training = TRAINING_STAGE_TEST_ONES; | |
1125 s->carrier_track_i = 400.0; | |
1126 s->carrier_track_p = 1000000.0; | |
1127 } | |
1128 break; | |
1129 case TRAINING_STAGE_TEST_ONES: | |
1130 decode_baud(s, &z); | |
1131 /* Measure the training error */ | |
1132 if (s->bit_rate == 4800) | |
1133 zz = complex_subf(&z, &v27ter_constellation[s->constellation_state]); | |
1134 else | |
1135 zz = complex_subf(&z, &v27ter_constellation[s->constellation_state << 1]); | |
1136 s->training_error += powerf(&zz); | |
1137 if (++s->training_count >= V27TER_TRAINING_SEG_6_LEN) | |
1138 { | |
1139 if ((s->bit_rate == 4800 && s->training_error < 1.0f) | |
1140 || | |
1141 (s->bit_rate == 2400 && s->training_error < 1.0f)) | |
1142 { | |
1143 /* We are up and running */ | |
1144 span_log(&s->logging, SPAN_LOG_FLOW, "Training succeeded (constellation mismatch %f)\n", s->training_error); | |
1145 s->put_bit(s->user_data, PUTBIT_TRAINING_SUCCEEDED); | |
1146 /* Apply some lag to the carrier off condition, to ensure the last few bits get pushed through | |
1147 the processing. */ | |
1148 s->carrier_present = (s->bit_rate == 4800) ? 90 : 120; | |
1149 s->in_training = TRAINING_STAGE_NORMAL_OPERATION; | |
1150 equalizer_save(s); | |
1151 s->carrier_phase_rate_save = s->carrier_phase_rate; | |
1152 s->agc_scaling_save = s->agc_scaling; | |
1153 } | |
1154 else | |
1155 { | |
1156 /* Training has failed */ | |
1157 span_log(&s->logging, SPAN_LOG_FLOW, "Training failed (constellation mismatch %f)\n", s->training_error); | |
1158 /* Park this modem */ | |
1159 s->in_training = TRAINING_STAGE_PARKED; | |
1160 s->put_bit(s->user_data, PUTBIT_TRAINING_FAILED); | |
1161 } | |
1162 } | |
1163 break; | |
1164 case TRAINING_STAGE_PARKED: | |
1165 /* We failed to train! */ | |
1166 /* Park here until the carrier drops. */ | |
1167 break; | |
1168 } | |
1169 if (s->qam_report) | |
1170 { | |
1171 s->qam_report(s->qam_user_data, | |
1172 &z, | |
1173 &v27ter_constellation[s->constellation_state], | |
1174 s->constellation_state); | |
1175 } | |
1176 } | |
1177 /*- End of function --------------------------------------------------------*/ | |
1178 | |
1179 int v27ter_rx(v27ter_rx_state_t *s, const int16_t amp[], int len) | |
1180 { | |
1181 int i; | |
1182 int j; | |
1183 int step; | |
1184 complexf_t z; | |
1185 complexf_t zz; | |
1186 complexf_t samplex; | |
1187 int32_t power; | |
1188 | |
1189 if (s->bit_rate == 4800) | |
1190 { | |
1191 for (i = 0; i < len; i++) | |
1192 { | |
1193 s->rrc_filter[s->rrc_filter_step] = | |
1194 s->rrc_filter[s->rrc_filter_step + V27TER_RX_4800_FILTER_STEPS] = amp[i]; | |
1195 if (++s->rrc_filter_step >= V27TER_RX_4800_FILTER_STEPS) | |
1196 s->rrc_filter_step = 0; | |
1197 | |
1198 /* There should be no DC in the signal, but sometimes there is. | |
1199 We need to measure the power with the DC blocked, but not using | |
1200 a slow to respond DC blocker. Use the most elementary HPF. */ | |
1201 power = power_meter_update(&(s->power), (amp[i] - s->last_sample) >> 1); | |
1202 s->last_sample = amp[i]; | |
1203 //span_log(&s->logging, SPAN_LOG_FLOW, "Power = %f\n", power_meter_dbm0(&(s->power))); | |
1204 if (s->carrier_present) | |
1205 { | |
1206 /* Look for power below turnoff threshold to turn the carrier off */ | |
1207 if (power < s->carrier_off_power) | |
1208 { | |
1209 if (--s->carrier_present <= 0) | |
1210 { | |
1211 /* Count down a short delay, to ensure we push the last | |
1212 few bits through the filters before stopping. */ | |
1213 v27ter_rx_restart(s, s->bit_rate, FALSE); | |
1214 s->put_bit(s->user_data, PUTBIT_CARRIER_DOWN); | |
1215 continue; | |
1216 } | |
1217 } | |
1218 } | |
1219 else | |
1220 { | |
1221 /* Look for power exceeding turnon threshold to turn the carrier on */ | |
1222 if (power < s->carrier_on_power) | |
1223 continue; | |
1224 s->carrier_present = 1; | |
1225 s->put_bit(s->user_data, PUTBIT_CARRIER_UP); | |
1226 } | |
1227 if (s->in_training != TRAINING_STAGE_PARKED) | |
1228 { | |
1229 /* Only spend effort processing this data if the modem is not | |
1230 parked, after training failure. */ | |
1231 z = dds_complexf(&(s->carrier_phase), s->carrier_phase_rate); | |
1232 | |
1233 /* Put things into the equalization buffer at T/2 rate. The Gardner algorithm | |
1234 will fiddle the step to align this with the symbols. */ | |
1235 if ((s->eq_put_step -= PULSESHAPER_4800_COEFF_SETS) <= 0) | |
1236 { | |
1237 if (s->in_training == TRAINING_STAGE_SYMBOL_ACQUISITION) | |
1238 { | |
1239 /* Only AGC during the initial training */ | |
1240 s->agc_scaling = (1.0f/PULSESHAPER_4800_GAIN)*1.414f/sqrtf(power); | |
1241 } | |
1242 /* Pulse shape while still at the carrier frequency, using a quadrature | |
1243 pair of filters. This results in a properly bandpass filtered complex | |
1244 signal, which can be brought directly to bandband by complex mixing. | |
1245 No further filtering, to remove mixer harmonics, is needed. */ | |
1246 step = -s->eq_put_step; | |
1247 if (step > PULSESHAPER_4800_COEFF_SETS - 1) | |
1248 step = PULSESHAPER_4800_COEFF_SETS - 1; | |
1249 s->eq_put_step += PULSESHAPER_4800_COEFF_SETS*5/2; | |
1250 zz.re = pulseshaper_4800[step][0].re*s->rrc_filter[s->rrc_filter_step]; | |
1251 zz.im = pulseshaper_4800[step][0].im*s->rrc_filter[s->rrc_filter_step]; | |
1252 for (j = 1; j < V27TER_RX_4800_FILTER_STEPS; j++) | |
1253 { | |
1254 zz.re += pulseshaper_4800[step][j].re*s->rrc_filter[j + s->rrc_filter_step]; | |
1255 zz.im += pulseshaper_4800[step][j].im*s->rrc_filter[j + s->rrc_filter_step]; | |
1256 } | |
1257 samplex.re = zz.re*s->agc_scaling; | |
1258 samplex.im = zz.im*s->agc_scaling; | |
1259 /* Shift to baseband - since this is done in a full complex form, the | |
1260 result is clean, and requires no further filtering, apart from the | |
1261 equalizer. */ | |
1262 zz.re = samplex.re*z.re - samplex.im*z.im; | |
1263 zz.im = -samplex.re*z.im - samplex.im*z.re; | |
1264 process_half_baud(s, &zz); | |
1265 } | |
1266 } | |
1267 } | |
1268 } | |
1269 else | |
1270 { | |
1271 for (i = 0; i < len; i++) | |
1272 { | |
1273 s->rrc_filter[s->rrc_filter_step] = | |
1274 s->rrc_filter[s->rrc_filter_step + V27TER_RX_2400_FILTER_STEPS] = amp[i]; | |
1275 if (++s->rrc_filter_step >= V27TER_RX_2400_FILTER_STEPS) | |
1276 s->rrc_filter_step = 0; | |
1277 | |
1278 /* There should be no DC in the signal, but sometimes there is. | |
1279 We need to measure the power with the DC blocked, but not using | |
1280 a slow to respond DC blocker. Use the most elementary HPF. */ | |
1281 power = power_meter_update(&(s->power), (amp[i] - s->last_sample) >> 1); | |
1282 s->last_sample = amp[i]; | |
1283 //span_log(&s->logging, SPAN_LOG_FLOW, "Power = %f\n", power_meter_dbm0(&(s->power))); | |
1284 if (s->carrier_present) | |
1285 { | |
1286 /* Look for power below turnoff threshold to turn the carrier off */ | |
1287 if (power < s->carrier_off_power) | |
1288 { | |
1289 if (--s->carrier_present <= 0) | |
1290 { | |
1291 /* Count down a short delay, to ensure we push the last | |
1292 few bits through the filters before stopping. */ | |
1293 v27ter_rx_restart(s, s->bit_rate, FALSE); | |
1294 s->put_bit(s->user_data, PUTBIT_CARRIER_DOWN); | |
1295 continue; | |
1296 } | |
1297 } | |
1298 } | |
1299 else | |
1300 { | |
1301 /* Look for power exceeding turnon threshold to turn the carrier on */ | |
1302 if (power < s->carrier_on_power) | |
1303 continue; | |
1304 s->carrier_present = 1; | |
1305 s->put_bit(s->user_data, PUTBIT_CARRIER_UP); | |
1306 } | |
1307 if (s->in_training != TRAINING_STAGE_PARKED) | |
1308 { | |
1309 /* Only spend effort processing this data if the modem is not | |
1310 parked, after training failure. */ | |
1311 z = dds_complexf(&(s->carrier_phase), s->carrier_phase_rate); | |
1312 | |
1313 /* Put things into the equalization buffer at T/2 rate. The Gardner algorithm | |
1314 will fiddle the step to align this with the symbols. */ | |
1315 if ((s->eq_put_step -= PULSESHAPER_2400_COEFF_SETS) <= 0) | |
1316 { | |
1317 if (s->in_training == TRAINING_STAGE_SYMBOL_ACQUISITION) | |
1318 { | |
1319 /* Only AGC during the initial training */ | |
1320 s->agc_scaling = (1.0f/PULSESHAPER_2400_GAIN)*1.414f/sqrtf(power); | |
1321 } | |
1322 /* Pulse shape while still at the carrier frequency, using a quadrature | |
1323 pair of filters. This results in a properly bandpass filtered complex | |
1324 signal, which can be brought directly to bandband by complex mixing. | |
1325 No further filtering, to remove mixer harmonics, is needed. */ | |
1326 step = -s->eq_put_step; | |
1327 if (step > PULSESHAPER_2400_COEFF_SETS - 1) | |
1328 step = PULSESHAPER_2400_COEFF_SETS - 1; | |
1329 s->eq_put_step += PULSESHAPER_2400_COEFF_SETS*20/(3*2); | |
1330 zz.re = pulseshaper_2400[step][0].re*s->rrc_filter[s->rrc_filter_step]; | |
1331 zz.im = pulseshaper_2400[step][0].im*s->rrc_filter[s->rrc_filter_step]; | |
1332 for (j = 1; j < V27TER_RX_2400_FILTER_STEPS; j++) | |
1333 { | |
1334 zz.re += pulseshaper_2400[step][j].re*s->rrc_filter[j + s->rrc_filter_step]; | |
1335 zz.im += pulseshaper_2400[step][j].im*s->rrc_filter[j + s->rrc_filter_step]; | |
1336 } | |
1337 samplex.re = zz.re*s->agc_scaling; | |
1338 samplex.im = zz.im*s->agc_scaling; | |
1339 /* Shift to baseband - since this is done in a full complex form, the | |
1340 result is clean, and requires no further filtering apart from the | |
1341 equalizer. */ | |
1342 zz.re = samplex.re*z.re - samplex.im*z.im; | |
1343 zz.im = -samplex.re*z.im - samplex.im*z.re; | |
1344 process_half_baud(s, &zz); | |
1345 } | |
1346 } | |
1347 } | |
1348 } | |
1349 return 0; | |
1350 } | |
1351 /*- End of function --------------------------------------------------------*/ | |
1352 | |
1353 void v27ter_rx_set_put_bit(v27ter_rx_state_t *s, put_bit_func_t put_bit, void *user_data) | |
1354 { | |
1355 s->put_bit = put_bit; | |
1356 s->user_data = user_data; | |
1357 } | |
1358 /*- End of function --------------------------------------------------------*/ | |
1359 | |
1360 int v27ter_rx_restart(v27ter_rx_state_t *s, int rate, int old_train) | |
1361 { | |
1362 span_log(&s->logging, SPAN_LOG_FLOW, "Restarting V.27ter\n"); | |
1363 if (rate != 4800 && rate != 2400) | |
1364 return -1; | |
1365 s->bit_rate = rate; | |
1366 | |
1367 vec_zerof(s->rrc_filter, sizeof(s->rrc_filter)/sizeof(s->rrc_filter[0])); | |
1368 s->rrc_filter_step = 0; | |
1369 | |
1370 s->scramble_reg = 0x3C; | |
1371 s->scrambler_pattern_count = 0; | |
1372 s->in_training = TRAINING_STAGE_SYMBOL_ACQUISITION; | |
1373 s->training_bc = 0; | |
1374 s->training_count = 0; | |
1375 s->training_error = 0.0f; | |
1376 s->carrier_present = 0; | |
1377 | |
1378 s->carrier_phase = 0; | |
1379 //s->carrier_track_i = 100000.0f; | |
1380 //s->carrier_track_p = 20000000.0f; | |
1381 s->carrier_track_i = 200000.0f; | |
1382 s->carrier_track_p = 10000000.0f; | |
1383 power_meter_init(&(s->power), 4); | |
1384 | |
1385 s->constellation_state = 0; | |
1386 | |
1387 if (s->old_train) | |
1388 { | |
1389 s->carrier_phase_rate = s->carrier_phase_rate_save; | |
1390 s->agc_scaling = s->agc_scaling_save; | |
1391 equalizer_restore(s); | |
1392 } | |
1393 else | |
1394 { | |
1395 s->carrier_phase_rate = dds_phase_ratef(CARRIER_NOMINAL_FREQ); | |
1396 s->agc_scaling = 0.0005f; | |
1397 equalizer_reset(s); | |
1398 } | |
1399 s->eq_skip = 0; | |
1400 s->last_sample = 0; | |
1401 | |
1402 s->gardner_integrate = 0; | |
1403 s->total_baud_timing_correction = 0; | |
1404 s->gardner_step = 512; | |
1405 s->baud_phase = 0; | |
1406 | |
1407 return 0; | |
1408 } | |
1409 /*- End of function --------------------------------------------------------*/ | |
1410 | |
1411 v27ter_rx_state_t *v27ter_rx_init(v27ter_rx_state_t *s, int rate, put_bit_func_t put_bit, void *user_data) | |
1412 { | |
1413 if (s == NULL) | |
1414 { | |
1415 if ((s = (v27ter_rx_state_t *) malloc(sizeof(*s))) == NULL) | |
1416 return NULL; | |
1417 } | |
1418 memset(s, 0, sizeof(*s)); | |
1419 v27ter_rx_signal_cutoff(s, -45.5f); | |
1420 s->put_bit = put_bit; | |
1421 s->user_data = user_data; | |
1422 span_log_init(&s->logging, SPAN_LOG_NONE, NULL); | |
1423 span_log_set_protocol(&s->logging, "V.27ter"); | |
1424 | |
1425 v27ter_rx_restart(s, rate, FALSE); | |
1426 return s; | |
1427 } | |
1428 /*- End of function --------------------------------------------------------*/ | |
1429 | |
1430 int v27ter_rx_release(v27ter_rx_state_t *s) | |
1431 { | |
1432 free(s); | |
1433 return 0; | |
1434 } | |
1435 /*- End of function --------------------------------------------------------*/ | |
1436 | |
1437 void v27ter_rx_set_qam_report_handler(v27ter_rx_state_t *s, qam_report_handler_t *handler, void *user_data) | |
1438 { | |
1439 s->qam_report = handler; | |
1440 s->qam_user_data = user_data; | |
1441 } | |
1442 /*- End of function --------------------------------------------------------*/ | |
1443 /*- End of file ------------------------------------------------------------*/ |