1 // Copyright (c) <2012> <Leif Asbrink>
2 //
3 // Permission is hereby granted, free of charge, to any person
4 // obtaining a copy of this software and associated documentation
5 // files (the "Software"), to deal in the Software without restriction,
6 // including without limitation the rights to use, copy, modify,
7 // merge, publish, distribute, sublicense, and/or sell copies of
8 // the Software, and to permit persons to whom the Software is
9 // furnished to do so, subject to the following conditions:
10 //
11 // The above copyright notice and this permission notice shall be
12 // included in all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
16 // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
18 // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
19 // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
21 // OR OTHER DEALINGS IN THE SOFTWARE.
22
23 #include "globdef.h"
24 #include "uidef.h"
25 #include "sigdef.h"
26 #include "screendef.h"
27 #include "fft1def.h"
28 #include "options.h"
29 #include "llsqdef.h"
30
31
32 void show_cw(char *s);
33
34
35 // Skip processing in case the number of dashes is below
36 // the MIN_NO_OF_CWDAT limit.
37 #define MIN_NO_OF_CWDAT 5
38
39 #define ZZ 0.000000001
40
41 // float[2] baseb_out=data to send to loudspeaker
42 // float[2] baseb=complex amplitude of first level coherent data.
43 // float[2] baseb_raw=complex amplitude of baseband signal. Raw data, pol. adapted.
44 // float[2] baseb_raw_orthog=complex amplitude of pol. orthog signal. Raw data.
45 // float[2] baseb_carrier=phase of carrier. Complex data, cosines and sines.
46 // float[1] baseb_carrier_ampl=amplitude of carrier
47 // float[1] baseb_totpwr=total power of baseb_raw
48 // float[2] baseb_envelope=complex amplitude from fitted dots and dashes.
49 // float[1] baseb_upthreshold=forward peak detector for power
50 // float[1] baseb_threshold=combined forward and backward peak detector at -6dB
51 // float[2] baseb_fit=fitted dots and dashes.
52 // float[2] baseb_tmp=array for intermediate data in complex format
53 // float[1] baseb_agc_level=used only when AGC is enabled.
54 // float[2] baseb_wb_raw=complex amplitude like baseb_raw at a larger bandwidth.
55 // float[2] baseb_wb=complex amplitude of coherent detect like baseb, at larger bw.
56 // short int[1] baseb_ramp=indicator for time of power above/below threshold.
57 // short_int[1] baseb_clock=CW code clock
58 // float[2] baseb_tmp=for debug during development
59
60 // baseb_pa The starting point of the latest mix2_size/2 points.
61 // baseb_pb The point up to which thresholds exist.
62 // baseb_pc The point up to which cw speed statistics and ramp is collected.
63 // baseb_pd A key up region close before baseb_pc
64 // baseb_pe The point up to which we have run first detect.
65 // baseb_pf
66 // baseb_px The oldest point that contains valid data.
67
68
check_cw(int num,int type)69 void check_cw(int num,int type)
70 {
71 int i;
72 float t1;
73 for(i=0; i<no_of_cwdat;i++)
74 {
75 if(cw[i].len == 0)
76 {
77 DEB"\nLen is zero");
78 goto err;
79 }
80 if(type > 0)
81 {
82 if(i>0)
83 {
84 t1=cw[i].midpoint-cw[i-1].midpoint;
85 if(t1 > baseband_neg)
86 {
87 DEB"\nt1>neg %f",t1);
88 goto err;
89 }
90 if(t1 < 0)t1+=baseband_size;
91 if(fabs (t1-cw[i].sep)/baseband_size > 0.0000001)
92 {
93 DEB"\nt1!=sep %f %f",t1,cw[i].sep);
94 goto err;
95 }
96 }
97 }
98 }
99 return;
100 err:;
101 DEB"\nERROR[%d] i=%d",num,i);
102 for(i=0; i<no_of_cwdat; i++)
103 {
104 DEB"\n%3d %10.3f %8.3f (re %f im %f)",i,
105 cw[i].midpoint,cw[i].sep, ZZ*cw[i].coh_re, ZZ*cw[i].coh_im );
106 }
107 DEB"\n");
108 DEB"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
109 lirerr(3001);
110 }
111
short_region_guesses(int types)112 int short_region_guesses(int types)
113 {
114 int i, j, k;
115 int dashadd;
116 float t1, t2, r1, r2;
117 float a1,a2,p1,p2;
118 float noise[5], npow[5], powston[5];
119 float re, im, re1, im1, re3, im3;
120 // Step through all the dashes and look for small separations that
121 // fit to the keying speed we just determined.
122 // Look for the following cases:
123 // Code Sep
124 // ___ ___ 4
125 // ___ _ ___ 6
126 // ___ ___ 6
127 // ___ _ _ ___ 8
128 // ___ ___ ___ 8
129 // ___ ___ 8
130 // Store the most probable signal in each case.
131 cw_ptr=1;
132 cg_wave_coh_re=0;
133 cg_wave_coh_im=0;
134 dashadd=0;
135 show_cw("**************short region guesses");
136 while(cw_ptr < no_of_cwdat)
137 {
138 if( (cw[cw_ptr].type==CW_DASH || types*cw[cw_ptr].type==CW_DOT) &&
139 (cw[cw_ptr-1].type==CW_DASH || types*cw[cw_ptr-1].type==CW_DOT))
140 {
141 r1=cw[cw_ptr].sep/cwbit_pts;
142 j=(cw[cw_ptr].len+cw[cw_ptr-1].len)/2;
143 r1-=j;
144 k=(int)(r1)&0xfffffffe;
145 if(r1-k > 1)k+=2;
146 if(k<0)k=0;
147 cw[cw_ptr].unkn=k;
148 switch (k)
149 {
150 case 0:
151 break;
152
153 case 2:
154 // ___ _ ___ 2 guess 0 (dash ? dash)
155 // ___ ___ 2 guess 1 (dash ? dash)
156 // 012
157 // ___ _ _ 2 guess 0 (dash ? dot)
158 // ___ _ 2 guess 1 (dash ? dot)
159 // 012
160 // _ _ ___ 2 guess 0 (dot ? dash)
161 // _ ___ 2 guess 1 (dot ? dash)
162 // 012
163 fprintf( dmp,"\n\ncheck2 [%f to %f] (%f,%f),(%f,%f)",cw[cw_ptr-1].midpoint,cw[cw_ptr].midpoint,
164 ZZ*cw[cw_ptr-1].raw_re,ZZ*cw[cw_ptr-1].raw_im, ZZ*cw[cw_ptr].raw_re,ZZ*cw[cw_ptr].raw_im);
165 cg_wave_midpoint=cw[cw_ptr].midpoint-0.5*cw[cw_ptr].sep;
166 fprintf( dmp,"\n midpnt=%f",cg_wave_midpoint);
167 cg_wave_midpoint-=0.25*(cw[cw_ptr].len-cw[cw_ptr-1].len)*cwbit_pts;
168 if(cg_wave_midpoint < 0)cg_wave_midpoint+=baseband_size;
169 fprintf( dmp," new midpnt=%f",cg_wave_midpoint);
170 wb_investigate_region(cg_wave_midpoint, 3);
171 // Compute signal and noise at the three positions assuming that
172 // phase and amplitude change linearly between the dashes.
173 // Put the total noise in noise[i] for the two guesses.
174 r1=reg_dot_re[0]*reg_dot_re[0]+reg_dot_im[0]*reg_dot_im[0]+
175 reg_dot_re[2]*reg_dot_re[2]+reg_dot_im[2]*reg_dot_im[2];
176 a1=sqrt(cw[cw_ptr-1].raw_re*cw[cw_ptr-1].raw_re+
177 cw[cw_ptr-1].raw_im*cw[cw_ptr-1].raw_im);
178 a2=sqrt(cw[cw_ptr ].raw_re*cw[cw_ptr ].raw_re+
179 cw[cw_ptr ].raw_im*cw[cw_ptr ].raw_im);
180 p1=atan2(cw[cw_ptr-1].raw_im,cw[cw_ptr-1].raw_re);
181 p2=atan2(cw[cw_ptr ].raw_im,cw[cw_ptr ].raw_re);
182 if(p1-p2 > PI_L)p1+=2*PI_L;
183 if(p2-p1 > PI_L)p2+=2*PI_L;
184 t1=0.5*(a1+a2);
185 t2=0.5*(p1+p2);
186 re=t1*cos(t2);
187 im=t1*sin(t2);
188 noise[0]=0.3333333*(r1+(re-reg_dot_re[1])*(re-reg_dot_re[1])+
189 (im-reg_dot_im[1])*(im-reg_dot_im[1]));
190 r2=reg_dot_re[1]*reg_dot_re[1]+reg_dot_im[1]*reg_dot_im[1];
191 noise[1]=0.3333333*(r1+r2);
192 // (due to operator preference of speed above accuracy) the phase
193 // could be incorrect. Compute S/N based on total power in the
194 // wb_raw signal so strong signals with phase errors will decode here.
195 powston[0]=2*reg_dot_power[1]/(reg_dot_power[0]+reg_dot_power[2])-1;
196 fprintf( dmp,"\nPOWSTON %f COHNOI %f %f", powston[0],ZZ*ZZ*noise[0],ZZ*ZZ*noise[1]);
197 // Take a decision (assuming that the surrounding dashes are correct):
198 if( (powston[0] > 10) ||
199 (powston[0] > 3 && noise[0] < 1.5*noise[1]) ||
200 (powston[0] > 0.4 && noise[0] < 2.0*noise[1]) )
201 {
202 cg_wave_raw_re=reg_dot_re[1];
203 cg_wave_raw_im=reg_dot_im[1];
204 insert_item(CW_DOT);
205 cw[cw_ptr].unkn=0;
206 if(kill_all_flag)return 0;
207 cw_ptr++;
208 cw[cw_ptr].unkn=0;
209 check_cw(100931,1);
210 if(kill_all_flag)return 0;
211 }
212 else
213 {
214 if( (powston[0] < 4 && noise[1] < 2.0*noise[0]) ||
215 (powston[0] < 1 && noise[1] < 1.5*noise[0]) )
216 {
217 cg_wave_raw_re=0;
218 cg_wave_raw_im=0;
219 insert_item(CW_SPACE);
220 cw[cw_ptr].unkn=0;
221 if(kill_all_flag)return 0;
222 cw_ptr++;
223 cw[cw_ptr].unkn=0;
224 check_cw(100932,1);
225 if(kill_all_flag)return 0;
226 }
227 }
228 break;
229
230 case 4:
231 // ___ ___ ___ 8 guess 0
232 // ___ _ _ ___ 8 guess 1
233 // ___ _ ___ 8 guess 2
234 // ___ _ ___ 8 guess 3
235 // ___ ___ 8 guess 4
236 // 01234
237 fprintf( dmp,"\n\ncheck4 [%f to %f] (%f,%f),(%f,%f)",cw[cw_ptr-1].midpoint,cw[cw_ptr].midpoint,
238 ZZ*cw[cw_ptr-1].raw_re,ZZ*cw[cw_ptr-1].raw_im, ZZ*cw[cw_ptr].raw_re,ZZ*cw[cw_ptr].raw_im);
239 cg_wave_midpoint=cw[cw_ptr].midpoint-0.5*cw[cw_ptr].sep;
240 cg_wave_midpoint-=0.25*(cw[cw_ptr].len-cw[cw_ptr-1].len)*cwbit_pts;
241 if(cg_wave_midpoint < 0)cg_wave_midpoint+=baseband_size;
242 wb_investigate_region(cg_wave_midpoint, 5);
243 // Compute the average noise power for the 5 different guesses and
244 // store in noise[i].
245 r1=reg_dot_re[0]*reg_dot_re[0]+reg_dot_im[0]*reg_dot_im[0]+
246 reg_dot_re[4]*reg_dot_re[4]+reg_dot_im[4]*reg_dot_im[4];
247 a1=sqrt(cw[cw_ptr-1].raw_re*cw[cw_ptr-1].raw_re+
248 cw[cw_ptr-1].raw_im*cw[cw_ptr-1].raw_im);
249 a2=sqrt(cw[cw_ptr ].raw_re*cw[cw_ptr ].raw_re+
250 cw[cw_ptr ].raw_im*cw[cw_ptr ].raw_im);
251 p1=atan2(cw[cw_ptr-1].raw_im,cw[cw_ptr-1].raw_re);
252 p2=atan2(cw[cw_ptr ].raw_im,cw[cw_ptr ].raw_re);
253 if(p1-p2 > PI_L)p1+=2*PI_L;
254 if(p2-p1 > PI_L)p2+=2*PI_L;
255 t1=0.5*(a1+a2);
256 t2=0.5*(p1+p2);
257 re=t1*cos(t2);
258 im=t1*sin(t2);
259 // Guess 0
260 noise[0]=0.2*(r1+3*((re-reg_dash_re)*(re-reg_dash_re)+
261 (im-reg_dash_im)*(im-reg_dash_im)) );
262 // Guess 4
263 t1=0;
264 for(i=1; i<4; i++)
265 {
266 npow[i]=reg_dot_re[i]*reg_dot_re[i]+
267 reg_dot_im[i]*reg_dot_im[i];
268 t1+=npow[i];
269 }
270 noise[4]=0.2*(r1+t1);
271 t1=0.625*a1+0.375*a2;
272 t2=0.625*p1+0.375*p2;
273 re1=t1*cos(t2);
274 im1=t1*sin(t2);
275 t1=0.375*a1+0.625*a2;
276 t2=0.375*p1+0.625*p2;
277 re3=t1*cos(t2);
278 im3=t1*sin(t2);
279 // Guess 1
280 noise[1]=0.2*(r1+npow[2]+
281 (re1-reg_dot_re[1])*(re1-reg_dot_re[1])+
282 (im1-reg_dot_im[1])*(im1-reg_dot_im[1])+
283 (re3-reg_dot_re[3])*(re3-reg_dot_re[3])+
284 (im3-reg_dot_im[3])*(im1-reg_dot_im[3]) );
285 // Guess 2
286 noise[2]=noise[4]+0.2*(
287 (re1-reg_dot_re[1])*(re1-reg_dot_re[1])+
288 (im1-reg_dot_im[1])*(im1-reg_dot_im[1])-npow[1] );
289 // Guess 3
290 noise[3]=noise[4]+0.2*(
291 (re3-reg_dot_re[3])*(re3-reg_dot_re[3])+
292 (im3-reg_dot_im[3])*(im3-reg_dot_im[3])-npow[3] );
293 // In case the signal went through a QSB minimum or AFC failed
294 // (due to operator preference of speed above accuracy) the phase
295 // could be incorrect. Compute (S+N)/N based on total power in the
296 // wb_raw signal so strong signals with phase errors will decode here.
297 r2=reg_dot_power[0]+reg_dot_power[4];
298 powston[0]=2*reg_dash_power/r2;
299 powston[4]=2.5*(r2+cw[cw_ptr-1].raw_re*cw[cw_ptr-1].raw_re+
300 cw[cw_ptr-1].raw_im*cw[cw_ptr-1].raw_im+
301 cw[cw_ptr ].raw_re*cw[cw_ptr ].raw_re+
302 cw[cw_ptr ].raw_im*cw[cw_ptr ].raw_im)/
303 (r2+3*reg_dash_power);
304 r2+=reg_dot_power[2];
305 powston[1]=1.5*(reg_dot_power[1]+reg_dot_power[3])/r2;
306 powston[2]=4*reg_dot_power[1]/(reg_dot_power[3]+r2);
307 powston[3]=4*reg_dot_power[3]/(reg_dot_power[1]+r2);
308 // Check if any of the guesses seems much more likely than the others.
309 // based on the integrated signal over a time unit on the assumption
310 // that the phase rotates slowly.
311 t1=BIG;
312 k=-1;
313
314 for(i=0; i<5; i++)
315 {
316 if(noise[i] < t1)
317 {
318 k=i;
319 t1=noise[i];
320 }
321 }
322 t2=0;
323 j=-1;
324 for(i=0; i<5; i++)
325 {
326 if(powston[i] > t2)
327 {
328 j=i;
329 t2=powston[i];
330 }
331 }
332 // In case we get different guesses based on powston and noise the
333 // guess for the phase and amplitude must be bad. Check if one or
334 // the other is good enough (while the other is bad) so we can
335 // base our decision on one or the other.
336 if(j != k)
337 {
338 if( t2 > 10 || (t2 > 3 && noise[j] < 1.25*t1) )
339 {
340 k=j;
341 }
342 else
343 {
344 if( (t2 < 4.0 && t1 > 2.0*noise[j]) ||
345 (t2 < 1.3 && t1 > 1.5*noise[j]) )
346 {
347 j=k;
348 }
349 else
350 {
351 goto skip8;
352 }
353 }
354 }
355 // Check the probability we made the correct guess.
356 // Hope for some help here!!!
357 t1=BIG;
358 t2=0;
359 for(i=0; i<5; i++)
360 {
361 if(i!=k)
362 {
363 if(noise[i]<t1)t1=noise[i];
364 if(powston[i]>t2)t2=powston[i];
365 }
366 }
367 if( (powston[k] > 10) ||
368 (powston[k] > 3 && noise[k] < 1.5*t1) ||
369 (powston[k] > 0.4 && noise[k] < 2.0*t1) )
370 {
371 switch (k)
372 {
373 case 0:
374 // ___ ___ ___ 8 guess 0
375 cg_wave_raw_re=reg_dash_re;
376 cg_wave_raw_im=reg_dash_im;
377 insert_item(CW_DASH);
378 dashadd++;
379 cw[cw_ptr].unkn=0;
380 if(kill_all_flag)return 0;
381 cw_ptr++;
382 cw[cw_ptr].unkn=0;
383 check_cw(110931,1);
384 if(kill_all_flag)return 0;
385 break;
386
387 case 1:
388 // ___ _ _ ___ 8 guess 1
389 cg_wave_raw_re=reg_dot_re[1];
390 cg_wave_raw_im=reg_dot_im[1];
391 cg_wave_midpoint-=cwbit_pts;
392 if(cg_wave_midpoint < 0)cg_wave_midpoint+=baseband_size;
393 insert_item(CW_DOT);
394 cw[cw_ptr].unkn=0;
395 if(kill_all_flag)return 0;
396 cw_ptr++;
397 check_cw(110931,1);
398 if(kill_all_flag)return 0;
399 cg_wave_raw_re=reg_dot_re[3];
400 cg_wave_raw_im=reg_dot_im[3];
401 cg_wave_midpoint+=2*cwbit_pts;
402 if(cg_wave_midpoint >= baseband_size)cg_wave_midpoint-=baseband_size;
403 insert_item(CW_DOT);
404 cw[cw_ptr].unkn=0;
405 if(kill_all_flag)return 0;
406 cw_ptr++;
407 cw[cw_ptr].unkn=0;
408 check_cw(110932,1);
409 if(kill_all_flag)return 0;
410 break;
411
412 case 2:
413 // ___ _ ___ 8 guess 2
414 cg_wave_raw_re=reg_dot_re[1];
415 cg_wave_raw_im=reg_dot_im[1];
416 cg_wave_midpoint-=cwbit_pts;
417 if(cg_wave_midpoint < 0)cg_wave_midpoint+=baseband_size;
418 insert_item(CW_DOT);
419 cw[cw_ptr].unkn=0;
420 if(kill_all_flag)return 0;
421 cw_ptr++;
422 check_cw(110931,1);
423 if(kill_all_flag)return 0;
424 cg_wave_raw_re=0;
425 cg_wave_raw_im=0;
426 cg_wave_midpoint+=2*cwbit_pts;
427 if(cg_wave_midpoint >= baseband_size)cg_wave_midpoint-=baseband_size;
428 insert_item(CW_SPACE);
429 cw[cw_ptr].unkn=0;
430 if(kill_all_flag)return 0;
431 cw_ptr++;
432 cw[cw_ptr].unkn=0;
433 check_cw(110932,1);
434 if(kill_all_flag)return 0;
435 break;
436
437 case 3:
438 // ___ _ ___ 8 guess 3
439 cg_wave_raw_re=0;
440 cg_wave_raw_im=0;
441 cg_wave_midpoint-=cwbit_pts;
442 if(cg_wave_midpoint < 0)cg_wave_midpoint+=baseband_size;
443 insert_item(CW_SPACE);
444 cw[cw_ptr].unkn=0;
445 if(kill_all_flag)return 0;
446 cw_ptr++;
447 check_cw(110932,1);
448 if(kill_all_flag)return 0;
449 cg_wave_raw_re=reg_dot_re[3];
450 cg_wave_raw_im=reg_dot_im[3];
451 cg_wave_midpoint+=2*cwbit_pts;
452 if(cg_wave_midpoint >= baseband_size)cg_wave_midpoint-=baseband_size;
453 insert_item(CW_DOT);
454 cw[cw_ptr].unkn=0;
455 if(kill_all_flag)return 0;
456 cw_ptr++;
457 cw[cw_ptr].unkn=0;
458 check_cw(110931,1);
459 if(kill_all_flag)return 0;
460 break;
461
462 case 4:
463 // ___ ___ 8 guess 4
464 cg_wave_raw_re=0;
465 cg_wave_raw_im=0;
466 insert_item(CW_WORDSEP);
467 cw[cw_ptr].unkn=0;
468 if(kill_all_flag)return 0;
469 cw_ptr++;
470 cw[cw_ptr].unkn=0;
471 check_cw(110931,1);
472 if(kill_all_flag)return 0;
473 break;
474 }
475 }
476 skip8:;
477
478 for(i=0;i<5;i++) fprintf( dmp,"\nguess %d WSTON %f COHNOI %f ",i, powston[i], ZZ*ZZ*noise[i]);
479 break;
480
481 default:
482 fprintf( dmp,"\n\ncheckx %d [%f to %f] (%f,%f),(%f,%f)",k,cw[cw_ptr-1].midpoint,cw[cw_ptr].midpoint,
483 ZZ*cw[cw_ptr-1].raw_re,ZZ*cw[cw_ptr-1].raw_im, ZZ*cw[cw_ptr].raw_re,ZZ*cw[cw_ptr].raw_im);
484 break;
485 }
486 }
487 cw_ptr++;
488 }
489 check_cw(1009,1);
490 show_cw("short reg exit ");
491 XZ(" ");
492 return dashadd;
493 }
494
find_good_dashes(int ia,int ic,char color)495 void find_good_dashes(int ia, int ic, char color)
496 {
497 int lmax, lmin, old_no_of_cwdat;
498 int i, j, k, ib;
499 char s[80];
500 float t1;
501 MORSE_DECODE_DATA tmpcw;
502 // Step backwards using baseb_ramp and fill in all good fits to
503 // dash_waveform. We try to find dashes first because they contain
504 // much more energy and occupy less bandwidth than the dots.
505 // Comparing the complex waveform to the desired waveform corresponds
506 // to a low pass filter so we look for dashes because they have much
507 // better S/N since they last 3 times longer.
508 // fit_dash returns 1.000 if the waveform fits exactly.
509 if(baseb_ramp[ic] >= 0)lirerr(925727);
510 old_no_of_cwdat=no_of_cwdat;
511 lmax=1.5*dash_pts;
512 lmin=0.4*dash_pts;
513 ib=ic;
514 check_cw(30232,0);
515 if(kill_all_flag)return;
516 while( ib != ia)
517 {
518 // Step downwards by the (negative) ramp length.
519 // We should always be on a negative ramp here.
520 ib=(ib+baseb_ramp[ib]+baseband_size)&baseband_mask;
521 if( ((ib-baseb_pe+baseband_size)&baseband_mask) >
522 baseband_neg)goto good_dash_x;
523 // Now we must be on a positive ramp.
524 if(baseb_ramp[ib] >= lmin && baseb_ramp[ib] <= lmax)
525 {
526 cg_wave_start=
527 (ib-((baseb_ramp[ib]+dash_pts)>>1)+baseband_size)&baseband_mask;
528 fit_dash();
529 if(cg_wave_fit >DASH_DETECT_LIMIT)
530 {
531 cw_ptr=no_of_cwdat;
532 cg_wave_raw_re=0;
533 cg_wave_raw_im=0;
534 insert_item(CW_DASH);
535 }
536 }
537 ib=(ib-baseb_ramp[ib]+baseband_size)&baseband_mask;
538 }
539 good_dash_x:;
540 sprintf(s,"%4d ",no_of_cwdat);
541 settextcolor(color);
542 lir_pixwrite(MAX_CG_OSCW+2,0,s);
543 settextcolor(7);
544 // We stepped backwards using the ramps when collecting dash midpoints.
545 // Reorder dash midpoints
546 if(no_of_cwdat - old_no_of_cwdat > 1)
547 {
548 i=no_of_cwdat-1;
549 j=old_no_of_cwdat;
550 while(j < i)
551 {
552 tmpcw=cw[i];
553 cw[i]=cw[j];
554 cw[j]=tmpcw;
555 j++;
556 i--;
557 }
558 }
559 // Collect dash separations
560 for(i=old_no_of_cwdat; i<no_of_cwdat; i++)
561 {
562 t1=cw[i].midpoint-cw[i-1].midpoint;
563 if(t1 < 0)t1+=baseband_size;
564 cw[i].sep=t1;
565 t1/=cwbit_pts;
566 j=(cw[i].len+cw[i-1].len)/2;
567 t1-=j;
568 k=(int)(t1)&0xfffffffe;
569 if(t1-k > 1)k+=2;
570 cw[i].unkn=k;
571 }
572 }
573
574
575
detect_cw_speed(void)576 void detect_cw_speed(void)
577 {
578 int first_icw, iter;
579 int i, j, k;
580 int dashadd;
581 float r1, t1;
582 float average_sep, largest_sep;
583 int largest_sep_pos;
584 // Use baseb ramp and our current guess for the dash waveform
585 // to find those dashes that are reasonably similar.
586 find_good_dashes(baseb_pe, baseb_pc,12);
587 if(no_of_cwdat < MIN_NO_OF_CWDAT)
588 {
589 fail:;
590 cw_detect_flag=CWDETECT_ERROR;
591 no_of_cwdat=0;
592 return;
593 }
594 // Collect dash separations
595 first_icw=1;
596 largest_sep=0;
597 largest_sep_pos=-1;
598 t1=cw[0].midpoint-baseb_px;
599 if(t1 < 0)t1+=baseband_size;
600 cw[0].sep=t1;
601 for(i=1; i<no_of_cwdat; i++)
602 {
603 if(cw[i].sep > largest_sep)
604 {
605 largest_sep=cw[i].sep;
606 largest_sep_pos=i;
607 }
608 }
609 check_cw(1003,1);
610 if(kill_all_flag)return;
611 // *****************************************************
612 // *****************************************************
613 // ************** Find cw keying speed *****************
614 // *****************************************************
615 // *****************************************************
616 // In case we are trying to find an extremely weak signal the
617 // waveform might be poor due to the inclusion of a lot of noise.
618 // We may also have incorrect speed information because the
619 // speed has changed - maybe one station stopped transmission and
620 // another started.
621 // largest_sep_pos points to the dash after the longest
622 // separation between dashes.
623 // If there are many enough dashes after it, skip data before it.
624
625
626 if(no_of_cwdat - largest_sep_pos > 8)
627 {
628 average_sep=cw[no_of_cwdat-1].midpoint-cw[0].midpoint;
629 if(average_sep < 0)average_sep+=baseband_size;
630 average_sep/=no_of_cwdat;
631 t1=cw[no_of_cwdat-1].midpoint-cw[largest_sep_pos].midpoint;
632 if(t1 < 0)t1+=baseband_size;
633 t1/=(no_of_cwdat-largest_sep_pos);
634 if(average_sep/t1 > 1.5)
635 {
636 first_icw=largest_sep_pos;
637 }
638 }
639 // Collect the average waveform for the selected dashes
640 // over a range that will contain surrounding dashes (and dots)
641 // and evaluate the cw keying speed and a more accurate dash waveform.
642 seldash_cwspeed(first_icw, no_of_cwdat);
643 if(cw_detect_flag == CWDETECT_ERROR)
644 {
645 return;
646 }
647 // *****************************************************
648 // *****************************************************
649 // *********** Find good dashes again. This time *******
650 // *********** use improved dash waveform *******
651 // *****************************************************
652 // *****************************************************
653 iter=0;
654 iterate:;
655 iter++;
656 no_of_cwdat=0;
657 find_good_dashes(baseb_pe, baseb_pc,12);
658 if(no_of_cwdat < MIN_NO_OF_CWDAT)goto fail;
659 check_cw(1007,1);
660 if(kill_all_flag)return;
661 // *****************************************************
662 // *****************************************************
663 // ******** Eliminate obvious errors ***********
664 // *****************************************************
665 // *****************************************************
666 cw_ptr=1;
667 while(cw_ptr < no_of_cwdat)
668 {
669 r1=cw[cw_ptr].sep/cwbit_pts;
670 if(r1 < 3)
671 {
672 // When two dashes have been stored too close, on top of each other,
673 // the waveform is most probably very ugly.
674 // Skip these dashes for now.
675 i=cw_ptr-1;
676 j=cw_ptr+1;
677 while(j < no_of_cwdat)
678 {
679 cw[i]=cw[j];
680 i++;
681 j++;
682 }
683 if(cw_ptr >= 2)
684 {
685 t1=cw[cw_ptr-1].midpoint-cw[cw_ptr-2].midpoint;
686 if(t1 < 0)t1+=baseband_size;
687 cw[cw_ptr-1].sep=t1;
688 }
689 t1=cw[cw_ptr].midpoint-cw[cw_ptr-1].midpoint;
690 if(t1 < 0)t1+=baseband_size;
691 cw[cw_ptr].sep=t1;
692 no_of_cwdat-=2;
693 cw_ptr--;
694 }
695 cw_ptr++;
696 }
697 check_cw(1008,1);
698 if(kill_all_flag)return;
699 get_wb_average_dashes();
700 guess_wb_average_dots();
701 qq2("WIDE OK");
702 // ***************************************************
703 // ***************************************************
704 // ****** Investigate short regions between ********
705 // ****** dashes we already detected. ********
706 // ***************************************************
707 // ***************************************************
708 dashadd=short_region_guesses(0);
709 if(kill_all_flag)return;
710 show_cw("**************************************");
711 // *****************************************************
712 // *****************************************************
713 // ************** Find cw keying speed again ***********
714 // **** by averaging the narrowband shape of dashes ****
715 // ****** but only if we have more dashes ************
716 // *****************************************************
717 // *****************************************************
718 cw_ptr=0;
719 if(dashadd == 0 && iter != 1)goto skip_shape_improvement;
720 fprintf( dmp,"\n more dashes!!");
721 first_icw=1;
722 largest_sep=0;
723 largest_sep_pos=-1;
724 for(i=1; i<no_of_cwdat; i++)
725 {
726 t1=cw[i].midpoint-cw[i-1].midpoint;
727 if(t1 < 0)t1+=baseband_size;
728 if(t1 > largest_sep)
729 {
730 largest_sep=t1;
731 largest_sep_pos=i;
732 }
733 }
734 // In case we are trying to find an extremely weak signal the
735 // waveform might be poor due to the inclusion of a lot of noise.
736 // We may also have incorrect speed information because the
737 // speed has changed - maybe one station stopped transmission and
738 // another started.
739 // largest_sep_pos points to the dash after the longest
740 // separation between dashes.
741 // If there are many enough dashes after it, skip data before it.
742 if(no_of_cwdat - largest_sep_pos > 8)
743 {
744 average_sep=cw[no_of_cwdat-1].midpoint-cw[0].midpoint;
745 if(average_sep < 0)average_sep+=baseband_size;
746 average_sep/=no_of_cwdat;
747 t1=cw[no_of_cwdat-1].midpoint-cw[largest_sep_pos].midpoint;
748 if(t1 < 0)t1+=baseband_size;
749 t1/=(no_of_cwdat-largest_sep_pos);
750 if(average_sep/t1 > 1.5)
751 {
752 first_icw=largest_sep_pos;
753 }
754 }
755 // Collect the average waveform for the selected dashes
756 // over a range that will contain surrounding dashes (and dots)
757 // and evaluate the cw keying speed and a more accurate dash waveform.
758 check_cw(102210,1);
759 for(cw_ptr=first_icw; cw_ptr<no_of_cwdat; cw_ptr++)
760 {
761 fprintf( dmp,"\ncw_ptr=%d",cw_ptr);
762 if(cw[cw_ptr].type == CW_DASH)
763 {
764 if(cw[cw_ptr].coh_re==0 && cw[cw_ptr].coh_im==0 )
765 {
766 cg_wave_start=cw[cw_ptr].midpoint-0.5*dash_pts+baseband_size;
767 cg_wave_start&=baseband_mask;
768 fit_dash();
769 cw[cw_ptr].coh_re=cg_wave_coh_re;
770 cw[cw_ptr].coh_im=cg_wave_coh_im;
771 cw[cw_ptr].midpoint=cg_wave_midpoint;
772 if(cw_ptr > 0)
773 {
774 t1=cw[cw_ptr].midpoint-cw[cw_ptr-1].midpoint;
775 if(t1 < 0)t1+=baseband_size;
776 cw[cw_ptr].sep=t1;
777 t1/=cwbit_pts;
778 j=(cw[cw_ptr].len+cw[cw_ptr-1].len)/2;
779 t1-=j;
780 k=(int)(t1)&0xfffffffe;
781 if(t1-k > 1)k+=2;
782 cw[cw_ptr].unkn=k;
783 }
784 if(cw_ptr+1 < no_of_cwdat)
785 {
786 if(cw[cw_ptr+1].coh_re!=0 || cw[cw_ptr+1].coh_im!=0 )
787 {
788 t1=cw[cw_ptr+1].midpoint-cw[cw_ptr].midpoint;
789 if(t1 < 0)t1+=baseband_size;
790 cw[cw_ptr+1].sep=t1;
791 t1/=cwbit_pts;
792 j=(cw[cw_ptr+1].len+cw[cw_ptr].len)/2;
793 t1-=j;
794 k=(int)(t1)&0xfffffffe;
795 if(t1-k > 1)k+=2;
796 cw[cw_ptr+1].unkn=k;
797 }
798 }
799 }
800 }
801 }
802 check_cw(102211,1);
803 seldash_cwspeed(first_icw, no_of_cwdat);
804 if(cw_detect_flag == CWDETECT_ERROR)
805 {
806 XZ("speed_error");
807 return;
808 }
809 if(kill_all_flag)return;
810 first_icw--;
811 cw_ptr=0;
812 if(first_icw > 0)
813 {
814 while(cw_ptr<first_icw)
815 {
816 if(cw[cw_ptr].type == CW_DASH)
817 {
818 cg_wave_start=cw[cw_ptr].midpoint-0.5*dash_pts+baseband_size;
819 cg_wave_start&=baseband_mask;
820 fit_dash();
821 if(cg_wave_fit < DASH_MISFIT_LIMIT)
822 {
823 remove_dash();
824 first_icw--;
825 }
826 else
827 {
828 cw[cw_ptr].coh_re=cg_wave_coh_re;
829 cw[cw_ptr].coh_im=cg_wave_coh_im;
830 cw_ptr++;
831 }
832 }
833 else
834 {
835 cw_ptr++;
836 }
837 }
838 }
839 if(iter < 2)goto iterate;
840 if(no_of_cwdat < MIN_NO_OF_CWDAT)goto fail;
841 get_wb_average_dashes();
842 guess_wb_average_dots();
843 skip_shape_improvement:;
844 if(collect_wb_ston() < CW_WAVEFORM_MINSTON )goto fail;
845 // ******************************************************
846 // ******************************************************
847 // ****** Morse code waveforms are accurate now. ******
848 // ****** Set flag so we will not return here ******
849 // ******************************************************
850 // ******************************************************
851 cw_detect_flag=CWDETECT_WAVEFORM_ESTABLISHED;
852 show_cw("WAVEFORM OK");
853 }
854
wb_investigate_region(float pos,int len)855 void wb_investigate_region(float pos, int len)
856 {
857 float rpos, pwr;
858 float re, im, r1, r2, t1, t2;
859 int i, j, ia, ib;
860 fprintf( dmp,"\nwb_investigate_region(%.1f, %d)",pos,len);
861 if(len == -5)goto dasheval;
862 // pos is the midpoint of a len code units region region that
863 // could be any of these waveforms:
864 // **************
865 // len = 3
866 // ??_ _ _??
867 // ??_ _??
868 // 123
869 // These two waveforms differ only in position 2.
870 //
871 // **************
872 // len = 5
873 // ??_ _ _ _??
874 // ??_ _ _??
875 // ??_ _ _??
876 // ??_ ___ _??
877 // ??_ _??
878 // 12345
879 // These five waveforms differ only in positions 2,3 and 4.
880 //
881 // We now want to find out which waveform is most likely.
882 // The final decision will be left to the calling routine.
883 // Information about what is before and after these 3 or 5
884 // code units will affect the final decision.
885 // Here we just compute powers and complex amplitudes for the
886 // different cases.
887 //
888 //
889 // First compute the phase and power we would attribute
890 // to a dot in each of the len positions.
891 i=len/2;
892 fprintf( dmp,"\npos %f dot_sizhalf %d i*cwbit_pts %f",pos,dot_sizhalf,i*cwbit_pts);
893 rpos=pos-dot_sizhalf+baseband_size-i*cwbit_pts;
894 for(i=0; i<len; i++)
895 {
896 re=0;
897 im=0;
898 pwr=0;
899 t1=rpos;
900 ia=rpos;
901 t1-=ia;
902 t2=1-t1;
903 ia+=dot_wb_ia;
904 ia &= baseband_mask;
905 ib=ia;
906 ib=(ia+1)&baseband_mask;
907 for(j=dot_wb_ia; j<dot_wb_ib; j++)
908 {
909 r1=baseb_wb_raw[2*ib ]*t1+baseb_wb_raw[2*ia ]*t2;
910 r2=baseb_wb_raw[2*ib+1]*t1+baseb_wb_raw[2*ia+1]*t2;
911 pwr+=r1*r1+r2*r2;
912 re+= dot_wb_waveform[2*j ]*r1+dot_wb_waveform[2*j+1]*r2;
913 im+=-dot_wb_waveform[2*j ]*r2+dot_wb_waveform[2*j+1]*r1;
914
915 if(mailbox[0]==9)
916 {
917 baseb_sho1[2*ia]=100*dot_wb_waveform[2*j ]/ZZ;
918 baseb_sho1[2*ia+1]=100*dot_wb_waveform[2*j+1]/ZZ;
919
920 baseb_sho2[2*ia]=r1;
921 baseb_sho2[2*ia+1]=r2;
922 }
923 ia=ib;
924 ib=(ib+1)&baseband_mask;
925 }
926 reg_dot_re[i]=re;
927 reg_dot_im[i]=im;
928 reg_dot_power[i]=pwr/(dot_wb_ib-dot_wb_ia);
929 rpos+=cwbit_pts;
930
931 {
932 t1=rpos+(dot_wb_ib-dot_wb_ia)/2;
933 if(t1>baseband_size)t1-=baseband_size;
934 t2=ZZ*reg_dot_re[i]*ZZ*reg_dot_re[i]+ZZ*reg_dot_im[i]*ZZ*reg_dot_im[i];
935 fprintf( dmp,"\nreg %d pos %f re %f im %f pwr %f %f",i, t1, ZZ*reg_dot_re[i], ZZ*reg_dot_im[i],ZZ*ZZ*reg_dot_power[i],t2);
936 }
937
938
939 }
940 // If we have len=5, check how well a dash would fit.
941 if(len==5)
942 {
943 dasheval:;
944 re=0;
945 im=0;
946 pwr=0;
947 rpos=pos-dash_sizhalf+baseband_size;
948 t1=rpos;
949 ia=rpos;
950 t1-=ia;
951 t2=1-t1;
952 ia+=dash_wb_ia;
953 ia &= baseband_mask;
954 ib=ia;
955 ib=(ia+1)&baseband_mask;
956 for(j=dash_wb_ia; j<dash_wb_ib; j++)
957 {
958 r1=baseb_wb_raw[2*ib ]*t1+baseb_wb_raw[2*ia ]*t2;
959 r2=baseb_wb_raw[2*ib+1]*t1+baseb_wb_raw[2*ia+1]*t2;
960 pwr+=r1*r1+r2*r2;
961 re+= dash_wb_waveform[2*j ]*r1+dash_wb_waveform[2*j+1]*r2;
962 im+=-dash_wb_waveform[2*j ]*r2+dash_wb_waveform[2*j+1]*r1;
963
964
965 /*
966 baseb_sho1[2*ia]=50*dash_wb_waveform[2*j ]/ZZ;
967 baseb_sho1[2*ia+1]=50*dash_wb_waveform[2*j+1]/ZZ;
968 baseb_sho2[2*ia]=r1;
969 baseb_sho2[2*ia+1]=r2;
970 */
971
972
973 ia=ib;
974 ib=(ib+1)&baseband_mask;
975 }
976 reg_dash_re=re;
977 reg_dash_im=im;
978 reg_dash_power=pwr/(dash_wb_ib-dash_wb_ia);
979 rpos+=cwbit_pts;
980
981 {
982 t1=rpos+(dash_wb_ib-dash_wb_ia)/2;
983 if(t1>baseband_size)t1-=baseband_size;
984 t2=ZZ*reg_dash_re*ZZ*reg_dash_re+ZZ*reg_dash_im*ZZ*reg_dash_im;
985 fprintf( dmp,"\nreg dashpos %f re %f im %f pwr %f %f", t1, ZZ*reg_dash_re, ZZ*reg_dash_im,ZZ*ZZ*reg_dash_power,t2);
986 }
987
988 }
989
990 }
991
992
get_wb_average_dashes(void)993 void get_wb_average_dashes(void)
994 {
995 int i, j, k, m, ia, ib;
996 int icw;
997 float t1, t2, r1, r2;
998 float re, im, avgpwr;
999 float *pwr;
1000 // Make an avergage waveform of all dashes in the larger bandwidth.
1001 dash_siz=4*cwbit_pts+4;
1002 dash_siz&=-2;
1003 j=dash_siz<<1;
1004 dash_sizhalf=dash_siz>>1;
1005 for(i=0; i<j; i++)fftn_tmp[i]=0;
1006 pwr=&fftn_tmp[j];
1007 for(icw=0; icw<no_of_cwdat; icw++)
1008 {
1009 if(cw[icw].type == CW_DASH)
1010 {
1011 re=cw[icw].raw_re;
1012 im=cw[icw].raw_im;
1013 t1=cw[icw].midpoint-dash_sizhalf+baseband_size;
1014 ia=t1;
1015 t1-=ia;
1016 t2=1-t1;
1017 ia &= baseband_mask;
1018 r2=sqrt(re*re+im*im);
1019 re/=r2;
1020 im/=r2;
1021 ib=ia;
1022 ib=(ia+1)&baseband_mask;
1023 for(j=0; j<dash_siz; j++)
1024 {
1025 r1=baseb_wb_raw[2*ib ]*t1+baseb_wb_raw[2*ia ]*t2;
1026 r2=baseb_wb_raw[2*ib+1]*t1+baseb_wb_raw[2*ia+1]*t2;
1027 //fprintf( dmp,"\n%d %d %f %f %f %f ",icw,j,re,im, ZZ*r1,ZZ*r2);
1028 fftn_tmp[2*j ]+=re*r1-im*r2;
1029 fftn_tmp[2*j+1]+=re*r2+im*r1;
1030 ia=ib;
1031 ib=(ib+1)&baseband_mask;
1032 }
1033 }
1034 }
1035 // Compute the power of the waveform, but divide by the midpoint
1036 // amplitude first to avoid overflows.
1037 t1=3/(fftn_tmp[dash_siz-2]+fftn_tmp[dash_siz]+fftn_tmp[dash_siz+2]);
1038 for(i=0;i<dash_siz; i++)
1039 {
1040 fftn_tmp[2*i ]*=t1;
1041 fftn_tmp[2*i+1]*=t1;
1042 pwr[i]=fftn_tmp[2*i]*fftn_tmp[2*i]+fftn_tmp[2*i+1]*fftn_tmp[2*i+1];
1043 //fprintf( dmp,"\n%d %f ",i,pwr[i]);
1044 }
1045 // The coherently averaged waveform should have a much better S/N than
1046 // the original waveform. It is however computed in a large bandwidth
1047 // so the points may scatter quite a bit due to noise.
1048 // The power should ideally be constant over the duration of the
1049 // dash. Some transmitters may give a somewhat higher power at the
1050 // beginning before the voltage of the power amplifier dropped, but
1051 // there is no reason to include such effects, the probability that
1052 // an incorrect detect decision will be made due to this neglect
1053 // is extremely small.
1054 // Ideally the full power should last 3*cwbit_pts symmetrically
1055 // around the midpoint dash_sizhalf.
1056 // Compute the power level as the average over 85% of this range.
1057 ia=dash_sizhalf-1.5*0.85*cwbit_pts;
1058 ib=dash_sizhalf+1.5*0.85*cwbit_pts+1;
1059 avgpwr=0;
1060 for(i=ia; i<ib; i++)avgpwr+=pwr[i];
1061 avgpwr/=ib-ia;
1062 // Step ia and ib outwards until the next point would have passed
1063 // the -3dB (half power) points
1064 t2=0.5*avgpwr;
1065 while(ia > 0 && pwr[ia-1] > t2)ia--;
1066 while(ib < dash_siz-1 && pwr[ib+1] > t2)ib++;
1067 // Fit a second order polynomial to the imaginary part between ia and ib.
1068 llsq_neq=ib-ia+1;
1069 llsq_errors=&pwr[dash_siz];
1070 llsq_derivatives=&llsq_errors[llsq_neq];
1071 llsq_npar=3;
1072 k=0;
1073 m=(ib+ia)/2;
1074 for(i=ia; i<=ib; i++)
1075 {
1076 llsq_derivatives[k]=1;
1077 llsq_derivatives[llsq_neq+k]=k;
1078 llsq_derivatives[2*llsq_neq+k]=(k-m)*(k-m);
1079 llsq_errors[k]=fftn_tmp[2*i+1];
1080 k++;
1081 }
1082 if(llsq1() != 0)
1083 {
1084 lirerr(532330);
1085 return;
1086 }
1087 dash_wb_ia=ia;
1088 dash_wb_ib=ib+1;
1089 // Store the fitted second order function, compute
1090 // its average and make the average zero.
1091 t1=0;
1092 k=0;
1093 for(i=dash_wb_ia; i<dash_wb_ib; i++)
1094 {
1095 r1=llsq_steps[0]+llsq_steps[1]*k+llsq_steps[2]*(k-m)*(k-m);
1096 fftn_tmp[2*i+1]=r1;
1097 t1+=r1;
1098 k++;
1099 }
1100 t1/=dash_wb_ib-dash_wb_ia;
1101 for(i=dash_wb_ia; i<dash_wb_ib; i++)
1102 {
1103 fftn_tmp[2*i+1]-=t1;
1104 }
1105 // The imaginary part is our fitted curve, the power is avgpwr.
1106 // Normalize the curve for the sum of amplitudes to
1107 // become 1.0 so we get the average amplitude of a dash by
1108 // a multiplication with this function.
1109 t2=1/sqrt(avgpwr);
1110 t2/=(dash_wb_ib-dash_wb_ia);
1111 for(i=dash_wb_ia; i<dash_wb_ib; i++)
1112 {
1113 r1=fftn_tmp[2*i+1];
1114 dash_wb_waveform[2*i+1]=r1*t2;
1115 dash_wb_waveform[2*i]=sqrt(avgpwr-r1*r1)*t2;
1116 }
1117 for(i=0; i<2*dash_wb_ia; i++) dash_wb_waveform[i]=0;
1118 for(i=2*dash_wb_ib; i<2*dash_siz; i++) dash_wb_waveform[i]=0;
1119 //for(i=0; i<dash_siz; i++)fprintf( dmp,"\nDASH %d %f %f",i,dash_wb_waveform[2*i],dash_wb_waveform[2*i+1]);
1120 // Use the new wb waveform to compute the real and imaginary parts
1121 // of all known dashes using the original wide baseband signal
1122 // baseb_wb_raw (without use of coherent detection)
1123 for(icw=0; icw<no_of_cwdat; icw++)
1124 {
1125 if(cw[icw].type == CW_DASH)
1126 {
1127 re=0;
1128 im=0;
1129 t1=cw[icw].midpoint-dash_sizhalf+baseband_size;
1130 ia=t1;
1131 t1-=ia;
1132 t2=1-t1;
1133 ia+=dash_wb_ia;
1134 ia &= baseband_mask;
1135 ib=ia;
1136 ib=(ia+1)&baseband_mask;
1137 for(j=dash_wb_ia; j<dash_wb_ib; j++)
1138 {
1139 r1=baseb_wb_raw[2*ib ]*t1+baseb_wb_raw[2*ia ]*t2;
1140 r2=baseb_wb_raw[2*ib+1]*t1+baseb_wb_raw[2*ia+1]*t2;
1141 re+= dash_wb_waveform[2*j ]*r1+dash_wb_waveform[2*j+1]*r2;
1142 im+=-dash_wb_waveform[2*j ]*r2+dash_wb_waveform[2*j+1]*r1;
1143 ia=ib;
1144 ib=(ib+1)&baseband_mask;
1145 }
1146 cw[icw].raw_re=re;
1147 cw[icw].raw_im=im;
1148 }
1149 }
1150 }
1151
collect_wb_ston(void)1152 float collect_wb_ston(void)
1153 {
1154 int j, k, m, ia, ib, icw;
1155 float s1, s2, t1, t2, r1, r2, r3, r4;
1156 float re, im;
1157 s1=0;
1158 s2=0;
1159 k=dash_wb_ib-dash_wb_ia;
1160 m=0;
1161 for(icw=0; icw<no_of_cwdat; icw++)
1162 {
1163 if(cw[icw].type == CW_DASH)
1164 {
1165 m++;
1166 t1=cw[icw].midpoint-dash_sizhalf+baseband_size;
1167 ia=t1;
1168 t1-=ia;
1169 t2=1-t1;
1170 ia+=dash_wb_ia;
1171 ia &= baseband_mask;
1172 ib=ia;
1173 ib=(ia+1)&baseband_mask;
1174 re=k*cw[icw].raw_re;
1175 im=k*cw[icw].raw_im;
1176 for(j=dash_wb_ia; j<dash_wb_ib; j++)
1177 {
1178 r1=baseb_wb_raw[2*ib ]*t1+baseb_wb_raw[2*ia ]*t2;
1179 r2=baseb_wb_raw[2*ib+1]*t1+baseb_wb_raw[2*ia+1]*t2;
1180 r3= dash_wb_waveform[2*j ]*re+dash_wb_waveform[2*j+1]*im;
1181 r4=-dash_wb_waveform[2*j ]*im+dash_wb_waveform[2*j+1]*re;
1182 s1+=r1*r1+r2*r2;
1183 s2+=(r1-r3)*(r1-r3)+(r2-r4)*(r2-r4);
1184 ia=ib;
1185 ib=(ib+1)&baseband_mask;
1186 }
1187 fprintf( dmp,"\ncollect_wb_ston: %d %f %f",m,ZZ*ZZ*s1, ZZ*ZZ*s2);
1188 }
1189 }
1190 cw_stoninv=s2/s1;
1191 seldash_cwspeed(0, no_of_cwdat);
1192 return sqrt((float)(m))*s1/s2;
1193 }
1194
seldash_cwspeed(int da,int db)1195 void seldash_cwspeed(int da, int db)
1196 {
1197 int i2, ir3;
1198 int i, j, k, strhalf;
1199 int ia, ib, icw;
1200 float a, r1, r2, rdiff, amin;
1201 float re, im, t1, t2, t3, t4, t5, t6, t7;
1202 float *z, *zm;
1203 int aptr;
1204 j=cw_avg_points<<1;
1205 z=&fftn_tmp[j];
1206 for(i=0; i<j; i++)fftn_tmp[i]=0;
1207 strhalf=cw_avg_points>>1;
1208 zm=&z[strhalf];
1209 // Step over the selected dashes and accumulate their
1210 // sum in fftn_tmp. Interpolate the position, we may
1211 // have a low sampling rate with few points on the rising and falling
1212 // edges.
1213 for(icw=da; icw<db; icw++)
1214 {
1215 if(cw[icw].type == CW_DASH)
1216 {
1217 re=cw[icw].coh_re;
1218 im=cw[icw].coh_im;
1219 t1=cw[icw].midpoint-strhalf+baseband_size;
1220 ia=t1;
1221 t1-=ia;
1222 t2=1-t1;
1223 ia &= baseband_mask;
1224 r2=sqrt(re*re+im*im);
1225 re/=r2;
1226 im/=r2;
1227 ib=ia;
1228 ib=(ia+1)&baseband_mask;
1229 for(j=0; j<(int)cw_avg_points; j++)
1230 {
1231 r1=baseb[2*ib ]*t1+baseb[2*ia ]*t2;
1232 r2=baseb[2*ib+1]*t1+baseb[2*ia+1]*t2;
1233 fftn_tmp[2*j ]+=re*r1-im*r2;
1234 fftn_tmp[2*j+1]+=re*r2+im*r1;
1235 ia=ib;
1236 ib=(ib+1)&baseband_mask;
1237 }
1238 }
1239 }
1240 // The average waveform should have minima at both
1241 // sides of the central dash. There should be other minima
1242 // on both sides that correspond to positions of key up
1243 // in case the dash is surrounded by dots, dual dots or dashes.
1244 // Form the symmetric component of the real part around
1245 // the midpoint. We have no interest in the individual minima
1246 // at both sides, we just want the average - and we assume
1247 // the carrier phase is reasonably good so the imaginary part
1248 // is just noise.
1249 j=cw_avg_points-2;
1250 k=cw_avg_points;
1251 for(i=0; i<strhalf; i++)
1252 {
1253 z[i]=fftn_tmp[j]+fftn_tmp[k];
1254 k+=2;
1255 j-=2;
1256 }
1257 // The zero point of the symmetric curve is at -0.5
1258 // Set up pointers t1,t2,it3 that point to the minima and
1259 // that relate as the expected minimum positions should do.
1260 // r1+0.5 = 2*cwbit_pts
1261 // r2+0.5 = 4*cwbit_pts
1262 // ir3+0.5 = 6*cwbit_pts
1263 // We expect a minimum for ir3=6*cwbit_pts-0.5;
1264 // Step a wide range around this position
1265 ia=3*cwbit_pts-0.25;
1266 ib=12*cwbit_pts;
1267 if(ib > strhalf)ib=strhalf;
1268 amin=BIG;
1269 aptr=0;
1270 for(ir3=ia; ir3<ib; ir3++)
1271 {
1272 r1=(ir3+0.5)/3;
1273 r2=2*r1-0.5;
1274 r1-=0.5;
1275 // The first point at r1
1276 i2=r1;
1277 rdiff=r1-i2;
1278 // Use Lagrange's interpolation formula to fit a third degree
1279 // polynomial to 4 points:
1280 // z[r1]=-rdiff * (rdiff-1)*(rdiff-2)*z[i1]/6
1281 // +(rdiff+1)*(rdiff-1)*(rdiff-2)*z[i2]/2
1282 // -(rdiff+1)* rdiff *(rdiff-2)*z[i3]/2
1283 // +(rdiff+1)* rdiff *(rdiff-1)*z[i4]/6;
1284 // Rewrite slightly to save a few multiplications - do not
1285 // think the compiler is smart enough to do it for us.
1286 t1=rdiff-1;
1287 t2=rdiff-2;
1288 t3=rdiff+1;
1289 t4=t1*t2;
1290 t5=t3*rdiff;
1291 t6=rdiff*t4;
1292 t4=t3*t4;
1293 t7=t5*t2;
1294 t5=t5*t1;
1295 a=((t5*z[i2+2]-t6*z[i2-1])/3+t4*z[i2]-t7*z[i2+1]);
1296 // The second point at r2
1297 i2=r2;
1298 rdiff=r2-i2;
1299 // Use Lagrange's interpolation formula to fit a third degree
1300 // polynomial to 4 points:
1301 // z[r1]=-rdiff * (rdiff-1)*(rdiff-2)*z[i1]/6
1302 // +(rdiff+1)*(rdiff-1)*(rdiff-2)*z[i2]/2
1303 // -(rdiff+1)* rdiff *(rdiff-2)*z[i3]/2
1304 // +(rdiff+1)* rdiff *(rdiff-1)*z[i4]/6;
1305 // Rewrite slightly to save a few multiplications - do not
1306 // think the compiler is smart enough to do it for us.
1307 t1=rdiff-1;
1308 t2=rdiff-2;
1309 t3=rdiff+1;
1310 t4=t1*t2;
1311 t5=t3*rdiff;
1312 t6=rdiff*t4;
1313 t4=t3*t4;
1314 t7=t5*t2;
1315 t5=t5*t1;
1316 a+=((t5*z[i2+2]-t6*z[i2-1])/3+t4*z[i2]-t7*z[i2+1]);
1317 // The third point at ir3 (note we did not divide by 2 above, do it now)
1318 a+=0.5*a+z[ir3];
1319 zm[ir3]=a;
1320 if(a > 1.5*amin)goto amin_x;
1321 if(a < amin)
1322 {
1323 amin=a;
1324 aptr=ir3;
1325 }
1326 }
1327 amin_x:;
1328 t1=-zm[aptr-1];
1329 t2=-amin;
1330 t3=-zm[aptr+1];
1331 parabolic_fit(&a,&t7,t1,t2,t3);
1332 if(store_symmetry_adapted_dash(FALSE) == TRUE)
1333 {
1334 cwbit_pts = (t7+aptr+0.5)/6;
1335 fprintf( dmp,"\ncwbit_pts %f",cwbit_pts);
1336 }
1337 else
1338 {
1339 cw_detect_flag=CWDETECT_ERROR;
1340 }
1341 }
1342
1343
make_dot_siz(void)1344 void make_dot_siz(void)
1345 {
1346 dot_siz=2*cwbit_pts+4;
1347 dot_siz&=-2;
1348 dot_sizhalf=dot_siz>>1;
1349 }
1350
guess_wb_average_dots(void)1351 void guess_wb_average_dots(void)
1352 {
1353 int i, k, ia, ib;
1354 float t1, t2, t3, r1, r2;
1355 // Make a guess for the dot waveform. We simply assume that the
1356 // waveform length is one third of the dash waveform and that
1357 // the chirp is the same as at the beginning of a dash.
1358 make_dot_siz();
1359 k=(2+dash_wb_ib-dash_wb_ia)/3;
1360 dot_wb_ia=dot_sizhalf-(k+1)/2;
1361 dot_wb_ib=dot_wb_ia+k;
1362 for(i=0; i<2*dot_wb_ia; i++) dot_wb_waveform[i]=0;
1363 for(i=2*dot_wb_ib; i<2*dot_siz; i++) dot_wb_waveform[i]=0;
1364 ia=dot_wb_ia;
1365 ib=dash_wb_ia;
1366 t1=0;
1367 t2=0;
1368 t3=0;
1369 while(ia<dot_wb_ib)
1370 {
1371 t1+=fftn_tmp[2*ib];
1372 dot_wb_waveform[2*ia]=fftn_tmp[2*ib];
1373 t2+=fftn_tmp[2*ib+1];
1374 dot_wb_waveform[2*ia+1]=fftn_tmp[2*ib+1];
1375 t3+=fftn_tmp[2*ib]*fftn_tmp[2*ib]+fftn_tmp[2*ib+1]*fftn_tmp[2*ib+1];
1376 ia++;
1377 ib++;
1378 }
1379 r1=t1*t1+t2*t2;
1380 r1=sqrt(r1);
1381 t1/=r1;
1382 t2/=r1;
1383 t3=sqrt(t3*(dot_wb_ib-dot_wb_ia));
1384 for(i=dot_wb_ia; i<dot_wb_ib; i++)
1385 {
1386 r1=dot_wb_waveform[2*i ]/t3;
1387 r2=dot_wb_waveform[2*i+1]/t3;
1388 dot_wb_waveform[2*i ]= r1*t1+r2*t2;
1389 dot_wb_waveform[2*i+1]=-r2*t1+r1*t2;
1390 k++;
1391 }
1392 }
1393
get_wb_average_dots(void)1394 void get_wb_average_dots(void)
1395 {
1396 int i, j, k, ia, ib, dotno;
1397 int icw;
1398 float t1, t2, r1, r2;
1399 float re, im, avgpwr;
1400 float *pwr;
1401 // Make an avergage waveform of all dots in the larger bandwidth.
1402 make_dot_siz();
1403 j=dot_siz<<1;
1404 for(i=0; i<j; i++)fftn_tmp[i]=0;
1405 pwr=&fftn_tmp[j];
1406 dotno=0;
1407 for(icw=0; icw<no_of_cwdat; icw++)
1408 {
1409 if(cw[icw].type == CW_DOT)
1410 {
1411 dotno++;
1412 re=cw[icw].raw_re;
1413 im=cw[icw].raw_im;
1414 t1=cw[icw].midpoint-dot_sizhalf+baseband_size;
1415 ia=t1;
1416 t1-=ia;
1417 t2=1-t1;
1418 ia &= baseband_mask;
1419 r2=sqrt(re*re+im*im);
1420 re/=r2;
1421 im/=r2;
1422 ib=ia;
1423 ib=(ia+1)&baseband_mask;
1424 for(j=0; j<dot_siz; j++)
1425 {
1426 r1=baseb_wb_raw[2*ib ]*t1+baseb_wb_raw[2*ia ]*t2;
1427 r2=baseb_wb_raw[2*ib+1]*t1+baseb_wb_raw[2*ia+1]*t2;
1428 fftn_tmp[2*j ]+=re*r1-im*r2;
1429 fftn_tmp[2*j+1]+=re*r2+im*r1;
1430 ia=ib;
1431 ib=(ib+1)&baseband_mask;
1432 }
1433 }
1434 }
1435 if(dotno < 4)return;
1436 // Compute the power of the waveform, but divide by the midpoint
1437 // amplitude first to avoid overflows.
1438 t1=3/(fftn_tmp[dot_siz-2]+fftn_tmp[dot_siz]+fftn_tmp[dot_siz+2]);
1439 for(i=0;i<dot_siz; i++)
1440 {
1441 fftn_tmp[2*i ]*=t1;
1442 fftn_tmp[2*i+1]*=t1;
1443 pwr[i]=fftn_tmp[2*i]*fftn_tmp[2*i]+fftn_tmp[2*i+1]*fftn_tmp[2*i+1];
1444 }
1445 // The coherently averaged waveform should have a much better S/N than
1446 // the original waveform. It is however computed in a large bandwidth
1447 // so the points may scatter quite a bit due to noise.
1448 // The power should ideally be constant over the duration of the
1449 // dot. Some transmitters may give a somewhat higher power at the
1450 // beginning before the voltage of the power amplifier dropped, but
1451 // there is no reason to include such effects, the probability that
1452 // an incorrect detect decision will be made due to this neglect
1453 // is extremely small.
1454 // Ideally the full power should last 3*cwbit_pts symmetrically
1455 // around the midpoint dot_sizhalf.
1456 // Compute the power level as the average over 85% of this range.
1457 ia=dot_sizhalf-.5*0.85*cwbit_pts;
1458 ib=dot_sizhalf+.5*0.85*cwbit_pts+1;
1459 avgpwr=0;
1460 for(i=ia; i<ib; i++)avgpwr+=pwr[i];
1461 avgpwr/=ib-ia;
1462 // Step ia and ib outwards until the next point would have passed
1463 // the -3dB (half power) points
1464 t2=0.5*sqrt(avgpwr);
1465 while(ia > 0 && pwr[ia-1] > t2)ia--;
1466 while(ib < dot_siz-1 && pwr[ib+1] > t2)ib++;
1467 // Fit a straight line to the imaginary part between ia and ib.
1468 llsq_neq=ib-ia+1;
1469 llsq_errors=&pwr[dot_siz];
1470 llsq_derivatives=&llsq_errors[llsq_neq];
1471 llsq_npar=2;
1472 k=0;
1473 for(i=ia; i<=ib; i++)
1474 {
1475 llsq_derivatives[k]=1;
1476 llsq_derivatives[llsq_neq+k]=k;
1477 llsq_errors[k]=fftn_tmp[2*i+1];
1478 k++;
1479 }
1480 if(llsq1() != 0)
1481 {
1482 lirerr(532330);
1483 return;
1484 }
1485 dot_wb_ia=ia;
1486 dot_wb_ib=ib+1;
1487 // Store the fitted line, compute
1488 // its average and make the average zero.
1489 t1=0;
1490 k=0;
1491 for(i=dot_wb_ia; i<dot_wb_ib; i++)
1492 {
1493 r1=llsq_steps[0]+llsq_steps[1]*k;
1494 fftn_tmp[2*i+1]=r1;
1495 t1+=r1;
1496 k++;
1497 }
1498 t1/=dot_wb_ib-dot_wb_ia;
1499 for(i=dot_wb_ia; i<dot_wb_ib; i++)
1500 {
1501 fftn_tmp[2*i+1]-=t1;
1502 }
1503 // The imaginary part is our fitted curve, the power is avgpwr.
1504 // Normalize the curve for the sum of amplitudes to
1505 // become 1.0 so we get the average amplitude of a dash by
1506 // a multiplication with this function.
1507 t2=1/sqrt(avgpwr);
1508 t2/=(dot_wb_ib-dot_wb_ia);
1509 for(i=dot_wb_ia; i<dot_wb_ib; i++)
1510 {
1511 r1=fftn_tmp[2*i+1];
1512 dot_wb_waveform[2*i+1]=r1*t2;
1513 dot_wb_waveform[2*i]=sqrt(avgpwr-r1*r1)*t2;
1514 }
1515 for(i=0; i<2*dot_wb_ia; i++) dot_wb_waveform[i]=0;
1516 for(i=2*dot_wb_ib; i<2*dot_siz; i++) dot_wb_waveform[i]=0;
1517 // Use the new wb waveform to compute the real and imaginary parts
1518 // of all known dots using the original wide baseband signal
1519 // baseb_wb_raw (without use of coherent detection)
1520 for(icw=0; icw<no_of_cwdat; icw++)
1521 {
1522 if(cw[icw].type == CW_DOT)
1523 {
1524 re=0;
1525 im=0;
1526 t1=cw[icw].midpoint-dot_sizhalf+baseband_size;
1527 ia=t1;
1528 t1-=ia;
1529 t2=1-t1;
1530 ia+=dot_wb_ia;
1531 ia &= baseband_mask;
1532 ib=ia;
1533 ib=(ia+1)&baseband_mask;
1534 for(j=dot_wb_ia; j<dot_wb_ib; j++)
1535 {
1536 r1=baseb_wb_raw[2*ib ]*t1+baseb_wb_raw[2*ia ]*t2;
1537 r2=baseb_wb_raw[2*ib+1]*t1+baseb_wb_raw[2*ia+1]*t2;
1538 re+= dot_wb_waveform[2*j ]*r1+dot_wb_waveform[2*j+1]*r2;
1539 im+=-dot_wb_waveform[2*j ]*r2+dot_wb_waveform[2*j+1]*r1;
1540 ia=ib;
1541 ib=(ib+1)&baseband_mask;
1542 }
1543 cw[icw].raw_re=re;
1544 cw[icw].raw_im=im;
1545 }
1546 }
1547 }
1548
1549