static int cdf_erfc (lua_State *L) { lua_Number x = luaL_checknumber(L, 1); int ind = 0; lua_pushnumber(L, erfc1(&ind, &x)); return 1; }
int main(int argc,char *argv[]){ unsigned char data[FRAMEBITS/8]; // One minor frame unsigned char symbols[2*FRAMEBITS]; unsigned char nsymbols[2*FRAMEBITS]; int i,fd; char *filename; struct stat statbuf; off_t length; short *samples; int nsamples; int start; int startsync = SYNC_FAIL,endsync = SYNC_FAIL; void *vd; // Viterbi decoder handle int symerrors; int firstsample; int frame; int begin; int maxmetric,minmetric; int ind; char *locale; double clock_tolerance = 5; // Maximum allowable clock offset, samples/frame if((locale = getenv("LANG")) != NULL) setlocale(LC_ALL,locale); else setlocale(LC_ALL,"en_US.utf8"); begin = 0; while((i = getopt(argc,argv,"c:o:r:t:")) != EOF){ switch(i){ case 't': clock_tolerance = atof(optarg); break; case 'c': Symrate = atof(optarg); break; case 'r': Samprate = atof(optarg); break; case 'o': begin = atoi(optarg); // Starting sample, default 0 break; } } Symbolsamples = Samprate/Symrate; Framesamples = Symbolsamples * 2*FRAMEBITS; // Read baseband samples, downsampled to Samprate (important!) and look for sync vector filename = argv[optind]; if(lstat(filename,&statbuf) == -1){ fprintf(stderr,"lstat(%s) failed: %s\n",filename,strerror(errno)); exit(1); } if(!S_ISREG(statbuf.st_mode)){ fprintf(stderr,"%s is not an ordinary file\n",filename); exit(1); } length = statbuf.st_size; if((fd = open(filename,O_RDONLY)) == -1){ fprintf(stderr,"open(%s,readonly) failed; %s\n",filename,strerror(errno)); exit(1); } if((samples = mmap(NULL,length,PROT_READ,MAP_SHARED,fd,0)) == MAP_FAILED){ fprintf(stderr,"mmap(%s,%lld) failed: %s\n",filename, (long long)length,strerror(errno)); close(fd); exit(1); } nsamples = length / sizeof(*samples); printf("%s: %'d samples, %'.3lf seconds @ %.1lf Hz\n",filename, nsamples,nsamples/Samprate,Samprate); generate_sync(Symrate); vd = create_viterbi224(FRAMEBITS); if(vd == NULL){ fprintf(stderr,"Can't create viterbi decoder\n"); exit(2); } for(frame=1;begin + Framesamples < nsamples;frame++){ int low,high; // Look for starting frame sync if(startsync == SYNC_FAIL){ // No endsync from previous frame, find initial sync while(1){ startsync = fft_sync_search(&samples[begin],0,(int)Framesamples,begin); if(startsync != SYNC_FAIL){ startsync += begin; break; } begin += Framesamples; // Skip a frame time and try again printf("Start sync search failure, skip to %'d\n",begin); } } assert(startsync != SYNC_FAIL); // Look for ending frame sync // Start halfway through the frame, but actually search the middle // of the result, which straddles the next sync. Only search in the // allowable range to keep the clock from being driven into the weeds by noise while(1){ start = startsync + Framesamples/2; low = 0.5 * Framesamples - clock_tolerance; // very tight tolerance, +/- 5 samples high = 0.5 * Framesamples + clock_tolerance; endsync = fft_sync_search(&samples[start],low,high,-1); if(endsync != SYNC_FAIL){ endsync += start; break; } // Go back to look for another start sync begin = startsync + Framesamples; printf("End sync search failure, skip to %'d\n",begin); startsync = SYNC_FAIL; goto again; } // Got both start and end sync, proceed i = startsync/Samprate; printf("Frame %'d @ sample %'d (%'d:%02d)\n",frame,startsync,i/60,i % 60); // Update estimate of sample clock rate et al #if 0 // Hack - not let it change Framesamples = endsync - startsync; // Actual samples in current frame (int) Symbolsamples = Framesamples/(2*FRAMEBITS); // Actual samples in symbol (float) Symrate = Samprate / Symbolsamples; #endif printf("Symbol rate: %'.3lf Hz; samples/sym: %'.3lf; samples/frame: %'.1lf\n", Symrate,Symbolsamples,Framesamples); #if 0 // If clock estimate has changed a lot, regenerate the sync vector with the new clock if(abs(SYNCBITS*Samprate/Symrate - Synclen) > Symbolsamples/10.){ printf("Clock changed; regenerate sync\n"); generate_sync(Symrate); } #endif // startsync points to the first symbol in the 34-bit sync sequence, // so we want to skip past it to the first symbol in the new frame firstsample = SYNCBITS*Symbolsamples + startsync; for(i=0; i < 2*FRAMEBITS; i++){ double sum; int midpoint,last; ind = firstsample + i * Symbolsamples; midpoint = firstsample + (i+0.5)*Symbolsamples; last = firstsample + (i+1.0)*Symbolsamples; // Integrate bit, remove manchester sum = 0; for(;ind < midpoint;ind++) // first half of symbol sum -= samples[ind]; for(; ind < last;ind++) sum += samples[ind]; sum += 128; // Offset-128 for Viterbi decoder symbols[i] = (sum > 255) ? 255 : ((sum < 0) ? 0 : sum); // Clip to range 0-255 } // We start with the encoder having just transmitted these five fixed bytes, // 3 bytes of coder dump and 2 bytes of sync: // 12 fc 81 9f be init_viterbi224(vd,0x819fbe); update_viterbi224_blk(vd,symbols,FRAMEBITS); chainback_viterbi224(vd,data,FRAMEBITS,0x819fbe); maxmetric = max_metric_viterbi224(vd); minmetric = min_metric_viterbi224(vd); for(i=0; i<128; i++){ printf("%02x",data[i]); if((i % 16) == 15) putchar('\n'); else putchar(' '); } // Re-encode and compare to received symbols to count channel errors encode(nsymbols,data,FRAMEBITS/8,0x819fbe); symerrors = 0; for(i=0;i<2*FRAMEBITS;i++){ if(nsymbols[i] != (symbols[i] > 128)){ symerrors++; #if 0 printf("sym error %d: %d != %d\n",i,nsymbols[i],symbols[i]); #endif } } printf("Viterbi path metric range %'d - %'d, diff %'d\n",minmetric,maxmetric,maxmetric-minmetric); if(symerrors){ double esn0; esn0 = erfc1(2.*symerrors/(2*FRAMEBITS)); // Amplitude ratio esn0 *= esn0; // square to get power ratio // ebn0 = 2 * esn0 for rate 1/2 code printf("re-encode symbol errors: %'d/%'d; estimated Eb/No = %.2lf dB\n", symerrors,2*FRAMEBITS,10*log10(2*esn0)); } else { printf("No re-encode symbol errors; estimated Eb/No > %.2lf dB\n",10.5); // hack; 7.5 dB has a BER < 1/2048 } putchar('\n'); fflush(stdout); startsync = endsync; again:; } delete_viterbi224(vd); exit(0); }
void grat1(double *a,double *x,double *r,double *p,double *q, double *eps) { static int K2 = 0; static double a2n,a2nm1,am0,an,an0,b2n,b2nm1,c,cma,g,h,j,l,sum,t,tol,w,z,T1,T3; /* .. .. Executable Statements .. */ /* ----------------------------------------------------------------------- EVALUATION OF THE INCOMPLETE GAMMA RATIO FUNCTIONS P(A,X) AND Q(A,X) IT IS ASSUMED THAT A .LE. 1. EPS IS THE TOLERANCE TO BE USED. THE INPUT ARGUMENT R HAS THE VALUE E**(-X)*X**A/GAMMA(A). ----------------------------------------------------------------------- */ if(*a**x == 0.0e0) goto S120; if(*a == 0.5e0) goto S100; if(*x < 1.1e0) goto S10; goto S60; S10: /* TAYLOR SERIES FOR P(A,X)/X**A */ an = 3.0e0; c = *x; sum = *x/(*a+3.0e0); tol = 0.1e0**eps/(*a+1.0e0); S20: an += 1.0e0; c = -(c*(*x/an)); t = c/(*a+an); sum += t; if(fabs(t) > tol) goto S20; j = *a**x*((sum/6.0e0-0.5e0/(*a+2.0e0))**x+1.0e0/(*a+1.0e0)); z = *a*log(*x); h = gam1(a); g = 1.0e0+h; if(*x < 0.25e0) goto S30; if(*a < *x/2.59e0) goto S50; goto S40; S30: if(z > -.13394e0) goto S50; S40: w = exp(z); *p = w*g*(0.5e0+(0.5e0-j)); *q = 0.5e0+(0.5e0-*p); return; S50: l = rexp(&z); w = 0.5e0+(0.5e0+l); *q = (w*j-l)*g-h; if(*q < 0.0e0) goto S90; *p = 0.5e0+(0.5e0-*q); return; S60: /* CONTINUED FRACTION EXPANSION */ a2nm1 = a2n = 1.0e0; b2nm1 = *x; b2n = *x+(1.0e0-*a); c = 1.0e0; S70: a2nm1 = *x*a2n+c*a2nm1; b2nm1 = *x*b2n+c*b2nm1; am0 = a2nm1/b2nm1; c += 1.0e0; cma = c-*a; a2n = a2nm1+cma*a2n; b2n = b2nm1+cma*b2n; an0 = a2n/b2n; if(fabs(an0-am0) >= *eps*an0) goto S70; *q = *r*an0; *p = 0.5e0+(0.5e0-*q); return; S80: /* SPECIAL CASES */ *p = 0.0e0; *q = 1.0e0; return; S90: *p = 1.0e0; *q = 0.0e0; return; S100: if(*x >= 0.25e0) goto S110; T1 = sqrt(*x); *p = erf1(&T1); *q = 0.5e0+(0.5e0-*p); return; S110: T3 = sqrt(*x); *q = erfc1(&K2,&T3); *p = 0.5e0+(0.5e0-*q); return; S120: if(*x <= *a) goto S80; goto S90; }