Bug fixes for wsprd and wsprsim utilities. Implemented fully-coherent signal subtraction in wsprd_exp.

git-svn-id: svn+ssh://svn.code.sf.net/p/wsjt/wsjt/branches/wsjtx@5621 ab8295b8-cf94-4d9e-aec4-7959e3be5d79
This commit is contained in:
Steven Franke 2015-06-18 02:24:06 +00:00
parent f256984d13
commit f511da3c53
5 changed files with 146 additions and 44 deletions

View File

@ -326,8 +326,10 @@ void sync_and_demodulate(double *id, double *qd, long np,
} }
return; return;
} }
//*************************************************************************** /***************************************************************************
void subtract_signal(double *id, double *qd, long np, symbol-by-symbol signal subtraction
****************************************************************************/
void subtract_signal(double *id, double *qd, long np,
float f0, int shift0, float drift0, unsigned char* channel_symbols) float f0, int shift0, float drift0, unsigned char* channel_symbols)
{ {
float dt=1.0/375.0, df=375.0/256.0; float dt=1.0/375.0, df=375.0/256.0;
@ -364,10 +366,12 @@ void subtract_signal(double *id, double *qd, long np,
} }
} }
// subtract the signal here. // subtract the signal here.
i0=i0/256.0; //will be wrong for partial symbols at the edges... i0=i0/256.0; //will be wrong for partial symbols at the edges...
q0=q0/256.0; q0=q0/256.0;
for (j=0; j<256; j++) { for (j=0; j<256; j++) {
k=shift0+i*256+j; k=shift0+i*256+j;
if( (k>0) & (k<np) ) { if( (k>0) & (k<np) ) {
@ -378,6 +382,92 @@ void subtract_signal(double *id, double *qd, long np,
} }
return; return;
} }
/******************************************************************************
Fully coherent signal subtraction
*******************************************************************************/
void subtract_signal2(double *id, double *qd, long np,
float f0, int shift0, float drift0, unsigned char* channel_symbols)
{
double dt=1.0/375.0, df=375.0/256.0;
int i, j, k, ii;
double pi=4.*atan(1.0),twopidt;
double refi[45000],refq[45000];
double ci[45000],cq[45000],cfi[45000],cfq[45000];
memset(refi,0,sizeof(double)*45000);
memset(refq,0,sizeof(double)*45000);
memset(ci,0,sizeof(double)*45000);
memset(cq,0,sizeof(double)*45000);
memset(cfi,0,sizeof(double)*45000);
memset(cfq,0,sizeof(double)*45000);
double phi=0, dphi;
// double dphi, cdphi, sdphi;
twopidt=2.0*pi*dt;
// measured signal is: s(t)=a(t)*exp( j*theta(t) )
// reference is: r(t) = exp( j*phi(t) )
// complex amplitude is estimated as: c(t)=LPF[s(t)*conjugate(r(t))]
// so c(t) has phase angle theta-phi
// multiply r(t) by c(t) and subtract from s(t), i.e. s'(t)=s(t)-c(t)r(t)
// create reference wspr signal vector, centered on f0.
for (i=0; i<162; i++) {
dphi=twopidt*
(
f0 + ((float)drift0/2.0)*((float)i-81.0)/81.0
+ ((double)channel_symbols[i]-1.5)*df
);
for ( j=0; j<256; j++ ) {
ii=256*i+j;
refi[ii]=refi[ii]+cos(phi); //cannot precompute sin/cos because dphi is changing
refq[ii]=refq[ii]+sin(phi);
phi=phi+dphi;
}
}
// s(t) * conjugate(r(t))
// place signal 1 impulse response width in so that we don't have to deal
// with partial convolutions at the beginning.
for (i=0; i<41472; i++) {
k=shift0+i;
if( (k>0) & (k<np) ) {
ci[i+500] = id[k]*refi[i] + qd[k]*refq[i];
cq[i+500] = qd[k]*refi[i] - id[k]*refq[i];
}
}
//quick and dirty filter - may want to do better
double w[500], norm=0;
for (i=0; i<500; i++) {
w[i]=sin(pi*i/499.0);
norm=norm+w[i];
}
for (i=0; i<500; i++) {
w[i]=w[i]/norm;
}
// LPF
for (i=500; i<45000-375; i++) {
cfi[i]=0.0; cfq[i]=0.0;
for (j=0; j<500; j++) {
cfi[i]=cfi[i]+w[j]*ci[i-250+j];
cfq[i]=cfq[i]+w[j]*cq[i-250+j];
}
}
// subtract c(t)*ref(i) here
// (ci+j*cq)(refi+j*refq)=(ci*refi-cq*refq)+j(ci*refq)+cq*refi)
for (i=0; i<41472; i++) {
k=shift0+i;
if( (k>0) & (k<np) ) {
id[k]=id[k] - (cfi[i+500]*refi[i]-cfq[i+500]*refq[i]);
qd[k]=qd[k] - (cfi[i+500]*refq[i]+cfq[i+500]*refi[i]);
}
}
return;
}
unsigned long writec2file(char *c2filename, int trmin, double freq unsigned long writec2file(char *c2filename, int trmin, double freq
, double *idat, double *qdat) , double *idat, double *qdat)
@ -417,6 +507,7 @@ void usage(void)
printf("\n"); printf("\n");
printf("Options:\n"); printf("Options:\n");
printf(" -a <path> path to writeable data files, default=\".\"\n"); printf(" -a <path> path to writeable data files, default=\".\"\n");
printf(" -c write .c2 file at the end of the first pass\n");
printf(" -e x (x is transceiver dial frequency error in Hz)\n"); printf(" -e x (x is transceiver dial frequency error in Hz)\n");
printf(" -f x (x is transceiver dial frequency in MHz)\n"); printf(" -f x (x is transceiver dial frequency in MHz)\n");
// blanking is not yet implemented. The options are accepted for compatibility // blanking is not yet implemented. The options are accepted for compatibility
@ -425,7 +516,6 @@ void usage(void)
// printf(" -b n (n is pct of time that is blanked)\n"); // printf(" -b n (n is pct of time that is blanked)\n");
printf(" -H do not use (or update) the hash table\n"); printf(" -H do not use (or update) the hash table\n");
printf(" -m decode wspr-15 .wav file\n"); printf(" -m decode wspr-15 .wav file\n");
printf(" -n write noise estimates to file noise.dat\n");
printf(" -q quick mode - doesn't dig deep for weak signals\n"); printf(" -q quick mode - doesn't dig deep for weak signals\n");
printf(" -s signal subtraction mode\n"); printf(" -s signal subtraction mode\n");
printf(" -t signal subtraction followed by a second pass\n"); printf(" -t signal subtraction followed by a second pass\n");
@ -449,7 +539,8 @@ int main(int argc, char *argv[])
char timer_fname[200],hash_fname[200]; char timer_fname[200],hash_fname[200];
char uttime[5],date[7]; char uttime[5],date[7];
int c,delta,maxpts=65536,verbose=0,quickmode=0; int c,delta,maxpts=65536,verbose=0,quickmode=0;
int writenoise=0,usehashtable=1,wspr_type=2, subtraction=0, ipass, npasses=1; int writenoise=0,usehashtable=1,wspr_type=2, subtraction=0, ipass;
int writec2=0, npasses=1;
int shift1, lagmin, lagmax, lagstep, worth_a_try, not_decoded; int shift1, lagmin, lagmax, lagstep, worth_a_try, not_decoded;
unsigned int nbits=81; unsigned int nbits=81;
unsigned int npoints, metric, maxcycles, cycles, maxnp; unsigned int npoints, metric, maxcycles, cycles, maxnp;
@ -501,11 +592,14 @@ int main(int argc, char *argv[])
idat=malloc(sizeof(double)*maxpts); idat=malloc(sizeof(double)*maxpts);
qdat=malloc(sizeof(double)*maxpts); qdat=malloc(sizeof(double)*maxpts);
while ( (c = getopt(argc, argv, "a:b:e:f:Hmnqstwvz:")) !=-1 ) { while ( (c = getopt(argc, argv, "a:ce:f:Hmqstwvz:")) !=-1 ) {
switch (c) { switch (c) {
case 'a': case 'a':
data_dir = optarg; data_dir = optarg;
break; break;
case 'c':
writec2=1;
break;
case 'e': case 'e':
dialfreq_error = strtof(optarg,NULL); // units of Hz dialfreq_error = strtof(optarg,NULL); // units of Hz
// dialfreq_error = dial reading - actual, correct frequency // dialfreq_error = dial reading - actual, correct frequency
@ -519,17 +613,14 @@ int main(int argc, char *argv[])
case 'm': case 'm':
wspr_type = 15; wspr_type = 15;
break; break;
case 'n':
writenoise = 1;
break;
case 'q': case 'q':
quickmode = 1; quickmode = 1;
break; break;
case 's': case 's':
subtraction = 1; subtraction = 1; //subtraction only, no second pass
break; break;
case 't': case 't':
subtraction = 1; subtraction = 1; //subtraction and a second pass (t for two)
npasses = 2; //npasses defaults to 1 npasses = 2; //npasses defaults to 1
break; break;
case 'v': case 'v':
@ -655,6 +746,14 @@ int main(int argc, char *argv[])
//*************** main loop starts here ***************** //*************** main loop starts here *****************
for (ipass=0; ipass<npasses; ipass++) { for (ipass=0; ipass<npasses; ipass++) {
if( ipass == 1 && uniques == 0 ) break;
if( ipass == 1 ) { //otherwise we bog down on the second pass
minsync1=0.18;
minsync2=0.2;
maxcycles=5000;
printf("-------------- 2 ----------------\n");
}
memset(ps,0.0, sizeof(float)*512*nffts); memset(ps,0.0, sizeof(float)*512*nffts);
for (i=0; i<nffts; i++) { for (i=0; i<nffts; i++) {
for(j=0; j<512; j++ ) { for(j=0; j<512; j++ ) {
@ -751,7 +850,6 @@ int main(int argc, char *argv[])
} }
npk=i; npk=i;
/*
// bubble sort on snr, bringing freq along for the ride // bubble sort on snr, bringing freq along for the ride
int pass; int pass;
float tmp; float tmp;
@ -767,7 +865,7 @@ int main(int argc, char *argv[])
} }
} }
} }
*/
t0=clock(); t0=clock();
/* Make coarse estimates of shift (DT), freq, and drift /* Make coarse estimates of shift (DT), freq, and drift
@ -943,12 +1041,12 @@ int main(int argc, char *argv[])
// call_loc_pow string and also callsign (for de-duping). // call_loc_pow string and also callsign (for de-duping).
noprint=unpk_(message,hashtab,call_loc_pow,callsign); noprint=unpk_(message,hashtab,call_loc_pow,callsign);
if( subtraction && !noprint ) { if( subtraction && (ipass == 0) && !noprint ) {
unsigned char channel_symbols[162]; unsigned char channel_symbols[162];
if( get_wspr_channel_symbols(call_loc_pow, channel_symbols) ) { if( get_wspr_channel_symbols(call_loc_pow, channel_symbols) ) {
subtract_signal(idat, qdat, npoints, f1, shift1, drift1, channel_symbols); subtract_signal2(idat, qdat, npoints, f1, shift1, drift1, channel_symbols);
} else { } else {
break; break;
} }
@ -1002,6 +1100,15 @@ int main(int argc, char *argv[])
} }
} }
} }
if( ipass == 0 && writec2 ) {
char c2filename[15];
double carrierfreq=dialfreq;
int wsprtype=2;
strcpy(c2filename,"000000_0001.c2");
printf("Writing %s\n",c2filename);
writec2file(c2filename, wsprtype, carrierfreq, idat, qdat);
}
} }
printf("<DecodeFinished>\n"); printf("<DecodeFinished>\n");
@ -1048,13 +1155,6 @@ int main(int argc, char *argv[])
fclose(fhash); fclose(fhash);
} }
// char c2filename[15];
// double carrierfreq=dialfreq;
// int wsprtype=2;
// strcpy(c2filename,"000000_0001.c2");
// printf("Writing %s\n",c2filename);
// writec2file(c2filename, wsprtype, carrierfreq, idat, qdat);
if(writenoise == 999) return -1; //Silence compiler warning if(writenoise == 999) return -1; //Silence compiler warning
return 0; return 0;
} }

View File

@ -66,7 +66,7 @@ void unpack50( signed char *dat, int32_t *n1, int32_t *n2 )
*n2=*n2+((i4>>6)&3); *n2=*n2+((i4>>6)&3);
} }
void unpackcall( int32_t ncall, char *call ) int unpackcall( int32_t ncall, char *call )
{ {
char c[]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E', char c[]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E',
'F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T', 'F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T',
@ -108,10 +108,13 @@ void unpackcall( int32_t ncall, char *call )
call[i]='\0'; call[i]='\0';
} }
} }
} else {
return 0;
} }
return 1;
} }
void unpackgrid( int32_t ngrid, char *grid) int unpackgrid( int32_t ngrid, char *grid)
{ {
char c[]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E', char c[]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E',
'F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T', 'F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T',
@ -139,7 +142,9 @@ void unpackgrid( int32_t ngrid, char *grid)
grid[3]=c[n2]; grid[3]=c[n2];
} else { } else {
strcpy(grid,"XXXX"); strcpy(grid,"XXXX");
return 0;
} }
return 1;
} }
int unpackpfx( int32_t nprefix, char *call) int unpackpfx( int32_t nprefix, char *call)
@ -233,8 +238,8 @@ int unpk_(signed char *message, char hashtab[32768][13], char *call_loc_pow, cha
char grid[5],grid6[7],cdbm[3]; char grid[5],grid6[7],cdbm[3];
unpack50(message,&n1,&n2); unpack50(message,&n1,&n2);
unpackcall(n1,callsign); if( !unpackcall(n1,callsign) ) return 1;
unpackgrid(n2, grid); if( !unpackgrid(n2, grid) ) return 1;
int ntype = (n2&127) - 64; int ntype = (n2&127) - 64;
callsign[12]=0; callsign[12]=0;
grid[4]=0; grid[4]=0;

View File

@ -12,9 +12,9 @@
void unpack50( signed char *dat, int32_t *n1, int32_t *n2 ); void unpack50( signed char *dat, int32_t *n1, int32_t *n2 );
void unpackcall( int32_t ncall, char *call ); int unpackcall( int32_t ncall, char *call );
void unpackgrid( int32_t ngrid, char *grid); int unpackgrid( int32_t ngrid, char *grid);
int unpackpfx( int32_t nprefix, char *call); int unpackpfx( int32_t nprefix, char *call);

View File

@ -133,7 +133,6 @@ int main(int argc, char *argv[])
message=malloc(sizeof(char)*23); message=malloc(sizeof(char)*23);
strcpy(c2filename,"000000_0001.c2"); strcpy(c2filename,"000000_0001.c2");
printf("%s\n",c2filename);
while ( (c = getopt(argc, argv, "cdo:s:")) !=-1 ) { while ( (c = getopt(argc, argv, "cdo:s:")) !=-1 ) {
switch (c) { switch (c) {
case 'c': case 'c':

View File

@ -84,7 +84,6 @@ void pack_prefix(char *callsign, int32_t *n, int32_t *m, int32_t *nadd ) {
char *call6; char *call6;
call6=malloc(sizeof(char)*6); call6=malloc(sizeof(char)*6);
memset(call6,32,sizeof(char)*6); memset(call6,32,sizeof(char)*6);
int i1=strcspn(callsign,"/"); int i1=strcspn(callsign,"/");
if( callsign[i1+2] == 0 ) { if( callsign[i1+2] == 0 ) {
@ -200,10 +199,9 @@ int get_wspr_channel_symbols(char* rawmessage, unsigned char* symbols) {
if( (i1>3) & (i1<7) & (i2==mlen) & (i3==mlen) ) { if( (i1>3) & (i1<7) & (i2==mlen) & (i3==mlen) ) {
// Type 1 message: K9AN EN50 33 // Type 1 message: K9AN EN50 33
// xxnxxxx xxnn nn // xxnxxxx xxnn nn
const char s[2]=" "; callsign = strtok(message," ");
callsign = strtok(message,s); grid = strtok(NULL," ");
grid = strtok(NULL,s); powstr = strtok(NULL," ");
powstr = strtok(NULL,s);
int power = atoi(powstr); int power = atoi(powstr);
n = pack_call(callsign); n = pack_call(callsign);
@ -239,6 +237,7 @@ int get_wspr_channel_symbols(char* rawmessage, unsigned char* symbols) {
} else if ( i2 < mlen ) { // just looks for a right slash } else if ( i2 < mlen ) { // just looks for a right slash
// Type 2: PJ4/K1ABC 37 // Type 2: PJ4/K1ABC 37
callsign=strtok(message," "); callsign=strtok(message," ");
if( strlen(callsign) < i2 ) return 0; //guards against pathological case
powstr=strtok(NULL," "); powstr=strtok(NULL," ");
int power = atoi(powstr); int power = atoi(powstr);
if( power < 0 ) power=0; if( power < 0 ) power=0;
@ -250,7 +249,6 @@ int get_wspr_channel_symbols(char* rawmessage, unsigned char* symbols) {
m=128*ng+ntype+64; m=128*ng+ntype+64;
n=n1; n=n1;
} else { } else {
// printf("Error: bad message format\n");
return 0; return 0;
} }