Basis functions for tunable gain surface

You use basis function expansions to parameterize gain
surfaces for tuning gain-scheduled controllers, with the `tunableSurface`

command.
The complexity of such expansions grows quickly when you have multiple
scheduling variables. Use `ndBasis`

to build N-dimensional
expansions from low-dimensional expansions. `ndBasis`

is
analogous to `ndgrid`

in the
way it spatially replicates the expansions along each dimension.

`shapefcn = ndBasis(F1,F2)`

`shapefcn = ndBasis(F1,F2,...,FN)`

forms
the outer (tensor) product of two basis function expansions. Each
basis function expansion is a function that returns a vector of expansion
terms, such as returned by `shapefcn`

= ndBasis(`F`

1,`F`

2)`polyBasis`

.
If $${F}_{1}\left({x}_{1}\right)=\left[{F}_{1,1}\left({x}_{1}\right),{F}_{1,2}\left({x}_{1}\right),\dots ,{F}_{1,i}\left({x}_{1}\right)\right]$$ and $${F}_{2}\left({x}_{2}\right)=\left[{F}_{2,1}\left({x}_{2}\right),{F}_{2,2}\left({x}_{2}\right),\dots ,{F}_{2,i}\left({x}_{2}\right)\right]$$,
then `shapefcn`

is a vector of terms of the form:

$${F}_{ij}={F}_{1,i}\left({x}_{1}\right){F}_{2,j}\left({x}_{2}\right).$$

The terms are listed in a column-oriented fashion, with *i* varying
first, then *j*.

forms
the outer product of three or more basis function expansions. The
terms in the vector returned by `shapefcn`

= ndBasis(`F`

1,`F`

2,...,`F`

N)`shapefcn`

are
of the form:

$${F}_{{i}_{1}\dots {i}_{N}}={F}_{1,{i}_{i}}\left({x}_{1}\right){F}_{2,{i}_{2}}\left({x}_{2}\right)\dots {F}_{N,{i}_{N}}\left({x}_{N}\right).$$

These terms are listed in sort order that of an N-dimensional
array, with *i*_{1} varying first,
then *i*_{2}, and so on. Each `Fj`

can
itself be a multi-dimensional basis function expansion.

The

`ndBasis`

operation is associative:ndBasis(F1,ndBasis(F2,F3)) = ndBasis(ndBasis(F1,F2),F3) = ndBasis(F1,F2,F3)