Interpolation
The Interpolation class provides static methods for fast, one-dimensional interpolation of tabulated data. It offers two complementary approaches: quick methods for single-point evaluation, and curve generator factories for reusable interpolating curves.
Quick Methods vs. Curve Generators
The Interpolation class provides two ways to interpolate data, each suited to different scenarios:
Aspect | Quick Methods | Curve Generators |
|---|---|---|
Use case | Single-point evaluation | Repeated evaluations, resampling |
Performance | No allocations, fast for one-off queries | Reusable object, efficient for multiple queries |
Capabilities | Evaluation only | Evaluation, derivatives, integration, resampling |
Example method | Linear(Double[], Double[], Double, OutOfRangeMode, Double) |
Quick Methods are ideal when you need to interpolate at a single point without storing a curve object. They operate directly on arrays and perform no allocations. Examples include Linear(Double[], Double[], Double, OutOfRangeMode, Double), Cubic(Double[], Double[], Double), and Nearest(Double[], Double[], Double, OutOfRangeMode, Double).
The following example demonstrates basic quick method usage:
// Define some data points
double[] x = new double[] { 0.0, 1.0, 2.0, 3.0 };
double[] y = new double[] { 0.0, 2.0, 4.0, 3.0 };
// Linear interpolation at x=1.5
double yq1 = Numerics.NET.Interpolation.Linear(x, y, 1.5);
Console.WriteLine($"Linear interpolation at x=1.5: {yq1}");Quick methods also support different out-of-range behaviors through the OutOfRangeMode parameter:
// Handling out-of-range values with different modes
double yq3 = Numerics.NET.Interpolation.Linear(x, y, 3.5,
OutOfRangeMode.Clamp);
Console.WriteLine($"Linear with Clamp at x=3.5: {yq3}");
double yq4 = Numerics.NET.Interpolation.Linear(x, y, 3.5,
OutOfRangeMode.Fill, fillValue: -1.0);
Console.WriteLine($"Linear with Fill at x=3.5: {yq4}");Curve Generators create reusable curve objects that can be evaluated at multiple points efficiently. They also support additional operations like differentiation, integration, and bulk resampling. Examples include PiecewiseLinearCurve(Double[], Double[]), CubicSpline(Double[], Double[]), and MonotoneCubicSpline(Double[], Double[]).
This example shows how to create a reusable cubic spline curve and evaluate it at multiple points:
// Define some data points
double[] x = new double[] { 0.0, 1.0, 2.0, 3.0, 4.0 };
double[] y = new double[] { 0.0, 2.0, 4.0, 3.0, 5.0 };
// Create a reusable cubic spline curve
CubicSpline spline = Numerics.NET.Interpolation.CubicSpline(x, y);
// Evaluate at multiple points
double y1 = spline.ValueAt(1.5);
double y2 = spline.ValueAt(2.5);
Console.WriteLine($"Spline at x=1.5: {y1}, at x=2.5: {y2}");Curves can be efficiently resampled at many query points using the Resample(Curve, Double[]) method:
// Resample at many points efficiently
double[] xq = new double[] { 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5 };
double[] ys = Numerics.NET.Interpolation.Resample(spline, xq);
Console.WriteLine("Resampled values:");
for (int i = 0; i < xq.Length; i++)
{
Console.WriteLine($" x={xq[i]}: y={ys[i]:F4}");
}Coordinate Transformations
The PiecewiseInterpolatingCurve class supports interpolation in transformed coordinate spaces. This is useful for data that varies exponentially, sigmoidally, or follows other nonlinear relationships.
The following transform modes are available through specialized factory methods:
Transform | Factory Method | Use Case |
|---|---|---|
Log-linear | Data varying logarithmically with x (e.g., frequency response) | |
Log-log | Power-law relationships (y ∝ xk) | |
Logit-linear | Probability data, sigmoid relationships (y ∈ (0,1)) | |
Decibel (amplitude) | DecibelAmplitudeCurve(Double[], Double[]) | Audio and signal processing (20×log₁₀) |
Decibel (power) | DecibelPowerCurve(Double[], Double[]) | Power measurements (10×log₁₀) |
Transformations are applied once during construction, and the inverse transformation is applied during evaluation. This ensures that interpolation is performed in the appropriate space while input and output remain in the original units.
The following example demonstrates log-linear interpolation for frequency response data:
// Example: Frequency response data (log-spaced frequencies)
double[] frequencies = new double[] { 1.0, 10.0, 100.0, 1000.0 };
double[] gains = new double[] { 10.0, 50.0, 200.0, 1000.0 };
// Create a log-linear curve (linear in log-frequency space)
PiecewiseInterpolatingCurve curve =
Numerics.NET.Interpolation.LogLinearCurve(frequencies, gains);
// Interpolate at intermediate frequency
double gainAt50Hz = curve.ValueAt(50.0);
Console.WriteLine($"Gain at 50 Hz: {gainAt50Hz:F2}");For power-law relationships where both axes should be logarithmic, use log-log interpolation:
// For log-log (power law relationships)
double[] x = new double[] { 1.0, 10.0, 100.0 };
double[] y = new double[] { 1.0, 100.0, 10000.0 }; // y = x^2
PiecewiseInterpolatingCurve logLogCurve =
Numerics.NET.Interpolation.LogLogCurve(x, y);
double yAt5 = logLogCurve.ValueAt(5.0);
Console.WriteLine($"Log-log interpolation at x=5: {yAt5:F2}");Periodic Interpolation
Periodic interpolation is useful for data that repeats with a fixed period, such as daily temperature cycles, seasonal patterns, or angular positions in rotating machinery.
The PeriodicLinearCurve(Double[], Double[], Double) method creates a curve that wraps query points modulo the specified period. Values outside the initial range [x₀, x₀ + period) are automatically mapped back into range before interpolation. The curve is seamless at the period boundaries.
The following example demonstrates periodic interpolation for a daily temperature cycle:
// Example: Temperature variation over 24 hours
double[] times = new double[] { 0, 6, 12, 18, 24 };
double[] temperatures = new double[] { 10, 8, 20, 15, 10 };
// Create a periodic curve with period=24 hours
PiecewiseInterpolatingCurve curve =
Numerics.NET.Interpolation.PeriodicLinearCurve(
times, temperatures, period: 24.0);
// Query at various times - automatically wraps
double temp0 = curve.ValueAt(0);
double temp24 = curve.ValueAt(24); // Same as at 0
double temp30 = curve.ValueAt(30); // Wraps to hour 6
Console.WriteLine($"Temperature at hour 0: {temp0}°C");
Console.WriteLine($"Temperature at hour 24: {temp24}°C");
Console.WriteLine($"Temperature at hour 30: {temp30}°C");Circular (Angular) Interpolation
Circular interpolation handles angular data correctly by accounting for the wraparound at 360° (or 2π radians). This prevents interpolation artifacts when angles cross the discontinuity boundary.
The CircularLinearCurve(Double[], Double[], Boolean) method creates a curve that unwraps angles during construction to minimize discontinuities, then wraps the interpolated result back to the standard range. This produces smooth interpolation across angle boundaries (e.g., from 359° to 1°).
Common applications include:
Compass headings and wind directions
Phase angles in signal processing
Rotational positions and orientations
Periodic angular measurements
The following example demonstrates circular interpolation for wind direction data that crosses the 360°/0° boundary:
// Example: Wind direction over time
// Angles cross the 360°/0° boundary
double[] times = new double[] { 0, 1, 2, 3, 4 };
double[] headings = new double[] { 350, 355, 5, 10, 15 };
// Create a circular curve for angles in degrees
PiecewiseInterpolatingCurve curve =
Numerics.NET.Interpolation.CircularLinearCurve(
times, headings, degrees: true);
// Interpolate at intermediate time
// This correctly interpolates across the 360°/0° boundary
double heading0_5 = curve.ValueAt(0.5);
double heading1_5 = curve.ValueAt(1.5);
Console.WriteLine($"Heading at t=0.5: {heading0_5:F1}°");
Console.WriteLine($"Heading at t=1.5: {heading1_5:F1}°");Inverse Interpolation
Inverse interpolation finds the x-coordinate corresponding to a given y-value. This is useful for finding thresholds, solving equations, and reversing functional relationships.
For strictly monotone data, use InverseLinear(Double[], Double[], Double), which uses efficient binary search.
For non-monotone data where multiple solutions may exist, use:
InverseLinearBefore(Double[], Double[], Double, Double) – finds the largest x ≤ reference where y equals the target
InverseLinearAfter(Double[], Double[], Double, Double) – finds the smallest x ≥ reference where y equals the target
InverseLinearNear(Double[], Double[], Double, Double) – finds the x closest to reference where y equals the target
The following example demonstrates inverse interpolation for monotone data:
// Example: Find x for a given y
double[] x = new double[] { 0, 1, 2, 3, 4 };
double[] y = new double[] { 0, 2, 5, 7, 10 };
// Find x where y=6 (monotone data)
double xAtY6 = Numerics.NET.Interpolation.InverseLinear(x, y, 6.0);
Console.WriteLine($"x where y=6: {xAtY6:F4}");For non-monotone data, use specialized methods to select which solution to return:
// For non-monotone data, use specialized methods
double[] xNonMono = new double[] { 0, 1, 2, 3, 4 };
double[] yNonMono = new double[] { 0, 3, 1, 4, 2 };
// Find the x closest to 2.5 where y=2
double xNear = Numerics.NET.Interpolation.InverseLinearNear(
xNonMono, yNonMono, y: 2.0, x: 2.5);
Console.WriteLine($"x nearest to 2.5 where y=2: {xNear:F4}");Quick Methods and Curve Generator Mapping
The following table maps quick interpolation methods to their corresponding curve generator factory methods:
Quick Method | Curve Generator | Curve Type |
|---|---|---|
Linear(Double[], Double[], Double, OutOfRangeMode, Double) | ||
Previous(Double[], Double[], Double, OutOfRangeMode, Double) | ||