Model Functions Reference¶
NLSQ provides built-in model functions for common curve fitting scenarios.
Using Built-in Functions¶
Import from nlsq.core.functions:
from nlsq.core.functions import gaussian, exponential_decay, lorentzian
All functions are JAX-compatible and JIT-compilable. Each function includes:
Automatic p0 estimation via
.estimate_p0(xdata, ydata)Reasonable default bounds via
.bounds()
Peak Functions¶
gaussian¶
- nlsq.core.functions.gaussian(x, amp, mu, sigma)[source]
Gaussian (normal distribution) function: y = amp * exp(-(x-mu)² / (2*sigma²))
Common for spectral peaks, chromatography peaks, probability distributions.
- Parameters:
- Returns:
y – Dependent variable
- Return type:
array_like
Notes
Peak position: x = mu
Peak height: y = amp
FWHM (Full Width at Half Maximum): FWHM = 2.355 * sigma
Integral: ∫ gaussian dx = amp * sigma * sqrt(2π)
Examples
>>> from nlsq import curve_fit >>> from nlsq.core.functions import gaussian >>> import numpy as np >>> >>> # Spectral peak at x=5 with FWHM ≈ 2.355 >>> x = np.linspace(0, 10, 200) >>> y = 10 * np.exp(-(x-5)**2 / (2*1**2)) + np.random.normal(0, 0.2, 200) >>> popt, pcov = curve_fit(gaussian, x, y, p0='auto') >>> print(f"Peak at {popt[1]:.2f}, FWHM = {2.355*popt[2]:.2f}")
lorentzian¶
- nlsq.core.functions.lorentzian(x, amp, x0, gamma)[source]
Lorentzian (Cauchy) peak function: y = amp / (1 + ((x - x0) / gamma)²)
Common for spectral line shapes (NMR, IR, Raman), resonance curves, and natural line broadening.
- Parameters:
- Returns:
y – Dependent variable
- Return type:
array_like
Notes
Peak position: x = x0
Peak height: y = amp
FWHM (Full Width at Half Maximum): FWHM = 2 * gamma
Integral: ∫ lorentzian dx = amp * gamma * π
Heavier tails than Gaussian (decays as 1/x² vs exp(-x²))
Examples
>>> from nlsq import curve_fit >>> from nlsq.core.functions import lorentzian >>> import numpy as np >>> >>> # Spectral peak at x=5 with FWHM = 2 >>> x = np.linspace(0, 10, 200) >>> y = 10 / (1 + ((x - 5) / 1)**2) + np.random.normal(0, 0.2, 200) >>> popt, pcov = curve_fit(lorentzian, x, y, p0='auto') >>> print(f"Peak at {popt[1]:.2f}, FWHM = {2*popt[2]:.2f}")
Exponential Functions¶
exponential_decay¶
- nlsq.core.functions.exponential_decay(x, a, b, c)[source]
Exponential decay: y = a * exp(-b*x) + c
Common for radioactive decay, cooling curves, discharge curves.
- Parameters:
- Returns:
y – Dependent variable
- Return type:
array_like
Notes
Half-life: t_half = ln(2) / b
Time constant: τ = 1 / b
At x=0: y = a + c
As x→∞: y → c
Examples
>>> from nlsq import curve_fit >>> from nlsq.core.functions import exponential_decay >>> import numpy as np >>> >>> # Radioactive decay with half-life = ln(2)/0.5 ≈ 1.4 >>> x = np.linspace(0, 10, 100) >>> y = 100 * np.exp(-0.5 * x) + 10 + np.random.normal(0, 2, 100) >>> popt, pcov = curve_fit(exponential_decay, x, y, p0='auto') >>> print(f"Half-life: {np.log(2)/popt[1]:.2f}")
exponential_growth¶
- nlsq.core.functions.exponential_growth(x, a, b, c)[source]
Exponential growth: y = a * exp(b*x) + c
Common for population growth, compound interest, bacterial growth.
- Parameters:
- Returns:
y – Dependent variable
- Return type:
array_like
Notes
Doubling time: t_double = ln(2) / b
At x=0: y = a + c
As x→∞: y → ∞ (unbounded growth)
Examples
>>> from nlsq import curve_fit >>> from nlsq.core.functions import exponential_growth >>> import numpy as np >>> >>> # Bacterial growth with doubling time = ln(2)/0.3 ≈ 2.3 >>> x = np.linspace(0, 5, 50) >>> y = 10 * np.exp(0.3 * x) + np.random.normal(0, 1, 50) >>> popt, pcov = curve_fit(exponential_growth, x, y, p0='auto') >>> print(f"Doubling time: {np.log(2)/popt[1]:.2f}")
Sigmoid Functions¶
sigmoid¶
- nlsq.core.functions.sigmoid(x, L, x0, k, b)[source]
Sigmoid (logistic) function: y = L / (1 + exp(-k*(x-x0))) + b
Common for dose-response curves, growth saturation, S-curves.
- Parameters:
- Returns:
y – Dependent variable
- Return type:
array_like
Notes
At x=x0: y = L/2 + b (midpoint)
As x→-∞: y → b (lower asymptote)
As x→+∞: y → L + b (upper asymptote)
Steeper curve: larger k
Examples
>>> from nlsq import curve_fit >>> from nlsq.core.functions import sigmoid >>> import numpy as np >>> >>> # Dose-response curve >>> x = np.linspace(0, 10, 100) >>> y = 5 / (1 + np.exp(-2*(x-5))) + 1 + np.random.normal(0, 0.1, 100) >>> popt, pcov = curve_fit(sigmoid, x, y, p0='auto') >>> print(f"EC50 (midpoint): {popt[1]:.2f}")
Power Functions¶
power_law¶
- nlsq.core.functions.power_law(x, a, b)[source]
Power law function: y = a * x^b
Common for scaling relationships, fractals, allometry.
- Parameters:
- Returns:
y – Dependent variable
- Return type:
array_like
Notes
b > 0: increasing function (growth)
b < 0: decreasing function (decay)
b = 1: linear relationship
For x=1: y = a
Examples
>>> from nlsq import curve_fit >>> from nlsq.core.functions import power_law >>> import numpy as np >>> >>> # Allometric scaling: metabolic rate ∝ mass^0.75 >>> x = np.linspace(1, 100, 50) >>> y = 3 * x**0.75 + np.random.normal(0, 0.5, 50) >>> popt, pcov = curve_fit(power_law, x, y, p0='auto') >>> print(f"Scaling exponent: {popt[1]:.2f}")
linear¶
- nlsq.core.functions.linear(x, a, b)[source]
Linear function: y = a*x + b
- Parameters:
- Returns:
y – Dependent variable
- Return type:
array_like
Examples
>>> from nlsq import curve_fit >>> from nlsq.core.functions import linear >>> import numpy as np >>> >>> x = np.array([1, 2, 3, 4, 5]) >>> y = 2 * x + 3 + np.random.normal(0, 0.1, 5) >>> popt, pcov = curve_fit(linear, x, y, p0='auto') >>> print(f"Slope: {popt[0]:.2f}, Intercept: {popt[1]:.2f}")
polynomial¶
- nlsq.core.functions.polynomial(degree)[source]
Create polynomial function of given degree.
Returns a function that computes: y = c0*x^n + c1*x^(n-1) + … + cn where n is the degree.
- Parameters:
degree (int) – Polynomial degree (0, 1, 2, 3, …)
- Returns:
poly_func – Polynomial function with signature poly(x, *coeffs)
- Return type:
callable
Examples
>>> from nlsq import curve_fit >>> from nlsq.core.functions import polynomial >>> import numpy as np >>> >>> # Fit quadratic: y = ax² + bx + c >>> quadratic = polynomial(2) >>> x = np.linspace(-5, 5, 50) >>> y = 2*x**2 + 3*x + 1 + np.random.normal(0, 0.5, 50) >>> popt, pcov = curve_fit(quadratic, x, y, p0='auto') >>> print(f"Coefficients: {popt}")
Polynomial function factory for arbitrary degree.
Example:
import jax.numpy as jnp
# Define directly for curve fitting
def quadratic(x, a, b, c):
return a + b * x + c * x**2
Creating Custom Functions¶
Custom model functions must use JAX operations:
import jax.numpy as jnp
def custom_model(x, a, b, c, d):
"""Custom model combining exponential and oscillation."""
decay = a * jnp.exp(-b * x)
oscillation = c * jnp.sin(d * x)
return decay * oscillation
# Use like any built-in function
popt, pcov = fit(custom_model, x, y, p0=[1, 0.1, 1, 2 * jnp.pi])
Rules for custom functions:
Use
jax.numpyinstead ofnumpyAvoid Python control flow on traced values
Keep functions pure (no side effects)
First parameter must be the independent variable
See Also¶
Your First Curve Fit - Basic usage examples
JAX and Automatic Differentiation - Why JAX is required
How to Choose a Model Function - Model selection guide