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 
24 #include "globdef.h"
25 #include "uidef.h"
26 #include "fft1def.h"
27 #include "sigdef.h"
28 #include "screendef.h"
29 
30 #define ZZ 0.0000001
31 
32 // Variables and definitions for morse decoding in sigdef.h.
33 // typedef struct {
34 // unsigned char type;    // Part type (CW_DOT, CW_SPACE,....A,B,C,...)
35 // unsigned char unkn;    // Number of unknown states before this part
36 // unsigned char len;     // Length of character in states
37 // float midpoint;
38 // float sep;
39 // float re;
40 // float im;
41 // float tmp;
42 // }MORSE_DECODE_DATA;
43 //
44 // Defines for MORSE_DECODE_DATA.type (cw.type)
45 // Note that CW_DASH must have the lowest value.
46 // The data in cw_item_len[255-CW_DASH]; must agree with these definitions!
47 //
48 // #define CW_WORDSEP 255
49 // #define CW_SPACE 254
50 // #define CW_DOT 253
51 // #define CW_DASH 252
52 
53 //   name     data    length
54 // CW_DASH    |---_|     4
55 //              ^
56 // CW_DOT     |-_|       2
57 //             ^
58 // CW_SPACE   |__|       2
59 //             ^
60 // CW_WORDSEP |____|     4
61 //              ^
62 // The way the midpoint is defined does not include the trailing
63 // key-up of each cw part.
64 // For characters, midpoint points to the first dash or dot
65 // of the decoded character.
66 
67 
68 
69 void check_cw(int num,int type);
70 void show_cw(char *s);
71 void find_preceeding_part(void);
72 void find_prev_char_part(void);
73 void extrapolate_region_downwards(void);
74 int mr_dotpos_nom, mr_dashpos_nom;
75 
insert_char(int charbits,int charlen,int charval)76 void insert_char(int charbits, int charlen, int charval)
77 {
78 char chr;
79 int i, j;
80 float r1;
81 if(charbits > 6)
82   {
83   chr=(char)243;
84   }
85 else
86   {
87   cw_decoded_chars++;
88   chr=morsascii[charbits-1][charval];
89   }
90 // The current character extends from cw_ptr-charbits to cw_ptr-1
91 // Include the trailing space at cw_ptr in the character,
92 // but leave trailing word separators unchanged.
93 // If a word separator preceeded by a character is present
94 // at cw_ptr-charbits-1, replace the word separator by a blank.
95 i=cw_ptr-charbits;
96 if(i >= 2)
97   {
98   if(cw[i-1].type == CW_WORDSEP && cw[i-2].type < CW_DASH)
99     {
100     cw[i-1].type=' ';
101     }
102   }
103 cw[i].type=chr;
104 cw[i].len=charlen;
105 j=cw_ptr;
106 if(cw[cw_ptr].type == CW_SPACE)j++;
107 cw_ptr=i;
108 i++;
109 if(j < no_of_cwdat)
110   {
111   r1=cw[j].midpoint-cw[cw_ptr].midpoint;
112   if(r1 < 0)r1+=baseband_size;
113   cw[j].sep=r1;
114   }
115 while(j < no_of_cwdat)
116   {
117   cw[i]=cw[j];
118   i++;
119   j++;
120   }
121 no_of_cwdat=i-1;
122 }
123 
detect_previous_character(int char_pos)124 void detect_previous_character(int char_pos)
125 {
126 int i, j, charlen, charbits, charval;
127 if(char_pos < 1)
128   {
129   lirerr(674421);
130   return;
131   }
132 if(cw[char_pos].type != CW_SPACE && cw[char_pos].type != CW_WORDSEP)
133   {
134   show_cw("ERROR in detect_previous_character");
135   lirerr(674422);
136   return;
137   }
138 // We have been called properly with the pointer on a space.
139 // Step backwards and see if it is preceeded by something
140 // we are likely to interpret correctly.
141 cw_ptr=char_pos-1;
142 restart:;
143 charlen=0;
144 charbits=0;
145 collect_parts:;
146 while(cw_ptr >= 0 && (cw[cw_ptr].type==CW_DASH || cw[cw_ptr].type==CW_DOT))
147   {
148   charbits++;
149   charlen+=cw[cw_ptr].len;
150   cw_ptr--;
151   }
152 if(charbits==0)return;
153 cw_ptr++;
154 XZ("xx1");
155 if( cw[cw_ptr].unkn > 0 &&
156     cw[cw_ptr].type != CW_SPACE &&
157     cw[cw_ptr].type != CW_WORDSEP)
158   {
159   XZ("xx2");
160 // We do not know what preceeds this sequence of dots and dashes
161 // and whatever it was, it was not good enough to give a morse decode.
162 // Try to fit a dot or a dash in the appropriate position.
163   i=no_of_cwdat;
164   find_preceeding_part();
165 if(kill_all_flag)return;
166   if(i != no_of_cwdat)
167     {
168     XZ("xx3");
169     goto collect_parts;
170     }
171   }
172 //show_cw("  XXXX  ");
173 if( cw[cw_ptr-1].type == CW_SPACE || cw[cw_ptr-1].type == CW_WORDSEP)
174   {
175   charlen=0;
176   charval=0;
177   j=charbits;
178   while(j > 0)
179     {
180     j--;
181     charlen+=cw[cw_ptr].len;
182     charval<<=1;
183     if(cw[cw_ptr].type==CW_DASH)charval++;
184     cw_ptr++;
185     }
186   insert_char(charbits, charlen, charval);
187 // Our search for code parts begins by a search for dashes.
188 // A sequence without dashes or with very poor ones may
189 // preceed what we now have detected.
190   cw_ptr--;
191   if(cw[cw_ptr].unkn > 0)
192     {
193     i=no_of_cwdat;
194     find_prev_char_part();
195 if(kill_all_flag)return;
196     if(i != no_of_cwdat)
197       {
198       XZ("goto restart");
199       goto restart;
200       }
201     }
202   }
203 else
204   {
205   DEB"\nWARNING: ROUTINE NOT COMPLETED  ");
206   lirerr(564397);
207   }
208 }
209 
conditional_insert_dashdot(void)210 void conditional_insert_dashdot(void)
211 {
212 lirerr(8888002);
213 return;
214 /*
215 int sizhalf;
216 float dash_re, dash_im, dashpos, dashpos_err, dash_fit;
217 float dot_re, dot_im, dotpos, dotpos_err, dot_fit;
218 sizhalf=baseband_size>>1;
219 cg_wave_start=mr_dashpos_nom-(dash_pts>>1)+baseband_size;
220 cg_wave_start&=baseband_mask;
221 fit_dash();
222 dash_re=cg_wave_coh_re;
223 dash_im=cg_wave_coh_im;
224 dashpos=cg_wave_midpoint;
225 dashpos_err=mr_dashpos_nom-cg_wave_midpoint;
226 if(dashpos_err < -sizhalf)dashpos_err+=baseband_size;
227 dash_fit=cg_wave_fit;
228 cg_wave_start=mr_dotpos_nom-(dot_pts>>1)+baseband_size;
229 cg_wave_start&=baseband_mask;
230 fit_dot();
231 dot_re=cg_wave_coh_re;
232 dot_im=cg_wave_coh_im;
233 dotpos=cg_wave_midpoint;
234 dotpos_err=mr_dotpos_nom-cg_wave_midpoint;
235 if(dotpos_err < -sizhalf)dotpos_err+=baseband_size;
236 dot_fit=cg_wave_fit;
237 //fprintf( dmp,"\n(fit) dot: %f  dash: %f",dot_fit,dash_fit);
238 //fprintf( dmp,"\n(err) dot: %f  dash: %f",dotpos_err,dashpos_err);
239 if( dash_fit >DASH_DETECT_LIMIT &&
240     dash_fit - dot_fit > 0.05 &&
241     fabs(dashpos_err) < 0.9 * cwbit_pts &&
242     cw[cw_ptr].unkn > 4)
243   {
244   insert_item(CW_DASH);
245 if(kill_all_flag)return;
246   cw[cw_ptr].unkn-=4;
247   cw[cw_ptr+1].unkn=0;
248 XZ("insert dash");
249   return;
250   }
251 if( dot_fit > DOT_DETECT_LIMIT &&
252     dot_fit-dash_fit > 0.05 &&
253     fabs(dotpos_err) < 0.9 * cwbit_pts)
254   {
255   insert_item(CW_DOT);
256 if(kill_all_flag)return;
257   cw[cw_ptr].unkn-=2;
258   cw[cw_ptr+1].unkn=0;
259 XZ("insert dot");
260   return;
261   }
262 */
263 }
264 
265 
266 
find_prev_char_part(void)267 void find_prev_char_part(void)
268 {
269 int i;
270 float t1;
271 if(cw[cw_ptr].type == CW_SPACE)
272   {
273   i=3;
274   }
275 else  // CW_WORDSEP
276   {
277   i=4;
278   }
279 t1=baseband_size+cw[cw_ptr].midpoint-i*cwbit_pts+0.5;
280 mr_dotpos_nom=((int)t1)&baseband_mask;
281 t1-=cwbit_pts;
282 mr_dashpos_nom=((int)t1)&baseband_mask;
283 conditional_insert_dashdot();
284 }
285 
286 
find_preceeding_part(void)287 void find_preceeding_part(void)
288 {
289 lirerr(888100);
290 /*
291 int i;
292 float dash_chk, dot_chk;
293 if( cw_ptr > 0 && cw[cw_ptr].unkn < 8 &&
294     (cw[cw_ptr-1].type == CW_DOT || cw[cw_ptr-1].type == CW_DASH))
295   {
296   set_region_envelope();
297   }
298 else
299   {
300   extrapolate_region_downwards();
301   }
302 if(cw[cw_ptr].type == CW_DASH)
303   {
304   i=4;
305   }
306 else  // CW_DOT
307   {
308   i=3;
309   }
310 mr_dashpos_nom=cw[cw_ptr].midpoint+baseband_size-i*cwbit_pts+0.5;
311 mr_dashpos_nom&=baseband_mask;
312 mr_dotpos_nom=(mr_dashpos_nom+(int)(cwbit_pts+0.5))&baseband_mask;
313 dot_chk=check_dot(mr_dotpos_nom);
314 if(cw[cw_ptr].unkn > 2)
315   {
316 // See if a dash will fit well.
317   dash_chk=check_dash(mr_dashpos_nom);
318   if(dash_chk < -0.25 && dot_chk < -0.25)
319     {
320     cg_wave_midpoint=mr_dashpos_nom;
321     cg_wave_coh_re=baseb_envelope[2*mr_dashpos_nom];
322     cg_wave_coh_im=baseb_envelope[2*mr_dashpos_nom+1];
323     insert_item(CW_WORDSEP);
324 if(kill_all_flag)return;
325     cw[cw_ptr].unkn-=4;
326     cw[cw_ptr+1].unkn=0;
327     return;
328     }
329   }
330 else
331   {
332   dash_chk=-1;
333   }
334 if(dash_chk < 0.25 && dot_chk < 0.25)return;
335 conditional_insert_dashdot();
336 */
337 }
338 
decoded_cwspeed(void)339 void decoded_cwspeed(void)
340 {
341 float t1, t2, r1, lsum_real, lsum_ideal;
342 int i, k;
343 cw_ptr=1;
344 lsum_real=0;
345 lsum_ideal=0;
346 t1=0;
347 t2=0;
348 while(cw_ptr < no_of_cwdat)
349   {
350 // Get the length of the gap between decoded dots and dashes.
351   r1=cw[cw_ptr].sep/cwbit_pts;
352   r1-=0.5*(cw[cw_ptr].len+cw[cw_ptr-1].len);
353   if(r1 < 0) r1=0;
354   k=(int)(r1)&0xfffffffe;
355   if(r1-k > 1)k+=2;
356 // Accumulate regions where we see the keying reasonably well.
357   if(k<=8 && fabs(r1-k) < 0.5)
358     {
359     lsum_real+=cw[cw_ptr].sep;
360     lsum_ideal+=k+0.5*(cw[cw_ptr].len+cw[cw_ptr-1].len);
361     }
362   else
363     {
364     t1+=lsum_ideal*lsum_real;  //ideal*ideal*(real/ideal)
365     t2+=lsum_ideal*lsum_ideal;
366     lsum_real=0;
367     lsum_ideal=0;
368     }
369   cw_ptr++;
370   }
371 t1+=lsum_ideal*lsum_real;  //ideal*ideal*(real/ideal)
372 t2+=lsum_ideal*lsum_ideal;
373 // Get the average ratio of real to ideal, weighted by ideal squared.
374 // Store as an improved value for cw speed
375 fprintf( dmp,"\ndecoded_cwspeed t1 %f t2 %f",t1,t2);
376 cwbit_pts=t1/t2;
377 // Compute the length of un-decoded regions and store in cw[].unkn
378 i=baseband_size+cw[0].midpoint-baseb_px;
379 i&=baseband_mask;
380 cw[0].unkn=(float)(i)/cwbit_pts-cw[0].len/2;
381 cw_ptr=1;
382 while(cw_ptr < no_of_cwdat)
383   {
384   r1=cw[cw_ptr].sep/cwbit_pts;
385   r1-=0.5*(cw[cw_ptr].len+cw[cw_ptr-1].len);
386   if(r1 < 0) r1=0;
387   k=(int)(r1)&0xfffffffe;
388   if(r1-k > 1)k+=2;
389   cw[cw_ptr].unkn=k;
390   cw_ptr++;
391   }
392 }
393 
394 
continued_morse_decode(void)395 void continued_morse_decode(void)
396 {
397 int charflag,charlen,charval,charbits;
398 cw_ptr=1;
399 charflag=0;
400 charlen=0;
401 charval=0;
402 charbits=0;
403 while(cw_ptr < no_of_cwdat)
404   {
405   if(cw[cw_ptr].unkn != 0)charflag=0;
406   if(charbits != 0 && charflag == 1 &&
407                (cw[cw_ptr].type == CW_WORDSEP || cw[cw_ptr].type == CW_SPACE))
408     {
409 // This is a character surrounded by spaces.
410 // Get an ascii character from the table.
411     insert_char(charbits, charlen, charval);
412     }
413   if(cw[cw_ptr].type != CW_DASH && cw[cw_ptr].type != CW_DOT)
414     {
415     charflag=1;
416     charlen=0;
417     charval=0;
418     charbits=0;
419     }
420   else
421     {
422     charbits++;
423     charlen+=cw[cw_ptr].len;
424     charval<<=1;
425     if(cw[cw_ptr].type==CW_DASH)charval++;
426     }
427   cw_ptr++;
428   }
429 }
430 
431 
first_morse_decode(void)432 void first_morse_decode(void)
433 {
434 int charflag,charlen,charval,charbits;
435 int first_char_pos;
436 // We have stored dashes and dots that are next to a dash.
437 // Look through the data and see if we can find characters.
438 //show_cw("  AAAA  ");
439 cw_decoded_chars=0;
440 first_char_pos=-1;
441 cw_ptr=1;
442 charflag=0;
443 charlen=0;
444 charval=0;
445 charbits=0;
446 while(cw_ptr < no_of_cwdat)
447   {
448   if(cw[cw_ptr].unkn != 0)charflag=0;
449   if(charbits != 0 && charflag == 1 &&
450                (cw[cw_ptr].type == CW_WORDSEP || cw[cw_ptr].type == CW_SPACE))
451     {
452 // This is a character surrounded by spaces.
453 // Get an ascii character from the table.
454     insert_char(charbits, charlen, charval);
455     if(first_char_pos==-1)first_char_pos=cw_ptr;
456     }
457   if(cw[cw_ptr].type != CW_DASH && cw[cw_ptr].type != CW_DOT)
458     {
459     charflag=1;
460     charlen=0;
461     charval=0;
462     charbits=0;
463     }
464   else
465     {
466     charbits++;
467     charlen+=cw[cw_ptr].len;
468     charval<<=1;
469     if(cw[cw_ptr].type==CW_DASH)charval++;
470     }
471   cw_ptr++;
472   }
473 if(cw_decoded_chars > 0)
474   {
475   if(first_char_pos > 1)
476   DEB"\nFirst char pos: %d",first_char_pos);
477   detect_previous_character(first_char_pos-1);
478   }
479 }
480 
481 
482 
483 
484 
remove_dash(void)485 void remove_dash(void)
486 {
487 float t1;
488 int ia, ib;
489 ia=cw[cw_ptr].midpoint-0.5*dash_pts+baseband_size;
490 ia&=baseband_mask;
491 ib=(ia+dash_pts+1)&baseband_mask;
492 while(ia != ib)
493   {
494   baseb_fit[2*ia]=0;
495   baseb_fit[2*ia+1]=0;
496   ia=(ia+1)&baseband_mask;
497   }
498 ia=cw_ptr+1;
499 while(ia < no_of_cwdat)
500   {
501   cw[ia-1]=cw[ia];
502   ia++;
503   }
504 if(cw_ptr !=0)
505   {
506   t1=cw[cw_ptr].midpoint-cw[cw_ptr-1].midpoint;
507   if(t1 < 0)t1+=baseband_size;
508   cw[cw_ptr].sep=t1;
509   }
510 no_of_cwdat--;
511 }
512 
513 
set_long_region_envelope(void)514 void set_long_region_envelope(void)
515 {
516 int i, ia, ib, len;
517 float t1,t2,r1,r2;
518 // We have two dashes pointed to by cw_ptr and cw_ptr-1.
519 // We know the envelope at these points but the separation is large.
520 // Set envelope at both ends by extrapolation.
521 ia=cw[cw_ptr-1].midpoint;
522 ia+=(dash_pts>>2);
523 ia&=baseband_mask;
524 ib=cw[cw_ptr].midpoint;
525 t1=cw[cw_ptr-1].coh_re;
526 r1=cw[cw_ptr-1].coh_im;
527 t2=cw[cw_ptr].coh_re;
528 r2=cw[cw_ptr].coh_im;
529 ib+=baseband_size-(dash_pts>>2);
530 ib&=baseband_mask;
531 len=10*cwbit_pts;
532 i=0;
533 while( i < len )
534   {
535   baseb_envelope[2*ia]=t1;
536   baseb_envelope[2*ia+1]=r1;
537   baseb_envelope[2*ib]=t2;
538   baseb_envelope[2*ib+1]=r2;
539   ia=(ia+1)&baseband_mask;
540   if(ia == ib)goto avgenv;
541   ib=(ib+baseband_mask)&baseband_mask;
542   if(ia == ib)goto avgenv;
543   i++;
544   }
545 return;
546 avgenv:;
547 t1=0.5*(t1+t2);
548 r1=0.5*(r1+r2);
549 while( i < len )
550   {
551   baseb_envelope[2*ia]=t1;
552   baseb_envelope[2*ia+1]=r1;
553   baseb_envelope[2*ib]=t1;
554   baseb_envelope[2*ib+1]=r1;
555   ia=(ia+1)&baseband_mask;
556   ib=(ib+baseband_mask)&baseband_mask;
557   i++;
558   }
559 }
560 
extrapolate_region_downwards(void)561 void extrapolate_region_downwards(void)
562 {
563 lirerr(8888003);
564 /*
565 int ia, ib;
566 float t1, r1;
567 // We have a dash or dot pointed to by cw_ptr.
568 // We know the envelope at this point.
569 // Set envelope at points preceeding this code part by extrapolation.
570 ib=cw[cw_ptr].midpoint+baseband_size;
571 ia=ib-6*cwbit_pts;
572 ia&=baseband_mask;
573 t1=cw[cw_ptr].coh_re;
574 r1=cw[cw_ptr].coh_im;
575 if(cw[cw_ptr].type == CW_DASH)
576   {
577   ib-=dash_pts>>2;
578   }
579 else
580   {
581   ib-=dot_pts>>2;
582   }
583 ib&=baseband_mask;
584 while( ia != ib )
585   {
586   baseb_envelope[2*ia]=t1;
587   baseb_envelope[2*ia+1]=r1;
588   ia=(ia+1)&baseband_mask;
589   }
590 */
591 }
592 
set_region_envelope(void)593 void set_region_envelope(void)
594 {
595 lirerr(8888005);
596 /*
597 int ia, ib, len;
598 float t1,t2,r1,r2;
599 // We have two dashes/dots pointed to by cw_ptr and cw_ptr-1.
600 // We know the envelope at these points.
601 // Set a reasonable envelope across the interval by linear interpolation.
602 ia=cw[cw_ptr-1].midpoint;
603 if(cw[cw_ptr-1].type == CW_DASH)
604   {
605   ia+=(dash_pts>>2);
606   }
607 else
608   {
609   ia+=(dot_pts>>2);
610   }
611 ia&=baseband_mask;
612 ib=baseband_size+cw[cw_ptr].midpoint;
613 if(cw[cw_ptr].type == CW_DASH)
614   {
615   ib-=(dash_pts>>2);
616   }
617 else
618   {
619   ib-=(dot_pts>>2);
620   }
621 ib&=baseband_mask;
622 t1=cw[cw_ptr-1].coh_re;
623 r1=cw[cw_ptr-1].coh_im;
624 len=(ib-ia+baseband_size)&baseband_mask;
625 t2=(cw[cw_ptr].coh_re-t1)/len;
626 r2=(cw[cw_ptr].coh_im-r1)/len;
627 while(ia != ib)
628   {
629   t1+=t2;
630   r1+=r2;
631   baseb_envelope[2*ia]=t1;
632   baseb_envelope[2*ia+1]=r1;
633   ia=(ia+1)&baseband_mask;
634   }
635 */
636 }
637 
clear_region(void)638 void clear_region(void)
639 {
640 int ia, ib;
641 // We have two dashes pointed to by cw_ptr and cw_ptr-1.
642 // We know the envelope at these points.
643 // Clear baseb_fit across the interval.
644 ia=cw[cw_ptr-1].midpoint+0.5*dash_pts+baseband_size;
645 ib=cw[cw_ptr].midpoint-0.5*dash_pts+1+baseband_size;
646 ia&=baseband_mask;
647 ib&=baseband_mask;
648 while(ia != ib)
649   {
650   baseb_fit[2*ia]=0;
651   baseb_fit[2*ia+1]=0;
652   ia=(ia+1)&baseband_mask;
653   }
654 }
655 
check_dash(float pos)656 float check_dash(float pos)
657 {
658 int ia, ib, ja, sw;
659 float c0, t1, t2, r1, r2, f1, f2;
660 float p,err1,err2;
661 // Place a dash at pos using the phase/amplitude information
662 // in baseb_envelope.
663 // Calculate the transformation required for optimum similarity
664 // between the observed waveform in baseb and the dash we have stored.
665 err1=0;
666 err2=0;
667 p=0;
668 ib=pos;
669 if( pos-ib < 0.001)pos+=0.001;
670 ia=(ib+1)&baseband_mask;
671 if( (dash_pts&1) == 0)
672   {
673   c0=0.5*(dash_pts-1);
674   }
675 else
676   {
677   c0=(dash_pts>>1)+1;
678   }
679 // pos is the center of where we want to place a dash.
680 sw=0;
681 while( sw!=2)
682   {
683   sw=0;
684   t1=ia-pos;
685   if(t1<0)t1+=baseband_size;
686   t1=c0+t1;
687   if(t1 >= dash_pts-1)
688     {
689     baseb_fit[2*ia  ]=0;
690     baseb_fit[2*ia+1]=0;
691     sw++;
692     }
693   else
694     {
695     ja=t1;
696     t1-=ja;
697     t2=1-t1;
698     f1=t2*dash_waveform[2*ja  ]+t1*dash_waveform[2*ja+2];
699     f2=t2*dash_waveform[2*ja+1]+t1*dash_waveform[2*ja+3];
700     r1=baseb_envelope[2*ia  ];
701     r2=baseb_envelope[2*ia+1];
702     baseb_fit[2*ia  ]=r1*f1+r2*f2;
703     baseb_fit[2*ia+1]=r1*f2-r2*f1;
704     }
705   err1+=baseb_totpwr[ia];
706   p+=baseb_fit[2*ia  ]*baseb_fit[2*ia  ]+baseb_fit[2*ia+1]*baseb_fit[2*ia+1];
707   err2+=(baseb_fit[2*ia  ]-baseb[2*ia  ])*(baseb_fit[2*ia  ]-baseb[2*ia  ])+
708         (baseb_fit[2*ia+1]-baseb[2*ia+1])*(baseb_fit[2*ia+1]-baseb[2*ia+1]);
709   t1=pos-ib;
710   if(t1<0)t1+=baseband_size;
711   t1=c0-t1;
712   if(t1 < 1)
713     {
714     baseb_fit[2*ib  ]=0;
715     baseb_fit[2*ib+1]=0;
716     sw++;
717     }
718   else
719     {
720     ja=t1;
721     t1-=ja;
722     t2=1-t1;
723     f1=t2*dash_waveform[2*ja  ]+t1*dash_waveform[2*ja+2];
724     f2=t2*dash_waveform[2*ja+1]+t1*dash_waveform[2*ja+3];
725     r1=baseb_envelope[2*ib  ];
726     r2=baseb_envelope[2*ib+1];
727     baseb_fit[2*ib  ]=r1*f1+r2*f2;
728     baseb_fit[2*ib+1]=r1*f2-r2*f1;
729     }
730   err1+=baseb_totpwr[ib];
731   p+=baseb_fit[2*ib  ]*baseb_fit[2*ib  ]+baseb_fit[2*ib+1]*baseb_fit[2*ib+1];
732   err2+=(baseb_fit[2*ib  ]-baseb[2*ib  ])*(baseb_fit[2*ib  ]-baseb[2*ib  ])+
733         (baseb_fit[2*ib+1]-baseb[2*ib+1])*(baseb_fit[2*ib+1]-baseb[2*ib+1]);
734   ia=(ia+1)&baseband_mask;
735   ib=(ib+baseband_mask)&baseband_mask;
736   }
737 // In a perfect fit (noise free) we expect this result:
738 //
739 //       Case     err1     err2
740 //       dash      p        0
741 //       space     0        p
742 //
743 // Due to the presence of noise we expect this instead:
744 //
745 //       Case     err1     err2       err1-err2
746 //       dash     p+n        n           p
747 //       space     n        p+n         -p
748 
749 return (err1-err2)/p;
750 }
751 
752 
store_dash(void)753 void store_dash(void)
754 {
755 short int ir;
756 int ia,ib;
757 float t2,r2;
758 // We calculated the dot product between the current waveform and
759 // the average waveform for a dash when cg_wave_start was computed.
760 // Normalise and use to set up fitted waveforms.
761 ia=cg_wave_midpoint-0.5*dash_pts+baseband_size;
762 ia&=baseband_mask;
763 ib=(ia+dash_pts)&baseband_mask;
764 t2=cg_wave_coh_re;
765 r2=cg_wave_coh_im;
766 // Store the average waveform at the optimum phase and amplitude giving
767 // the smallest residue when subtracted from baseb.
768 ir=0;
769 while(ia != ib)
770   {
771   baseb_fit[2*ia  ]=t2*dash_waveform[2*ir  ]+r2*dash_waveform[2*ir+1];
772   baseb_fit[2*ia+1]=t2*dash_waveform[2*ir+1]-r2*dash_waveform[2*ir  ];
773   ir++;
774   ia=(ia+1)&baseband_mask;
775   }
776 }
777 
778