#include "globdef.h" #include "uidef.h" #include "sigdef.h" #include "screendef.h" #include "fft1def.h" #include "options.h" #define ZZ 0.000000001 void show_cw(char *s); // ************************************************************ // ************************************************************ // These defines allow a lot of information to be written to dmp #if DUMPFILE == TRUE #define PR00 0 #define PR01 0 #define PR02 0 #define PR03 0 #define PR04 0 #define PR05 0 #define PR06 1 #else #define PR00 0 #define PR01 0 #define PR02 0 #define PR03 0 #define PR04 0 #define PR05 0 #define PR06 0 #endif #define PRT00 if(PR00 != 0)DEB #define PRT01 if(PR01 != 0)DEB #define PRT02 if(PR02 != 0)DEB #define PRT03 if(PR03 != 0)DEB #define PRT04 if(PR04 != 0)DEB #define PRT05 if(PR05 != 0)DEB #define PRT06 if(PR06 != 0)DEB // ************************************************************ // ************************************************************ extern int zzpos; // float[2] baseb_out=data to send to loudspeaker // float[2] baseb=complex amplitude of first level coherent data. // float[2] baseb_raw=complex amplitude of baseband signal. Raw data, pol. adapted. // float[2] baseb_raw_orthog=complex amplitude of pol. orthog signal. Raw data. // float[2] baseb_carrier=phase of carrier. Complex data, cosines and sines. // float[1] baseb_carrier_ampl=amplitude of carrier // float[1] baseb_totpwr=total power of baseb_raw // float[2] baseb_envelope=complex amplitude from fitted dots and dashes. // float[1] baseb_upthreshold=forward peak detector for power // float[1] baseb_threshold=combined forward and backward peak detector at -6dB // float[2] baseb_fit=fitted dots and dashes. // float[2] baseb_tmp=array for intermediate data in complex format // float[1] baseb_agc_level=used only when AGC is enabled. // short int[1] baseb_ramp=indicator for time of power above/below threshold. // short_int[1] baseb_clock=CW code clock // float[2] baseb_tmp=for debug during development // baseb_pa The starting point of the latest mix2_size/2 points. // baseb_pb The point up to which thresholds exist. // baseb_pc The point up to which cw speed statistics and ramp is collected. // baseb_pd A key up region close before baseb_pc // baseb_pe The point up to which we have run first detect. // baseb_pf // baseb_px The oldest point that contains valid data. void seldash_cwspeed(int da, int db) { int i2, ir3; int i, j, k, strhalf; int ia, ib, icw; float a, r1, r2, rdiff, amin; float re, im, t1, t2, t3, t4, t5, t6, t7; float *z, *zm; int aptr; j=cw_avg_points<<1; z=&fftn_tmp[j]; for(i=0; i>1; zm=&z[strhalf]; // Step over the selected dashes and accumulate their // sum in fftn_tmp. Interpolate the position, we may // have a low sampling rate with few points on the rising and falling // edges. for(icw=da; icwCG_AMAX)t7=CG_AMAX; if(t7<-CG_AMAX)t7=-CG_AMAX; k=zzpos-t7; lir_setpixel(j+ZX,k,10); t7=ampfac*fftn_tmp[2*j+1]/no_of_cwdat; if(t7>CG_AMAX)t7=CG_AMAX; if(t7<-CG_AMAX)t7=-CG_AMAX; k=zzpos-t7; lir_setpixel(j+ZX,k,13); } zzpos+=1.5*CG_AMAX; if(zzpos > screen_height-80)zzpos=screen_height-1.5*CG_AMAX; } // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // The average waveform should have minima at both // sides of the central dash. There should be other minima // on both sides that correspond to positions of key up // in case the dash is surrounded by dots, dual dots or dashes. // Form the symmetric component of the real part around // the midpoint. We have no interest in the individual minima // at both sides, we just want the average - and we assume // the carrier phase is reasonably good so the imaginary part // is just noise. j=cw_avg_points-2; k=cw_avg_points; for(i=0; i strhalf)ib=strhalf; amin=BIG; aptr=0; for(ir3=ia; ir3 1.5*amin)goto amin_x; if(a < amin) { amin=a; aptr=ir3; } } amin_x:; t1=-zm[aptr-1]; t2=-amin; t3=-zm[aptr+1]; parabolic_fit(&a,&t7,t1,t2,t3); PRT06"\nseldash_cwspeed: old cwbit_pts %f no_of_cwdat %d", cwbit_pts,no_of_cwdat); if(store_symmetry_adapted_dashdot(FALSE) == TRUE) { cwbit_pts = (t7+aptr+0.5)/6; } else { cwbit_pts=0; cw_detect_flag=CWDETECT_ERROR; } PRT06" new:(%f) ",cwbit_pts); } void check_cw(int num,int type) { int i,ia; float t1; for(i=0; i 0) { if(i>0) { t1=cw[i].midpoint-cw[i-1].midpoint; if(t1 > baseband_neg) { DEB"\nt1>neg %f",t1); goto err; } if(t1 < 0)t1+=baseband_size; if(fabs (t1-cw[i].sep)/baseband_size > 0.0000001) { DEB"\nt1!=sep %f %f",t1,cw[i].sep); goto err; } } } } return; err:; DEB"\nERROR[%d] i=%d",num,i); for(i=0; i>1; // Clear some variables to suppress compiler error messages. // Actually store something big to invalidate them. icw=0x55555; // Step backwards using baseb_ramp and fill in all good fits to // dash_waveform. We try to find dashes first because they contain // much more energy and occupy less bandwidth than the dots. // Comparing the complex waveform to the desired waveform corresponds // to a low pass filter so we look for dashes because they have much // better S/N since they last 3 times longer. // fit_dash returns 1.000 if the waveform fits exactly. // In this first search, accept very good fits only // ***************************************************** // ***************************************************** // *********** Find good dashes in a new region ******** // ***************************************************** // ***************************************************** old_no_of_dashes=no_of_cwdat; lmax=1.5*dash_pts; lmin=0.4*dash_pts; ia=baseb_pc; xz("AAA"); while( ((ia-baseb_pe+baseband_size)&baseband_mask) < baseband_neg) { // Step downwards by the (negative) ramp length. // We should always be on a negative ramp here. ia=(ia+baseb_ramp[ia]+baseband_size)&baseband_mask; if( ((ia-baseb_pe+baseband_size)&baseband_mask) > baseband_neg)goto good_dash_x; // Now we must be on a positive ramp. if(baseb_ramp[ia] >= lmin && baseb_ramp[ia] <= lmax) { cg_wave_start= (ia-((baseb_ramp[ia]+dot_pts)>>1)+baseband_size)&baseband_mask; fit_dot(); t2=cg_wave_fit; cg_wave_start= (ia-((baseb_ramp[ia]+dash_pts)>>1)+baseband_size)&baseband_mask; fit_dash(); if(cg_wave_fit >DASH_DETECT_LIMIT && cg_wave_fit-t2 > 0.05 ) { store_dash(); cw_ptr=no_of_cwdat; insert_item(CW_DASH); check_cw(1001,0); if(kill_all_flag)return; } } ia=(ia-baseb_ramp[ia]+baseband_size)&baseband_mask; } good_dash_x:; if(PR00 == 1)show_cw("cwspeed 1"); sprintf(s,"%4d ",no_of_cwdat); settextcolor(14); lir_pixwrite(MAX_CG_OSCW+2,0,s); settextcolor(7); // We stepped backwards using the ramps when collecting dash midpoints. // Reorder dash midpoints if(no_of_cwdat - old_no_of_dashes > 1) { i=no_of_cwdat-1; j=old_no_of_dashes; while(j < i) { tmpcw=cw[i]; cw[i]=cw[j]; cw[j]=tmpcw; j++; i--; } } check_cw(1002,0); if(kill_all_flag)return; if(PR00 == 1)show_cw("cwspeed 1A"); if(no_of_cwdat < 10)goto detect_fail2; // First collect dash separations first_icw=1; largest_sep=0; largest_sep_pos=-1; t1=cw[0].midpoint-baseb_px; if(t1 < 0)t1+=baseband_size; cw[0].sep=t1; for(i=1; i largest_sep) { largest_sep=t1; largest_sep_pos=i; } } check_cw(1003,1); if(kill_all_flag)return; if(PR00 == 1)show_cw("cwspeed 1B"); // ***************************************************** // ***************************************************** // ************** Find cw keying speed ***************** // ***************************************************** // ***************************************************** // In case we are trying to find an extremely weak signal the // waveform might be poor due to the inclusion of a lot of noise. // We may also have incorrect speed information because the // speed has changed - maybe one station stopped transmission and // another started. // largest_sep_pos points to the dash after the longest // separation between dashes. // If there are many enough dashes after it, skip data before it. if(no_of_cwdat - largest_sep_pos > 8) { average_sep=cw[no_of_cwdat-1].midpoint-cw[0].midpoint; if(average_sep < 0)average_sep+=baseband_size; average_sep/=no_of_cwdat; t1=cw[no_of_cwdat-1].midpoint-cw[largest_sep_pos].midpoint; if(t1 < 0)t1+=baseband_size; t1/=(no_of_cwdat-largest_sep_pos); if(average_sep/t1 > 1.5) { first_icw=largest_sep_pos; } } // Collect the average waveform for the selected dashes // over a range that will contain surrounding dashes (and dots) // and evaluate the cw keying speed and a more accurate dash waveform. seldash_cwspeed(first_icw, no_of_cwdat); if(cwbit_pts == 0)return; // ***************************************************** // ***************************************************** // *********** Find good dashes in a new region ******** // *********** use improved dash waveform ******** // ***************************************************** // ***************************************************** // Now that we have a better shape for the dashes, step through // our recent data once more. lmax=4.5*cwbit_pts; lmin=1.5*cwbit_pts; ia=baseb_pc; old_no_of_dashes=no_of_cwdat; check_cw(1004,1); if(kill_all_flag)return; while( ((ia-baseb_pe+baseband_size)&baseband_mask) < baseband_neg) { // Step downwards by the (negative) ramp length. // We should always be on a negative ramp here. ia=(ia+baseb_ramp[ia]+baseband_size)&baseband_mask; if( ((ia-baseb_pe+baseband_size)&baseband_mask) > baseband_neg)goto good_dash2_x; // Now we must be on a positive ramp. ib=ia; ia=(ia-baseb_ramp[ia]+baseband_size)&baseband_mask; if(baseb_ramp[ib] >= lmin && baseb_ramp[ib] <= lmax) { check_cw(1005,1); if(kill_all_flag)return; // Point icw to the most recent dash then step icw // downwards until we have reached a point before ib. icw=no_of_cwdat-1; good_dash2_b:; i=ib-cw[icw].midpoint+baseband_size; i&=baseband_mask; if( i > baseband_neg && icw >0) { icw--; goto good_dash2_b; } if( i > baseband_neg) { icw--; j=0; } else { j=ia-cw[icw].midpoint+baseband_size; j&=baseband_mask; } if( j < baseband_neg) { PRT00"\n%d %d %d %f %f",icw,ia,ib,cw[icw].midpoint,cw[icw+1].midpoint); cg_wave_start= (ib-((baseb_ramp[ia]+dot_pts)>>1)+baseband_mask)&baseband_mask; fit_dot(); t2=cg_wave_fit; cg_wave_start= (ib-((baseb_ramp[ia]+dash_pts)>>1)+baseband_mask)&baseband_mask; fit_dash(); check_cw(10062,1); if(kill_all_flag)return; if(cg_wave_fit >DASH_DETECT_LIMIT && cg_wave_fit-t2 > 0.05 ) { // The new dash has to be stored at icw+1. cw_ptr=icw+1; if(cw_ptr != no_of_cwdat) { r1=cg_wave_midpoint-lmin-cw[icw].midpoint; if(r1 < 0)r1+=baseband_size; r2=cw[cw_ptr].midpoint-lmin-cg_wave_midpoint; if(r2 < 0)r2+=baseband_size; PRT00"\nTEST icw=%d %f %f",icw,r1,r2); if(r1 < baseband_neg && r2 < baseband_neg) { PRT00"\nINSERT icw=%d %f",icw,cg_wave_midpoint); insert_item(CW_DASH); if(kill_all_flag)return; if(PR00 == 1)show_cw("cwspeed 1C"); check_cw(10069,1); if(kill_all_flag)return; } } } } } } good_dash2_x:; check_cw(1007,1); if(kill_all_flag)return; if(PR00 == 1)show_cw("cwspeed 2"); // ***************************************************** // ***************************************************** // ******** Eliminate obvious errors *********** // ***************************************************** // ***************************************************** cw_ptr=1; while(cw_ptr < no_of_cwdat) { r1=cw[cw_ptr].sep/cwbit_pts; if(r1 < 3) { // When two dashes have been stored too close, on top of each other, // the waveform is most probably very ugly. // Skip these dashes for now. i=cw_ptr-1; j=cw_ptr+1; while(j < no_of_cwdat) { cw[i]=cw[j]; i++; j++; } if(cw_ptr >= 2) { t1=cw[cw_ptr-1].midpoint-cw[cw_ptr-2].midpoint; if(t1 < 0)t1+=baseband_size; cw[cw_ptr-1].sep=t1; } t1=cw[cw_ptr].midpoint-cw[cw_ptr-1].midpoint; if(t1 < 0)t1+=baseband_size; cw[cw_ptr].sep=t1; no_of_cwdat-=2; old_no_of_dashes-=3; cw_ptr--; } cw_ptr++; } check_cw(1008,1); if(kill_all_flag)return; // ***************************************************** // ***************************************************** // ****** Fit dashes in short regions between ******** // ****** dashes we already detected. ******** // ***************************************************** // ***************************************************** // Step through all the dashes and look for small separations that // fit to the keying speed we just determined. // Look for the following cases: // Code Sep // --- --- 4 // ___ _ ___ 6 // ___ ___ 6 // ___ _ _ ___ 8 // ___ ___ ___ 8 // ___ ___ 8 // ___ ___ ___ 10 // ___ ___ ___ 10 // ___??? default // ???___ default PRT00"\nCWBIT PTS %f",cwbit_pts); if(PR00 == 1)show_cw("cwspeed 3"); // Store the most probable signal in each case. cw_ptr=1; while(cw_ptr < no_of_cwdat) { r1=cw[cw_ptr].sep/cwbit_pts; k=(int)(r1)&0xfffffffe; if(r1-k > 1)k+=2; PRT01"\ncwspeed dashes: %d %d %f [%f] tot=%d", cw_ptr,k,r1,cw[cw_ptr].midpoint,no_of_cwdat); switch (k) { case 2: case 4: case 6: break; case 8: // ___ _ _ ___ 8 // ___ ___ ___ 8 // ___ ___ 8 set_region_envelope(); ity=0; // See if a dash will fit well. dashpos1_nom=cw[cw_ptr].midpoint-0.5*cw[cw_ptr].sep; if(dashpos1_nom < 0)dashpos1_nom+=baseband_size; dash1_chk=check_dash(dashpos1_nom); cg_wave_start=dashpos1_nom-(dash_pts>>1)+baseband_size; cg_wave_start&=baseband_mask; fit_dash(); dash1_re=cg_wave_re; dash1_im=cg_wave_im; dashpos1=cg_wave_midpoint; dashpos1_err=dashpos1_nom-cg_wave_midpoint; if(dashpos1_err < -sizhalf)dashpos1_err+=baseband_size; dash_fit1=cg_wave_fit; if( dash_fit1 < DASH_MISFIT_LIMIT)goto skip8; PRT01"\n{8}CHK DASH %f fit= %f (%f) [%f]", dash1_chk,cg_wave_fit,dashpos1_nom,cg_wave_midpoint); dotpos1_nom=cw[cw_ptr].midpoint-0.625*cw[cw_ptr].sep; if(dotpos1_nom < 0)dotpos1_nom+=baseband_size; dot1_chk=check_dot(dotpos1_nom); dotpos2_nom=cw[cw_ptr].midpoint-0.375*cw[cw_ptr].sep; if(dotpos2_nom < 0)dotpos2_nom+=baseband_size; dot2_chk=check_dot(dotpos2_nom); if(dash1_chk < -0.25 && dot1_chk < -0.25 && dot2_chk < -0.25) { PRT01"\nALL chk NEG (< -0.25)"); goto skip8; } cg_wave_start=dotpos1_nom-(dot_pts>>1)+baseband_size; cg_wave_start&=baseband_mask; fit_dot(); dot1_re=cg_wave_re; dot1_im=cg_wave_im; dotpos1=cg_wave_midpoint; dotpos1_err=dotpos1_nom-cg_wave_midpoint; if(dotpos1_err < -sizhalf)dotpos1_err+=baseband_size; dot_fit1=cg_wave_fit; PRT01"\n{8}CHK DOT1 %f fit=%f (%f) [%f]", dot1_chk,cg_wave_fit,dotpos1_nom,cg_wave_midpoint); cg_wave_start=dotpos2_nom-(dot_pts>>1)+baseband_size; cg_wave_start&=baseband_mask; fit_dot(); dot2_re=cg_wave_re; dot2_im=cg_wave_im; dotpos2=cg_wave_midpoint; dot_fit2=cg_wave_fit; PRT01"\n{8}CHK DOT2 %f fit=%f (%f) [%f]", dot2_chk,cg_wave_fit,dotpos2_nom,cg_wave_midpoint); if(dash_fit1-dot_fit1<0.05 || dash_fit1-dot_fit2<0.05)goto skip8; if( (dash1_chk < 0 && fabs(dashpos1_err) > 0.5*cwbit_pts) || (dash1_chk < 0.5 && fabs(dashpos1_err) > 0.7*cwbit_pts) ) { skip8:; clear_region(); goto skip_dashadd; } t3=0; if(dash_fit1 > DASH_DETECT_LIMIT && fabs(dashpos1_err) < 0.25*cwbit_pts) { if(dash1_chk < 0.25) { t3=0.75; } else { t3=0.5; } } t2=1-t3; cg_wave_midpoint=dashpos1+t2*dashpos1_err; if(cg_wave_midpoint < 0)cg_wave_midpoint+=baseband_size; if(cg_wave_midpoint >= baseband_size)cg_wave_midpoint-=baseband_size; ia=cg_wave_midpoint; cg_wave_re=t3*dash1_re+t2*baseb_envelope[2*ia ]; cg_wave_im=t3*dash1_im+t2*baseb_envelope[2*ia+1]; PRT01"\nstore_dash %f",cg_wave_midpoint); insert_item(CW_DASH); if(kill_all_flag)return; cw_ptr++; check_cw(10093,1); if(kill_all_flag)return; break; case 10: // ___ ___ ___ 10 // ___ ___ ___ 10 set_region_envelope(); // See if a dash will fit in the first position. dashpos1_nom=cw[cw_ptr].midpoint-0.6*cw[cw_ptr].sep; if(dashpos1_nom < 0)dashpos1_nom+=baseband_size; dash1_chk=check_dash(dashpos1_nom); cg_wave_start=dashpos1_nom-(dash_pts>>1)+baseband_size; cg_wave_start&=baseband_mask; fit_dash(); dash1_re=cg_wave_re; dash1_im=cg_wave_im; dashpos1=cg_wave_midpoint; dashpos1_err=dashpos1_nom-cg_wave_midpoint; if(dashpos1_err < -sizhalf)dashpos1_err+=baseband_size; dash_fit1=cg_wave_fit; PRT02"\n{10a}CHK DASH %f fit= %f (%f) [%f]", dash1_chk,cg_wave_fit,dashpos1_nom,cg_wave_midpoint); // See if a dash will fit in the second position. dashpos2_nom=cw[cw_ptr].midpoint-0.4*cw[cw_ptr].sep; if(dashpos2_nom < 0)dashpos2_nom+=baseband_size; dash2_chk=check_dash(dashpos2_nom); cg_wave_start=dashpos2_nom-(dash_pts>>1)+baseband_size; cg_wave_start&=baseband_mask; fit_dash(); dash2_re=cg_wave_re; dash2_im=cg_wave_im; dashpos2=cg_wave_midpoint; dashpos2_err=dashpos2_nom-cg_wave_midpoint; if(dashpos2_err < -sizhalf)dashpos2_err+=baseband_size; dash_fit2=cg_wave_fit; PRT02"\n{10b}CHK DASH %f fit= %f (%f) [%f]", dash2_chk,cg_wave_fit,dashpos2_nom,cg_wave_midpoint); ity=0; clear_region(); if( (dash_fit1 > DASH_DETECT_LIMIT && fabs(dashpos1_err) < 0.7*cwbit_pts && dash_fit1-dash_fit2 >0.05 && dash1_chk > 0) || (dash_fit1 > DASH_MISFIT_LIMIT && fabs(dashpos1_err) < 0.5*cwbit_pts && dash_fit1-dash_fit2 >0.05 && dash1_chk > 0.5) ) { ity=1; } if( (dash_fit2 > DASH_DETECT_LIMIT && fabs(dashpos2_err) < 0.7*cwbit_pts && dash_fit2-dash_fit1 >0.05 && dash2_chk > 0) || (dash_fit2 > DASH_MISFIT_LIMIT && fabs(dashpos2_err) < 0.5*cwbit_pts && dash_fit2-dash_fit1 >0.05 && dash2_chk > 0.5) ) { ity=1; dashpos1=dashpos2; dashpos1_err=dashpos2_err; dash1_chk=dash2_chk; } if(ity != 0) { // Check that a dot and space combination will not fit well. dotpos1_nom=dashpos1-cwbit_pts; if(dotpos1_nom < 0)dotpos1_nom+=baseband_size; dot1_chk=check_dot(dotpos1_nom); dotpos2_nom=dashpos1+cwbit_pts; if(dotpos2_nom >= baseband_size)dotpos2_nom-=baseband_size; dot2_chk=check_dot(dotpos2_nom); cg_wave_start=dotpos1_nom-(dot_pts>>1)+baseband_size; cg_wave_start&=baseband_mask; fit_dot(); dotpos1=cg_wave_midpoint; dotpos1_err=dotpos1_nom-cg_wave_midpoint; if(dotpos1_err < -sizhalf)dotpos1_err+=baseband_size; dot_fit1=cg_wave_fit; PRT03"\n{def}CHK DOT1 %f fit=%f (%f) [%f]", dot1_chk,cg_wave_fit,dotpos1_nom,cg_wave_midpoint); cg_wave_start=dotpos2_nom-(dot_pts>>1)+baseband_size; cg_wave_start&=baseband_mask; fit_dot(); dotpos2=cg_wave_midpoint; dotpos2_err=dotpos2_nom-cg_wave_midpoint; if(dotpos2_err < -sizhalf)dotpos2_err+=baseband_size; dot_fit2=cg_wave_fit; PRT03"\n{def}CHK DOT2 %f fit=%f (%f) [%f]", dot2_chk,cg_wave_fit,dotpos2_nom,cg_wave_midpoint); if(fabs(dotpos1_err) < 0.5 * cwbit_pts && dash_fit1-dot_fit1 < 0.05 && dot1_chk > 0.25) { PRT03"\nskip, dot1 good"); goto skip_dashadd; } if(fabs(dotpos2_err) < 0.5 * cwbit_pts && dash_fit1-dot_fit2 < 0.05 && dot2_chk > 0.25) { PRT03"\nskip, dot2 good"); goto skip_dashadd; } t2=0.5; t3=0.5; cg_wave_midpoint=dashpos1+t2*dashpos1_err; if(cg_wave_midpoint < 0)cg_wave_midpoint+=baseband_size; if(cg_wave_midpoint >= baseband_size)cg_wave_midpoint-=baseband_size; ia=cg_wave_midpoint; cg_wave_re=t3*dash1_re+t2*baseb_envelope[2*ia ]; cg_wave_im=t3*dash1_im+t2*baseb_envelope[2*ia+1]; PRT02"\nstore_dash %f",cg_wave_midpoint); insert_item(CW_DASH); if(kill_all_flag)return; cw_ptr--; } check_cw(10092,1); if(kill_all_flag)return; break; default: // ___ ___ ...... ___ ?? // ___ ...... ___ ___ ?? // Extrapolate baseb_envelope upwards from [cw_ptr-1] and // downwards from cw_ptr. // Check which of the two places is more likely for a dash. set_long_region_envelope(); // See if a dash will fit in the first position. dashpos1_nom=cw[cw_ptr-1].midpoint+4*cwbit_pts; if(dashpos1_nom >= baseband_size)dashpos1_nom-=baseband_size; dash1_chk=check_dash(dashpos1_nom); ia=dashpos1_nom; t1= baseb_envelope[2*ia ] * baseb_envelope[2*ia ]+ baseb_envelope[2*ia+1] * baseb_envelope[2*ia+1]; cg_wave_start=dashpos1_nom-(dash_pts>>1)+baseband_size; cg_wave_start&=baseband_mask; fit_dash(); dash1_re=cg_wave_re; dash1_im=cg_wave_im; dashpos1=cg_wave_midpoint; dashpos1_err=dashpos1_nom-cg_wave_midpoint; if(dashpos1_err < -sizhalf)dashpos1_err+=baseband_size; dash_fit1=cg_wave_fit; PRT03"\n{def a}CHK DASH %f fit= %f (%f) [%f] ampl=%f", dash1_chk,cg_wave_fit,dashpos1_nom,cg_wave_midpoint,sqrt(t1)); // See if a dash will fit in the second position. dashpos2_nom=cw[cw_ptr].midpoint-4*cwbit_pts; if(dashpos2_nom < 0)dashpos2_nom+=baseband_size; dash2_chk=check_dash(dashpos2_nom); ia=dashpos2_nom; t2= baseb_envelope[2*ia ] * baseb_envelope[2*ia ]+ baseb_envelope[2*ia+1] * baseb_envelope[2*ia+1]; cg_wave_start=dashpos2_nom-(dash_pts>>1)+baseband_size; cg_wave_start&=baseband_mask; fit_dash(); dash2_re=cg_wave_re; dash2_im=cg_wave_im; dashpos2=cg_wave_midpoint; dashpos2_err=dashpos2_nom-cg_wave_midpoint; if(dashpos2_err < -sizhalf)dashpos2_err+=baseband_size; dash_fit2=cg_wave_fit; PRT03"\n{def b}CHK DASH %f fit= %f (%f) [%f], ampl=%f", dash2_chk,cg_wave_fit,dashpos2_nom,cg_wave_midpoint,sqrt(t2)); ity=0; clear_region(); if( t1 > 0.25*t2 && ((dash_fit1 > DASH_DETECT_LIMIT && fabs(dashpos1_err) < 0.7*cwbit_pts && dash1_chk > 0) || (dash_fit1 > DASH_MISFIT_LIMIT && fabs(dashpos1_err) < 0.5*cwbit_pts && dash1_chk > 0.5)) ) { ity=1; } if( t2 > 0.25*t1 && ((dash_fit2 > DASH_DETECT_LIMIT && fabs(dashpos2_err) < 0.7*cwbit_pts && dash2_chk > 0) || (dash_fit2 > DASH_MISFIT_LIMIT && fabs(dashpos2_err) < 0.5*cwbit_pts && dash2_chk > 0.5)) ) { ity+=2; } PRT03"\nity(0)=%d ",ity); if(ity != 0) { if(ity == 3) { // Seems there is one dash at each side. // Pick the best one, the one with best S/N. r1=1-dash1_chk; r1=t1/(r1*r1); r2=1-dash2_chk; r2=t2/(r2*r2); if(r1 > r2) { ity=1; } else { ity=2; } if( fabs((r1-r2)/(r1+r2)) < 25) { if(r1 > r2) { ity=1; } else { ity=2; } } } PRT03"\nity(1)=%d ",ity); if(ity == 2) { dashpos1=dashpos2; dashpos1_err=dashpos2_err; dash_fit1=dash_fit2; } // Check that a dot and space combination will not fit well. dotpos1_nom=dashpos1-cwbit_pts; if(dotpos1_nom < 0)dotpos1_nom+=baseband_size; dot1_chk=check_dot(dotpos1_nom); dotpos2_nom=dashpos1+cwbit_pts; if(dotpos2_nom >= baseband_size)dotpos2_nom-=baseband_size; dot2_chk=check_dot(dotpos2_nom); cg_wave_start=dotpos1_nom-(dot_pts>>1)+baseband_size; cg_wave_start&=baseband_mask; fit_dot(); dotpos1=cg_wave_midpoint; dotpos1_err=dotpos1_nom-cg_wave_midpoint; if(dotpos1_err < -sizhalf)dotpos1_err+=baseband_size; dot_fit1=cg_wave_fit; PRT03"\n{def}CHK DOT1 %f fit=%f (%f) [%f]", dot1_chk,cg_wave_fit,dotpos1_nom,cg_wave_midpoint); cg_wave_start=dotpos2_nom-(dot_pts>>1)+baseband_size; cg_wave_start&=baseband_mask; fit_dot(); dotpos2=cg_wave_midpoint; dotpos2_err=dotpos2_nom-cg_wave_midpoint; if(dotpos2_err < -sizhalf)dotpos2_err+=baseband_size; dot_fit2=cg_wave_fit; PRT03"\n{def}CHK DOT2 %f fit=%f (%f) [%f]", dot2_chk,cg_wave_fit,dotpos2_nom,cg_wave_midpoint); if(fabs(dotpos1_err) < 0.5 * cwbit_pts && dash_fit1-dot_fit1 < 0.05 && dot1_chk > 0.25) { PRT03"\nskip, dot1 good"); goto skip_dashadd; } if(fabs(dotpos2_err) < 0.5 * cwbit_pts && dash_fit1-dot_fit2 < 0.05 && dot2_chk > 0.25) { PRT03"\nskip, dot2 good"); goto skip_dashadd; } t2=0.25; t3=0.75; cg_wave_midpoint=dashpos1+t2*dashpos1_err; if(cg_wave_midpoint < 0)cg_wave_midpoint+=baseband_size; if(cg_wave_midpoint >= baseband_size)cg_wave_midpoint-=baseband_size; ia=cg_wave_midpoint; cg_wave_re=t3*dash1_re+t2*baseb_envelope[2*ia ]; cg_wave_im=t3*dash1_im+t2*baseb_envelope[2*ia+1]; PRT03"\nstore_dash %f tot=%d",cg_wave_midpoint,no_of_cwdat); insert_item(CW_DASH); if(kill_all_flag)return; cw_ptr--; } check_cw(10091,1); if(kill_all_flag)return; break; } skip_dashadd:; cw_ptr++; } check_cw(1009,1); if(kill_all_flag)return; // ***************************************************** // ***************************************************** // ************** Find cw keying speed ***************** // ****** but only if we have more dashes ************ // ***************************************************** // ***************************************************** if(no_of_cwdat == old_no_of_dashes)goto skip_shape_improvement; first_icw=1; largest_sep=0; largest_sep_pos=-1; for(i=1; i largest_sep) { largest_sep=t1; largest_sep_pos=i; } } // In case we are trying to find an extremely weak signal the // waveform might be poor due to the inclusion of a lot of noise. // We may also have incorrect speed information because the // speed has changed - maybe one station stopped transmission and // another started. // largest_sep_pos points to the dash after the longest // separation between dashes. // If there are many enough dashes after it, skip data before it. if(no_of_cwdat - largest_sep_pos > 8) { average_sep=cw[no_of_cwdat-1].midpoint-cw[0].midpoint; if(average_sep < 0)average_sep+=baseband_size; average_sep/=no_of_cwdat; t1=cw[no_of_cwdat-1].midpoint-cw[largest_sep_pos].midpoint; if(t1 < 0)t1+=baseband_size; t1/=(no_of_cwdat-largest_sep_pos); if(average_sep/t1 > 1.5) { first_icw=largest_sep_pos; } } // Collect the average waveform for the selected dashes // over a range that will contain surrounding dashes (and dots) // and evaluate the cw keying speed and a more accurate dash waveform. seldash_cwspeed(first_icw, no_of_cwdat); if(cwbit_pts == 0)return; skip_shape_improvement:; // ******************************************************** // ******************************************************** // ************** Store the new dash shape **************** // ************** get RMS deviation **************** // ******************************************************** // ******************************************************** check_cw(1022,1); if(kill_all_flag)return; first_icw--; t1=0; t2=0; cw_ptr=0; if(first_icw > 0) { while(cw_ptr 0) { cw[cw_ptr].sep=cg_wave_midpoint-cw[cw_ptr-1].midpoint; if(cw[cw_ptr].sep<0)cw[cw_ptr].sep+=baseband_size; } cw[cw_ptr].re=cg_wave_re; cw[cw_ptr].im=cg_wave_im; if(cw_ptr+1 < no_of_cwdat) { cw[cw_ptr+1].sep=cw[cw_ptr+1].midpoint-cg_wave_midpoint; if(cw[cw_ptr+1].sep<0)cw[cw_ptr+1].sep+=baseband_size; check_cw(10230,1); if(kill_all_flag)return; } r1+=cg_wave_dat; r2+=cg_wave_err; cw_ptr++; } } check_cw(1024,1); if(kill_all_flag)return; // Update dash separations. cw_ptr=1; while(cw_ptr < no_of_cwdat) { r3=cw[cw_ptr].midpoint-cw[cw_ptr-1].midpoint; if(r3 < 0)r3+=baseband_size; cw[cw_ptr].sep=r3; r3/=cwbit_pts; k=(int)(r3)&0xfffffffe; if(r3-k > 1)k+=2; PRT05"\ncwspeed new fit %3d %3d %6.3f [%11.4f]", cw_ptr,k,r3,cw[cw_ptr].midpoint); cw_ptr++; } t1+=r1; t2+=r2; k=no_of_cwdat-first_icw; r3=r2/(r1*sqrt((float)(k))); t3=t2/(t1*sqrt((float)(no_of_cwdat))); PRT05"\n (Waveform S/N %f %f)",t3,r3); // The accuracy of the waveform is given by its S/N. // r1=S+N and r3=N for the fitted wave. // The noise in the average is reduced by the square root of // the number over which averages are taken. // Skip if the noise in the waveform is above 2% check_cw(31025,1); if(kill_all_flag)return; if(r3 > CWSPEED_STON && t3 > CWSPEED_STON)goto detect_fail; if(r3 < t3) { cw_stoninv=r2/r1; } else { cw_stoninv=t2/t1; } // ****************************************************** // ****************************************************** // ****** Morse code waveforms are accurate now. ****** // ****** Set flag so we will not return here ****** // ****************************************************** // ****************************************************** cw_detect_flag=CWDETECT_WAVEFORM_ESTABLISHED; PRT05"\n*** SET cw_detect_flag=CWDETECT_WAVEFORM_ESTABLISHED ***"); return; detect_fail:; check_cw(11025,1); if(kill_all_flag)return; detect_fail2:; cw_detect_flag=CWDETECT_ERROR; }