New information added at bottom of post
This is an outgrowth of this earlier question. Let us suppose that we have an instrumental response function given here:
response[t_] = 0.2583*(1/(E^(0.25*(-2.6 + t))*(1 +
13.5/E^(1.67*(-2.6 + t)))^10.9) + (961*(1 -
E^(-0.236*(-2.6 + t))))/(E^(1.67*(-2.6 + t))*(1 +
13.5/E^(1.67*(-2.6 + t)))^11.9));
Plot[response[t], {t, -10, 50}, PlotRange -> Full]
And the underlying physical phenomenon I am expecting to be occurring is given by:
model[t_, Finf_, A1_, k1_, A2_, k2_, t0_] = Finf-A1-A2+
UnitStep[t-t0] (A1+A2-A1 E^(-k1(t-t0)) - A2 E^(-k2(t-t0)));
We will take some test parameters just to evaluate the shape of the curve as follows:
testparams = {Finf->4, A1->1.5, A2->2.0, k1->0.3, k2->0.06, t0->50};
Plot[model[t, Finf, A1, k1, A2, k2, t0] /. testparams, {t, 0, 200},
PlotRange -> {{0, 200}, {0, 4}}]
The end goal will be to find the values of the parameters that best fit experimental data. So naturally what I want to do is find the convolution of response and model, preferably as a function although evaluated at a set of x values that match my experimental x axis could work too, and then do a NonlinearModelFit on that convolution in order to find the values of those parameters. I am having a lot of trouble with the convolution, however.
fn[x_, Finf_, A1_, k1_, A2_, k2_, t0_] =
Convolve[response[t], model[t, Finf, A1, k1, A2, k2, t0], t, x]
When I try it in MMA 11.3 and plot it using the same test parameters from above, I get this:
When I try it in MMA 12.0 and plot it using the same test parameters from above, I get this:
Zooming in, I see this:
In all cases I get numerous warnings along the lines of: General: [Some fraction] is too small to represent as a normalized machine number; precision may be lost.
That earlier question was (sort of) resolved by multiplying the response function by UnitStep[t]. This does not change the MMA 11.3 version's resulting plot. It does change the MMA 12.0 version's resulting plot:
So it's looking like some kind of edge effect, possibly due to the (slight) discontinuity at t=0 in the response function. So I then changed the UnitStep[t] in the response function to UnitStep[t-3] in order to get it as close as possible to matching at zero, to find:
The edge effects look to be gone (even if I have no idea where they were coming from), but look at the shape of that curve compared to the original model. It has a faster rise to the asymptote than the unconvoluted model, which is clearly wrong.
Finally, if I take the t-3 version but swap the order of two functions in the convolution, we see this:
And again, throughout, I am getting those number too small warnings. Trying to swap the order of the function in the convolution in MMA 11.3, however, seems to hang the kernel.
If I plug in the parameters first before convolution in MMA 12.0 (even without the UnitStep in the response function), I get a result that looks right:
Although with all of the other problems, I have a hard time trusting this result. Plus, having to recalculate the convolution at each set of parameters would be computationally intractable during a NonlinearModelFit. And in MMA 11.3, the results are still wrong.
Both of my functions look well-behaved enough that convolution should be possible. My response function is not all that bizarre. It is an extremely common problem in science to use an instrument response function to help model data, so it is hard to believe that this problem hasn't been come across before. Am I missing something, or doing something wrong?
As a side note, I saw a couple of other posted questions where the response was to use PiecewiseExpand to replace the UnitStep with a piecewise function in order to speed things up, but unfortunately the convolution doesn't seem to execute for me when I try that with my functions.
Edited to add a new test I ran: Ok, this has me completely baffled.
You can visualize a convolution as an integral where you swap the x axis of one of the functions and then look at different x-offsets. So I set it up with a Manipulate and then looked at the integral:
Manipulate[
Show[Plot[{model[t, Finf, A1, k1, A2, k2, t0] /. testparams,
response[-t + offset] 10}, {t, 0, 200}, PlotRange -> Full,
PlotPoints -> 200, ImageSize -> Large,
LabelStyle -> Directive[Background -> White]],
ListPlot[{{offset,
NIntegrate[(model[x, Finf, A1, k1, A2, k2, t0] /.
testparams) response[-x + offset], {x, 0, 200}]}}]],
{{offset, 30}, 0, 250}]
Strictly, you are supposed to integrate from -Infinity to Infinity. Here I am restricting the integral to the viewing window of 0-200, but the result is the same.
That makes NO sense at all!
Further information:
Yeah, NIntegrate is simply giving incoherent results. Witness:
mdl[x_] = (model[x, Finf, A1, k1, A2, k2, t0] /. testparams)
rsp[x_] = response[-x + 121]
Plot[{mdl[x], rsp[x], mdl[x] rsp[x]}, {x, 0, 200},
Filling -> {3 -> 0}, Background -> White,
LabelStyle -> Background -> White]
NIntegrate[mdl[x] rsp[x], {x, 0, 200}, AccuracyGoal -> 10]
So first I define the functions as just being functions of x. I plot them individually plus their product (with the product being filled to the x axis, since we will be integrating). The functions are well-behaved, and the product is >= zero over the whole integration range (barring a VERY small ringing region in the response function). Yet NIntegrate gives me a result of zero. What in the actual @$!&?
model[t_, Finf_, A1_, k1_, A2_, k2_, t0_] = (Finf - A1 - A2 + UnitStep[ t - t0] (A1 + A2 - A1 E^(-k1 (t - t0)) - A2 E^(-k2 (t - t0)))) UnitStep[t];
. I get a decent plot. Neither the model or response function are defined prior to t=0, right? At least not t=-Infinity. $\endgroup$