/* psffilt.c ********************************************************************************
* psffilt.c -- Support routines to evaluate filter coefficients.
*
* User routines
* Pro_PSFFilter() returns coefficients of a filter based on a
* desired effective point spread function.
*
* Programmer routines
* XPro_PSFInfo() returns information about a point spread
* function.
* XPro_PSFInteg() returns the integral of the product of two point
* spread functions.
*
* NOTE: For most purposes, the absolute amplitude of the XPro_PSFInteg()
* integral is unimportant; what really matters is that its amplitude be correct
* relative to integrals calculated with alternative values of parameter b. By
* default, this function returns values that are unnormalized and so not
* necessarily correct in absolute amplitude. Re-compile this routine with the
* symbol ZPRO_NORMALIZED_INTEGRALS defined to produce properly normalized
* results.
*
* Mark Showalter, PDS Ring-Moon Systems Node, March 1998
*******************************************************************************/
#include <stdio.h>
#include <string.h>
#include <math.h>
#include "profile.h"
#include "fortran.h"
#ifndef M_PI
#define M_PI 3.141592653589793238462643
#endif
/**********************
* Internal constants *
**********************/
#define SINC_TYPE 1
#define BOXCAR_TYPE 2
#define TRIANGLE_TYPE 3
/********************************
* Internal function prototypes *
********************************/
static RL_FLT8 ZPro_SincSinc RL_PROTO((RL_FLT8 a, RL_FLT8 b,
RL_FLT8 s1, RL_FLT8 s2));
static RL_FLT8 ZPro_SincBox RL_PROTO((RL_FLT8 a, RL_FLT8 b,
RL_FLT8 s1, RL_FLT8 h2));
static RL_FLT8 ZPro_SincTri RL_PROTO((RL_FLT8 a, RL_FLT8 b,
RL_FLT8 s1, RL_FLT8 h2));
static RL_FLT8 ZPro_BoxSinc RL_PROTO((RL_FLT8 a, RL_FLT8 b,
RL_FLT8 h1, RL_FLT8 s2));
static RL_FLT8 ZPro_BoxBox RL_PROTO((RL_FLT8 a, RL_FLT8 b,
RL_FLT8 h1, RL_FLT8 h2));
static RL_FLT8 ZPro_BoxTri RL_PROTO((RL_FLT8 a, RL_FLT8 b,
RL_FLT8 h1, RL_FLT8 h2));
static RL_FLT8 ZPro_TriSinc RL_PROTO((RL_FLT8 a, RL_FLT8 b,
RL_FLT8 h1, RL_FLT8 s2));
static RL_FLT8 ZPro_TriBox RL_PROTO((RL_FLT8 a, RL_FLT8 b,
RL_FLT8 h1, RL_FLT8 h2));
static RL_FLT8 ZPro_TriTri RL_PROTO((RL_FLT8 a, RL_FLT8 b,
RL_FLT8 h1, RL_FLT8 h2));
static RL_FLT8 ZPro_LinLin RL_PROTO((RL_FLT8 xa1, RL_FLT8 ya1,
RL_FLT8 xa2, RL_FLT8 ya2,
RL_FLT8 xb1, RL_FLT8 yb1,
RL_FLT8 xb2, RL_FLT8 yb2));
static RL_FLT8 ZPro_Si RL_PROTO((RL_FLT8 x));
/*
********************************************************************************
* EXPORTED USER ROUTINES
********************************************************************************
*$ Component_name:
* Pro_PSFFilter (psffilt.c)
*$ Abstract:
* This function returns the set of filter coefficents needed to evaluate
* a sample in a series given its new point spread function (PSF), based on
* the original PSF and the transformation from old sample index to new.
*$ Keywords:
* PROFILE, FILTER
* C, PUBLIC, SUBROUTINE
*$ Declarations:
* RL_INT4 Pro_PSFFilter(oldpsf, newpsf, center, expand, filter,
* nfilter, f1, f2)
* PRO_OBJECT *oldpsf, *newpsf;
* RL_FLT8 center, expand, *filter;
* RL_INT4 nfilter, *f1, *f2;
*$ Inputs:
* oldpsf pointer to the PSF of the original series.
* newpsf pointer to the intended PSF of each new sample.
* center sample index in original series corresponding to
* midpoint of new PSF.
* expand expansion factor from original series sampling interval
* to new samples.
* nfilter size of filter array.
*$ Outputs:
* filter[] array of filter coefficients
* *f1,*f2 indices in original series corresponding to first and
* last filter coefficients returned.
*$ Returns:
* size of new filter, f2-f1+1, or 0 on error. If value > nfilter, then
* the array provided is too small so the coefficients are not returned.
*$ Detailed_description:
* This function returns the set of filter coefficents needed to evaluate
* a sample in a series given its new point spread function (PSF), based on
* the original PSF and the transformation from old sample index to new.
* Note that these weights are unnormalized.
*
* The x-axis of each PSF is assumed to be in units of the series sample
* index.
*$ External_references:
* Profile toolkit
*$ Side_effects:
* none
*$ Examples:
* This snippet of code makes a filter appropriate for filtering a series
* so that each new sample is the average of the three nearest samples in
* another series.
*
* PRO_OBJECT *oldpsf, *newpsf;
* RL_FLT8 filter[101], f1, f2;
*
* // Create unit-width boxcar functions
* oldpsf = Pro_BoxcarFunc(1., 0.5);
* newpsf = Pro_BoxcarFunc(1., 0.5);
*
* // Create filter for 3x expansion
* Pro_PSFFilter(oldpsf, newpsf, 0., 3., filter, 101, &f1, &f2)
*
* At this point, f1=-1, f2=1, and filter[0] = filter[1] = filter[2] != 0.
*$ Error_handling:
* Profile library error handling is in effect.
*
* Conditions raised:
* PRO_CLASS_ERROR if either PSF is NULL or is not one of the
* allowed function types.
* PRO_SETUP_FAILURE if the array is too small to hold all the
* necessary filter coefficients.
*$ Limitations:
* Only boxcar, triangle and sinc PSFs are supported.
*
* Coefficients when both PSFs are sinc functions are based on the
* assumption that both sinc functions have limited domains. This
* approximation is acceptable when the width of both sinc functions is at
* least several cycles.
*$ Author_and_institution:
* Mark R. Showalter
* NASA/Ames Research Center
*$ Version_and_date:
* 1.0: March 1998
*$ Change_history:
* none
*******************************************************************************/
RL_INT4 Pro_PSFFilter(oldpsf, newpsf, center, expand, filter, nfilter,
f1, f2)
PRO_OBJECT *oldpsf, *newpsf;
RL_FLT8 center, expand, *filter;
RL_INT4 nfilter, *f1, *f2;
{
RL_INT4 oldtype, newtype, fsize, n;
RL_FLT8 oldpar, oldhw, newpar, newhw, sumhw;
/* Extract PSF parameters */
oldtype = XPro_PSFInfo(oldpsf, &oldhw, &oldpar);
if (oldtype == 0) return 0;
newtype = XPro_PSFInfo(newpsf, &newhw, &newpar);
if (newtype == 0) return 0;
/* Determine filter size and check it */
sumhw = oldhw + newhw*expand - 1.;
*f1 = floor(center - sumhw);
*f2 = ceil (center + sumhw);
fsize = *f2 - *f1 + 1;
if (fsize > nfilter) {
(void) sprintf(xpro_message, "PSF filter setup failure\n\
array too small to hold %d coefficients", fsize);
RL_RaiseError("PRO_SETUP_FAILURE", xpro_message);
return fsize;
}
/*
* The integral we wish to return is
* f[n] = Integral[ oldpsf(x-(n-center)) newpsf(x/expand) dx ]
* for
* *f1 <= n <= *f2
*
* The integral rearranges to
* f[n] = Integral[ oldpsf(x) newpsf((x+(n-center)/expand) dx ]
*/
for (n = *f1; n <= *f2; n++) {
filter[n-*f1] = XPro_PSFInteg(oldtype, newtype,
1./expand, (n-center)/expand, oldpar, newpar);
}
return fsize;
}
/*
********************************************************************************
* EXPORTED PROGRAMMER ROUTINES
********************************************************************************
* XPro_PSFInfo(psf, halfwidth, param)
*
* This programmer routine checks the that given function is a valid point
* spread function and returns information about it.
*
* Input:
* psf point spread function object
*
* Output:
* *halfwidth halfwidth of function.
* *param parameter of function: halfwidth for boxcar and triangle
* functions; step size for sinc functions.
*
* Return: type of PSF: 1=sincp, 2=boxcar, 3=triangle.
*
* Errors:
* PRO_CLASS_ERROR if the psf is NULL or is not one of the supported
* function types.
*******************************************************************************/
RL_INT4 XPro_PSFInfo(psf, halfwidth, param)
PRO_OBJECT *psf;
RL_FLT8 *halfwidth, *param;
{
if (XPro_FuncPtr(psf) == NULL) return 0;
if (Pro_SincInfo(psf, NULL, param, halfwidth, NULL)) {
return 1;
}
if (Pro_BoxcarInfo(psf, NULL, halfwidth)) {
*param = *halfwidth;
return 2;
}
if (Pro_TriangleInfo(psf, NULL, halfwidth)) {
*param = *halfwidth;
return 3;
}
XPro_ClassError("supported point spread function type", psf);
return 0;
}
/*
********************************************************************************
* XPro_PSFInteg(type1, type2, a, b, par1, par2)
*
* This programmer function returns the integral of the product of two point
* spread functions (PSFs), after the second PSF has been translated and scaled:
* Integral(-infinity,infinity) [psf1(x) psf2(ax+b) dx]
*
* Input:
* type1, type2 type of each PSF: 1=sincp, 2=boxcar, 3=triangle.
* a, b scaling coefficients in argument to second PSF.
* par1, par2 step size for sincp functions, halfwidth values for
* boxcar and triangle PSFs; must be positive.
*
* Return: value of integral, possibly unnormalized.
*
* Three different types of PSFs are supported:
*
* Type #1: sincp(x) == sin(pi*x/step) / (pi*x/step)
*
* Type #2: boxcar(x) == { 1 if -halfwidth <= x <= halfwidth.
* { 0 otherwise.
*
* Type #3: triangle(x) == { 1 + x/halfwidth if -halfwidth <= x <= 0.
* { 1 - x/halfwidth if 0 <= x <= halfwidth.
* { 0 otherwise.
*
* A handy transformation used below...
* Let I(a,b) == Integral[ f(x) g(ax+b) dx ]
* Let J(a,b) == Integral[ g(x) f(ax+b) dx ]
* Let u = ax+b, du = a dx, x = u/a - b/a.
* J(a,b) = Integral[ g(u/a - b/a) f(u) du/a ]
* = I(1/a, -b/a) / abs(a)
*******************************************************************************/
RL_FLT8 XPro_PSFInteg(type1, type2, a, b, par1, par2)
RL_INT4 type1, type2;
RL_FLT8 a, b, par1, par2;
{
switch (type1) {
case SINC_TYPE:
switch (type2) {
case SINC_TYPE: return ZPro_SincSinc(a, b, par1, par2);
case BOXCAR_TYPE: return ZPro_SincBox (a, b, par1, par2);
case TRIANGLE_TYPE: return ZPro_SincTri (a, b, par1, par2);
default: return 0.;
}
case BOXCAR_TYPE:
switch (type2) {
case SINC_TYPE: return ZPro_BoxSinc(a, b, par1, par2);
case BOXCAR_TYPE: return ZPro_BoxBox (a, b, par1, par2);
case TRIANGLE_TYPE: return ZPro_BoxTri (a, b, par1, par2);
default: return 0.;
}
case TRIANGLE_TYPE:
switch (type2) {
case SINC_TYPE: return ZPro_TriSinc(a, b, par1, par2);
case BOXCAR_TYPE: return ZPro_TriBox (a, b, par1, par2);
case TRIANGLE_TYPE: return ZPro_TriTri (a, b, par1, par2);
default: return 0.;
}
}
}
/*
********************************************************************************
* INTERNAL ROUTINES
********************************************************************************
* Integrate sincp(x) * sincp(ax+b) dx
*******************************************************************************/
static RL_FLT8 ZPro_SincSinc(a, b, step1, step2)
RL_FLT8 a, b, step1, step2;
{
RL_FLT8 arg, sinc_arg;
/* The integral of sinc(u) sinc(au+b) du can be shown to equal
* pi/amax sinc(b/amax)
* where amax = max(a,1)
*
* Let I(a,b) == Integral[ sincp(x/step1) sincp((ax+b)/step2) dx ]
* = integral[ sinc(pi/step1 * x) sinc(pi*a/step2 * x + pi*b/step2) dx ]
*
* Let u = pi/step1 * x. dx = du * step1/pi.
* I = integral[ sinc(u) sinc(a*step1/step2 * u + pi*b/step2) du * step1/pi]
* = step1/pi integral[ sinc(u) sinc(a*step1/step2 * u + pi*b/step2) du ]
*
* = step1/amax sinc(pi*b/step2/amax)
* where amax = max(a*step1/step2,1)
*/
a *= step1/step2;
if (a < 0.) a = -a;
if (a < 1.) a = 1.;
arg = M_PI * b/(step2*a);
sinc_arg = (arg == 0. ? 1. : sin(arg)/arg);
return sinc_arg
#ifdef ZPRO_NORMALIZED_INTEGRALS
* step1/a
#endif
;
}
/*
********************************************************************************
* Integrate boxcar(x) * boxcar(ax+b) dx
*******************************************************************************/
static RL_FLT8 ZPro_BoxBox(a, b, halfwidth1, halfwidth2)
RL_FLT8 a, b, halfwidth1, halfwidth2;
{
RL_FLT8 xlo, xhi, dx, xtemp;
/* Find domain of second function */
xlo = (-halfwidth2 - b) / a;
xhi = ( halfwidth2 - b) / a;
if (xlo > xhi) {xtemp = xlo; xlo = xhi; xhi = xtemp;}
/* Find intersection of domains */
if (xlo < -halfwidth1) xlo = -halfwidth1;
if (xhi > halfwidth1) xhi = halfwidth1;
dx = xhi - xlo;
/* If domains do not intersect, return zero */
if (dx < 0.) return 0.;
/* Return integral, equivalent to size of intersection */
return dx;
}
/*
********************************************************************************
* Integrate sincp(x) * boxcar(ax+b) dx
*******************************************************************************/
static RL_FLT8 ZPro_SincBox(a, b, step1, halfwidth2)
RL_FLT8 a, b, step1, halfwidth2;
{
RL_FLT8 xlo, xhi, xtemp, factor;
/* Find domain of boxcar function */
xlo = (-halfwidth2 - b) / a;
xhi = ( halfwidth2 - b) / a;
if (xlo > xhi) {xtemp = xlo; xlo = xhi; xhi = xtemp;}
/* The integral from 0 to x of sinc(u) du is the sine integral, Si(x).
*
* I = integral(xlo,xhi) [ sincp(u/step1) du ]
* = integral(xlo,xhi) [ sinc(pi/step1 * x) dx ]
* Let u = pi/step1 * x
* = integral(pi/step1 * xlo, pi/step1 * xhi) [ sinc(u) du * step1/pi ]
* = step1/pi (Si(pi/step1 * xhi) - Si(pi/step1 * xlo))
*/
factor = M_PI/step1;
return (ZPro_Si(xhi*factor) - ZPro_Si(xlo*factor))
#ifdef ZPRO_NORMALIZED_INTEGRALS
/ factor
#endif
;
}
/*
********************************************************************************
* Integrate boxcar(x) * sincp(ax+b) dx
*******************************************************************************/
static RL_FLT8 ZPro_BoxSinc(a, b, halfwidth1, step2)
RL_FLT8 a, b, halfwidth1, step2;
{
return ZPro_SincBox(1./a, -b/a, step2, halfwidth1)
#ifdef ZPRO_NORMALIZED_INTEGRALS
/ fabs(a)
#endif
;
}
/*
********************************************************************************
* Integrate triangle(x) * triangle(ax+b) dx
*******************************************************************************/
static RL_FLT8 ZPro_TriTri(a, b, halfwidth1, halfwidth2)
RL_FLT8 a, b, halfwidth1, halfwidth2;
{
RL_FLT8 xlo, xhi, xmid, xtemp;
xlo = (-halfwidth2 - b) / a;
xmid = - b / a;
xhi = ( halfwidth2 - b) / a;
if (xlo > xhi) {xtemp = xlo; xlo = xhi; xhi = xtemp;}
return ZPro_LinLin(-halfwidth1, 0., 0., 1., xlo, 0., xmid, 1.) +
ZPro_LinLin(-halfwidth1, 0., 0., 1., xmid, 1., xhi, 0.) +
ZPro_LinLin(0., 1., halfwidth1, 0., xlo, 0., xmid, 1.) +
ZPro_LinLin(0., 1., halfwidth1, 0., xmid, 1., xhi, 0.);
}
/*
********************************************************************************
* Integrate triangle(x) * boxcar(ax+b) dx
*******************************************************************************/
static RL_FLT8 ZPro_TriBox(a, b, halfwidth1, halfwidth2)
RL_FLT8 a, b, halfwidth1, halfwidth2;
{
RL_FLT8 xlo, xhi, xtemp;
xlo = (-halfwidth2 - b) / a;
xhi = ( halfwidth2 - b) / a;
if (xlo > xhi) {xtemp = xlo; xlo = xhi; xhi = xtemp;}
return ZPro_LinLin(-halfwidth1, 0., 0., 1., xlo, 1., xhi, 1.) +
ZPro_LinLin(0., 1., halfwidth1, 0., xlo, 1., xhi, 1.);
}
/*
********************************************************************************
* Integrate boxcar(x) * triangle(ax+b) dx
*******************************************************************************/
static RL_FLT8 ZPro_BoxTri(a, b, halfwidth1, halfwidth2)
RL_FLT8 a, b, halfwidth1, halfwidth2;
{
return ZPro_TriBox(1./a, -b/a, halfwidth2, halfwidth1)
#ifdef ZPRO_NORMALIZED_INTEGRALS
/ fabs(a)
#endif
;
}
/*
********************************************************************************
* Integrate sincp(x) * triangle(ax+b) dx
*******************************************************************************/
static RL_FLT8 ZPro_SincTri(a, b, step1, halfwidth2)
RL_FLT8 a, b, step1, halfwidth2;
{
RL_FLT8 ulo, umid, uhi, utemp, factor;
/* We need to evaluate the integral of a two linear functions times a sinc.
* I(a,b) = Integral[sinc(pi/step1*x) * triangle(a*x + b) dx]
*
* Let u = pi/step1 * x
* I(a,b) = Integral[sinc(u) * triangle(a*step1/pi*u + b) du * step1/pi]
*
* Replace the triangle function with its definition
* I(a,b) = step1/pi * (Integral(ulo,umid)[sinc(u) * (u-ulo)/(uhi-umid) du]
* - Integral(umid,uhi)[sinc(u) * (u-uhi)/(uhi-umid) du])
* where
* ulo = (-hw2 - b)/a * pi/step1
* umid = ( - b)/a * pi/step1
* uhi = ( hw2 - b)/a * pi/step1
*
* Rearrange the two integrals so their form is identical
* I(a,b) = (step1/pi)^2 * a/hw2 * (Integral(ulo,umid)[sinc(u) * (u-ulo) du]
* + Integral(uhi,umid)[sinc(u) * (u-uhi) du])
* I(a,b) = (J(ulo,umid) + J(uhi,umid)) * (step1/pi)^2 * a/hw2
* where
* J(s,t) = Integral(s,t)[sinc(u) * (u-s) du]
*
* Expand the new integral
* J(s,t) = Integral(s,t)[sin(u) du] - s*Integral(s,t)[sinc(u) du]
* = cos(s) - cos(t) - s*Si(t) + s*Si(s)
*
* Back-substitute
* I(a,b) = (cos(ulo) - cos(umid) - ulo*Si(umid) + ulo*Si(ulo) +
* cos(uhi) - cos(umid) - uhi*Si(umid) + uhi*Si(uhi))
* * (step1/pi)^2 * a/hw2
* I(a,b) = (cos(ulo) + cos(uhi) - 2*cos(umid) +
* ulo*Si(ulo) + uhi*Si(uhi) - (ulo+uhi)*Si(umid))
* * (step1/pi)^2 * a/hw2
*/
factor = M_PI / (a*step1);
ulo = (-halfwidth2 - b) * factor;
umid = - b * factor;
uhi = ( halfwidth2 - b) * factor;
if (ulo > uhi) {utemp = ulo; ulo = uhi; uhi = utemp;}
return (cos(ulo) + cos(uhi) - 2.*cos(umid) +
uhi*ZPro_Si(uhi) + ulo*ZPro_Si(ulo) - (ulo+uhi)*ZPro_Si(umid))
#ifdef ZPRO_NORMALIZED_INTEGRALS
* step1 / (M_PI * (uhi - umid));
#endif
;
}
/*
********************************************************************************
* Integrate triangle(x) * sincp(ax+b) dx
*******************************************************************************/
static RL_FLT8 ZPro_TriSinc(a, b, halfwidth1, step2)
RL_FLT8 a, b, halfwidth1, step2;
{
return ZPro_SincTri(1./a, -b/a, step2, halfwidth1)
#ifdef ZPRO_NORMALIZED_INTEGRALS
/ fabs(a)
#endif
;
}
/*
********************************************************************************
* Internal workhorse function to evaluate a product of two linear functions over
* their common domain.
*******************************************************************************/
static RL_FLT8 ZPro_LinLin(xa1, ya1, xa2, ya2, xb1, yb1, xb2, yb2)
RL_FLT8 xa1, ya1, xa2, ya2, xb1, yb1, xb2, yb2;
{
RL_FLT8 x1, x2, slope_a, yintercept_a, slope_b, yintercept_b,
aa, bb, cc;
/* Find common domain */
x1 = (xa1 > xb1 ? xa1 : xb1);
x2 = (xa2 < xb2 ? xa2 : xb2);
/* If it's empty, return zero */
if (x1 >= x2) return 0.;
/* Derive coefficients of function A: y = slope*x + intercept */
slope_a = (ya2 - ya1) / (xa2 - xa1);
yintercept_a = ya1 - slope_a * xa1;
/* Derive coefficients of function B: y = slope*x + intercept */
slope_b = (yb2 - yb1) / (xb2 - xb1);
yintercept_b = yb1 - slope_b * xb1;
/* Derive coefficients of integral of product: ax^3 + bx^2 + cx */
aa = slope_a * slope_b / 3.;
bb = (slope_a * yintercept_b + slope_b * yintercept_a) / 2.;
cc = yintercept_a * yintercept_b;
/* Evaluate definite integral */
return ((aa*x2 + bb)*x2 + cc)*x2 - ((aa*x1 + bb)*x1 + cc)*x1;
}
/*
********************************************************************************
* ZPro_Si(x) -- Approximate sine integral
*
* Si(x) == Integral{0...x} [ sin(u)/u du ]
*
* This routine uses a fast but approximate expression for x > 1. It should be
* accurate to 6 digits, good enough for most purposes.
*******************************************************************************/
#define CUTOFF 1.
static RL_FLT8 ZPro_Si(x)
RL_FLT8 x;
{
RL_FLT8 value, absx, x2, term, sum, prev, fx, gx;
RL_INT4 j;
RL_FLT8 a1 = 38.027264, a2 = 265.187033, a3 = 335.677320, a4 = 38.102495;
RL_FLT8 b1 = 40.021433, b2 = 322.624911, b3 = 570.236280, b4 = 157.105423;
RL_FLT8 c1 = 42.242855, c2 = 302.757865, c3 = 352.018498, c4 = 21.821899;
RL_FLT8 d1 = 48.196927, d2 = 482.485984, d3 = 1114.978885, d4 = 449.690326;
absx = fabs(x);
x2 = x * x;
/*******************************************************************************
* Handle the easy case first
*******************************************************************************/
if (x == 0.) {
value = 0.;
}
/*******************************************************************************
* Small x solution: si(x) = x - x^3/3*3! + x^5/5*5! - x^7/7*7! ...
*
* In the algorithm below, term = (-1)^((j-1)/2) x^j / j! at each step:
* term(1) = x
* term(3) = -x^3 / 3!
* term(5) = x^5 / 5!
* The series is a sum of term(j)/j. The value returned is exact.
*******************************************************************************/
else if (absx <= CUTOFF) {
j = 1;
term = x;
sum = x;
do {
j += 2;
term *= x2 / (double) ((1-j) * j);
prev = sum;
sum += term / j;
} while (prev != sum);
value = sum;
}
/*******************************************************************************
* Large x solution: si(x) = PI/2 - f(x)cos(x) - g(x)sin(x)
*
* where f(x) and g(x) are auxiliary functions defined by
* Abramowitz, M., and I. A. Stegun 1966. Handbook of Mathematical
* Functions. National Bureau of Standards Applied Mathematics Series
* 55, pp. 231--233.
* See Section 5.2.
*
* Expressions for f(x) and g(x) have errors of magnitude < 5e-7 for x >= 1.
*******************************************************************************/
else {
/* Evaluate approximate auxiliary functions */
fx = ((((x2 + a1)*x2 + a2)*x2 + a3)*x2 + a4) /
(((((x2 + b1)*x2 + b2)*x2 + b3)*x2 + b4)*absx);
gx = ((((x2 + c1)*x2 + c2)*x2 + c3)*x2 + c4) /
(((((x2 + d1)*x2 + d2)*x2 + d3)*x2 + d4)*x2);
/* Solve for sine integral */
value = M_PI/2. - fx*cos(absx) - gx*sin(absx);
if (x < 0.) value = -value;
}
return value;
}
/*
********************************************************************************
* FORTRAN INTERFACE ROUTINES
********************************************************************************
*$ Component_name:
* FPro_PSFFilter (psffilt.c)
*$ Abstract:
* This function returns the set of filter coefficents needed to evaluate
* a sample in a series given its new point spread function (PSF), based on
* the original PSF and the transformation from old sample index to new.
*$ Keywords:
* PROFILE, FILTER
* FORTRAN, PUBLIC, SUBROUTINE
*$ Declarations:
* integer*4 function FPro_PSFFilter(oldpsf, newpsf, center, expand, filter,
* nfilter, f1, f2)
* integer*4 oldpsf, newpsf, nfilter, f1, f2
* real*8 center, expand, filter(*)
*$ Inputs:
* oldpsf FORTRAN pointer to the PSF of original series.
* newpsf FORTRAN pointer to the intended PSF of each new sample.
* center sample index in original series corresponding to
* midpoint of new PSF.
* expand expansion factor from original series sampling interval
* to new samples.
* nfilter size of filter array.
*$ Outputs:
* filter(*) array of filter coefficients
* f1, f2 indices in original series corresponding to first and
* last filter coefficients returned.
*$ Returns:
* size of new filter, f2-f1+1, or 0 on error. If value > nfilter, then
* the array provided is too small so the coefficients are not returned.
*$ Detailed_description:
* This function returns the set of filter coefficents needed to evaluate
* a sample in a series given its new point spread function (PSF), based on
* the original PSF and the transformation from old sample index to new.
* Note that these weights are unnormalized.
*
* The x-axis of each PSF is assumed to be in units of the series sample
* index.
*$ External_references:
* Profile toolkit
*$ Side_effects:
* none
*$ Examples:
* This snippet of code makes a filter appropriate for filtering a series
* so that each new sample is the average of the three nearest samples in
* another series.
*
* integer*4 oldpsf, newpsf
* real*8 filter(101), f1, f2
*
* ! Create unit-width boxcar functions
* oldpsf = FPro_BoxcarFunc(1.d0, 0.5d0)
* newpsf = FPro_BoxcarFunc(1.d0, 0.5d0)
*
* ! Create filter for 3x expansion
* call Pro_PSFFilter(oldpsf, newpsf, 0.d0, 3.d0, filter, 101, f1, f2)
*
* At this point, f1=-1, f2=1, and filter(1) = filter(2) = filter(3) != 0.
*$ Error_handling:
* Profile library error handling is in effect.
*
* Conditions raised:
* PRO_CLASS_ERROR if either PSF is NULL or is not one of the
* allowed function types.
* PRO_SETUP_FAILURE if the array is too small to hold all the
* necessary filter coefficients.
* FORTRAN_POINTER_ERROR if any object is not a valid FORTRAN pointer.
*$ Limitations:
* Only boxcar, triangle and sinc PSFs are supported.
*
* Coefficients when both PSFs are sinc functions are based on the
* assumption that both sinc functions have limited domains. This
* approximation is acceptable when the width of both sinc functions is at
* least several cycles.
*$ Author_and_institution:
* Mark R. Showalter
* NASA/Ames Research Center
*$ Version_and_date:
* 1.0: March 1998
*$ Change_history:
* none
*******************************************************************************/
RL_INT4 FORTRAN_NAME(fpro_psffilter) (oldpsf, newpsf, center, expand, filter,
nfilter, f1, f2)
RL_INT4 *oldpsf, *newpsf, *nfilter, *f1, *f2;
RL_FLT8 *center, *expand, *filter;
{
RL_VOID *oldptr, *newptr;
/* Look up function pointers */
oldptr = FORT_GetPointer(*oldpsf);
if (oldptr == NULL) return 0;
newptr = FORT_GetPointer(*newpsf);
if (newptr == NULL) return 0;
/* call function */
return Pro_PSFFilter((PRO_OBJECT *) oldptr, (PRO_OBJECT *) newptr,
*center, *expand, filter, *nfilter, f1, f2);
}
/*******************************************************************************
*/