*kf
by An Uncommon Lab

fdiff

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)

Inputs

f

A handle to the function to differentiate

alpha

Step size, a scalar or vector (1e-6 by default)

index

The argument number with respect to which the function should be differentiated (e.g., to differentiate f(t, x, u) wrt x, the index would be 2.

(etc.)

The arguments to pass to the function; varargin{index} is the state to use for differentiation.

Outputs

dfdx

The finite difference of the function wrt the indicated input

Example: The Jacobian of the Polar to Cartesian Coversion

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.

Example: Many Function Inputs

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

See Also

Mr. Eustace's Jump

Table of Contents

  1. Inputs
  2. Outputs
  3. Example: The Jacobian of the Polar to Cartesian Coversion
  4. Example: Many Function Inputs
  5. See Also