Mercurial > hg > ltpda
diff m-toolbox/test/new_ltf_code/ltf_plan.c @ 0:f0afece42f48
Import.
author | Daniele Nicolodi <nicolodi@science.unitn.it> |
---|---|
date | Wed, 23 Nov 2011 19:22:13 +0100 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/m-toolbox/test/new_ltf_code/ltf_plan.c Wed Nov 23 19:22:13 2011 +0100 @@ -0,0 +1,419 @@ + +/* + +indent ltf_plan.c && \ +gcc -g -O9 -ffast-math -Wconversion -Wall -W -o ltf_plan ltf_plan.c -lm && \ +./ltf_plan > plan.tex + +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <math.h> +#include <assert.h> +#include <complex.h> + +#define TEX 0 + +struct ltf_plan_one_t +{ + double f; /* frequency at bin center [Hz] */ + double fres; /* frequency resolution (bin width) [Hz] */ + double bin; /* bin number (possibly non-integer) */ + unsigned dftlen; /* length of one DFT segment */ + unsigned nseg; /* number of DFT segments */ + unsigned *segstart; /* starting position of each of the nseg segments */ +}; +typedef struct ltf_plan_one_t ltf_plan_one; + +struct ltf_plan_t +{ +/* copy of input data */ + unsigned ndata; /* total number of input data */ + double fsamp; /* sampling frequency [Hz] */ + double ovlap; /* window overlap in % */ + double binmin; /* smallest bin-number to use */ + unsigned mindftlen; /* minimum length of one segment */ + unsigned freqdes; /* desired number of frequencies */ + unsigned avgdes; /* desired number of averages */ + +/* scheduler results */ + unsigned nfreq; /* final number of frequencies */ + unsigned maxdftlen; /* maximal length of one DFT segment */ + unsigned maxnseg; /* maximal number of averages */ + ltf_plan_one *fplan; /* detailed plan for each of nfreq frequencies */ +}; +typedef struct ltf_plan_t ltf_plan; + +void +gerror (const char *err) +{ + fprintf (stderr, "\n*** Error: %s\n", err); + exit (1); +} + +int +myround (double x) +{ + return ((int) (floor (x + 0.5))); +} + + +void +ltf_plan_alloc (ltf_plan * p, unsigned size) +{ + char err[160]; + + p->fplan = realloc (p->fplan, size * sizeof (ltf_plan_one)); + + if (p->fplan == NULL) + { + sprintf (err, + "ltf_plan: error in allocating %u*%u=%u bytes for p.fplan", + size, sizeof (ltf_plan_one), size * sizeof (ltf_plan_one)); + gerror (err); + } +} + +ltf_plan +plan (unsigned ndata, double fsamp, double ovlap, double binmin, + unsigned mindftlen, unsigned freqdes, unsigned avgdes, + unsigned getsegstart) +{ + ltf_plan p; + ltf_plan_one *p1; + double fmin, fmax, fres, f; + unsigned j, k, dftlen, segstartpos; + double bin; + unsigned nseg; + double xov; + double freslim, fresmin; + unsigned nalloc; + char err[160]; + double logfact; + unsigned nsegstart; /* number of segstart entries */ + unsigned *segstartmemory; /* begin of segstart entries */ + double segincr; + + if (ndata < 500) + { + sprintf (err, "ltf_plan: illegal value for ndata: %u<500", ndata); + gerror (err); + } + + if (ndata < 500) + { + sprintf (err, "ltf_plan: illegal value for ndata: %u<500", ndata); + gerror (err); + } + + if (fsamp <= 0) + { + sprintf (err, "ltf_plan: illegal value for fsamp: %g<=0", fsamp); + gerror (err); + } + + if (binmin < 0) + { + sprintf (err, "ltf_plan: illegal value for binmin: %g<0", binmin); + gerror (err); + } + + if (ovlap < 0) + { + sprintf (err, "ltf_plan: illegal value for ovlap: %g<=0", ovlap); + gerror (err); + } + + if (ovlap > 99) + { + sprintf (err, "ltf_plan: illegal value for ovlap: %g>99%%", ovlap); + gerror (err); + } + + if (freqdes < 3) + { + sprintf (err, "ltf_plan: illegal value for freqdes: %u<3", freqdes); + gerror (err); + } + + if (freqdes > ndata / 2) + { + sprintf (err, "ltf_plan: illegal value for freqdes: %u>%u", freqdes, + ndata / 2); + gerror (err); + } + + /* copy input data */ + p.ndata = ndata; + p.fsamp = fsamp; + p.ovlap = ovlap; + if (binmin < 1) + binmin = 1; + p.binmin = binmin; + p.mindftlen = mindftlen; + p.freqdes = freqdes; + p.avgdes = avgdes; + p.maxdftlen = p.maxnseg = 0; + nsegstart = 0; + + xov = (1. - ovlap / 100.); + fmin = fsamp / ndata * binmin; + fmax = fsamp / 2; + fresmin = fsamp / (double) ndata; /* absolute minimal allowed frequency resolution */ + freslim = fresmin * (1 + xov * (avgdes - 1)); /* limit above which fres leads to desired number of averages */ + logfact = (pow (ndata / 2., 1. / freqdes) - 1.); + + /* initial allocation */ + p.fplan = NULL; + nalloc = freqdes; + ltf_plan_alloc (&p, nalloc); + + for (j = 0, f = fmin; f < fmax; j++) + { + if (j >= nalloc) + { + /* enlarge allocation */ + nalloc *= 2; + ltf_plan_alloc (&p, nalloc); + } + + p1 = &(p.fplan[j]); + + fres = f * logfact; + fres = (fres > freslim) ? fres : sqrt (fres * freslim); + if (fres < fresmin) + fres = fresmin; + + bin = (f / fres); + if (bin < binmin) + { + bin = binmin; + fres = f / bin; + } + + dftlen = myround (fsamp / fres); + if (dftlen > ndata) + dftlen = ndata; + if (dftlen < mindftlen) + dftlen = mindftlen; + nseg = myround (((double) (ndata - dftlen) / + (xov * (double) dftlen)) + 1); + if (nseg == 1) + dftlen = ndata; + + fres = fsamp / dftlen; + bin = f / fres; + + p1->f = f; + p1->fres = fres; + p1->bin = bin; + p1->dftlen = dftlen; + p1->nseg = nseg; + if (nseg > p.maxnseg) + p.maxnseg = nseg; + nsegstart += nseg; + if (dftlen > p.maxdftlen) + p.maxdftlen = dftlen; + f += fres; + } + p.nfreq = j; + /* allocation shrink to fit */ + nalloc = p.nfreq; + ltf_plan_alloc (&p, nalloc); + + /* determine starting indices of DFT segments */ + if (!getsegstart) + { + for (j = 0; j < p.nfreq; j++) + p.fplan[j].segstart = NULL; + } + else + { + segstartmemory = malloc (nsegstart * sizeof (unsigned)); + if (segstartmemory == NULL) + { + sprintf (err, + "ltf_plan: error allocating %u bytes for segment start indices", + nsegstart * sizeof (unsigned)); + gerror (err); + } + segstartpos = 0; + for (j = 0; j < p.nfreq; j++) + { + p1 = &(p.fplan[j]); + p1->segstart = &(segstartmemory[segstartpos]); + p1->segstart[0] = 0; + if (p1->nseg > 1) + { + segincr = + (double) (ndata - p1->dftlen) / (double) (p1->nseg - 1); + for (k = 1; k < p1->nseg - 1; k++) + p1->segstart[k] = myround ((double) k * segincr); + p1->segstart[p1->nseg - 1] = ndata - p1->dftlen; + } + segstartpos += p1->nseg; + } + } + return p; +} + +void +ltf_plan_free (ltf_plan p) +{ + if ((p.fplan[0]).segstart != NULL) + free ((p.fplan[0]).segstart); + free (p.fplan); +} + +void +fprint (double f, char *s) +{ + if (f < 1e-5) + sprintf (s, "%.3f$\\mu$", 1e6 * f); + else if (f < 1e-4) + sprintf (s, "%.2f$\\mu$", 1e6 * f); + else if (f < 1e-3) + sprintf (s, "%.1f$\\mu$", 1e6 * f); + else if (f < 1e-2) + sprintf (s, "%.3fm", 1e3 * f); + else if (f < 1e-1) + sprintf (s, "%.2fm", 1e3 * f); + else if (f < 1) + sprintf (s, "%.1fm", 1e3 * f); + else + sprintf (s, "%.3f", f); +} + +int +main (void) +{ + ltf_plan p; + ltf_plan_one *p1; + unsigned ndata = 1000000; + double fsamp = 10.; + double ovlap = 75; + double binmin = 5.3; + unsigned mindftlen = 100; + unsigned freqdes = 200; + unsigned avgdes = 100; + unsigned j, k; + double eq1, eq2; + double dfdown, dfup; + double logfact, logres; + + logfact = (pow (ndata / 2., 1. / freqdes) - 1.); + + p = plan (ndata, fsamp, ovlap, binmin, mindftlen, freqdes, avgdes, 1); + + if (TEX) + { + + printf ("\\section{Sample output}\n"); + printf + ("As reference for other implementations, here are the results for the case\\\\\n"); + printf ("$N_{\\rm data}$ ({\\tt ndata}) $=%d$\\\\\n", ndata); + printf ("$f_{\\rm samp}$ ({\\tt fsamp}) $=%g$\\,Hz\\\\\n", fsamp); + printf ("$\\xi_{\\rm ovlap}$ ({\\tt ovlap}) $=%g$\\,\\%%\\\\\n", ovlap); + printf ("$b_{\\rm min}$ ({\\tt binmin}) $=%g$\\\\\n", binmin); + printf ("$L_{\\rm min}$ ({\\tt mindftlen}) $=%d$\\\\\n", mindftlen); + printf ("$J_{\\rm des}$ ({\\tt freqdes}) $=%d$\\\\\n", freqdes); + printf ("$K_{\\rm des}$ ({\\tt avgdes}) $=%d$\n", avgdes); + printf ("\n"); + printf + ("Usually, $J_{\\rm des}$ ({\\tt freqdes}) will be chosen higher (1000\ + is a typical value); %d has been chosen here to save space in the\ + printed table.\n", + freqdes); + printf ("\n"); + printf + ("Targets that are not met are printed {\\bfseries \\slshape like this}\n"); + printf ("\n"); + + printf ("\\small{\n"); + printf + ("\\tablehead{$j$ & $f_j$ & $r_j$ & $b_j$ & $K_j$ & $L_j$ & $\\frac{f_j-f_{j-1}}{r_j}$ & $\\frac{f_{j+1}-f_j}{r_j}$ & $\\frac{r_j}{c\\cdot f_j}$ & $q_k^{(j)}$\\\\\\hline}\n"); + printf ("\\begin{supertabular}{|r|r|r|r|r|r|r|r|r|l|}\n"); + } + + for (j = 0; j < p.nfreq; j++) + { + p1 = &(p.fplan[j]); + + /* check required relations */ + eq1 = p1->f - p1->fres * p1->bin; + assert (fabs (eq1 / p1->f) < 1e-10); + eq2 = p.fsamp - p1->fres * p1->dftlen; + assert (fabs (eq2 / p.fsamp) < 1e-10); + + if (j > 0) + dfdown = p.fplan[j].f - p.fplan[j - 1].f; + else + dfdown = 0; + if (j < p.nfreq - 1) + dfup = p.fplan[j + 1].f - p.fplan[j].f; + else + dfup = 0; + logres = p1->fres / (p1->f * logfact); + + if (TEX) + { + char sf[80], sfres[80], snseg[80], sdown[80], sup[80], slogres[80]; + fprint (p1->f, sf); + fprint (p1->fres, sfres); + if (p1->nseg < avgdes) + sprintf (snseg, "{\\bfseries \\slshape %7d}", p1->nseg); + else + sprintf (snseg, "%7d", p1->nseg); + if (j > 0) + sprintf (sdown, "%.3f", dfdown / p1->fres); + else + sprintf (sdown, "---"); + if (j < p.nfreq - 1) + sprintf (sup, "%.3f", dfup / p1->fres); + else + sprintf (sup, "---"); + if (logres < .995 || logres > 1.005) + sprintf (slogres, "{\\bfseries \\slshape %.3f}", logres); + else + sprintf (slogres, "%.3f", logres); + printf + ("%4d & %s & %s & %.2f & %s & %7d & %s & %s & %s & ", + j, sf, sfres, p1->bin, snseg, p1->dftlen, sdown, sup, slogres); + } + else + { + printf ("%4d %20.20f %20.20f %20.20f %20d %20d %20.20f %20.20f %20.20f ", j, + p1->f, p1->fres, p1->bin, p1->nseg, p1->dftlen, + dfdown / p1->fres, dfup / p1->fres, logres); + } + if (p1->segstart != NULL) + { +// if (p1->nseg < 5) +// { +// for (k = 0; k < p1->nseg; k++) +// printf ("%u ", p1->segstart[k]); +// printf ("\\\\\n"); +// } +// else +// { +// printf ("%u %u %u ... %u\\\\\n", +// p1->segstart[0], +// p1->segstart[1], p1->segstart[2], +// p1->segstart[p1->nseg - 1]); +// } + printf("\n"); + assert (p1->segstart[p1->nseg - 1] + p1->dftlen == ndata); + } + else + printf (" (NULL)\n"); + } + if (TEX) + { + printf ("\\end{supertabular}}\n"); + } +// else +// printf ("% max. %u segments %u dftlen\n", p.maxnseg, p.maxdftlen); + ltf_plan_free (p); + return 0; +}