This is Unofficial EPICS BASE Doxygen Site
makeBpt.c
Go to the documentation of this file.
1 /*************************************************************************\
2 * Copyright (c) 2002 The University of Chicago, as Operator of Argonne
3 * National Laboratory.
4 * Copyright (c) 2002 The Regents of the University of California, as
5 * Operator of Los Alamos National Laboratory.
6 * EPICS BASE Versions 3.13.7
7 * and higher are distributed subject to a Software License Agreement found
8 * in file LICENSE that is included with this distribution.
9 \*************************************************************************/
10 /*
11  * Author: Marty Kraimer
12  * Date: 9/28/95
13  * Replacement for old bldCvtTable
14  */
15 
16 #include <stdlib.h>
17 #include <stddef.h>
18 #include <stdio.h>
19 #include <errno.h>
20 #include <string.h>
21 #include <ctype.h>
22 
23 #include "dbDefs.h"
24 #include "ellLib.h"
25 #include "cvtTable.h"
26 
27 #define MAX_LINE_SIZE 160
28 #define MAX_BREAKS 100
29 struct brkCreateInfo {
30  double engLow; /* Lowest value desired: engineering units */
31  double engHigh; /* Highest value desired: engineering units */
32  double rawLow; /* Raw value for EngLow */
33  double rawHigh; /* Raw value for EngHigh */
34  double accuracy; /* accuracy desired in engineering units */
35  double tblEngFirst; /* First table value: engineering units */
36  double tblEngLast; /* Last table value: engineering units */
37  double tblEngDelta; /* Change per table entry: eng units */
38  long nTable; /* number of table entries */
39  /* (last-first)/delta + 1 */
40  double *pTable; /* addr of data table */
42 
43 typedef struct brkInt { /* breakpoint interval */
44  double raw; /* raw value for beginning of interval */
45  double slope; /* slope for interval */
46  double eng; /* converted value for beginning of interval */
47 } brkInt;
48 
50 
51 static int create_break(struct brkCreateInfo *pbci, brkInt *pabrkInt,
52  int max_breaks, int *n_breaks);
53 static char inbuf[MAX_LINE_SIZE];
54 static int linenum=0;
55 
56 typedef struct dataList{
57  struct dataList *next;
58  double value;
59 }dataList;
60 
61 static int getNumber(char **pbeg, double *value)
62 {
63  int nchars=0;
64 
65  while(isspace((int)**pbeg) && **pbeg!= '\0') (*pbeg)++;
66  if(**pbeg == '!' || **pbeg == '\0') return(-1);
67  if(sscanf(*pbeg,"%lf%n",value,&nchars)!=1) return(-1);
68  *pbeg += nchars;
69  return(0);
70 }
71 
72 static void errExit(char *pmessage)
73 {
74  fprintf(stderr, "%s\n", pmessage);
75  fflush(stderr);
76  exit(-1);
77 }
78 
79 int main(int argc, char **argv)
80 {
81  char *pbeg;
82  char *pend;
83  double value;
84  char *pname = NULL;
85  dataList *phead;
86  dataList *pdataList;
87  dataList *pnext;
88  double *pdata;
89  long ndata;
90  int nBreak,n;
91  size_t len;
92  char *outFilename;
93  char *pext;
94  FILE *outFile;
95  FILE *inFile;
96  char *plastSlash;
97 
98 
99  if(argc<2) {
100  fprintf(stderr,"usage: makeBpt file.data [outfile]\n");
101  exit(-1);
102  }
103  if (argc==2) {
104  plastSlash = strrchr(argv[1],'/');
105  plastSlash = (plastSlash ? plastSlash+1 : argv[1]);
106  outFilename = calloc(1,strlen(plastSlash)+2);
107  if(!outFilename) {
108  fprintf(stderr,"calloc failed\n");
109  exit(-1);
110  }
111  strcpy(outFilename,plastSlash);
112  pext = strstr(outFilename,".data");
113  if(!pext) {
114  fprintf(stderr,"Input file MUST have .data extension\n");
115  exit(-1);
116  }
117  strcpy(pext,".dbd");
118  } else {
119  outFilename = calloc(1,strlen(argv[2])+1);
120  if(!outFilename) {
121  fprintf(stderr,"calloc failed\n");
122  exit(-1);
123  }
124  strcpy(outFilename,argv[2]);
125  }
126  inFile = fopen(argv[1],"r");
127  if(!inFile) {
128  fprintf(stderr,"Error opening %s\n",argv[1]);
129  exit(-1);
130  }
131  outFile = fopen(outFilename,"w");
132  if(!outFile) {
133  fprintf(stderr,"Error opening %s\n",outFilename);
134  exit(-1);
135  }
136  while(fgets(inbuf,MAX_LINE_SIZE,inFile)) {
137  linenum++;
138  pbeg = inbuf;
139  while(isspace((int)*pbeg) && *pbeg!= '\0') pbeg++;
140  if(*pbeg == '!' || *pbeg == '\0') continue;
141  while(*pbeg!='"' && *pbeg!= '\0') pbeg++;
142  if(*pbeg!='"' ) errExit("Illegal Header");
143  pbeg++; pend = pbeg;
144  while(*pend!='"' && *pend!= '\0') pend++;
145  if(*pend!='"') errExit("Illegal Header");
146  len = pend - pbeg;
147  if(len<=1) errExit("Illegal Header");
148  pname = calloc(len+1,sizeof(char));
149  if(!pname) {
150  fprintf(stderr,"calloc failed while processing line %d\n",linenum);
151  exit(-1);
152  }
153  strncpy(pname,pbeg,len);
154  pname[len]='\0';
155  pbeg = pend + 1;
156  if(getNumber(&pbeg,&value)) errExit("Illegal Header");
158  if(getNumber(&pbeg,&value)) errExit("Illegal Header");
160  if(getNumber(&pbeg,&value)) errExit("Illegal Header");
162  if(getNumber(&pbeg,&value)) errExit("Illegal Header");
164  if(getNumber(&pbeg,&value)) errExit("Illegal Header");
166  if(getNumber(&pbeg,&value)) errExit("Illegal Header");
168  if(getNumber(&pbeg,&value)) errExit("Illegal Header");
170  if(getNumber(&pbeg,&value)) errExit("Illegal Header");
172  goto got_header;
173  }
174  errExit("Illegal Header");
175 got_header:
176  phead = pnext = 0;
177  ndata = 0;
178  errno = 0;
179  while(fgets(inbuf,MAX_LINE_SIZE,inFile)) {
180  double value;
181 
182  linenum++;
183  pbeg = inbuf;
184  while(!getNumber(&pbeg,&value)) {
185  ndata++;
186  pdataList = (dataList *)calloc(1,sizeof(dataList));
187  if(!pdataList) {
188  fprintf(stderr,"calloc failed (after header)"
189  " while processing line %d\n",linenum);
190  exit(-1);
191  }
192  if(!phead)
193  phead = pdataList;
194  else
195  pnext->next = pdataList;
196  pdataList->value = value;
197  pnext = pdataList;
198  }
199  }
200  if(!pname) {
201  errExit("create_break failed: no name specified\n");
202  }
203  brkCreateInfo.nTable = ndata;
204  pdata = (double *)calloc(brkCreateInfo.nTable,sizeof(double));
205  if(!pdata) {
206  fprintf(stderr,"calloc failed for table length %ld\n",brkCreateInfo.nTable);
207  exit(-1);
208  }
209  pnext = phead;
210  for(n=0; n<brkCreateInfo.nTable; n++) {
211  pdata[n] = pnext->value;
212  pdataList = pnext;
213  pnext = pnext->next;
214  free((void *)pdataList);
215  }
216  brkCreateInfo.pTable = pdata;
217  if(create_break(&brkCreateInfo,&brkint[0],MAX_BREAKS,&nBreak))
218  errExit("create_break failed\n");
219  fprintf(outFile,"breaktable(%s) {\n",pname);
220  for(n=0; n<nBreak; n++) {
221  fprintf(outFile,"\t%f %f\n",brkint[n].raw,brkint[n].eng);
222  }
223  fprintf(outFile,"}\n");
224  fclose(inFile);
225  fclose(outFile);
226  return(0);
227 }
228 
229 static int create_break( struct brkCreateInfo *pbci, brkInt *pabrkInt,
230  int max_breaks, int *n_breaks)
231 {
232  brkInt *pbrkInt;
233  double *table = pbci->pTable;
234  long ntable = pbci->nTable;
235  double ilow,
236  ihigh,
237  tbllow,
238  tblhigh,
239  slope,
240  offset;
241  int ibeg,
242  iend,
243  i,
244  inc,
245  imax,
246  n;
247  double rawBeg,
248  engBeg,
249  rawEnd,
250  engEnd,
251  engCalc,
252  engActual,
253  error;
254  int valid,
255  all_ok,
256  expanding;
257  /* make checks to ensure that brkCreateInfo makes sense */
258  if (pbci->engLow >= pbci->engHigh) {
259  errExit("create_break: engLow >= engHigh");
260  return (-1);
261  }
262  if ((pbci->engLow < pbci->tblEngFirst)
263  || (pbci->engHigh > pbci->tblEngLast)) {
264  errExit("create_break: engLow > engHigh");
265  return (-1);
266  }
267  if (pbci->tblEngDelta <= 0.0) {
268  errExit("create_break: tblEngDelta <= 0.0");
269  return (-1);
270  }
271  if (ntable < 3) {
272  errExit("raw data must have at least 3 elements");
273  return (-1);
274  }
275 /***************************************************************************
276  Convert Table to raw values
277  *
278  * raw and table values are assumed to be related by an equation of the form:
279  *
280  * raw = slope*table + offset
281  *
282  * The following algorithm converts each table value to raw units
283  *
284  * 1) Finds the locations in Table corresponding to engLow and engHigh
285  * Note that these locations need not be exact integers
286  * 2) Interpolates to obtain table values corresponding to engLow and enghigh
287  * we now have the equations:
288  * rawLow = slope*tblLow + offset
289  * rawHigh = slope*tblHigh + offset
290  * 4) Solving these equations for slope and offset gives:
291  * slope=(rawHigh-rawLow)/(tblHigh-tblLow)
292  * offset=rawHigh-slope*tblHigh
293  * 5) for each table value set table[i]=table[i]*slope+offset
294  *************************************************************************/
295  /* Find engLow in Table and then compute tblLow */
296  ilow = (pbci->engLow - pbci->tblEngFirst) / (pbci->tblEngDelta);
297  i = (int) ilow;
298  if (i >= ntable - 1)
299  i = ntable - 2;
300  tbllow = table[i] + (table[i + 1] - table[i]) * (ilow - (double) i);
301  /* Find engHigh in Table and then compute tblHigh */
302  ihigh = (pbci->engHigh - pbci->tblEngFirst) / (pbci->tblEngDelta);
303  i = (int) ihigh;
304  if (i >= ntable - 1)
305  i = ntable - 2;
306  tblhigh = table[i] + (table[i + 1] - table[i]) * (ihigh - (double) i);
307  /* compute slope and offset */
308  slope = (pbci->rawHigh - pbci->rawLow) / (tblhigh - tbllow);
309  offset = pbci->rawHigh - slope * tblhigh;
310  /* convert table to raw units */
311  for (i = 0; i < ntable; i++)
312  table[i] = table[i] * slope + offset;
313 
314 /*****************************************************************************
315  * Now create break point table
316  *
317  * The algorithm does the following:
318  *
319  * It finds one breakpoint interval at a time. For each it does the following:
320  *
321  * 1) Use a relatively large portion of the remaining table as an interval
322  * 2) It attempts to use the entire interval as a breakpoint interval
323  * Success is determined by the following algorithm:
324  * a) compute the slope using the entire interval
325  * b) for each table entry in the interval determine the eng value
326  * using the slope just determined.
327  * c) compare the computed value with eng value associated with table
328  * d) if all table entries are within the accuracy desired then success.
329  * 3) If successful then attempt to expand the interval and try again.
330  * Note that it is expanded by up to 1/10 of the table size.
331  * 4) If not successful reduce the interval by 1 and try again.
332  * Once the interval is being decreased it will never be increased again.
333  * 5) The algorithm will ultimately fail or will have determined the optimum
334  * breakpoint interval
335  *************************************************************************/
336 
337  /* Must start with table entry corresponding to engLow; */
338  i = (int) ilow;
339  if (i >= ntable - 1)
340  i = ntable - 2;
341  rawBeg = table[i] + (table[i + 1] - table[i]) * (ilow - (double) i);
342  engBeg = pbci->engLow;
343  ibeg = (int) (ilow); /* Make sure that ibeg > ilow */
344  if( ibeg < ilow ) ibeg = ibeg + 1;
345  /* start first breakpoint interval */
346  n = 1;
347  pbrkInt = pabrkInt;
348  pbrkInt->raw = rawBeg;
349  pbrkInt->eng = engBeg;
350  /* determine next breakpoint interval */
351  while ((engBeg <= pbci->engHigh) && (ibeg < ntable - 1)) {
352  /* determine next interval to try. Up to 1/10 full range */
353  rawEnd = rawBeg;
354  engEnd = engBeg;
355  iend = ibeg;
356  inc = (int) ((ihigh - ilow) / 10.0);
357  if (inc < 1)
358  inc = 1;
359  valid = TRUE;
360  /* keep trying intervals until cant do better */
361  expanding = TRUE; /* originally we are trying larger and larger
362  * intervals */
363  while (valid) {
364  imax = iend + inc;
365  if (imax >= ntable) {
366  /* don't go past end of table */
367  imax = ntable - 1;
368  inc = ntable - iend - 1;
369  expanding = FALSE;
370  }
371  if (imax > (int) (ihigh + 1.0)) { /* Don't go to far past
372  * engHigh */
373  imax = (int) (ihigh + 1.0);
374  inc = (int) (ihigh + 1.0) - iend;
375  expanding = FALSE;
376  }
377  if (imax <= ibeg)
378  break; /* failure */
379  rawEnd = table[imax];
380  engEnd = pbci->tblEngFirst + (double) imax *(pbci->tblEngDelta);
381  slope = (engEnd - engBeg) / (rawEnd - rawBeg);
382  all_ok = TRUE;
383  for (i = ibeg + 1; i <= imax; i++) {
384  engCalc = engBeg + slope * (table[i] - rawBeg);
385  engActual = pbci->tblEngFirst + ((double) i) * (pbci->tblEngDelta);
386  error = engCalc - engActual;
387  if (error < 0.0)
388  error = -error;
389  if (error >= pbci->accuracy) {
390  /* we will be trying smaller intervals */
391  expanding = FALSE;
392  /* just decrease inc and let while(valid) try again */
393  inc--;
394  all_ok = FALSE;
395  break;
396  }
397  } /* end for */
398  if (all_ok) {
399  iend = imax;
400  /* if not expanding we found interval */
401  if (!expanding)
402  break;
403  /* will automatically try larger interval */
404  }
405  } /* end while(valid) */
406  /* either we failed or optimal interval has been found */
407  if ((iend <= ibeg) && (iend < (int) ihigh)) {
408  errExit("Could not meet accuracy criteria");
409  return (-1);
410  }
411  pbrkInt->slope = slope;
412  /* get ready for next breakpoint interval */
413  if (n++ >= max_breaks) {
414  errExit("Break point table too large");
415  return (-1);
416  }
417  ibeg = iend;
418  pbrkInt++;
419  rawBeg = rawEnd;
420  engBeg = engEnd;
421  pbrkInt->raw = rawBeg;
422  pbrkInt->eng = engBeg + (pbrkInt->raw - rawBeg) * slope;
423  }
424  pbrkInt->slope = 0.0;
425  *n_breaks = n;
426  return (0);
427 }
double tblEngFirst
Definition: makeBpt.c:35
Definition: link.h:174
#define MAX_BREAKS
Definition: makeBpt.c:28
#define FALSE
Definition: dbDefs.h:32
struct brkInt brkInt
int i
Definition: scan.c:967
double tblEngDelta
Definition: makeBpt.c:37
double accuracy
Definition: makeBpt.c:34
double rawLow
Definition: makeBpt.c:32
long nTable
Definition: makeBpt.c:38
#define NULL
Definition: catime.c:38
Miscellaneous macro definitions.
#define MAX_LINE_SIZE
Definition: makeBpt.c:27
A doubly-linked list library.
double engHigh
Definition: makeBpt.c:31
double engLow
Definition: makeBpt.c:30
double rawHigh
Definition: makeBpt.c:33
double eng
Definition: makeBpt.c:46
struct brkCreateInfo brkCreateInfo
Definition: makeBpt.c:43
struct dataList * next
Definition: makeBpt.c:57
double value
Definition: makeBpt.c:58
#define TRUE
Definition: dbDefs.h:27
double * pTable
Definition: makeBpt.c:40
int main(int argc, char **argv)
Definition: makeBpt.c:79
#define stderr
Definition: epicsStdio.h:32
const std::string pname
double tblEngLast
Definition: makeBpt.c:36
struct dataList dataList
brkInt brkint[MAX_BREAKS]
Definition: makeBpt.c:49
double raw
Definition: makeBpt.c:44
double slope
Definition: makeBpt.c:45