Two-Dimensional Grid Interpolation

This documentation was generated with the assistance of AI. Please report any inaccuracies.

When a function of two variables is tabulated on a complete rectangular grid — every combination of a set of values and a set of values — its interpolation can be built entirely out of the 1D interpolators already described on this page, applied one dimension at a time. This is described in Press et al., 2007, Section 3.6 (page 132), and implemented as BilinearInterpolator, Polynomial2DInterpolator, and BicubicSpline2DInterpolator in the com.irurueta.numerical.interpolation package.

The grid square

Given tabulated values , any point falls inside a grid square bounded by four tabulated points, numbered counterclockwise from the lower left. Defining the normalized local coordinates:

(both lying in ), the simplest possible interpolation — bilinear — is:

This is continuous as the interpolation point crosses from one grid square to the next, but its gradient changes discontinuously at grid-square boundaries.

Two directions beyond bilinear

Going beyond bilinear interpolation means picking one of two distinct goals: higher accuracy for sufficiently smooth functions, without necessarily fixing up derivative continuity; or explicit smoothness of the gradient across grid-square boundaries.

Higher order for accuracy: tensor-product polynomial interpolation

To do order interpolation in the direction and order in : locate the sub-block of the table surrounding the target point, run polynomial interpolations along the rows (in the direction) to get values at , then one final polynomial interpolation across those values in the direction.

Higher order for smoothness: bicubic spline

To get smoothness instead: construct one cubic spline across each row of the table (once, at setup time). For each interpolated value: run all of those row splines at the target to get a column of values , construct one more cubic spline through that column, and evaluate it at the target .

flowchart TD A["Tabulated grid y_ij, arrays x1, x2"] --> B{"Which 2D interpolator?"} B -->|"Bilinear"| C["Locate grid square (i,j);\nweighted average of 4 corners using t, u"] B -->|"Polynomial2DInterpolator"| D["Locate m x n sub-block;\nm row-wise polynomial interpolations at x2,\nthen 1 column-wise polynomial interpolation at x1"] B -->|"BicubicSpline2DInterpolator"| E["One spline per row (built once);\nevaluate all rows at x2,\nbuild 1 column spline through the results, evaluate at x1"]

Bicubic splines cost more: setup scales with the full table size , and each interpolated value costs roughly — versus a constant plus for local, tensor-product polynomial interpolation. That price buys the nonlocal smoothness a spline provides. For modest table sizes (a few hundred points per side), the extra cost is usually not a concern.

Library implementation

Class Built from Notes

BilinearInterpolator

Two LinearInterpolator instances (reused only for their locate/hunt search, not for interpolation itself)

Fixed bilinear order; no tunable parameters.

Polynomial2DInterpolator

Row/column PolynomialInterpolator instances

Constructor takes mp/np — the local order (points used) in each direction; defaults to using every point in each array.

BicubicSpline2DInterpolator

One CubicSplineInterpolator per table row, plus one more built per call for the column

No tunable order; natural spline boundary conditions throughout.

All three share the same constructor shape — an array of values, an array of values, and a Matrix of tabulated values — and expose interpolate(x1p, x2p).

BilinearInterpolator is the right place to start for two-dimensional interpolation unless a specific need for higher accuracy or gradient smoothness is already known — it is by far the cheapest of the three.

Example

final var interpolator = new BilinearInterpolator(x1, x2, y);
final var value = interpolator.interpolate(x1Target, x2Target);