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.7071For 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.7071Our 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.7071Note 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.7216It'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.7071This 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.0000To instead differentiate wrt u, the third input:
dfdu = fdiff(f, 1e-6, 3, t0, x0, u0)dfdu =
0
1.0000*kf v1.0.3