TPCCLIB
Loading...
Searching...
No Matches
interpolate.c File Reference

Linear interpolation and integration. More...

#include "tpcclibConfig.h"
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include <string.h>
#include "tpcextensions.h"
#include "tpcli.h"

Go to the source code of this file.

Functions

double liFirstStepSize (double *x, const int nr)
 Find the initial x step size.
unsigned int simSamples (double initStep, double maxStep, double endTime, int mode, double *x)
int liInterpolate (double *x, double *y, const int nr, double *newx, double *newy, double *newyi, double *newyii, const int newnr, const int se, const int ee, const int verbose)
 Linear interpolation and/or integration with trapezoidal method.
int liInterpolateForPET (double *x, double *y, const int nr, double *newx1, double *newx2, double *newy, double *newyi, double *newyii, const int newnr, const int se, const int ee, const int verbose)
 Linear TAC interpolation and/or integration to PET frames.

Detailed Description

Linear interpolation and integration.

Todo
Separate float version of this library, maybe lif.

Definition in file interpolate.c.

Function Documentation

◆ liFirstStepSize()

double liFirstStepSize ( double * x,
const int nr )

Find the initial x step size.

Author
Vesa Oikonen
Returns
the first x[i+1]-x[i] that is > 0, or x[last] if not found, or 0 if even that was not possible.
Parameters
xArray of x (time) values; must be sorted by ascending x, but consecutive points may have the same x. Negative x is accepted. Array must not contain NaNs.
nrNumber of samples in data.

Definition at line 25 of file interpolate.c.

32 {
33 int i;
34 double s, d;
35 if(nr<1 || x==NULL) return 0.0;
36 s=x[nr-1];
37 for(i=1; i<nr; i++) {
38 d=x[i]-x[i-1];
39 if(d>1.0E-20) {s=d; break;}
40 }
41 return s;
42}

Referenced by liInterpolate().

◆ liInterpolate()

int liInterpolate ( double * x,
double * y,
const int nr,
double * newx,
double * newy,
double * newyi,
double * newyii,
const int newnr,
const int se,
const int ee,
const int verbose )

Linear interpolation and/or integration with trapezoidal method.

PET data must be frequently sampled to get accurate results. AUC calculation is started from time 0 or first input sample time, whichever is smaller. Very simple data extrapolation can be optionally enabled. Results will be wrong if data contains NaNs. To get the same result as with interpolate() in the libtpcmodel, set se=3 and ee=1.

Author
Vesa Oikonen
Returns
0 if successful, otherwise >0.
See also
liInterpolateForPET, tacInterpolate, tacAUC
Todo
Compute tyi only if either of integrals is needed.
Parameters
xArray of input data x (time) values; obligatory. Data must be sorted by ascending x, but consecutive points may have the same x. Negative x is accepted, AUCs are then started from the first x, otherwise from 0. Array must not contain NaNs.
yArray of input data y (concentration) values; obligatory. Array must not contain NaNs.
nrNumber of samples in input data; obligatory.
newxArray of output data x values; obligatory. Must be in ascending order. Negative x is accepted. Array must not contain NaNs.
newyArray for interpolated (extrapolated) y values; NULL can be given if not needed.
newyiArray for integrals (AUCs); NULL can be given if not needed.
newyiiArrays for 2nd integrals; NULL can be given if not needed.
newnrNr of samples in output data; obligatory.
seExtrapolation setting for the start of data:
  • 0= assuming y=0 when newx<x[0]
  • 1= assuming y=y[0] when 0<=newx<x[0] and y=0 when newx<x[0]<0
  • 2= assuming y=0 when newx<=0 and x[0]>0, and y=newx*y[0]/x[0] when 0<newx<x[0] and y[0]>0
  • 3= same as '2' if 2*x[0]-x[1]<=0, otherwise same as '0'
  • 4= same as '2' if 2*x[0]-x[1]<=0, otherwise assuming y=0 when newx<=2*x[0]-x[1], and y=(newx-(2*x[0]-x[1]))*y[0]/x[0] when (2*x[0]-x[1])<newx<x[0] and y[0]>0.
eeExtrapolation setting for the end of data:
  • 0= assuming y=0 when newx>x[nr-1]
  • 1= assuming y=y[nr-1] when newx>x[nr-1]
verboseVerbose level; if zero, then nothing is printed to stderr or stdout

Definition at line 139 of file interpolate.c.

179 {
180 if(verbose>0) printf("%s(x, y, %d, nx, ny, ni, ni2, %d, %d, %d)\n", __func__, nr, newnr, se, ee);
181 /* Check for data */
182 if(nr<1 || newnr<1) return 1;
183 if(x==NULL || y==NULL || newx==NULL) return 1;
184
185 int i, j;
186 double ty, tyi, tyii;
187 double ox1, ox2, oy1, oy2, oi1, oi2, oii1, oii2, dt, ndt;
188
189 /* Initiate first two input samples */
190 if(se==0) {
191 if(x[0]<0.0) {ox1=ox2=x[0]; oy1=oy2=y[0];}
192 else {ox1=0.0; ox2=x[0]; oy1=0.0; oy2=0.0;}
193 } else if(se==1) {
194 if(x[0]<0.0) {ox1=ox2=x[0]; oy1=oy2=y[0];}
195 else {ox1=0.0; ox2=x[0]; oy1=oy2=y[0];}
196 } else {
197 ox1=ox2=x[0];
198 oy1=oy2=y[0];
199 }
200 /* Extrapolate the initial phase with triangle... */
201 if(ox1>0.0 && se>=2) {
202 oy1=0.0;
203 if(se==2) { // always
204 ox1=0.0;
205 } else if(se==3 && y[0]>0.0) { // if y[0]>0
206 // and initial gap is not too big
207 if(liFirstStepSize(x, nr)-x[0] >= 1.0E-20)
208 ox1=0.0;
209 } else if(se==4 && y[0]>0.0) { // if y[0]>0
210 // if initial gap is not too big, start triangle from zero
211 if(liFirstStepSize(x, nr)-x[0] >= 1.0E-20)
212 ox1=0.0;
213 else
214 // otherwise start triangle from guessed zero sample
215 ox1=x[0]-liFirstStepSize(x, nr);
216 }
217 }
218
219 /* Integrals too */
220 oi1=oii1=0.0;
221 oi2=oi1 + (ox2-ox1)*(oy1+oy2)/2.0;
222 oii2=oii1 + (ox2-ox1)*(oi1+oi2)/2.0;
223 if(verbose>1) {
224 printf("ox1=%g oy1=%g oi1=%g oii1=%g\n", ox1, oy1, oi1, oii1);
225 printf("ox2=%g oy2=%g oi2=%g oii2=%g\n", ox2, oy2, oi2, oii2);
226 }
227
228 /* Set interpolated data before input data (even imaginary) to zero */
229 if(verbose>2) printf("before input start\n");
230 j=0; while(j<newnr && newx[j]<ox1) {
231 ty=tyi=tyii=0.0; if(verbose>2) printf(" ndt=%g\n", ox1-newx[j]);
232 if(verbose>2) printf(" j=%d newx=%g ty=%g tyi=%g tyii=%g\n", j, newx[j], ty, tyi, tyii);
233 if(newy!=NULL) newy[j]=ty;
234 if(newyi!=NULL) newyi[j]=tyi;
235 if(newyii!=NULL) newyii[j]=tyii;
236 j++;
237 }
238
239 /* Set interpolated data between ox1 and ox2 */
240 if(verbose>2) printf("before input start #2\n");
241// dt=ox2-ox1; if(dt>0.0) while(j<newnr && newx[j]<=ox2) {
242 dt=ox2-ox1; if(dt>0.0) while(j<newnr && newx[j]<ox2) {
243 ndt=newx[j]-ox1; if(verbose>2) printf(" ndt=%g\n", ndt);
244 ty=((oy2-oy1)/dt)*ndt + oy1; if(newy!=NULL) newy[j]=ty;
245 tyi=oi1 + 0.5*(ty+oy1)*ndt; if(newyi!=NULL) newyi[j]=tyi;
246 if(newyii!=NULL) newyii[j]=tyii= oii1 + 0.5*(tyi+oi1)*ndt;
247 if(verbose>2) printf(" j=%d newx=%g ty=%g tyi=%g tyii=%g\n", j, newx[j], ty, tyi, tyii);
248 j++;
249 }
250
251 /* Go through input data, sample-by-sample */
252 if(verbose>2) printf("inside input range\n");
253 for(i=0; i<nr && j<newnr; i++) {
254
255 ox1=ox2; oy1=oy2; oi1=oi2; oii1=oii2;
256 ox2=x[i]; oy2=y[i];
257 oi2=oi1 + (ox2-ox1)*(oy1+oy2)/2.0;
258 oii2=oii1 + (ox2-ox1)*(oi1+oi2)/2.0;
259 if(verbose>2) {
260 printf("ox1=%g oy1=%g oi1=%g oii1=%g\n", ox1, oy1, oi1, oii1);
261 printf("ox2=%g oy2=%g oi2=%g oii2=%g\n", ox2, oy2, oi2, oii2);
262 }
263
264 /* Calculate input sample distance */
265 dt=ox2-ox1; if(dt<0.0) return 3; else if(dt==0.0) continue;
266
267 /* Any need for interpolation between ox1 and ox2? */
268 while(j<newnr && newx[j]<=ox2) {
269 ndt=newx[j]-ox1;
270 ty=((oy2-oy1)/dt)*ndt + oy1; if(newy!=NULL) newy[j]=ty;
271 tyi=oi1 + 0.5*(ty+oy1)*ndt; if(newyi!=NULL) newyi[j]=tyi;
272 if(newyii!=NULL) newyii[j]=tyii= oii1 + 0.5*(tyi+oi1)*ndt;
273 if(verbose>4)
274 printf(" j=%d newx=%g ndt=%g ty=%g tyi=%g tyii=%g\n", j, newx[j], ndt, ty, tyi, tyii);
275 j++;
276 }
277
278 } // next input sample
279
280 /* Set interpolated data after input data, assuming zero or steady input */
281 if(verbose>2) printf("after input range\n");
282 while(j<newnr) {
283 ndt=newx[j]-ox2;
284 if(ee==0) ty=0.0; else ty=oy2;
285 if(ee==0) tyi=oi2; else tyi=oi2 + oy2*ndt;
286 tyii=oii2 + 0.5*(tyi+oi2)*ndt;
287 if(newy!=NULL) newy[j]=ty;
288 if(newyi!=NULL) newyi[j]=tyi;
289 if(newyii!=NULL) newyii[j]=tyii;
290 if(verbose>4) printf(" j=%d newx=%g ty=%g tyi=%g tyii=%g\n", j, newx[j], ty, tyi, tyii);
291 j++;
292 }
293
294 if(verbose>3) printf("%s() ready\n", __func__);
295 return 0;
296}
double liFirstStepSize(double *x, const int nr)
Find the initial x step size.
Definition interpolate.c:25

Referenced by bfm1TCM(), liInterpolateForPET(), tacAUC(), tacDelay(), tacDelayCMFit(), tacInput2sim(), tacInterpolate(), and tacInterpolateInto().

◆ liInterpolateForPET()

int liInterpolateForPET ( double * x,
double * y,
const int nr,
double * newx1,
double * newx2,
double * newy,
double * newyi,
double * newyii,
const int newnr,
const int se,
const int ee,
const int verbose )

Linear TAC interpolation and/or integration to PET frames.

PET data must be frequently sampled to get accurate results. AUC calculation is started from time 0 or first input sample time, whichever is smaller. Original data and new x values must be sorted by ascending x. Subsequent x values can have equal values, enabling the use of step functions. PET frames can overlap, but interpolation may then be slower. Negative x (time) values can be processed. Results will be wrong if data contains NaNs. Very simple data extrapolation can be optionally enabled. To get the same result as with interpolate4pet() in the libtpcmodel, set se=3 and ee=1.

Author
Vesa Oikonen
See also
liInterpolate(), liIntegratePET(), tacInterpolateInto, tacInterpolate, tacAUC
Returns
0 if successful, otherwise >0.
Parameters
xArray of input data x (time) values; obligatory. Data must be sorted by ascending x, but consecutive points may have the same x. Negative x is accepted, AUCs are then started from the first x, otherwise from 0.
yArray of input data y (concentration) values; obligatory.
nrNumber of samples in input data; obligatory.
newx1Array of PET frame start times for output data; obligatory. Must be in ascending order. Negative times are accepted.
newx2Array of PET frame end times for output data; obligatory. Must be in ascending order. Negative times are accepted, but frame duration (x2-x1) must be >=0.
newyArray for mean concentration values for each PET frame; NULL can be given if not needed.
newyiArray for integrals (AUCs) at frame middle times; NULL can be given if not needed.
newyiiArrays for 2nd integrals at frame middle times; NULL can be given if not needed.
newnrNr of samples in output data; obligatory.
seExtrapolation setting for the start of data:
  • 0= assuming y=0 when newx<x[0]
  • 1= assuming y=y[0] when 0<=newx<x[0] and y=0 when newx<x[0]<0
  • 2= assuming y=0 when newx<=0 and x[0]>0, and y=newx*y[0]/x[0] when 0<newx<x[0] and y[0]>0
  • 3= same as '2' if 2*x[0]-x[1]<=0, otherwise same as '0'
  • 4= same as '2' if 2*x[0]-x[1]<=0, otherwise assuming y=0 when newx<=2*x[0]-x[1], and y=(newx-(2*x[0]-x[1]))*y[0]/x[0] when (2*x[0]-x[1])<newx<x[0] and y[0]>0.
eeExtrapolation setting for the end of data:
  • 0= assuming y=0 when newx>x[nr-1]
  • 1= assuming y=y[nr-1] when newx>x[nr-1]
verboseVerbose level; if zero, then nothing is printed to stderr or stdout.

Definition at line 317 of file interpolate.c.

361 {
362 if(verbose>0)
363 printf("%s(x, y, %d, nx1, nx2, ny, ni, ni2, %d, %d, %d)\n", __func__, nr, newnr, se, ee);
364
365 /* Check for data */
366 if(nr<1 || newnr<1) return 1;
367 if(x==NULL || y==NULL || newx1==NULL || newx2==NULL) return 1;
368 /* Check that input data is not totally outside the input data */
369 if(newx2[newnr-1]<=x[0] || newx1[0]>=x[nr-1]) return 3;
370
371 /* Nothing to do if output arrays were not given */
372 if(newy==NULL && newyi==NULL && newyii==NULL) return 0;
373
374 int ret, fi, zeroframe=0, overlap=0;
375 double fdur;
376
377 /* Check frame lengths, also for overlap and zero length frames */
378 for(fi=0; fi<newnr; fi++) {
379 /* Calculate frame length */
380 fdur=newx2[fi]-newx1[fi];
381 /* If frame length is <0, that is an error */
382 if(fdur<0.0) return 4;
383 if(fdur==0.0) zeroframe++;
384 /* Overlap? */
385 if(fi>0 && newx2[fi-1]>newx1[fi]) overlap++;
386 }
387 if(verbose>2) {
388 printf("overlap := %d\n", overlap);
389 printf("zeroframe := %d\n", zeroframe);
390 }
391
392 /* Interpolate and integrate one frame at a time, if:
393 -there are overlapping frames
394 -there are frames of zero length
395 -only few interpolated frames
396 -if frame mean values are not needed
397 */
398
399 if(overlap>0 || zeroframe>0 || newnr<=3 || newy==NULL )
400 {
401 double petx[3], pety[3], petyi[3], petyii[3];
402
403 if(verbose>1) printf("frame-by-frame interpolation/integration\n");
404 for(fi=0; fi<newnr; fi++) {
405 /* Set frame start, middle and end times */
406 petx[0]=newx1[fi]; petx[2]=newx2[fi]; petx[1]=0.5*(petx[0]+petx[2]);
407 /* Calculate frame length */
408 fdur=petx[2]-petx[0];
409 /* If frame length is <0, that is an error */
410 if(fdur<0.0) return 4;
411 /* If frame length is 0, then use direct interpolation */
412 if(fdur==0.0) {
413 ret=liInterpolate(x, y, nr, petx, pety, petyi, petyii, 1, se, ee, verbose-1);
414 if(ret) return 10+ret;
415 if(newy!=NULL) newy[fi]=petyi[0];
416 if(newyi!=NULL) newyi[fi]=petyi[0];
417 if(newyii!=NULL) newyii[fi]=petyii[0];
418 continue;
419 }
420 /* Calculate integrals at frame start, middle, and end */
421 ret=liInterpolate(x, y, nr, petx, NULL, petyi, petyii, 3, se, ee, verbose-1);
422 if(ret) return 20+ret;
423 /* Set output integrals, if required */
424 if(newyi!=NULL) newyi[fi]=petyi[1];
425 if(newyii!=NULL) newyii[fi]=petyii[1];
426 /* Calculate frame mean, if required */
427 if(newy!=NULL) newy[fi]=(petyi[2]-petyi[0])/fdur;
428 } // next frame
429
430 } else {
431
432 if(verbose>1) printf("all-frames-at-once interpolation/integration\n");
433 /* Set temp array */
434 double *tp=NULL; tp=malloc(newnr*sizeof(double)); if(tp==NULL) return 7;
435 /* Integrate at frame start times */
436 ret=liInterpolate(x, y, nr, newx1, NULL, tp, NULL, newnr, se, ee, verbose-1);
437 if(ret) {free(tp); return 10+ret;}
438 /* Integrate at frame end times */
439 ret=liInterpolate(x, y, nr, newx2, NULL, newy, NULL, newnr, se, ee, verbose-1);
440 if(ret) {free(tp); return 10+ret;}
441 /* Calculate average frame value */
442 for(fi=0; fi<newnr; fi++)
443 newy[fi]=(newy[fi]-tp[fi])/(newx2[fi]-newx1[fi]);
444 /* Calculate integrals */
445 if(newyi!=NULL || newyii!=NULL) {
446 for(fi=0; fi<newnr; fi++) tp[fi]=0.5*(newx2[fi]+newx1[fi]);
447 ret=liInterpolate(x, y, nr, tp, NULL, newyi, newyii, newnr, se, ee, verbose-1);
448 if(ret) {free(tp); return 10+ret;}
449 }
450 free(tp);
451 }
452
453 if(verbose>1) printf("%s() ready\n", __func__);
454
455
456 return 0;
457}
int liInterpolate(double *x, double *y, const int nr, double *newx, double *newy, double *newyi, double *newyii, const int newnr, const int se, const int ee, const int verbose)
Linear interpolation and/or integration with trapezoidal method.

Referenced by bfm1TCM(), tacDelay(), tacDelayCMFit(), tacInterpolate(), tacInterpolateInto(), and tacInterpolateToEqualLengthFrames().

◆ simSamples()

unsigned int simSamples ( double initStep,
double maxStep,
double endTime,
int mode,
double * x )

Create sample times with more frequent sampling in the beginning.

Returns
Returns the number of samples.
See also
liInterpolate, liInterpolateForPET, simC1, simBTAC
Parameters
initStepInitial sampling frequency.
maxStepMaximal sampling frequency which is never exceeded; enter 0 to set it automatically.
endTimeEnd time; last sample will usually be later.
modeSampling scheme:
  • Mode 0: 1s, 2s, 3s, 4s, ...
  • Mode 1: 10 x s, 5 x 2s, 2 x 5s, s*=10, ...
  • Mode 2: 20 x s, 10 x 2s, 5 x 5s, s*=10, ...
xAllocated array for the samples; NULL if only computing the number of samples.

Definition at line 50 of file interpolate.c.

65 {
66 unsigned int n=0;
67 if(initStep<=0.0 || endTime<=0.0 || endTime<initStep) return(n);
68 if(maxStep<initStep) maxStep=endTime;
69
70 double x1=0.0, s=initStep;
71 if(mode==0) {
72 while(x1<endTime) {
73 if(x!=NULL) x[n]=x1;
74 x1+=s; n++;
75 }
76 if(x!=NULL) x[n]=x1;
77 n++;
78 } else if(mode==1) {
79 while(x1<endTime) {
80 for(int i=0; i<10 && x1<endTime; i++, n++) {
81 if(x!=NULL) x[n]=x1;
82 x1+=s;
83 }
84 s*=2.0; if(s>maxStep) s=maxStep;
85 for(int i=0; i<5 && x1<endTime; i++, n++) {
86 if(x!=NULL) x[n]=x1;
87 x1+=s;
88 }
89 s*=2.5; if(s>maxStep) s=maxStep;
90 for(int i=0; i<2 && x1<endTime; i++, n++) {
91 if(x!=NULL) x[n]=x1;
92 x1+=s;
93 }
94 s*=2.0; if(s>maxStep) s=maxStep;
95 }
96 if(x!=NULL) x[n]=x1;
97 n++;
98 } else if(mode==2) {
99 while(x1<endTime) {
100 for(int i=0; i<20 && x1<endTime; i++, n++) {
101 if(x!=NULL) x[n]=x1;
102 x1+=s;
103 }
104 s*=2.0; if(s>maxStep) s=maxStep;
105 for(int i=0; i<10 && x1<endTime; i++, n++) {
106 if(x!=NULL) x[n]=x1;
107 x1+=s;
108 }
109 s*=2.5; if(s>maxStep) s=maxStep;
110 for(int i=0; i<5 && x1<endTime; i++, n++) {
111 if(x!=NULL) x[n]=x1;
112 x1+=s;
113 }
114 s*=2.0; if(s>maxStep) s=maxStep;
115 }
116 if(x!=NULL) x[n]=x1;
117 n++;
118 }
119 return(n);
120}