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