Search code examples
pythonfunctioncurve-fittingpiecewise

Combination (piecewise) function of two pre-defined functions


I'm currently making a custom function that I will eventually feed into scipy.optimize.curve_fit() for a custom curve fit. My curve fit will be shaped like a bump. Gaussian rise and exponential fall, pieced together at the highest point of the gaussian. I have defined a Gaussian and an exponential function and currently trying to define a combo() function. Here's what I have so far:

    def exp(x, a, b, c):
          return a * np.exp((-b * x) + c)
    def gauss(x,d,e,f):
          return d * np.exp(-((x-e)**2)/(2*(f**2)))
    def combo(x,a,b,c,d,e,f):
          ex = exp(x,a,b,c)
          ga = gauss(x,d,e,f)
    num = np.arange(0,1000,1)
    test =combo(num,1,2,3,10,4,3)

I've tried to use if statements in my combo function (if x<d: return ga) but I get the error message: "The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()". Maybe this is the solution but I'm not sure how to employ it.


Solution

  • I think the best way to do this using numpy is to use array slicing. Use the mean value, b, to mask the values in x so that only values prior to or equal to b are calculated with the Gaussian function, and the values of x greater than b are calculated with the exponential function:

    def exp(x, a, b, c):
        return a * np.exp(-c * (x-b))
    def gauss(x, a, b, d):
        return a * np.exp(-((x-b)**2)/(2 * (d**2)))
    def combo(x, a, b, c, d):
        y = np.zeros(x.shape)
        y[x <= b] = gauss(x[x <= b], a, b, d)
        y[x > b] = exp(x[x > b], a, b, c)
        return y
    num = np.arange(-50, 50, 0.5)
    test = combo(num, 10, 4, 3, 3)
    

    I assume that you want this function to be continuous, so I changed your parameters so that the values input into exp and gauss are consistent with each other, and I changed the arange parameters so the plot is more meaningful. It looks like the solution you posted will do the piecewise part, but not the continuous part. Presumably the use of lambda isn't necessary but not familiar with np.piecewise.

    Output:

    enter image description here