This function allows one to partially differentiate a function about some input state vector using finite-differencing. This produces the Jacobian of the function wrt the state about the given inputs.
dFdx = fdiff(f, x)
dFdx = fdiff(f, alpha, x)
dFdx = fdiff(f, alpha, index, varargin)
f | A handle to the function to differentiate |
---|---|
alpha | Step size, a scalar or vector ( |
index | The argument number with respect to which the function should
be differentiated (e.g., to differentiate |
(etc.) | The arguments to pass to the function; |
dfdx | The finite difference of the function wrt the indicated input |
---|
Suppose we have a function to convert from polar to cartesian coordinates: $$\begin{bmatrix} x \\ y\end{bmatrix} = f(\begin{bmatrix}\theta \\ r\end{bmatrix})$$
and want to partially differentiate it about \(\theta = \frac{\pi}{4}\) and \(r = 2\). We can use finite differencing to do this.
pol0 = [pi/4; 2];
f = @(pol) pol(2) * [cos(pol(1)); sin(pol(1))];
F = fdiff(f, pol0)
F =
-1.4142 0.7071
1.4142 0.7071
For this example, we know the theoretical value, so let's check against it.
F_theory = [-pol0(2) * sin(pol0(1)), cos(pol0(1)); ...
pol0(2) * cos(pol0(1)), sin(pol0(1))]
F_theory =
-1.4142 0.7071
1.4142 0.7071
Our finite-differenced result looks exactly like the theoretical result.
Instead of letting fdiff
use its default value (1e-6) for the finite
step size, we can also specify the step size:
F = fdiff(f, 1e-1, pol0)
F =
-1.4119 0.7071
1.4119 0.7071
Note that this bigger step is not as good as what we had. Let's try a very small step instead.
F = fdiff(f, 1e-14, pol0)
F =
-1.4100 0.7216
1.4100 0.7216
It's even worse due to roundoff error -- 1e-14 is too small compared to the states we're using and the results of the function. It's best to stay within a dozen orders of magnitude of the input states.
If our function involved two values of very different magnitudes, we can
instead difference with as many step sizes as states. Let's use 1e-6
times the magnitude of each state as the step size.
step_sizes = 1e-6 * pol0
F = fdiff(f, step_sizes, pol0)
step_sizes =
1.0e-05 *
0.0785
0.2000
F =
-1.4142 0.7071
1.4142 0.7071
This works well. Of course, care must be taken to ensure no step size is actually 0.
Suppose our function took in many inputs, such as the following:
f = @(t, x, u) t * norm(x) * x + [0; 1] * u;
We can use fdiff
here by passing in all of the necessary inputs for the
function along with an index indicating which input should be used for
differencing. For instance, to differentiate wrt x
, which is index 2:
t0 = 10;
x0 = [1; 0];
u0 = 2;
dfdx = fdiff(f, 1e-6, 2, t0, x0, u0)
dfdx =
20.0000 0
0 10.0000
To instead differentiate wrt u
, the third input:
dfdu = fdiff(f, 1e-6, 3, t0, x0, u0)
dfdu =
0
1.0000
*kf
v1.0.3