// Copyright (c) CNES 2008 // // This software is part of CelestLab, a CNES toolbox for Scilab // // This software is governed by the CeCILL license under French law and // abiding by the rules of distribution of free software. You can use, // modify and/ or redistribute the software under the terms of the CeCILL // license as circulated by CEA, CNRS and INRIA at the following URL // 'http://www.cecill.info'. function [xres, yres] = CL__detectSign(x, y, fct, args, sgn, ytol, xbounds, nsub, meth, impr) // Intervals of positive or negative values (low level) // // Calling Sequence // [xres, yres] = CL__detectSign(x, y, fct, args, sgn, ytol, meth, impr) // // Description // //

Computes the intervals where fct(x) is positive or negative.

//

x and y are 2 row vectors. If y is empty => computed. y can be computed by:

//

y = fct(x, ind, args) [in unused).

//

//

The other arguments are:

//

- ytol: Desired accuracy on f(x).

//

- meth: Method used to finely compute the zeros of y(x): "s": secant, "d": dichotomy, // "ds": mix of secant, "d": dichotomy (see CL_fsolveb).

//

- impr: True (%t) if the improved detection mechanism is active (see below).

//

//

The method consists in selecting the abscissas for which the sign of y changes, and then computing a more // exact value using CL_fsolveb. If the improved detection mechanism is selected, the function first detects when // y reaches a extremum, which avoids choosing a very small step. The improved detection works however if the // function is twice differentiable.

//
//

// // //

Note:

//

- The abscissae x must be strictly increasing.

//

- The results may be degraded is the data are not continuous.

//

// // Parameters // x: Abscissae. (1xN) // y: Ordinates, or []. (1xN) // fct: y = fct(x, ind, args). // args: (any type) argument for fct. // sgn: Wanted sign: 1: positive, -1: negative. // ytol: Accuracy on ordinates or empty (empty <=> default value). // xbounds: Abscissae intervals. (2xQ) // nsub: (integer) Number of sub-division points (>= 0). // meth: (string) Method for zero computation: "s", "d" or "ds". // impr: (boolean) True if improved detection mechanism is selected. // xres: intervals of abscissae where value is positive (2xP) // yres: corresponding ordinates (should be close to zero) (2xP) // // Authors // CNES - DCT/SB // // See also // CL_detectZero // CL_fsolveb // // Examples // x = linspace(0, 10, 30); // // function [y] = myfunction(x, ind, args) // y = sin(x) - args; // endfunction // // args = 0.99; // sgn = 1; // ytol = 1.e-6; // xbounds = [-%inf, %inf]; // nsub = 0; // meth = "ds"; // impr = %t; // xres = CL__detectSign(x, [], myfunction, args, sgn, ytol, xbounds, nsub, meth, impr) // ================================================= // Declarations // ================================================= // factor for computation of ytol ATOL_FACTOR = 1.e-8; RTOL_FACTOR = 1.e-4; // ================================================= // MAIN // ================================================= // ------------------------------------------------- // Arguments Checking // ------------------------------------------------- if (argn(2) <> 10) CL__error("Invalid number of input arguments (10 expected)"); end if (sgn <> 1 & sgn <> -1) CL__error("Invalid value for argument sgn (1 or -1 expected)"); end if (typeof(ytol) <> "constant" | size(ytol,"*") > 1) CL__error("Invalid size for argument ytol"); end // xbounds: 0 or 2 rows if (size(xbounds,1) <> 2 & size(xbounds,1) <> 0) CL__error("Invalid size for argument xbounds"); end if (nsub <> round(nsub) | nsub < 0) CL__error("Invalid value for argument nsub"); end if (meth <> "s" & meth <> "d" & meth <> "ds") CL__error("Invalid value for argument meth"); end if (typeof(impr) <> "boolean") CL__error("Invalid type for argument impr"); end if (size(x,1) > 1 | size(y,1) > 1 | (size(x,2) <> size(y,2) & y <> [])) CL__error("Invalid size for argument x or y"); end // Check x is strictly increasing if (size(x, 2) >= 2) if (find(x(2:$) - x(1:$-1) <= 0) <> []) CL__error("Invalid abscissas: not strictly increasing"); end end // check there is no Nan value // NB: works even if y is [] if (find(isnan(x+y)) <> []) CL__error("Invalid data (data contain Nan values)"); end // ------------------------------------------------- // Computation // ------------------------------------------------- xres = []; yres = []; // special cases: x contains less than 2 values // If x == [] (=> y == []): finished if (size(x, 2) <= 1 | xbounds == []) return; // <= RETURN end // find all zeros // NB: zeros belong to xbounds idirect = 0; xzero = CL__detectZero(x, y, fct, args, idirect, ytol, xbounds, nsub, meth, impr); // make xbounds in [x(1), x($)) + eliminates intersections // NB: includes validation of xbounds (beginning <= end) xbounds = CL_intervInters([x(1); x($)], CL_intervUnion(xbounds)); xall = gsort(unique([xbounds(1,:), xbounds(2,:), xzero]), "c", "i"); // NB: xres: not empty xres = CL_intervInters(xbounds, [xall(1:$-1); xall(2:$)]); // select intervals with correct sign ymid = fct((xres(1,:) + xres(2,:))/2, [], args); I = find(ymid * sgn > 0); xres = CL_intervUnion(xres(:,I)); // generate y values if necessary nbargs_out = argn(1); if (xres <> [] & nbargs_out >= 2) yres = matrix(fct([xres(1,:), xres(2,:)], [], args), 2, -1); end endfunction