1
$\begingroup$

I am trying to manipulate the function $f(x)=a-b\exp(-xc)$, where $a,b$ and $c$ are parameters and $x$ my variable. I want to fix the value and gradient at $f(x=1400)$ and the value at $f(x>4000)$. Here's how I am doing it:

NSolve[{
  ((a - b*Exp[-c*x]) /. x -> 1400) == 0.129417,
  ((a - b*Exp[-c*x]) /. x -> 4000) == 0.26304,
  (D[(a - b*Exp[-c*x]), x] /. x -> 1400) == 0.0002219136
  }, {a, b, c}]

However, NSolve isn't returning anything and eventually fails. Is there a different function in Mathematica appropriate for this problem?

$\endgroup$
  • $\begingroup$ If you have some initial guess, you can use FindRoot. $\endgroup$ – Sumit Oct 27 '17 at 17:29
2
$\begingroup$

The following works (The initial values were found by trials.).

FindRoot[{((a-b*Exp[-c*x]) /. x -> 1400)==0.129417,((a - b*Exp[-c*x])/.x -> 4000)==0.26304,
(D[(a - b*Exp[-c*x]), x] /. x -> 1400) == 0.0002219136}, {a,0.2}, {b, .03}, {c, .00009},
 WorkingPrecision -> 20,AccuracyGoal -> 3]

{a->0.26496040221501131952,b->1.3412964939715005005,c->0.0016372143267284541222}

Verification confirms it.

{((a - b*Exp[-c*x]) /. x -> 1400), ((a - b*Exp[-c*x]) /. 
x -> 4000), (D[(a - b*Exp[-c*x]), x] /. x -> 1400)} /.
{a -> 0.26496040221501131952, b -> 1.3412964939715005005, c -> 0.0016372143267284541222}

0.1294169999999148617, 0.2630399999999959833, 0.0002219136000000732043}

Addition. The FindRoot also works with the initial values {a, 1.}, {b, 1.}, {c, .0001}. The initial values of a and b are taken $1$ as usually, the initial value of c is chosen in such awy that $1000c \approx 1$.

$\endgroup$
3
$\begingroup$

If you don't have any initial guess that works, but it seems reasonable that a solution should exist, then rewriting the problem to solve for one fit variable at a time may also work. If there isn't a solution, this process is a fair bit more likely to show that than FindRoot is as well.

f[a_,b_,c_] := a-b Exp[-# c]& (* this defines the family of functions of f *)

Solve for b by implementing the gradient constraint at the first x point.

solb = First@Solve[f[a,b,c]'[x1]==g,b]

Solve for a by implementing the y value constraint at the first x point and the b constraint.

sola = First@Solve[f[a,b,c][x1]==y1/.solb,a]

Solve for c by implementing the y value constraint at the second x point and the previous 2 solutions.

solc = First@Solve[f[a,b,c][x2]==y2/.solb/.sola,c]

Now insert the numerical parameters:

params = {x1->1400,x2->4000,y1->0.129417,y2->0.26304,g->0.0002219136};

And expand the previous solutions:

nc = solc/.params;
nb = solb/.params/.nc;
na = sola/.params/.nc/.nb;
nsol = Flatten[{na,nb,nc}]

nsol should contain {a->0.26496,b->1.3413,c->0.00163721}.

(f[a,b,c]/.nsol)[x] will generate the final function in terms of x.

In my experience normally if this process would work, then Solve is probably able to solve a symbolic version of this problem as well, but that doesn't appear to be true in this case.

$\endgroup$
1
$\begingroup$
$Version

(* "11.2.0 for Mac OS X x86 (64-bit) (September 11, 2017)" *)

Rationalize and Simplify the equations

eqns = {((a - b*Exp[-c*x]) /. x -> 1400) == 0.129417,
     ((a - b*Exp[-c*x]) /. x -> 4000) == 0.26304,
     (D[(a - b*Exp[-c*x]), x] /. x -> 1400) == 0.0002219136} //
    Rationalize[#, 0] & // Simplify;

Restrict NSolve to the real domain

(sol = NSolve[eqns, {a, b, c}, Reals][[1]]) // AbsoluteTiming

(* {16.7754, {a -> 0.26496, b -> 1.3413, c -> 0.00163721}} *)

Verifying the solutions

And @@ (eqns /. sol)

(* True *)
$\endgroup$
  • $\begingroup$ The Simplify command may be omitted. $\endgroup$ – user64494 Oct 27 '17 at 19:20
  • $\begingroup$ @user64494 - while it is not necessary, it makes the equations "cleaner". It is just a matter of personal preference. $\endgroup$ – Bob Hanlon Oct 27 '17 at 19:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.