Basis Functions
The topic Overview of the Least Squares Estimation describes how the linear least squares method separates the "rubber function" (the function being fit) into the dot product of two vectors: a coefficient vector and a basis vector. The function must evaluate each data point to create a basis vector from its independent variables. The basis vectors are then used to compute the coefficient vector. The basis vector therefore determines exactly what is fit.
Mira provides 2 built-in basis functions:
an n-dimensional polynomial of up to 10 variables and 100 coefficients, and
a hyperplane of up to 10 variables.
The polynomial is the default. You can between these two options using the SetBasisFunc method. In addition, you can create your own basis function in a script. This topic describes how to write your own basis functions.
Note that the term "array" is used extensively in this description, and it has the usual meaning in Lua: a table with numeric indices. The basis vector, coefficient vector, and other vectors described here all are expressed as lua arrays.
A basis function declared in the script has a standard interface: it receives 2 or 3 arguments and returns 1 argument. The input arguments describe the number of coefficients being fit, the value(s) of the independent variable(s) being fit and, optionally, the mean coordinates for each independent variable. The basis function uses these arguments to create a basis vector in a Lua table and then returns that table. For example, if b is the basis vector assembled by the basis function, then the function must return b.
The basis function is declared using either of the following 2 forms:
function( n, v )
function( n, v, m )
where the arguments are defined as follows:
n |
The number of coefficients being fit, including forced coefficients. |
v |
An array containing the values of the independent variable(s), or coordinates, at the sample point. The number of array elements equals the number of basis dimensions. |
m |
An array containing the mean coordinate for the independent variable(s). This parameter is optional. The number of array elements equals the number of basis dimensions. |
First, note that there is nothing special about the letters n, v, and m; these are just the letters used in this description. As usual, it is the position in the function parameter list that determines how a value is used by the function.
The optional argument m is used if you want to estimate the fit about the mean coordinate(s) rather than about the origin. Fitting about the mean minimizes the statistical uncertainties of the coefficients. If you don't care to fit about the mean, your basis function can declare only the first 2 arguments. Remember that the coordinate vector v is always passed as an array (i.e., a Lua table), even if the fit is made to only 1 variable such as the x-coordinate. Therefore, when fitting a single variable, the basis function still must use subscript [1] to access value in dimension 1 of the array.
In the CLsqFit class, the term "dimension" is often used in place of "independent variable" or "coordinate". Thus fitting up to 10 independent variables corresponds to fitting up to 10 basis dimensions. After declaring your basis function, you must specify the number of coefficients and dimensions it uses; these are the number of independent variables used by the data points andthe number of coefficients involved in the fit.
The following methods are used along with your choice of basis function:
This method registers your basis function with the CLsqFit object. If you do not call this method, the basis function defaults to the built-in n-dimensional polynomial. |
|
Declares the number of coefficients to be fit, which equals the numbers used by your basis function, as well as the number of basis dimensions. Note: forced coefficients are included in the coefficient count since they are represented in the basis function. |
|
Returns the number of basis dimensions declared by the SetNumCoefs method. |
A basis function defined in your script takes the functional form shown below. This is the basic template for basis functions you would write in your script:
Template of a Basis Function
|
-- declare the function |
|
-- create a table for the basis vector |
-- |
-- code that fills the basis vector |
|
-- return the status and the basis vector |
|
-- end of the basis function |
Several examples of a script basis function are given below.
To fit a line, the basis function would look like this:
|
-- n is the number of coefs; v is the independent variable |
|
-- declare a Lua table for the basis vector |
|
-- basis vector element [1] is 1 |
|
-- basis vector element [2] is v[1], or the x coordinate |
|
-- return the basis vector |
|
-- end of the basis function |
To fit the line about the mean x coordinate, the basis function would look like this:
|
-- n is the number of coefs; c is the independent variable; m is the mean |
|
-- declare a Lua table for the basis vector |
|
-- basis vector element [1] is 1 |
|
-- basis vector element [2] is v[1] |
|
-- return the basis vector |
|
-- end of the basis function |
Note that fitting the line about the origin and about the mean coordinates give different coefficients and errors for the same data.
To fit a quadratic about the origin, the basis function would look like this:
|
-- n is the number of coefs; v is the independent variable |
|
-- declare a Lua table for the basis vector |
|
-- basis vector element [1] is 1 |
|
-- basis vector element [2] is v (the x coordinate) |
|
-- basis vector element [3] is v^2 |
|
-- return the basis vector |
|
-- end of the basis function |
To see how the parameter n might be used, consider fitting a polynomial of order n-1 (the order of a polynomial is the highest power in the polynomial). Including the "constant" term, the polynomial of order n-1 has n coefficients. Here is the basis function:
|
-- n is the number of coefs; v is the independent variable |
|
-- declare a Lua table for the basis vector |
|
-- basis vector element [1] is 1 |
|
-- compute each power of the polynomial recursively |
|
-- basis vector element [n] is v^(n-1) |
|
-- end of loop |
|
-- return the basis vector |
|
-- end of the basis function |
Note that the tables v and m can contain up to 10 elements for fitting as many as 10 independent variables, or "basis dimensions". For example, if fitting to x,y coordinates (i.e., 2 dimensions), the array v has 2 elements, v[1] for the x coordinate and v[2] for the y coordinate. The following basis function fits a warped plan to an (x,y) surface using using coordinates about the mean:
|
-- n is the number of coefs; v is the independent variable |
|
-- declare a Lua table for the basis vector |
|
-- basis vector element b[1] is 1 (the constant term) |
|
-- set b[2] = x |
|
-- set b[3] = y |
|
-- set b[4] = x * y |
|
-- return the basis vector |
|
-- end of the basis function |
This case is handled by the built-in, n-dimensional polynomial basis function selected using SetBasisFunc(1). Mira defaults to this basis function if you do not explicitly select a basis function in the script. In this example, you would then specify a 2x2 coefficient fit using SetNumCoefs({2,2}). In this latter case, notice that coefficients for multiple dimensions are passed as an array using {}.
As a final example, consider a "hyperplane" of the form f = a[1] + a[2] x + a[3] y + a[4] z + ... The hyperplane fits n+1 coefficients because of the constant term a[1]. This is the same as the built-in basis function selected using SetBasisFunc( 2 ).
|
-- n is the number of coefs; v is the independent variable |
|
-- declare a Lua table for the basis vector |
|
-- basis vector element [1] is 1 (the constant term) |
|
|
|
|
|
|
|
-- return the basis vector |
|
-- end of the basis function |