1.2. Your First Curve Fit¶
In this tutorial, you’ll fit an exponential decay model to data using NLSQ.
1.2.1. What You’ll Learn¶
How to define a model function
How to use
fit()to fit dataHow to extract fitted parameters
1.2.2. Step 1: Import NLSQ¶
from nlsq import fit
import jax.numpy as jnp
import numpy as np
Important
Model functions must use jax.numpy (imported as jnp), not regular
numpy. This enables automatic differentiation and GPU acceleration.
1.2.3. Step 2: Create Sample Data¶
Let’s create synthetic data with known parameters:
# True parameters we want to recover
A_true = 2.5
k_true = 0.5
# Generate data with noise
np.random.seed(42)
x = np.linspace(0, 10, 50)
y_true = A_true * np.exp(-k_true * x)
y = y_true + 0.1 * np.random.normal(size=len(x))
1.2.4. Step 3: Define Your Model¶
The model function describes the mathematical relationship:
def exponential_decay(x, A, k):
"""Exponential decay: y = A * exp(-k * x)"""
return A * jnp.exp(-k * x)
Model function rules:
First argument is always
x(independent variable)Subsequent arguments are fit parameters
Use
jnpfor mathematical operations
1.2.5. Step 4: Fit the Model¶
Now fit the model to data:
# Fit with initial guess
popt, pcov = fit(exponential_decay, x, y, p0=[1.0, 0.3])
# Extract fitted parameters
A_fit, k_fit = popt
print(f"Fitted parameters:")
print(f" A = {A_fit:.4f} (true: {A_true})")
print(f" k = {k_fit:.4f} (true: {k_true})")
Expected output:
Fitted parameters:
A = 2.4892 (true: 2.5)
k = 0.4987 (true: 0.5)
1.2.6. Step 5: Visualize Results¶
import matplotlib.pyplot as plt
plt.figure(figsize=(10, 6))
plt.scatter(x, y, label="Data", alpha=0.7)
x_smooth = np.linspace(0, 10, 200)
y_fit = exponential_decay(x_smooth, *popt)
plt.plot(x_smooth, y_fit, "r-", label="Fitted curve", linewidth=2)
plt.xlabel("x")
plt.ylabel("y")
plt.title("Exponential Decay Fit")
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()
1.2.7. Complete Example¶
from nlsq import fit
import jax.numpy as jnp
import numpy as np
# Define model
def exponential_decay(x, A, k):
return A * jnp.exp(-k * x)
# Generate data
np.random.seed(42)
x = np.linspace(0, 10, 50)
y = 2.5 * np.exp(-0.5 * x) + 0.1 * np.random.normal(size=len(x))
# Fit
popt, pcov = fit(exponential_decay, x, y, p0=[1.0, 0.3])
print(f"A = {popt[0]:.4f}")
print(f"k = {popt[1]:.4f}")
1.2.8. Key Takeaways¶
fit() is the main entry point for curve fitting
Model functions must use
jax.numpyfor mathp0 provides the initial guess for parameters
Returns
popt(fitted parameters) andpcov(covariance matrix)
1.2.9. Initial Guess Tips¶
A good initial guess helps the optimizer converge:
Exponential decay: Start with reasonable amplitude and rate
Gaussian: Use data range for center, width from peak shape
Polynomial: Start with zeros or small values
If unsure, try workflow='auto_global' with bounds for robust fitting.
1.2.10. Common Mistakes¶
Using numpy instead of jax.numpy:
# Wrong - will not work correctly
def model(x, a, b):
return a * np.exp(-b * x)
# Correct
def model(x, a, b):
return a * jnp.exp(-b * x)
Missing initial guess:
# Error: p0 is required
popt, pcov = fit(model, x, y)
# Correct
popt, pcov = fit(model, x, y, p0=[1.0, 0.5])
1.2.11. Next Steps¶
Continue to Understanding Results to learn how to interpret
pcov and calculate parameter uncertainties.