comparison spandsp-0.0.3/spandsp-0.0.3/src/v22bis_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 * v22bis_rx.c - ITU V.22bis modem receive part
5 *
6 * Written by Steve Underwood <steveu@coppice.org>
7 *
8 * Copyright (C) 2004 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: v22bis_rx.c,v 1.32 2006/11/19 14:07:26 steveu Exp $
26 */
27
28 /*! \file */
29
30 /* THIS IS A WORK IN PROGRESS - NOT YET FUNCTIONAL! */
31
32 #ifdef HAVE_CONFIG_H
33 #include <config.h>
34 #endif
35
36 #include <inttypes.h>
37 #include <string.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #if defined(HAVE_TGMATH_H)
41 #include <tgmath.h>
42 #endif
43 #if defined(HAVE_MATH_H)
44 #include <math.h>
45 #endif
46
47 #include "spandsp/telephony.h"
48 #include "spandsp/logging.h"
49 #include "spandsp/vector_float.h"
50 #include "spandsp/async.h"
51 #include "spandsp/power_meter.h"
52 #include "spandsp/arctan2.h"
53 #include "spandsp/complex.h"
54 #include "spandsp/dds.h"
55 #include "spandsp/complex_filters.h"
56
57 #include "spandsp/v29rx.h"
58 #include "spandsp/v22bis.h"
59
60 #define ms_to_symbols(t) (((t)*600)/1000)
61
62 #define EQUALIZER_DELTA 0.25f
63
64 /*
65 The basic method used by the V.22bis receiver is:
66
67 Put each sample into the pulse-shaping and phase shift filter buffer
68
69 At T/2 rate:
70 Filter and demodulate the contents of the input filter buffer, producing a sample
71 in the equalizer filter buffer.
72
73 Tune the symbol timing based on the latest 3 samples in the equalizer buffer. This
74 updates the decision points for taking the T/2 samples.
75
76 Equalize the contents of the equalizer buffer, producing a demodulated constellation
77 point.
78
79 Find the nearest constellation point to the received position. This is our received
80 symbol.
81
82 Tune the local carrier, based on the angular mismatch between the actual signal and
83 the decision.
84
85 Tune the equalizer, based on the mismatch between the actual signal and the decision.
86
87 Descramble and output the bits represented by the decision.
88 */
89
90 enum
91 {
92 V22BIS_TRAINING_STAGE_NORMAL_OPERATION,
93 V22BIS_TRAINING_STAGE_SYMBOL_ACQUISITION,
94 V22BIS_TRAINING_STAGE_LOG_PHASE,
95 V22BIS_TRAINING_STAGE_UNSCRAMBLED_ONES,
96 V22BIS_TRAINING_STAGE_UNSCRAMBLED_0011,
97 V22BIS_TRAINING_STAGE_SCRAMBLED_ONES_AT_1200,
98 V22BIS_TRAINING_STAGE_SCRAMBLED_ONES_AT_2400,
99 V22BIS_TRAINING_STAGE_WAIT_FOR_START_1,
100 V22BIS_TRAINING_STAGE_WAIT_FOR_START_2,
101 V22BIS_TRAINING_STAGE_PARKED
102 };
103
104 /* Raised root cosine pulse shaping; Beta = 0.75; 4 symbols either
105 side of the centre. We cannot simplify this by using only half
106 the filter, as each variant are each skewed by a n/PULSESHAPER_COEFF_SETS of a
107 sample. Only one is symmetric. */
108 //#define PULSESHAPER_GAIN 159.37711522f
109 #define PULSESHAPER_GAIN 39.98830768f
110 #define PULSESHAPER_COEFF_SETS 12
111 static const complexf_t pulseshaper_1200[PULSESHAPER_COEFF_SETS][V22BIS_RX_FILTER_STEPS] =
112 {
113 {
114 { 0.0079885982f, -0.0245863758f}, /* Filter 0 */
115 { 0.0511994623f, -0.0166357141f},
116 { 0.0660513043f, 0.0479890816f},
117 {-0.0000000000f, 0.1045738682f},
118 {-0.0949529186f, 0.0689873323f},
119 {-0.1091215536f, -0.0354557447f},
120 {-0.0284108873f, -0.0874397159f},
121 { 0.0266686007f, -0.0367061794f},
122 {-0.0269077960f, -0.0000000000f},
123 {-0.0733404681f, -0.1009444892f},
124 { 0.0759629756f, -0.2337899953f},
125 { 0.3664972484f, -0.1190821752f},
126 { 0.4341508448f, 0.3154290617f},
127 {-0.0000000001f, 0.6913219094f},
128 {-0.6796512008f, 0.4937954843f},
129 {-0.9258067012f, -0.3008128405f},
130 {-0.3345100582f, -1.0295161009f},
131 { 0.6816816330f, -0.9382542372f},
132 { 1.1997879744f, 0.0000000000f},
133 { 0.7052176595f, 0.9706488252f},
134 {-0.3583812416f, 1.1029839516f},
135 {-1.0295161009f, 0.3345100582f},
136 {-0.7875382304f, -0.5721800327f},
137 {-0.0000000001f, -0.8400950432f},
138 { 0.5592911839f, -0.4063488245f},
139 { 0.5103749037f, 0.1658308655f},
140 { 0.1190821752f, 0.3664972484f},
141 {-0.1444901675f, 0.1988736391f},
142 {-0.1247742549f, 0.0000000000f},
143 {-0.0158160049f, -0.0217688642f},
144 {-0.0140205137f, 0.0431507044f},
145 {-0.0874397159f, 0.0284108873f},
146 {-0.0928243399f, -0.0674408302f},
147 {-0.0000000000f, -0.1173682660f},
148 { 0.0846020356f, -0.0614669770f},
149 { 0.0776479617f, 0.0252293516f},
150 { 0.0166357141f, 0.0511994623f},
151 },
152 {
153 { 0.0086805914f, -0.0267161131f}, /* Filter 1 */
154 { 0.0534664392f, -0.0173722990f},
155 { 0.0678047314f, 0.0492630191f},
156 {-0.0000000000f, 0.1061014757f},
157 {-0.0953093544f, 0.0692462996f},
158 {-0.1081032082f, -0.0351248607f},
159 {-0.0275043193f, -0.0846495852f},
160 { 0.0237129591f, -0.0326380879f},
161 {-0.0341038331f, -0.0000000000f},
162 {-0.0787785500f, -0.1084293649f},
163 { 0.0793628618f, -0.2442537695f},
164 { 0.3781612813f, -0.1228720471f},
165 { 0.4445744753f, 0.3230022490f},
166 {-0.0000000001f, 0.7040774226f},
167 {-0.6892225146f, 0.5007494688f},
168 {-0.9354411960f, -0.3039432764f},
169 {-0.3369024098f, -1.0368790627f},
170 { 0.6845118403f, -0.9421496987f},
171 { 1.2013363838f, 0.0000000000f},
172 { 0.7041431069f, 0.9691697955f},
173 {-0.3568129838f, 1.0981574059f},
174 {-1.0219419003f, 0.3320490718f},
175 {-0.7792053819f, -0.5661258698f},
176 {-0.0000000001f, -0.8281568289f},
177 { 0.5489386916f, -0.3988272846f},
178 { 0.4981442094f, 0.1618568748f},
179 { 0.1153177992f, 0.3549116850f},
180 {-0.1380993575f, 0.1900774688f},
181 {-0.1156847477f, 0.0000000000f},
182 {-0.0116915042f, -0.0160919763f},
183 {-0.0155188413f, 0.0477620810f},
184 {-0.0900719389f, 0.0292661469f},
185 {-0.0935767666f, -0.0679875016f},
186 {-0.0000000000f, -0.1168202460f},
187 { 0.0833092555f, -0.0605277158f},
188 { 0.0755547658f, 0.0245492328f},
189 { 0.0158989299f, 0.0489318743f},
190 },
191 {
192 { 0.0093799150f, -0.0288684089f}, /* Filter 2 */
193 { 0.0557304025f, -0.0181079060f},
194 { 0.0695286095f, 0.0505154915f},
195 {-0.0000000000f, 0.1075555831f},
196 {-0.0955764726f, 0.0694403723f},
197 {-0.1069486886f, -0.0347497351f},
198 {-0.0265459362f, -0.0816999897f},
199 { 0.0206513591f, -0.0284241568f},
200 {-0.0414781198f, -0.0000000000f},
201 {-0.0843107775f, -0.1160438284f},
202 { 0.0828017443f, -0.2548375726f},
203 { 0.3898994923f, -0.1266860217f},
204 { 0.4550133944f, 0.3305865824f},
205 {-0.0000000001f, 0.7167864442f},
206 {-0.6987025142f, 0.5076370835f},
207 {-0.9449097514f, -0.3070197999f},
208 {-0.3392250240f, -1.0440272093f},
209 { 0.6871879101f, -0.9458330274f},
210 { 1.2026044130f, 0.0000000000f},
211 { 0.7029046416f, 0.9674652219f},
212 {-0.3551651835f, 1.0930860043f},
213 {-1.0141602755f, 0.3295206726f},
214 {-0.7707393169f, -0.5599749088f},
215 {-0.0000000001f, -0.8161166310f},
216 { 0.5385575294f, -0.3912849724f},
217 { 0.4859414399f, 0.1578919441f},
218 { 0.1115802750f, 0.3434087634f},
219 {-0.1317866892f, 0.1813888103f},
220 {-0.1067595631f, 0.0000000000f},
221 {-0.0076726158f, -0.0105604501f},
222 {-0.0169618148f, 0.0522031002f},
223 {-0.0925478712f, 0.0300706252f},
224 {-0.0942174047f, -0.0684529543f},
225 {-0.0000000000f, -0.1161677912f},
226 { 0.0819620788f, -0.0595489368f},
227 { 0.0734324455f, 0.0238596480f},
228 { 0.0151627110f, 0.0466660261f},
229 },
230 {
231 { 0.0100859674f, -0.0310414154f}, /* Filter 3 */
232 { 0.0579889156f, -0.0188417397f},
233 { 0.0712205172f, 0.0517447330f},
234 {-0.0000000000f, 0.1089330688f},
235 {-0.0957518741f, 0.0695678070f},
236 {-0.1056557149f, -0.0343296230f},
237 {-0.0255352631f, -0.0785894617f},
238 { 0.0174835511f, -0.0240640435f},
239 {-0.0490297712f, -0.0000000000f},
240 {-0.0899358466f, -0.1237860769f},
241 { 0.0862785354f, -0.2655380368f},
242 { 0.4017075598f, -0.1305226982f},
243 { 0.4654633999f, 0.3381789625f},
244 {-0.0000000001f, 0.7294434309f},
245 {-0.7080869079f, 0.5144552588f},
246 {-0.9542079568f, -0.3100409508f},
247 {-0.3414767087f, -1.0509572029f},
248 { 0.6897085309f, -0.9493023753f},
249 { 1.2035913467f, 0.0000000000f},
250 { 0.7015029192f, 0.9655358791f},
251 {-0.3534386754f, 1.0877723694f},
252 {-1.0061750412f, 0.3269260824f},
253 {-0.7621439099f, -0.5537299514f},
254 {-0.0000000001f, -0.8039799333f},
255 { 0.5281522870f, -0.3837251067f},
256 { 0.4737714827f, 0.1539376825f},
257 { 0.1078709438f, 0.3319926262f},
258 {-0.1255540103f, 0.1728102714f},
259 {-0.0980006009f, 0.0000000000f},
260 {-0.0037596615f, -0.0051747300f},
261 {-0.0183496606f, 0.0564744473f},
262 {-0.0948692262f, 0.0308248810f},
263 {-0.0947483405f, -0.0688387007f},
264 {-0.0000000000f, -0.1154139340f},
265 { 0.0805630460f, -0.0585324802f},
266 { 0.0712837577f, 0.0231614988f},
267 { 0.0144278063f, 0.0444042198f},
268 },
269 {
270 { 0.0107981311f, -0.0332332328f}, /* Filter 4 */
271 { 0.0602394938f, -0.0195729975f},
272 { 0.0728780255f, 0.0529489815f},
273 {-0.0000000000f, 0.1102307960f},
274 {-0.0958332121f, 0.0696269050f},
275 {-0.1042220443f, -0.0338637941f},
276 {-0.0244718455f, -0.0753165931f},
277 { 0.0142093524f, -0.0195574965f},
278 {-0.0567577891f, -0.0000000000f},
279 {-0.0956523716f, -0.1316542029f},
280 { 0.0897921249f, -0.2763517499f},
281 { 0.4135811031f, -0.1343806386f},
282 { 0.4759201407f, 0.3457762301f},
283 {-0.0000000001f, 0.7420427203f},
284 {-0.7173712850f, 0.5212007165f},
285 {-0.9633312821f, -0.3130052984f},
286 {-0.3436563909f, -1.0576655865f},
287 { 0.6920724511f, -0.9525560141f},
288 { 1.2042965889f, 0.0000000000f},
289 { 0.6999385953f, 0.9633828402f},
290 {-0.3516343236f, 1.0822191238f},
291 {-0.9979898930f, 0.3242665529f},
292 {-0.7534233332f, -0.5473940969f},
293 {-0.0000000001f, -0.7917523384f},
294 { 0.5177274346f, -0.3761509955f},
295 { 0.4616391361f, 0.1499956548f},
296 { 0.1041911170f, 0.3206672966f},
297 {-0.1194031686f, 0.1643443555f},
298 {-0.0894096494f, 0.0000000000f},
299 { 0.0000471013f, 0.0000648294f},
300 {-0.0196826290f, 0.0605769046f},
301 {-0.0970377848f, 0.0315294862f},
302 {-0.0951716974f, -0.0691462904f},
303 {-0.0000000000f, -0.1145617142f},
304 { 0.0791146755f, -0.0574801750f},
305 { 0.0691114515f, 0.0224556718f},
306 { 0.0136949494f, 0.0421487205f},
307 },
308 {
309 { 0.0115157729f, -0.0354419053f}, /* Filter 5 */
310 { 0.0624796189f, -0.0203008596f},
311 { 0.0744986683f, 0.0541264527f},
312 {-0.0000000000f, 0.1114456356f},
313 {-0.0958181471f, 0.0696159601f},
314 {-0.1026455015f, -0.0333515443f},
315 {-0.0233552568f, -0.0718800873f},
316 { 0.0108286384f, -0.0149043426f},
317 {-0.0646610633f, -0.0000000000f},
318 {-0.1014589071f, -0.1396462023f},
319 { 0.0933413655f, -0.2872751951f},
320 { 0.4255155921f, -0.1382583976f},
321 { 0.4863792956f, 0.3533752263f},
322 {-0.0000000001f, 0.7545788884f},
323 {-0.7265513539f, 0.5278704762f},
324 {-0.9722753763f, -0.3159114122f},
325 {-0.3457630277f, -1.0641491413f},
326 { 0.6942784786f, -0.9555923343f},
327 { 1.2047197819f, 0.0000000000f},
328 { 0.6982125044f, 0.9610070586f},
329 {-0.3497529626f, 1.0764288902f},
330 {-0.9896088243f, 0.3215433955f},
331 {-0.7445815802f, -0.5409702063f},
332 {-0.0000000001f, -0.7794392109f},
333 { 0.5072873235f, -0.3685658276f},
334 { 0.4495492578f, 0.1460674107f},
335 { 0.1005420759f, 0.3094367087f},
336 {-0.1133359149f, 0.1559935063f},
337 {-0.0809883848f, 0.0000000000f},
338 { 0.0037474802f, 0.0051579643f},
339 {-0.0209610034f, 0.0645113364f},
340 {-0.0990553871f, 0.0321850479f},
341 {-0.0954896435f, -0.0693772882f},
342 {-0.0000000000f, -0.1136142015f},
343 { 0.0776194856f, -0.0563938580f},
344 { 0.0669182166f, 0.0217430461f},
345 { 0.0129648596f, 0.0399017334f},
346 },
347 {
348 { 0.0122382389f, -0.0376654267f}, /* Filter 6 */
349 { 0.0647067279f, -0.0210244898f},
350 { 0.0760799870f, 0.0552753434f},
351 {-0.0000000000f, 0.1125744730f},
352 {-0.0957043841f, 0.0695333034f},
353 {-0.1009239629f, -0.0327921845f},
354 {-0.0221851002f, -0.0682787150f},
355 { 0.0073413476f, -0.0101044979f},
356 {-0.0727383792f, -0.0000000000f},
357 {-0.1073539481f, -0.1477600336f},
358 { 0.0969250873f, -0.2983047366f},
359 { 0.4375065267f, -0.1421544850f},
360 { 0.4968364835f, 0.3609728217f},
361 {-0.0000000001f, 0.7670462132f},
362 {-0.7356228828f, 0.5344613194f},
363 {-0.9810359478f, -0.3187578917f},
364 {-0.3477955461f, -1.0704045296f},
365 { 0.6963254809f, -0.9584097862f},
366 { 1.2048609257f, 0.0000000000f},
367 { 0.6963254809f, 0.9584097862f},
368 {-0.3477955461f, 1.0704045296f},
369 {-0.9810359478f, 0.3187578917f},
370 {-0.7356228828f, -0.5344613194f},
371 {-0.0000000001f, -0.7670462132f},
372 { 0.4968364835f, -0.3609728217f},
373 { 0.4375065267f, 0.1421544850f},
374 { 0.0969250873f, 0.2983047366f},
375 {-0.1073539481f, 0.1477600336f},
376 {-0.0727383792f, 0.0000000000f},
377 { 0.0073413476f, 0.0101044979f},
378 {-0.0221851002f, 0.0682787150f},
379 {-0.1009239629f, 0.0327921845f},
380 {-0.0957043841f, -0.0695333034f},
381 {-0.0000000000f, -0.1125744730f},
382 { 0.0760799870f, -0.0552753434f},
383 { 0.0647067279f, 0.0210244898f},
384 { 0.0122382389f, 0.0376654267f},
385 },
386 {
387 { 0.0129648596f, -0.0399017334f}, /* Filter 7 */
388 { 0.0669182166f, -0.0217430461f},
389 { 0.0776194856f, 0.0563938580f},
390 {-0.0000000000f, 0.1136142015f},
391 {-0.0954896435f, 0.0693772882f},
392 {-0.0990553871f, -0.0321850479f},
393 {-0.0209610034f, -0.0645113364f},
394 { 0.0037474802f, -0.0051579643f},
395 {-0.0809883848f, -0.0000000000f},
396 {-0.1133359149f, -0.1559935063f},
397 { 0.1005420759f, -0.3094367087f},
398 { 0.4495492578f, -0.1460674107f},
399 { 0.5072873235f, 0.3685658276f},
400 {-0.0000000001f, 0.7794392109f},
401 {-0.7445815802f, 0.5409702063f},
402 {-0.9896088243f, -0.3215433955f},
403 {-0.3497529626f, -1.0764288902f},
404 { 0.6982125044f, -0.9610070586f},
405 { 1.2047197819f, 0.0000000000f},
406 { 0.6942784786f, 0.9555923343f},
407 {-0.3457630277f, 1.0641491413f},
408 {-0.9722753763f, 0.3159114122f},
409 {-0.7265513539f, -0.5278704762f},
410 {-0.0000000001f, -0.7545788884f},
411 { 0.4863792956f, -0.3533752263f},
412 { 0.4255155921f, 0.1382583976f},
413 { 0.0933413655f, 0.2872751951f},
414 {-0.1014589071f, 0.1396462023f},
415 {-0.0646610633f, 0.0000000000f},
416 { 0.0108286384f, 0.0149043426f},
417 {-0.0233552568f, 0.0718800873f},
418 {-0.1026455015f, 0.0333515443f},
419 {-0.0958181471f, -0.0696159601f},
420 {-0.0000000000f, -0.1114456356f},
421 { 0.0744986683f, -0.0541264527f},
422 { 0.0624796189f, 0.0203008596f},
423 { 0.0115157729f, 0.0354419053f},
424 },
425 {
426 { 0.0136949494f, -0.0421487205f}, /* Filter 8 */
427 { 0.0691114515f, -0.0224556718f},
428 { 0.0791146755f, 0.0574801750f},
429 {-0.0000000000f, 0.1145617142f},
430 {-0.0951716974f, 0.0691462904f},
431 {-0.0970377848f, -0.0315294862f},
432 {-0.0196826290f, -0.0605769046f},
433 { 0.0000471013f, -0.0000648294f},
434 {-0.0894096494f, -0.0000000000f},
435 {-0.1194031686f, -0.1643443555f},
436 { 0.1041911170f, -0.3206672966f},
437 { 0.4616391361f, -0.1499956548f},
438 { 0.5177274346f, 0.3761509955f},
439 {-0.0000000001f, 0.7917523384f},
440 {-0.7534233332f, 0.5473940969f},
441 {-0.9979898930f, -0.3242665529f},
442 {-0.3516343236f, -1.0822191238f},
443 { 0.6999385953f, -0.9633828402f},
444 { 1.2042965889f, 0.0000000000f},
445 { 0.6920724511f, 0.9525560141f},
446 {-0.3436563909f, 1.0576655865f},
447 {-0.9633312821f, 0.3130052984f},
448 {-0.7173712850f, -0.5212007165f},
449 {-0.0000000001f, -0.7420427203f},
450 { 0.4759201407f, -0.3457762301f},
451 { 0.4135811031f, 0.1343806386f},
452 { 0.0897921249f, 0.2763517499f},
453 {-0.0956523716f, 0.1316542029f},
454 {-0.0567577891f, 0.0000000000f},
455 { 0.0142093524f, 0.0195574965f},
456 {-0.0244718455f, 0.0753165931f},
457 {-0.1042220443f, 0.0338637941f},
458 {-0.0958332121f, -0.0696269050f},
459 {-0.0000000000f, -0.1102307960f},
460 { 0.0728780255f, -0.0529489815f},
461 { 0.0602394938f, 0.0195729975f},
462 { 0.0107981311f, 0.0332332328f},
463 },
464 {
465 { 0.0144278063f, -0.0444042198f}, /* Filter 9 */
466 { 0.0712837577f, -0.0231614988f},
467 { 0.0805630460f, 0.0585324802f},
468 {-0.0000000000f, 0.1154139340f},
469 {-0.0947483405f, 0.0688387007f},
470 {-0.0948692262f, -0.0308248810f},
471 {-0.0183496606f, -0.0564744473f},
472 {-0.0037596615f, 0.0051747300f},
473 {-0.0980006009f, -0.0000000000f},
474 {-0.1255540103f, -0.1728102714f},
475 { 0.1078709438f, -0.3319926262f},
476 { 0.4737714827f, -0.1539376825f},
477 { 0.5281522870f, 0.3837251067f},
478 {-0.0000000001f, 0.8039799333f},
479 {-0.7621439099f, 0.5537299514f},
480 {-1.0061750412f, -0.3269260824f},
481 {-0.3534386754f, -1.0877723694f},
482 { 0.7015029192f, -0.9655358791f},
483 { 1.2035913467f, 0.0000000000f},
484 { 0.6897085309f, 0.9493023753f},
485 {-0.3414767087f, 1.0509572029f},
486 {-0.9542079568f, 0.3100409508f},
487 {-0.7080869079f, -0.5144552588f},
488 {-0.0000000001f, -0.7294434309f},
489 { 0.4654633999f, -0.3381789625f},
490 { 0.4017075598f, 0.1305226982f},
491 { 0.0862785354f, 0.2655380368f},
492 {-0.0899358466f, 0.1237860769f},
493 {-0.0490297712f, 0.0000000000f},
494 { 0.0174835511f, 0.0240640435f},
495 {-0.0255352631f, 0.0785894617f},
496 {-0.1056557149f, 0.0343296230f},
497 {-0.0957518741f, -0.0695678070f},
498 {-0.0000000000f, -0.1089330688f},
499 { 0.0712205172f, -0.0517447330f},
500 { 0.0579889156f, 0.0188417397f},
501 { 0.0100859674f, 0.0310414154f},
502 },
503 {
504 { 0.0151627110f, -0.0466660261f}, /* Filter 10 */
505 { 0.0734324455f, -0.0238596480f},
506 { 0.0819620788f, 0.0595489368f},
507 {-0.0000000000f, 0.1161677912f},
508 {-0.0942174047f, 0.0684529543f},
509 {-0.0925478712f, -0.0300706252f},
510 {-0.0169618148f, -0.0522031002f},
511 {-0.0076726158f, 0.0105604501f},
512 {-0.1067595631f, -0.0000000000f},
513 {-0.1317866892f, -0.1813888103f},
514 { 0.1115802750f, -0.3434087634f},
515 { 0.4859414399f, -0.1578919441f},
516 { 0.5385575294f, 0.3912849724f},
517 {-0.0000000001f, 0.8161166310f},
518 {-0.7707393169f, 0.5599749088f},
519 {-1.0141602755f, -0.3295206726f},
520 {-0.3551651835f, -1.0930860043f},
521 { 0.7029046416f, -0.9674652219f},
522 { 1.2026044130f, 0.0000000000f},
523 { 0.6871879101f, 0.9458330274f},
524 {-0.3392250240f, 1.0440272093f},
525 {-0.9449097514f, 0.3070197999f},
526 {-0.6987025142f, -0.5076370835f},
527 {-0.0000000001f, -0.7167864442f},
528 { 0.4550133944f, -0.3305865824f},
529 { 0.3898994923f, 0.1266860217f},
530 { 0.0828017443f, 0.2548375726f},
531 {-0.0843107775f, 0.1160438284f},
532 {-0.0414781198f, 0.0000000000f},
533 { 0.0206513591f, 0.0284241568f},
534 {-0.0265459362f, 0.0816999897f},
535 {-0.1069486886f, 0.0347497351f},
536 {-0.0955764726f, -0.0694403723f},
537 {-0.0000000000f, -0.1075555831f},
538 { 0.0695286095f, -0.0505154915f},
539 { 0.0557304025f, 0.0181079060f},
540 { 0.0093799150f, 0.0288684089f},
541 },
542 {
543 { 0.0158989299f, -0.0489318743f}, /* Filter 11 */
544 { 0.0755547658f, -0.0245492328f},
545 { 0.0833092555f, 0.0605277158f},
546 {-0.0000000000f, 0.1168202460f},
547 {-0.0935767666f, 0.0679875016f},
548 {-0.0900719389f, -0.0292661469f},
549 {-0.0155188413f, -0.0477620810f},
550 {-0.0116915042f, 0.0160919763f},
551 {-0.1156847477f, -0.0000000000f},
552 {-0.1380993575f, -0.1900774688f},
553 { 0.1153177992f, -0.3549116850f},
554 { 0.4981442094f, -0.1618568748f},
555 { 0.5489386916f, 0.3988272846f},
556 {-0.0000000001f, 0.8281568289f},
557 {-0.7792053819f, 0.5661258698f},
558 {-1.0219419003f, -0.3320490718f},
559 {-0.3568129838f, -1.0981574059f},
560 { 0.7041431069f, -0.9691697955f},
561 { 1.2013363838f, 0.0000000000f},
562 { 0.6845118403f, 0.9421496987f},
563 {-0.3369024098f, 1.0368790627f},
564 {-0.9354411960f, 0.3039432764f},
565 {-0.6892225146f, -0.5007494688f},
566 {-0.0000000001f, -0.7040774226f},
567 { 0.4445744753f, -0.3230022490f},
568 { 0.3781612813f, 0.1228720471f},
569 { 0.0793628618f, 0.2442537695f},
570 {-0.0787785500f, 0.1084293649f},
571 {-0.0341038331f, 0.0000000000f},
572 { 0.0237129591f, 0.0326380879f},
573 {-0.0275043193f, 0.0846495852f},
574 {-0.1081032082f, 0.0351248607f},
575 {-0.0953093544f, -0.0692462996f},
576 {-0.0000000000f, -0.1061014757f},
577 { 0.0678047314f, -0.0492630191f},
578 { 0.0534664392f, 0.0173722990f},
579 { 0.0086805914f, 0.0267161131f},
580 },
581 };
582
583 static const complexf_t pulseshaper_2400[PULSESHAPER_COEFF_SETS][V22BIS_RX_FILTER_STEPS] =
584 {
585 {
586 { 0.0209144205f, 0.0151952161f}, /* Filter 0 */
587 {-0.0435528643f, 0.0316430070f},
588 {-0.0252293516f, -0.0776479617f},
589 { 0.1045738682f, 0.0000000001f},
590 {-0.0362687893f, 0.1116238534f},
591 {-0.0928243399f, -0.0674408302f},
592 { 0.0743806660f, -0.0540407188f},
593 { 0.0140205137f, 0.0431507044f},
594 { 0.0269077960f, 0.0000000000f},
595 {-0.0385573655f, 0.1186673641f},
596 {-0.1988736391f, -0.1444901675f},
597 { 0.3117611706f, -0.2265077531f},
598 { 0.1658308655f, 0.5103749037f},
599 {-0.6913219094f, -0.0000000002f},
600 { 0.2596036494f, -0.7989778519f},
601 { 0.7875382304f, 0.5721800327f},
602 {-0.8757586479f, 0.6362759471f},
603 {-0.3583812416f, -1.1029839516f},
604 { 1.1997879744f, 0.0000000000f},
605 {-0.3707548678f, 1.1410661936f},
606 {-0.9382542372f, -0.6816816330f},
607 { 0.8757586479f, -0.6362759471f},
608 { 0.3008128405f, 0.9258067012f},
609 {-0.8400950432f, 0.0000000002f},
610 { 0.2136302292f, -0.6574862003f},
611 { 0.4341508448f, 0.3154290617f},
612 {-0.3117611706f, 0.2265077531f},
613 {-0.0759629756f, -0.2337899953f},
614 { 0.1247742549f, -0.0000000001f},
615 {-0.0083149662f, 0.0255908351f},
616 { 0.0367061794f, 0.0266686007f},
617 {-0.0743806660f, 0.0540407188f},
618 {-0.0354557447f, -0.1091215536f},
619 { 0.1173682660f, -0.0000000001f},
620 {-0.0323151015f, 0.0994556621f},
621 {-0.0660513043f, -0.0479890816f},
622 { 0.0435528643f, -0.0316430070f},
623 },
624 {
625 { 0.0227260832f, 0.0165114664f}, /* Filter 1 */
626 {-0.0454812683f, 0.0330440775f},
627 {-0.0258991010f, -0.0797092393f},
628 { 0.1061014757f, 0.0000000001f},
629 {-0.0364049338f, 0.1120428666f},
630 {-0.0919580832f, -0.0668114573f},
631 { 0.0720072389f, -0.0523163229f},
632 { 0.0124666411f, 0.0383683741f},
633 { 0.0341038331f, 0.0000000000f},
634 {-0.0414163321f, 0.1274663657f},
635 {-0.2077746689f, -0.1509571373f},
636 { 0.3216831982f, -0.2337165177f},
637 { 0.1698123366f, 0.5226286054f},
638 {-0.7040774226f, -0.0000000002f},
639 { 0.2632595599f, -0.8102296591f},
640 { 0.7957338095f, 0.5781344771f},
641 {-0.8820219636f, 0.6408264637f},
642 {-0.3598691821f, -1.1075633764f},
643 { 1.2013363838f, 0.0000000000f},
644 {-0.3701899350f, 1.1393274069f},
645 {-0.9341484904f, -0.6786985993f},
646 { 0.8693157434f, -0.6315948367f},
647 { 0.2976299822f, 0.9160109162f},
648 {-0.8281568289f, 0.0000000002f},
649 { 0.2096759230f, -0.6453161240f},
650 { 0.4237467945f, 0.3078700602f},
651 {-0.3019059300f, 0.2193474919f},
652 {-0.0726031289f, -0.2234494686f},
653 { 0.1156847477f, -0.0000000001f},
654 {-0.0061465879f, 0.0189172514f},
655 { 0.0406288542f, 0.0295185894f},
656 {-0.0766197667f, 0.0556675196f},
657 {-0.0357431434f, -0.1100060865f},
658 { 0.1168202460f, -0.0000000001f},
659 {-0.0318213031f, 0.0979359001f},
660 {-0.0642707273f, -0.0466954149f},
661 { 0.0416239388f, -0.0302415621f},
662 },
663 {
664 { 0.0245569348f, 0.0178416576f}, /* Filter 2 */
665 {-0.0474071130f, 0.0344432816f},
666 {-0.0265575647f, -0.0817357823f},
667 { 0.1075555831f, 0.0000000001f},
668 {-0.0365069620f, 0.1123568788f},
669 {-0.0909759924f, -0.0660979301f},
670 { 0.0694981664f, -0.0504933707f},
671 { 0.0108570615f, 0.0334145986f},
672 { 0.0414781198f, 0.0000000000f},
673 {-0.0443248004f, 0.1364177018f},
674 {-0.2167777866f, -0.1574982852f},
675 { 0.3316683173f, -0.2409711480f},
676 { 0.1737996489f, 0.5349003077f},
677 {-0.7167864442f, -0.0000000002f},
678 { 0.2668806314f, -0.8213740587f},
679 { 0.8037882447f, 0.5839863420f},
680 {-0.8881026506f, 0.6452443004f},
681 {-0.3612760901f, -1.1118934155f},
682 { 1.2026044130f, 0.0000000000f},
683 {-0.3695388138f, 1.1373236179f},
684 {-0.9298345447f, -0.6755643487f},
685 { 0.8626962900f, -0.6267855763f},
686 { 0.2943962216f, 0.9060583711f},
687 {-0.8161166310f, 0.0000000002f},
688 { 0.2057106793f, -0.6331123710f},
689 { 0.4133664668f, 0.3003283143f},
690 {-0.2921209633f, 0.2122382969f},
691 {-0.0692843646f, -0.2132353336f},
692 { 0.1067595631f, -0.0000000001f},
693 {-0.0040337327f, 0.0124145532f},
694 { 0.0444066115f, 0.0322632901f},
695 {-0.0787259191f, 0.0571977310f},
696 {-0.0359878466f, -0.1107592061f},
697 { 0.1161677912f, -0.0000000001f},
698 {-0.0313067287f, 0.0963522047f},
699 {-0.0624653697f, -0.0453837477f},
700 { 0.0396964923f, -0.0288411900f},
701 },
702 {
703 { 0.0264054053f, 0.0191846490f}, /* Filter 3 */
704 {-0.0493283160f, 0.0358391218f},
705 {-0.0272038169f, -0.0837247372f},
706 { 0.1089330688f, 0.0000000001f},
707 {-0.0365739614f, 0.1125630811f},
708 {-0.0898761228f, -0.0652988255f},
709 { 0.0668521896f, -0.0485709570f},
710 { 0.0091916462f, 0.0282889791f},
711 { 0.0490297712f, 0.0000000000f},
712 {-0.0472820736f, 0.1455192566f},
713 {-0.2258801460f, -0.1641115248f},
714 { 0.3417128623f, -0.2482689321f},
715 { 0.1777911931f, 0.5471850634f},
716 {-0.7294434309f, -0.0000000002f},
717 { 0.2704651356f, -0.8324060440f},
718 { 0.8116977811f, 0.5897329450f},
719 {-0.8939976096f, 0.6495273113f},
720 {-0.3626012504f, -1.1159719229f},
721 { 1.2035913467f, 0.0000000000f},
722 {-0.3688018918f, 1.1350555420f},
723 {-0.9253144860f, -0.6722803116f},
724 { 0.8559035659f, -0.6218503714f},
725 { 0.2911130786f, 0.8959538937f},
726 {-0.8039799333f, 0.0000000002f},
727 { 0.2017362267f, -0.6208803058f},
728 { 0.4030140936f, 0.2928068638f},
729 {-0.2824097872f, 0.2051827312f},
730 {-0.0660076514f, -0.2031506598f},
731 { 0.0980006009f, -0.0000000001f},
732 {-0.0019765710f, 0.0060832603f},
733 { 0.0480400361f, 0.0349031277f},
734 {-0.0807005838f, 0.0586324073f},
735 {-0.0361906476f, -0.1113833562f},
736 { 0.1154139340f, -0.0000000001f},
737 {-0.0307723451f, 0.0947075412f},
738 {-0.0606375895f, -0.0440557860f},
739 { 0.0377724878f, -0.0274433177f},
740 },
741 {
742 { 0.0282698758f, 0.0205392670f}, /* Filter 4 */
743 {-0.0512427762f, 0.0372300558f},
744 {-0.0278369281f, -0.0856732503f},
745 { 0.1102307960f, 0.0000000001f},
746 {-0.0366050303f, 0.1126586944f},
747 {-0.0886565670f, -0.0644127652f},
748 { 0.0640681237f, -0.0465482138f},
749 { 0.0074702986f, 0.0229912158f},
750 { 0.0567577891f, 0.0000000000f},
751 {-0.0502874292f, 0.1547687948f},
752 {-0.2350788414f, -0.1707947701f},
753 { 0.3518131077f, -0.2556071877f},
754 { 0.1817853153f, 0.5594776869f},
755 {-0.7420427203f, -0.0000000002f},
756 { 0.2740114331f, -0.8433204889f},
757 { 0.8194585443f, 0.5953714848f},
758 {-0.8997041583f, 0.6536732912f},
759 {-0.3638440073f, -1.1197967529f},
760 { 1.2042965889f, 0.0000000000f},
761 {-0.3679794967f, 1.1325244904f},
762 {-0.9205905795f, -0.6688482165f},
763 { 0.8489409089f, -0.6167916656f},
764 { 0.2877821028f, 0.8857022524f},
765 {-0.7917523384f, 0.0000000002f},
766 { 0.1977542788f, -0.6086250544f},
767 { 0.3926937282f, 0.2853086889f},
768 {-0.2727758884f, 0.1981832832f},
769 {-0.0627739578f, -0.1931983829f},
770 { 0.0894096494f, -0.0000000000f},
771 { 0.0000247626f, -0.0000762115f},
772 { 0.0515297912f, 0.0374385864f},
773 {-0.0825452656f, 0.0599726476f},
774 {-0.0363523550f, -0.1118810475f},
775 { 0.1145617142f, -0.0000000001f},
776 {-0.0302191172f, 0.0930048823f},
777 {-0.0587897114f, -0.0427132249f},
778 { 0.0358538441f, -0.0260493420f},
779 },
780 {
781 { 0.0301486850f, 0.0219043009f}, /* Filter 5 */
782 {-0.0531483367f, 0.0386145264f},
783 {-0.0284559596f, -0.0875784382f},
784 { 0.1114456356f, 0.0000000001f},
785 {-0.0365992747f, 0.1126409844f},
786 {-0.0873154774f, -0.0634384081f},
787 { 0.0611448549f, -0.0444243364f},
788 { 0.0056929523f, 0.0175211057f},
789 { 0.0646610633f, 0.0000000000f},
790 {-0.0533401072f, 0.1641639620f},
791 {-0.2443708777f, -0.1775458306f},
792 { 0.3619651794f, -0.2629830837f},
793 { 0.1857803613f, 0.5717731118f},
794 {-0.7545788884f, -0.0000000002f},
795 { 0.2775179148f, -0.8541123271f},
796 { 0.8270668387f, 0.6008992195f},
797 {-0.9052193165f, 0.6576803327f},
798 {-0.3650037944f, -1.1233661175f},
799 { 1.2047197819f, 0.0000000000f},
800 {-0.3670720458f, 1.1297315359f},
801 {-0.9156650901f, -0.6652696729f},
802 { 0.8418115377f, -0.6116119027f},
803 { 0.2844048440f, 0.8753081560f},
804 {-0.7794392109f, 0.0000000002f},
805 { 0.1937665194f, -0.5963520408f},
806 { 0.3824094236f, 0.2778367102f},
807 {-0.2632225752f, 0.1912423968f},
808 {-0.0595842153f, -0.1833813637f},
809 { 0.0809883848f, -0.0000000000f},
810 { 0.0019701670f, -0.0060635507f},
811 { 0.0548766218f, 0.0398701988f},
812 {-0.0842615440f, 0.0612195991f},
813 {-0.0364737995f, -0.1122548133f},
814 { 0.1136142015f, -0.0000000001f},
815 {-0.0296480060f, 0.0912471786f},
816 {-0.0569240339f, -0.0413577296f},
817 { 0.0339424424f, -0.0246606283f},
818 },
819 {
820 { 0.0320401229f, 0.0232785121f}, /* Filter 6 */
821 {-0.0550428294f, 0.0399909541f},
822 {-0.0290599689f, -0.0894373879f},
823 { 0.1125744730f, 0.0000000001f},
824 {-0.0365558229f, 0.1125072464f},
825 {-0.0858510509f, -0.0623744428f},
826 { 0.0580813438f, -0.0421985686f},
827 { 0.0038595749f, 0.0118785501f},
828 { 0.0727383792f, 0.0000000000f},
829 {-0.0564393103f, 0.1737023294f},
830 {-0.2537531555f, -0.1843624711f},
831 { 0.3721652627f, -0.2703939080f},
832 { 0.1897746474f, 0.5840663314f},
833 {-0.7670462132f, -0.0000000002f},
834 { 0.2809829414f, -0.8647765517f},
835 { 0.8345190287f, 0.6063135862f},
836 {-0.9105405211f, 0.6615464091f},
837 {-0.3660799563f, -1.1266783476f},
838 { 1.2048609257f, 0.0000000000f},
839 {-0.3660799563f, 1.1266783476f},
840 {-0.9105405211f, -0.6615464091f},
841 { 0.8345190287f, -0.6063135862f},
842 { 0.2809829414f, 0.8647765517f},
843 {-0.7670462132f, 0.0000000002f},
844 { 0.1897746474f, -0.5840663314f},
845 { 0.3721652627f, 0.2703939080f},
846 {-0.2537531555f, 0.1843624711f},
847 {-0.0564393103f, -0.1737023294f},
848 { 0.0727383792f, -0.0000000000f},
849 { 0.0038595749f, -0.0118785501f},
850 { 0.0580813438f, 0.0421985686f},
851 {-0.0858510509f, 0.0623744428f},
852 {-0.0365558229f, -0.1125072464f},
853 { 0.1125744730f, -0.0000000001f},
854 {-0.0290599689f, 0.0894373879f},
855 {-0.0550428294f, -0.0399909541f},
856 { 0.0320401229f, -0.0232785121f},
857 },
858 {
859 { 0.0339424424f, 0.0246606283f}, /* Filter 7 */
860 {-0.0569240339f, 0.0413577296f},
861 {-0.0296480060f, -0.0912471786f},
862 { 0.1136142015f, 0.0000000001f},
863 {-0.0364737995f, 0.1122548133f},
864 {-0.0842615440f, -0.0612195991f},
865 { 0.0548766218f, -0.0398701988f},
866 { 0.0019701670f, 0.0060635507f},
867 { 0.0809883848f, 0.0000000000f},
868 {-0.0595842153f, 0.1833813637f},
869 {-0.2632225752f, -0.1912423968f},
870 { 0.3824094236f, -0.2778367102f},
871 { 0.1937665194f, 0.5963520408f},
872 {-0.7794392109f, -0.0000000002f},
873 { 0.2844048440f, -0.8753081560f},
874 { 0.8418115377f, 0.6116119027f},
875 {-0.9156650901f, 0.6652696729f},
876 {-0.3670720458f, -1.1297315359f},
877 { 1.2047197819f, 0.0000000000f},
878 {-0.3650037944f, 1.1233661175f},
879 {-0.9052193165f, -0.6576803327f},
880 { 0.8270668387f, -0.6008992195f},
881 { 0.2775179148f, 0.8541123271f},
882 {-0.7545788884f, 0.0000000002f},
883 { 0.1857803613f, -0.5717731118f},
884 { 0.3619651794f, 0.2629830837f},
885 {-0.2443708777f, 0.1775458306f},
886 {-0.0533401072f, -0.1641639620f},
887 { 0.0646610633f, -0.0000000000f},
888 { 0.0056929523f, -0.0175211057f},
889 { 0.0611448549f, 0.0444243364f},
890 {-0.0873154774f, 0.0634384081f},
891 {-0.0365992747f, -0.1126409844f},
892 { 0.1114456356f, -0.0000000001f},
893 {-0.0284559596f, 0.0875784382f},
894 {-0.0531483367f, -0.0386145264f},
895 { 0.0301486850f, -0.0219043009f},
896 },
897 {
898 { 0.0358538441f, 0.0260493420f}, /* Filter 8 */
899 {-0.0587897114f, 0.0427132249f},
900 {-0.0302191172f, -0.0930048823f},
901 { 0.1145617142f, 0.0000000001f},
902 {-0.0363523550f, 0.1118810475f},
903 {-0.0825452656f, -0.0599726476f},
904 { 0.0515297912f, -0.0374385864f},
905 { 0.0000247626f, 0.0000762115f},
906 { 0.0894096494f, 0.0000000000f},
907 {-0.0627739578f, 0.1931983829f},
908 {-0.2727758884f, -0.1981832832f},
909 { 0.3926937282f, -0.2853086889f},
910 { 0.1977542788f, 0.6086250544f},
911 {-0.7917523384f, -0.0000000002f},
912 { 0.2877821028f, -0.8857022524f},
913 { 0.8489409089f, 0.6167916656f},
914 {-0.9205905795f, 0.6688482165f},
915 {-0.3679794967f, -1.1325244904f},
916 { 1.2042965889f, 0.0000000000f},
917 {-0.3638440073f, 1.1197967529f},
918 {-0.8997041583f, -0.6536732912f},
919 { 0.8194585443f, -0.5953714848f},
920 { 0.2740114331f, 0.8433204889f},
921 {-0.7420427203f, 0.0000000002f},
922 { 0.1817853153f, -0.5594776869f},
923 { 0.3518131077f, 0.2556071877f},
924 {-0.2350788414f, 0.1707947701f},
925 {-0.0502874292f, -0.1547687948f},
926 { 0.0567577891f, -0.0000000000f},
927 { 0.0074702986f, -0.0229912158f},
928 { 0.0640681237f, 0.0465482138f},
929 {-0.0886565670f, 0.0644127652f},
930 {-0.0366050303f, -0.1126586944f},
931 { 0.1102307960f, -0.0000000001f},
932 {-0.0278369281f, 0.0856732503f},
933 {-0.0512427762f, -0.0372300558f},
934 { 0.0282698758f, -0.0205392670f},
935 },
936 {
937 { 0.0377724878f, 0.0274433177f}, /* Filter 9 */
938 {-0.0606375895f, 0.0440557860f},
939 {-0.0307723451f, -0.0947075412f},
940 { 0.1154139340f, 0.0000000001f},
941 {-0.0361906476f, 0.1113833562f},
942 {-0.0807005838f, -0.0586324073f},
943 { 0.0480400361f, -0.0349031277f},
944 {-0.0019765710f, -0.0060832603f},
945 { 0.0980006009f, 0.0000000001f},
946 {-0.0660076514f, 0.2031506598f},
947 {-0.2824097872f, -0.2051827312f},
948 { 0.4030140936f, -0.2928068638f},
949 { 0.2017362267f, 0.6208803058f},
950 {-0.8039799333f, -0.0000000002f},
951 { 0.2911130786f, -0.8959538937f},
952 { 0.8559035659f, 0.6218503714f},
953 {-0.9253144860f, 0.6722803116f},
954 {-0.3688018918f, -1.1350555420f},
955 { 1.2035913467f, 0.0000000000f},
956 {-0.3626012504f, 1.1159719229f},
957 {-0.8939976096f, -0.6495273113f},
958 { 0.8116977811f, -0.5897329450f},
959 { 0.2704651356f, 0.8324060440f},
960 {-0.7294434309f, 0.0000000002f},
961 { 0.1777911931f, -0.5471850634f},
962 { 0.3417128623f, 0.2482689321f},
963 {-0.2258801460f, 0.1641115248f},
964 {-0.0472820736f, -0.1455192566f},
965 { 0.0490297712f, -0.0000000000f},
966 { 0.0091916462f, -0.0282889791f},
967 { 0.0668521896f, 0.0485709570f},
968 {-0.0898761228f, 0.0652988255f},
969 {-0.0365739614f, -0.1125630811f},
970 { 0.1089330688f, -0.0000000001f},
971 {-0.0272038169f, 0.0837247372f},
972 {-0.0493283160f, -0.0358391218f},
973 { 0.0264054053f, -0.0191846490f},
974 },
975 {
976 { 0.0396964923f, 0.0288411900f}, /* Filter 10 */
977 {-0.0624653697f, 0.0453837477f},
978 {-0.0313067287f, -0.0963522047f},
979 { 0.1161677912f, 0.0000000001f},
980 {-0.0359878466f, 0.1107592061f},
981 {-0.0787259191f, -0.0571977310f},
982 { 0.0444066115f, -0.0322632901f},
983 {-0.0040337327f, -0.0124145532f},
984 { 0.1067595631f, 0.0000000001f},
985 {-0.0692843646f, 0.2132353336f},
986 {-0.2921209633f, -0.2122382969f},
987 { 0.4133664668f, -0.3003283143f},
988 { 0.2057106793f, 0.6331123710f},
989 {-0.8161166310f, -0.0000000002f},
990 { 0.2943962216f, -0.9060583711f},
991 { 0.8626962900f, 0.6267855763f},
992 {-0.9298345447f, 0.6755643487f},
993 {-0.3695388138f, -1.1373236179f},
994 { 1.2026044130f, 0.0000000000f},
995 {-0.3612760901f, 1.1118934155f},
996 {-0.8881026506f, -0.6452443004f},
997 { 0.8037882447f, -0.5839863420f},
998 { 0.2668806314f, 0.8213740587f},
999 {-0.7167864442f, 0.0000000002f},
1000 { 0.1737996489f, -0.5349003077f},
1001 { 0.3316683173f, 0.2409711480f},
1002 {-0.2167777866f, 0.1574982852f},
1003 {-0.0443248004f, -0.1364177018f},
1004 { 0.0414781198f, -0.0000000000f},
1005 { 0.0108570615f, -0.0334145986f},
1006 { 0.0694981664f, 0.0504933707f},
1007 {-0.0909759924f, 0.0660979301f},
1008 {-0.0365069620f, -0.1123568788f},
1009 { 0.1075555831f, -0.0000000001f},
1010 {-0.0265575647f, 0.0817357823f},
1011 {-0.0474071130f, -0.0344432816f},
1012 { 0.0245569348f, -0.0178416576f},
1013 },
1014 {
1015 { 0.0416239388f, 0.0302415621f}, /* Filter 11 */
1016 {-0.0642707273f, 0.0466954149f},
1017 {-0.0318213031f, -0.0979359001f},
1018 { 0.1168202460f, 0.0000000001f},
1019 {-0.0357431434f, 0.1100060865f},
1020 {-0.0766197667f, -0.0556675196f},
1021 { 0.0406288542f, -0.0295185894f},
1022 {-0.0061465879f, -0.0189172514f},
1023 { 0.1156847477f, 0.0000000001f},
1024 {-0.0726031289f, 0.2234494686f},
1025 {-0.3019059300f, -0.2193474919f},
1026 { 0.4237467945f, -0.3078700602f},
1027 { 0.2096759230f, 0.6453161240f},
1028 {-0.8281568289f, -0.0000000002f},
1029 { 0.2976299822f, -0.9160109162f},
1030 { 0.8693157434f, 0.6315948367f},
1031 {-0.9341484904f, 0.6786985993f},
1032 {-0.3701899350f, -1.1393274069f},
1033 { 1.2013363838f, 0.0000000000f},
1034 {-0.3598691821f, 1.1075633764f},
1035 {-0.8820219636f, -0.6408264637f},
1036 { 0.7957338095f, -0.5781344771f},
1037 { 0.2632595599f, 0.8102296591f},
1038 {-0.7040774226f, 0.0000000002f},
1039 { 0.1698123366f, -0.5226286054f},
1040 { 0.3216831982f, 0.2337165177f},
1041 {-0.2077746689f, 0.1509571373f},
1042 {-0.0414163321f, -0.1274663657f},
1043 { 0.0341038331f, -0.0000000000f},
1044 { 0.0124666411f, -0.0383683741f},
1045 { 0.0720072389f, 0.0523163229f},
1046 {-0.0919580832f, 0.0668114573f},
1047 {-0.0364049338f, -0.1120428666f},
1048 { 0.1061014757f, -0.0000000001f},
1049 {-0.0258991010f, 0.0797092393f},
1050 {-0.0454812683f, -0.0330440775f},
1051 { 0.0227260832f, -0.0165114664f},
1052 },
1053 };
1054
1055 static const uint8_t space_map_v22bis[6][6] =
1056 {
1057 {11, 9, 9, 6, 6, 7},
1058 {10, 8, 8, 4, 4, 5},
1059 {10, 8, 8, 4, 4, 5},
1060 {13, 12, 12, 0, 0, 2},
1061 {13, 12, 12, 0, 0, 2},
1062 {15, 14, 14, 1, 1, 3}
1063 };
1064
1065 float v22bis_rx_carrier_frequency(v22bis_state_t *s)
1066 {
1067 return dds_frequencyf(s->rx_carrier_phase_rate);
1068 }
1069 /*- End of function --------------------------------------------------------*/
1070
1071 float v22bis_rx_symbol_timing_correction(v22bis_state_t *s)
1072 {
1073 return (float) s->total_baud_timing_correction/((float) PULSESHAPER_COEFF_SETS*40.0f/(3.0f*2.0f));
1074 }
1075 /*- End of function --------------------------------------------------------*/
1076
1077 float v22bis_rx_signal_power(v22bis_state_t *s)
1078 {
1079 return power_meter_dbm0(&s->rx_power);
1080 }
1081 /*- End of function --------------------------------------------------------*/
1082
1083 int v22bis_rx_equalizer_state(v22bis_state_t *s, complexf_t **coeffs)
1084 {
1085 *coeffs = s->eq_coeff;
1086 return 2*V22BIS_EQUALIZER_LEN + 1;
1087 }
1088 /*- End of function --------------------------------------------------------*/
1089
1090 static void equalizer_reset(v22bis_state_t *s)
1091 {
1092 int i;
1093
1094 /* Start with an equalizer based on everything being perfect */
1095 for (i = 0; i < 2*V22BIS_EQUALIZER_LEN + 1; i++)
1096 s->eq_coeff[i] = complex_setf(0.0f, 0.0f);
1097 s->eq_coeff[V22BIS_EQUALIZER_LEN] = complex_setf(3.0f, 0.0f);
1098 for (i = 0; i <= V22BIS_EQUALIZER_MASK; i++)
1099 s->eq_buf[i] = complex_setf(0.0f, 0.0f);
1100
1101 s->eq_coeff[V22BIS_EQUALIZER_LEN - 6].re = -0.02f;
1102 s->eq_coeff[V22BIS_EQUALIZER_LEN - 5].re = 0.035f;
1103 s->eq_coeff[V22BIS_EQUALIZER_LEN - 4].re = 0.08f;
1104 s->eq_coeff[V22BIS_EQUALIZER_LEN - 3].re = -0.30f;
1105 s->eq_coeff[V22BIS_EQUALIZER_LEN - 2].re = -0.37f;
1106 s->eq_coeff[V22BIS_EQUALIZER_LEN - 1].re = 0.09f;
1107 s->eq_coeff[V22BIS_EQUALIZER_LEN].re = 3.19f;
1108 s->eq_coeff[V22BIS_EQUALIZER_LEN + 1].re = 0.09f;
1109 s->eq_coeff[V22BIS_EQUALIZER_LEN + 2].re = -0.37f;
1110 s->eq_coeff[V22BIS_EQUALIZER_LEN + 3].re = -0.30f;
1111 s->eq_coeff[V22BIS_EQUALIZER_LEN + 5].re = 0.035f;
1112 s->eq_coeff[V22BIS_EQUALIZER_LEN + 6].re = -0.02f;
1113
1114 s->eq_put_step = 20 - 1;
1115 s->eq_step = 0;
1116 s->eq_delta = EQUALIZER_DELTA/(2*V22BIS_EQUALIZER_LEN + 1);
1117 }
1118 /*- End of function --------------------------------------------------------*/
1119
1120 static complexf_t equalizer_get(v22bis_state_t *s)
1121 {
1122 int i;
1123 int p;
1124 complexf_t z;
1125 complexf_t z1;
1126
1127 /* Get the next equalized value. */
1128 z = complex_setf(0.0f, 0.0f);
1129 p = s->eq_step - 1;
1130 for (i = 0; i < 2*V22BIS_EQUALIZER_LEN + 1; i++)
1131 {
1132 p = (p - 1) & V22BIS_EQUALIZER_MASK;
1133 z1 = complex_mulf(&s->eq_coeff[i], &s->eq_buf[p]);
1134 z = complex_addf(&z, &z1);
1135 }
1136 return z;
1137 }
1138 /*- End of function --------------------------------------------------------*/
1139
1140 static void tune_equalizer(v22bis_state_t *s, const complexf_t *z, const complexf_t *target)
1141 {
1142 int i;
1143 int p;
1144 complexf_t ez;
1145 complexf_t z1;
1146
1147 /* Find the x and y mismatch from the exact constellation position. */
1148 ez = complex_subf(target, z);
1149 ez.re *= s->eq_delta;
1150 ez.im *= s->eq_delta;
1151
1152 p = s->eq_step - 1;
1153 for (i = 0; i < 2*V22BIS_EQUALIZER_LEN + 1; i++)
1154 {
1155 p = (p - 1) & V22BIS_EQUALIZER_MASK;
1156 z1 = complex_conjf(&s->eq_buf[p]);
1157 z1 = complex_mulf(&ez, &z1);
1158 s->eq_coeff[i] = complex_addf(&s->eq_coeff[i], &z1);
1159 /* If we don't leak a little bit we seem to get some wandering adaption */
1160 s->eq_coeff[i].re *= 0.9999f;
1161 s->eq_coeff[i].im *= 0.9999f;
1162 }
1163 }
1164 /*- End of function --------------------------------------------------------*/
1165
1166 static __inline__ void track_carrier(v22bis_state_t *s, const complexf_t *z, const complexf_t *target)
1167 {
1168 float error;
1169
1170 /* For small errors the imaginary part of the difference between the actual and the target
1171 positions is proportional to the phase error, for any particular target. However, the
1172 different amplitudes of the various target positions scale things. */
1173 error = z->im*target->re - z->re*target->im;
1174
1175 s->rx_carrier_phase_rate += (int32_t) (s->carrier_track_i*error);
1176 s->rx_carrier_phase += (int32_t) (s->carrier_track_p*error);
1177 //span_log(&s->logging, SPAN_LOG_FLOW, "Im = %15.5f f = %15.5f\n", error, dds_frequencyf(s->carrier_phase_rate));
1178 }
1179 /*- End of function --------------------------------------------------------*/
1180
1181 static __inline__ void put_bit(v22bis_state_t *s, int bit)
1182 {
1183 int out_bit;
1184
1185 bit &= 1;
1186
1187 /* Descramble the bit */
1188 s->rx_scramble_reg = (s->rx_scramble_reg << 1) | bit;
1189 out_bit = (bit ^ (s->rx_scramble_reg >> 15) ^ (s->rx_scramble_reg >> 18)) & 1;
1190 if (s->rx_scrambler_pattern_count >= 64)
1191 {
1192 out_bit ^= 1;
1193 s->rx_scrambler_pattern_count = 0;
1194 }
1195 if (bit)
1196 s->rx_scrambler_pattern_count++;
1197 else
1198 s->rx_scrambler_pattern_count = 0;
1199
1200 s->put_bit(s->user_data, out_bit);
1201 }
1202 /*- End of function --------------------------------------------------------*/
1203
1204 static void decode_baud(v22bis_state_t *s, int nearest)
1205 {
1206 static const uint8_t phase_steps[4] =
1207 {
1208 1, 0, 2, 3
1209 };
1210 int raw_bits;
1211
1212 raw_bits = phase_steps[((nearest - s->rx_constellation_state) >> 2) & 3];
1213 /* The first two bits are the quadrant */
1214 put_bit(s, raw_bits);
1215 put_bit(s, raw_bits >> 1);
1216 if (s->bit_rate == 2400)
1217 {
1218 /* The other two bits are the position within the quadrant */
1219 put_bit(s, nearest >> 1);
1220 put_bit(s, nearest);
1221 }
1222 s->rx_constellation_state = nearest;
1223 }
1224 /*- End of function --------------------------------------------------------*/
1225
1226 static __inline__ int find_quadrant(const complexf_t *z)
1227 {
1228 int b1;
1229 int b2;
1230
1231 #if 0
1232 /* Split along the axes, as follows:
1233 1 0
1234 2 3
1235 */
1236 b1 = (z->re <= 0.0f);
1237 b2 = (z->im <= 0.0f);
1238 return (b2 << 1) | (b1 ^ b2);
1239 #endif
1240 /* Split the space along the two diagonals, as follows:
1241 \ 1 /
1242 2 0
1243 / 3 \
1244 */
1245 b1 = (z->im > z->re);
1246 b2 = (z->im < -z->re);
1247 return (b2 << 1) | (b1 ^ b2);
1248 }
1249 /*- End of function --------------------------------------------------------*/
1250
1251 static void process_half_baud(v22bis_state_t *s, const complexf_t *sample)
1252 {
1253 complexf_t a;
1254 complexf_t b;
1255 complexf_t c;
1256
1257 complexf_t z;
1258 complexf_t zz;
1259 const complexf_t *target;
1260 float p;
1261 float q;
1262 int re;
1263 int im;
1264 int nearest;
1265
1266 z.re = sample->re;
1267 z.im = sample->im;
1268
1269 /* Add a sample to the equalizer's circular buffer, but don't calculate anything
1270 at this time. */
1271 s->eq_buf[s->eq_step] = z;
1272 s->eq_step = (s->eq_step + 1) & V22BIS_EQUALIZER_MASK;
1273
1274 /* On alternate insertions we have a whole baud and must process it. */
1275 if ((s->rx_baud_phase ^= 1))
1276 return;
1277
1278 /* Perform a Gardner test for baud alignment on the three most recent samples. */
1279 #if 0
1280 p = s->eq_buf[(s->eq_step - 3) & V22BIS_EQUALIZER_MASK].re
1281 - s->eq_buf[(s->eq_step - 1) & V22BIS_EQUALIZER_MASK].re;
1282 p *= s->eq_buf[(s->eq_step - 2) & V22BIS_EQUALIZER_MASK].re;
1283
1284 q = s->eq_buf[(s->eq_step - 3) & V22BIS_EQUALIZER_MASK].im
1285 - s->eq_buf[(s->eq_step - 1) & V22BIS_EQUALIZER_MASK].im;
1286 q *= s->eq_buf[(s->eq_step - 2) & V22BIS_EQUALIZER_MASK].im;
1287 #else
1288 if (s->sixteen_way_decisions)
1289 {
1290 p = s->eq_buf[(s->eq_step - 3) & V22BIS_EQUALIZER_MASK].re
1291 - s->eq_buf[(s->eq_step - 1) & V22BIS_EQUALIZER_MASK].re;
1292 p *= s->eq_buf[(s->eq_step - 2) & V22BIS_EQUALIZER_MASK].re;
1293
1294 q = s->eq_buf[(s->eq_step - 3) & V22BIS_EQUALIZER_MASK].im
1295 - s->eq_buf[(s->eq_step - 1) & V22BIS_EQUALIZER_MASK].im;
1296 q *= s->eq_buf[(s->eq_step - 2) & V22BIS_EQUALIZER_MASK].im;
1297 }
1298 else
1299 {
1300 /* Rotate the points to the 45 degree positions, to maximise the effectiveness of the Gardner algorithm */
1301 zz = complex_setf(cosf(26.57f*3.14159f/180.0f), sinf(26.57f*3.14159f/180.0f));
1302 a = complex_mulf(&s->eq_buf[(s->eq_step - 3) & V22BIS_EQUALIZER_MASK], &zz);
1303 b = complex_mulf(&s->eq_buf[(s->eq_step - 2) & V22BIS_EQUALIZER_MASK], &zz);
1304 c = complex_mulf(&s->eq_buf[(s->eq_step - 1) & V22BIS_EQUALIZER_MASK], &zz);
1305 p = (a.re - c.re)*b.re;
1306 q = (a.im - c.im)*b.im;
1307 }
1308 #endif
1309
1310 p += q;
1311 s->gardner_integrate += ((p + q) > 0.0f) ? s->gardner_step : -s->gardner_step;
1312
1313 if (abs(s->gardner_integrate) >= 16)
1314 {
1315 /* This integrate and dump approach avoids rapid changes of the equalizer put step.
1316 Rapid changes, without hysteresis, are bad. They degrade the equalizer performance
1317 when the true symbol boundary is close to a sample boundary. */
1318 s->eq_put_step += (s->gardner_integrate/16);
1319 s->total_baud_timing_correction += (s->gardner_integrate/16);
1320 span_log(&s->logging, SPAN_LOG_FLOW, "Gardner kick %d [total %d]\n", s->gardner_integrate, s->total_baud_timing_correction);
1321 if (s->qam_report)
1322 s->qam_report(s->qam_user_data, NULL, NULL, s->gardner_integrate);
1323 s->gardner_integrate = 0;
1324 }
1325
1326 z = equalizer_get(s);
1327 printf("VVV %15.5f %15.5f\n", z.re, z.im);
1328
1329 span_log(&s->logging, SPAN_LOG_FLOW, "VVV %p %d\n", s->user_data, s->rx_training);
1330 if (s->sixteen_way_decisions)
1331 {
1332 re = (int) (z.re + 3.0f);
1333 if (re > 5)
1334 re = 5;
1335 else if (re < 0)
1336 re = 0;
1337 im = (int) (z.im + 3.0f);
1338 if (im > 5)
1339 im = 5;
1340 else if (im < 0)
1341 im = 0;
1342 nearest = space_map_v22bis[re][im];
1343 }
1344 else
1345 {
1346 zz = complex_setf(3.0f/sqrtf(10.0f), -1.0f/sqrtf(10.0f));
1347 zz = complex_mulf(&z, &zz);
1348 nearest = (find_quadrant(&zz) << 2) | 0x01;
1349 printf("Trackit %15.5f %15.5f %15.5f %15.5f %d\n", z.re, z.im, zz.re, zz.im, nearest);
1350 }
1351
1352 switch (s->rx_training)
1353 {
1354 case V22BIS_TRAINING_STAGE_NORMAL_OPERATION:
1355 /* Normal operation. */
1356 track_carrier(s, &z, &v22bis_constellation[nearest]);
1357 tune_equalizer(s, &z, &v22bis_constellation[nearest]);
1358 decode_baud(s, nearest);
1359 target = &v22bis_constellation[s->rx_constellation_state];
1360 break;
1361 case V22BIS_TRAINING_STAGE_SYMBOL_ACQUISITION:
1362 /* Allow time for the Gardner algorithm to settle the symbol timing. */
1363 target = &z;
1364 if (++s->rx_training_count >= 40)
1365 {
1366 s->gardner_step = 4;
1367 if (s->caller)
1368 {
1369 s->rx_training = V22BIS_TRAINING_STAGE_UNSCRAMBLED_ONES;
1370 }
1371 else
1372 {
1373 if (s->bit_rate == 2400)
1374 s->rx_training = V22BIS_TRAINING_STAGE_UNSCRAMBLED_0011;
1375 else
1376 s->rx_training = V22BIS_TRAINING_STAGE_SCRAMBLED_ONES_AT_1200;
1377 }
1378 break;
1379 }
1380
1381 /* QAM and Gardner only play nicely with heavy damping, so we need to change to
1382 a slow rate of symbol timing adaption. However, it must not be so slow that it
1383 cannot track the worst case timing error specified in V.22bis. This should be 0.01%,
1384 but since we might be off in the opposite direction from the source, the total
1385 error could be higher. */
1386 if (s->rx_training_count == 30)
1387 s->gardner_step = 32;
1388 break;
1389 case V22BIS_TRAINING_STAGE_UNSCRAMBLED_ONES:
1390 /* The answering modem should initially receive unscrambled ones at 1200bps */
1391 track_carrier(s, &z, &v22bis_constellation[nearest]);
1392 target = &z;
1393 if (nearest == ((s->rx_constellation_state - 4) & 0x0F))
1394 s->detected_unscrambled_ones++;
1395 if (nearest == ((s->rx_constellation_state + 4) & 0x0F))
1396 s->detected_unscrambled_zeros++;
1397 s->rx_constellation_state = nearest;
1398 span_log(&s->logging, SPAN_LOG_FLOW, "TWIDDLING THUMBS - %d\n", s->rx_training_count);
1399 if (++s->rx_training_count == ms_to_symbols(155 + 456))
1400 {
1401 if (s->detected_unscrambled_ones >= 250 || s->detected_unscrambled_zeros >= 250)
1402 s->detected_unscrambled_ones_or_zeros = TRUE;
1403 }
1404 if (s->rx_training_count == ms_to_symbols(155 + 457))
1405 {
1406 /* We should only bother looking for the 2400bps marker if we are allowed to use
1407 2400bps */
1408 s->rx_training_count = 0;
1409 if (s->bit_rate == 2400)
1410 s->rx_training = V22BIS_TRAINING_STAGE_UNSCRAMBLED_0011;
1411 else
1412 s->rx_training = V22BIS_TRAINING_STAGE_SCRAMBLED_ONES_AT_1200;
1413 }
1414 break;
1415 case V22BIS_TRAINING_STAGE_UNSCRAMBLED_0011:
1416 s->sixteen_way_decisions = TRUE;
1417 /* If we can actually find this it means we can use 2400bps. If we find unscrambled ones, it means we
1418 we must use 1200bps. */
1419 track_carrier(s, &z, &v22bis_constellation[nearest]);
1420 tune_equalizer(s, &z, &v22bis_constellation[nearest]);
1421 target = &z;
1422 //s->carrier_track_i = 1000.0f;
1423 //s->carrier_track_p = 1000000.0f;
1424 #if 0
1425 if (++s->rx_training_count > ms_to_symbols(800))
1426 {
1427 s->detected_unscrambled_0011_ending = TRUE;
1428 s->rx_training = V22BIS_TRAINING_STAGE_UNSCRAMBLED_ONES;
1429 }
1430 #else
1431 if (++s->rx_training_count == 1)
1432 {
1433 s->detected_unscrambled_zeros = nearest;
1434 s->detected_unscrambled_ones = 0;
1435 }
1436 else
1437 {
1438 span_log(&s->logging, SPAN_LOG_FLOW, "0x%X 0x%X 0x%X\n", s->detected_unscrambled_zeros, nearest, (s->detected_unscrambled_zeros + nearest) & 0x0F);
1439 if ((s->rx_training_count & 1) == 0)
1440 {
1441 span_log(&s->logging, SPAN_LOG_FLOW, "AAA\n");
1442 if (((s->detected_unscrambled_zeros + nearest) & 0x0F) == 0x06)
1443 s->detected_unscrambled_ones = 1;
1444 else if (((s->detected_unscrambled_zeros + nearest) & 0x0F) == 0x02)
1445 s->detected_unscrambled_ones = -1;
1446 else
1447 {
1448 span_log(&s->logging, SPAN_LOG_FLOW, "AAA 1\n");
1449 if (s->detected_unscrambled_ones > 5 || s->detected_unscrambled_ones < -5)
1450 s->detected_unscrambled_0011_ending = TRUE;
1451 else
1452 s->bit_rate = 1200;
1453 s->rx_training = V22BIS_TRAINING_STAGE_SCRAMBLED_ONES_AT_1200;
1454 }
1455 }
1456 else
1457 {
1458 span_log(&s->logging, SPAN_LOG_FLOW, "BBB\n");
1459 if (((s->detected_unscrambled_zeros + nearest) & 0x0F) == 0x06)
1460 s->detected_unscrambled_ones = 1;
1461 else if (((s->detected_unscrambled_zeros + nearest) & 0x0F) == 0x02)
1462 s->detected_unscrambled_ones = -1;
1463 else
1464 {
1465 span_log(&s->logging, SPAN_LOG_FLOW, "BBB 1\n");
1466 if (s->detected_unscrambled_ones > 5 || s->detected_unscrambled_ones < -5)
1467 s->detected_unscrambled_0011_ending = TRUE;
1468 else
1469 s->bit_rate = 1200;
1470 s->rx_training = V22BIS_TRAINING_STAGE_SCRAMBLED_ONES_AT_1200;
1471 }
1472 }
1473 }
1474 #endif
1475 break;
1476 case V22BIS_TRAINING_STAGE_SCRAMBLED_ONES_AT_1200:
1477 track_carrier(s, &z, &v22bis_constellation[nearest]);
1478 tune_equalizer(s, &z, &v22bis_constellation[nearest]);
1479 target = &z;
1480 span_log(&s->logging, SPAN_LOG_FLOW, "S11 0x%02x\n", nearest);
1481 if (++s->rx_training_count > ms_to_symbols(900))
1482 {
1483 s->detected_scrambled_ones_or_zeros_at_1200bps = TRUE;
1484 s->rx_training = V22BIS_TRAINING_STAGE_NORMAL_OPERATION;
1485 }
1486 if (s->bit_rate == 2400 && s->rx_training_count == ms_to_symbols(450))
1487 s->sixteen_way_decisions = TRUE;
1488 break;
1489 case V22BIS_TRAINING_STAGE_SCRAMBLED_ONES_AT_2400:
1490 track_carrier(s, &z, &v22bis_constellation[nearest]);
1491 tune_equalizer(s, &z, &v22bis_constellation[nearest]);
1492 s->sixteen_way_decisions = TRUE;
1493 target = &z;
1494 break;
1495 case V22BIS_TRAINING_STAGE_PARKED:
1496 default:
1497 /* We failed to train! */
1498 /* Park here until the carrier drops. */
1499 target = &z;
1500 break;
1501 }
1502 if (s->qam_report)
1503 s->qam_report(s->qam_user_data, &z, target, s->rx_constellation_state);
1504 }
1505 /*- End of function --------------------------------------------------------*/
1506
1507 int v22bis_rx(v22bis_state_t *s, const int16_t amp[], int len)
1508 {
1509 int i;
1510 int j;
1511 int step;
1512 complexf_t z;
1513 complexf_t zz;
1514 int32_t power;
1515 complexf_t sample;
1516 float ii;
1517 float qq;
1518
1519 for (i = 0; i < len; i++)
1520 {
1521 /* Complex bandpass filter the signal, using a pair of FIRs, and RRC coeffs shifted
1522 to centre at 1200Hz or 2400Hz. The filters support 12 fractional phase shifts, to
1523 permit signal extraction very close to the middle of a symbol. */
1524 s->rx_rrc_filter[s->rx_rrc_filter_step] =
1525 s->rx_rrc_filter[s->rx_rrc_filter_step + V22BIS_RX_FILTER_STEPS] = amp[i];
1526 if (++s->rx_rrc_filter_step >= V22BIS_RX_FILTER_STEPS)
1527 s->rx_rrc_filter_step = 0;
1528
1529 /* Calculate the I filter, with an arbitrary phase step, just so we can calculate
1530 the signal power. */
1531 /* TODO: get rid of this */
1532 if (s->caller)
1533 {
1534 ii = pulseshaper_2400[6][0].re*s->rx_rrc_filter[s->rx_rrc_filter_step];
1535 for (j = 1; j < V22BIS_RX_FILTER_STEPS; j++)
1536 ii += pulseshaper_2400[6][j].re*s->rx_rrc_filter[j + s->rx_rrc_filter_step];
1537 }
1538 else
1539 {
1540 ii = pulseshaper_1200[6][0].re*s->rx_rrc_filter[s->rx_rrc_filter_step];
1541 for (j = 1; j < V22BIS_RX_FILTER_STEPS; j++)
1542 ii += pulseshaper_1200[6][j].re*s->rx_rrc_filter[j + s->rx_rrc_filter_step];
1543 }
1544 power = power_meter_update(&(s->rx_power), (int16_t) (ii/10.0f));
1545 if (s->carrier_present)
1546 {
1547 /* Look for power below -48dBm0 to turn the carrier off */
1548 if (power < s->carrier_off_power)
1549 {
1550 v22bis_rx_restart(s, s->bit_rate);
1551 s->put_bit(s->user_data, PUTBIT_CARRIER_DOWN);
1552 continue;
1553 }
1554 }
1555 else
1556 {
1557 /* Look for power exceeding -43dBm0 to turn the carrier on */
1558 if (power < s->carrier_on_power)
1559 continue;
1560 s->carrier_present = TRUE;
1561 s->put_bit(s->user_data, PUTBIT_CARRIER_UP);
1562 }
1563 if (s->rx_training != V22BIS_TRAINING_STAGE_PARKED)
1564 {
1565 /* Only spend effort processing this data if the modem is not
1566 parked, after training failure. */
1567 z = dds_complexf(&(s->rx_carrier_phase), s->rx_carrier_phase_rate);
1568 if (s->rx_training == V22BIS_TRAINING_STAGE_SYMBOL_ACQUISITION)
1569 {
1570 /* Only AGC during the initial symbol acquisition, and then lock the gain. */
1571 s->agc_scaling = 0.018f*3.60f/sqrtf(power);
1572 }
1573 /* Put things into the equalization buffer at T/2 rate. The Gardner algorithm
1574 will fiddle the step to align this with the symbols. */
1575 if ((s->eq_put_step -= PULSESHAPER_COEFF_SETS) <= 0)
1576 {
1577 /* Pulse shape while still at the carrier frequency, using a quadrature
1578 pair of filters. This results in a properly bandpass filtered complex
1579 signal, which can be brought directly to bandband by complex mixing.
1580 No further filtering, to remove mixer harmonics, is needed. */
1581 step = -s->eq_put_step;
1582 if (step > PULSESHAPER_COEFF_SETS - 1)
1583 step = PULSESHAPER_COEFF_SETS - 1;
1584 s->eq_put_step += PULSESHAPER_COEFF_SETS*40/(3*2);
1585 if (s->caller)
1586 {
1587 ii = pulseshaper_2400[step][0].re*s->rx_rrc_filter[s->rx_rrc_filter_step];
1588 qq = pulseshaper_2400[step][0].im*s->rx_rrc_filter[s->rx_rrc_filter_step];
1589 for (j = 1; j < V22BIS_RX_FILTER_STEPS; j++)
1590 {
1591 ii += pulseshaper_2400[step][j].re*s->rx_rrc_filter[j + s->rx_rrc_filter_step];
1592 qq += pulseshaper_2400[step][j].im*s->rx_rrc_filter[j + s->rx_rrc_filter_step];
1593 }
1594 }
1595 else
1596 {
1597 ii = pulseshaper_1200[step][0].re*s->rx_rrc_filter[s->rx_rrc_filter_step];
1598 qq = pulseshaper_1200[step][0].im*s->rx_rrc_filter[s->rx_rrc_filter_step];
1599 for (j = 1; j < V22BIS_RX_FILTER_STEPS; j++)
1600 {
1601 ii += pulseshaper_1200[step][j].re*s->rx_rrc_filter[j + s->rx_rrc_filter_step];
1602 qq += pulseshaper_1200[step][j].im*s->rx_rrc_filter[j + s->rx_rrc_filter_step];
1603 }
1604 }
1605 sample.re = ii*s->agc_scaling;
1606 sample.im = qq*s->agc_scaling;
1607 /* Shift to baseband - since this is done in a full complex form, the
1608 result is clean, and requires no further filtering apart from the
1609 equalizer. */
1610 zz.re = sample.re*z.re - sample.im*z.im;
1611 zz.im = -sample.re*z.im - sample.im*z.re;
1612 process_half_baud(s, &zz);
1613 }
1614 }
1615 }
1616 return 0;
1617 }
1618 /*- End of function --------------------------------------------------------*/
1619
1620 int v22bis_rx_restart(v22bis_state_t *s, int bit_rate)
1621 {
1622 /* If bit_rate is 2400, the real bit rate is negotiated. If bit_rate
1623 is 1200, the real bit rate is forced to 1200. */
1624 s->bit_rate = bit_rate;
1625 vec_zerof(s->rx_rrc_filter, sizeof(s->rx_rrc_filter)/sizeof(s->rx_rrc_filter[0]));
1626 s->rx_rrc_filter_step = 0;
1627 s->rx_scramble_reg = 0;
1628 s->rx_scrambler_pattern_count = 0;
1629 s->rx_training = V22BIS_TRAINING_STAGE_SYMBOL_ACQUISITION;
1630 s->rx_training_count = 0;
1631 s->carrier_present = FALSE;
1632
1633 s->rx_carrier_phase_rate = dds_phase_ratef((s->caller) ? 2400.0f : 1200.0f);
1634 s->rx_carrier_phase = 0;
1635 power_meter_init(&(s->rx_power), 5);
1636 s->carrier_on_power = power_meter_level_dbm0(-43);
1637 s->carrier_off_power = power_meter_level_dbm0(-48);
1638 s->agc_scaling = 0.0005f*0.025f;
1639
1640 s->rx_constellation_state = 0;
1641 s->sixteen_way_decisions = FALSE;
1642
1643 equalizer_reset(s);
1644
1645 s->detected_unscrambled_ones = 0;
1646 s->detected_unscrambled_zeros = 0;
1647 s->gardner_integrate = 0;
1648 s->gardner_step = 256;
1649 s->rx_baud_phase = 0;
1650 s->carrier_track_i = 8000.0f;
1651 s->carrier_track_p = 8000000.0f;
1652 return 0;
1653 }
1654 /*- End of function --------------------------------------------------------*/
1655
1656 void v22bis_rx_set_qam_report_handler(v22bis_state_t *s, qam_report_handler_t *handler, void *user_data)
1657 {
1658 s->qam_report = handler;
1659 s->qam_user_data = user_data;
1660 }
1661 /*- End of function --------------------------------------------------------*/
1662 /*- End of file ------------------------------------------------------------*/

Repositories maintained by Peter Meerwald, pmeerw@pmeerw.net.