AGENT SKILL

physics-fitting

Nonlinear curve fitting for physics data with proper error propagation, chi-squared analysis, residual diagnostics, confidence intervals, and model comparison (AIC/BIC). Use for any parameter extraction from experimental or simulation data.

License 许可
MIT
所属仓库
fadrienne/MyGitHub
最近更新
2026-10-28
Stars
★ 0
Forks
0

01 前言 Front Matter

name
physics-fitting
tags
[ "Curve Fitting", "Regression", "Chi-Squared", "Error Propagation", "Parameter Estimation", "Physics" ]
author
Synthetic Sciences
license
MIT
version
1.0.0
category
physics
description
Nonlinear curve fitting for physics data with proper error propagation, chi-squared analysis, residual diagnostics, confidence intervals, and model comparison (AIC/BIC). Use for any parameter extraction from experimental or simulation data.
dependencies
[ "scipy>=1.11.0", "numpy>=1.24.0", "matplotlib>=3.7.0", "lmfit>=1.2.0" ]

03 SKILL.md 正文

Physics Data Fitting

Overview

Extract physical parameters from data using nonlinear least squares, chi-squared minimization, and Bayesian inference. Proper error propagation, residual analysis, confidence intervals, and model comparison included.

When to Use

  • Fitting a model function to experimental data
  • Extracting physical constants from measurements
  • Comparing competing models (which theory fits better?)
  • Propagating measurement uncertainties to derived quantities
  • Any parameter estimation with proper error bars

Do NOT Use When

  • You need MCMC / full posterior distributions (use bayesian-inference with emcee/PyMC)
  • You're discovering the model itself (use symbolic-regression)
  • Data is a time series from an ODE (use ode-solver + this skill)

Core Workflows

1. Basic Nonlinear Fit (scipy)

import numpy as np
from scipy.optimize import curve_fit
import matplotlib.pyplot as plt

# Model function
def exponential_decay(t, A, tau, C):
    """y = A * exp(-t/tau) + C"""
    return A * np.exp(-t / tau) + C

# Data with uncertainties
t_data = np.array([0.5, 1, 2, 3, 5, 7, 10, 15, 20])
y_data = np.array([9.8, 8.1, 5.5, 3.9, 2.1, 1.3, 0.7, 0.35, 0.22])
y_err = np.array([0.3, 0.2, 0.2, 0.15, 0.1, 0.1, 0.08, 0.05, 0.04])

# Fit with uncertainties
popt, pcov = curve_fit(exponential_decay, t_data, y_data,
                       sigma=y_err, absolute_sigma=True,
                       p0=[10, 3, 0.1])  # initial guess

# Extract parameters with uncertainties
perr = np.sqrt(np.diag(pcov))
A, tau, C = popt
dA, dtau, dC = perr
print(f"A   = {A:.3f} ± {dA:.3f}")
print(f"τ   = {tau:.3f} ± {dtau:.3f}")
print(f"C   = {C:.3f} ± {dC:.3f}")

# Chi-squared
residuals = (y_data - exponential_decay(t_data, *popt)) / y_err
chi2 = np.sum(residuals**2)
ndof = len(t_data) - len(popt)
chi2_red = chi2 / ndof
print(f"χ²/ndof = {chi2:.2f}/{ndof} = {chi2_red:.2f}")

2. Advanced Fitting with lmfit

from lmfit import Model, Parameters

model = Model(exponential_decay)
params = Parameters()
params.add('A', value=10, min=0)         # bounded
params.add('tau', value=3, min=0.01)     # positive definite
params.add('C', value=0, min=-1, max=1)  # bounded

result = model.fit(y_data, params, t=t_data,
                   weights=1/y_err)

# Full report
print(result.fit_report())

# Confidence intervals (profile likelihood)
ci = result.conf_interval()
print("\nConfidence Intervals:")
for name in result.params:
    print(f"  {name}: {ci[name]}")

# Plot with confidence band
fig, axes = plt.subplots(2, 1, figsize=(10, 8), gridspec_kw={'height_ratios': [3, 1]})

t_fine = np.linspace(0, 22, 200)

ax = axes[0]
ax.errorbar(t_data, y_data, yerr=y_err, fmt='ko', capsize=3, label='Data')
ax.plot(t_fine, exponential_decay(t_fine, *popt), 'r-', linewidth=2, label='Best fit')

# Confidence band via parameter covariance
from scipy.stats import t as t_dist
n_boot = 1000
y_samples = np.zeros((n_boot, len(t_fine)))
rng = np.random.default_rng(42)
for i in range(n_boot):
    p_sample = rng.multivariate_normal(popt, pcov)
    y_samples[i] = exponential_decay(t_fine, *p_sample)
y_lo = np.percentile(y_samples, 2.5, axis=0)
y_hi = np.percentile(y_samples, 97.5, axis=0)
ax.fill_between(t_fine, y_lo, y_hi, alpha=0.2, color='red', label='95% CI')
ax.set_ylabel('y', fontsize=13)
ax.legend(fontsize=11)
ax.grid(True, alpha=0.3)

# Residuals
ax = axes[1]
ax.errorbar(t_data, residuals, yerr=1, fmt='ko', capsize=3)
ax.axhline(0, color='r', linestyle='--')
ax.set_xlabel('t', fontsize=13)
ax.set_ylabel('Residual (σ)', fontsize=13)
ax.grid(True, alpha=0.3)

plt.tight_layout()
plt.savefig('fit_with_residuals.png', dpi=150, bbox_inches='tight')

3. Model Comparison (AIC / BIC)

def model_comparison(models, data_x, data_y, data_err):
    """Compare models using AIC and BIC."""
    results = []

    for name, func, p0 in models:
        try:
            popt, pcov = curve_fit(func, data_x, data_y,
                                   sigma=data_err, absolute_sigma=True, p0=p0)
            residuals = (data_y - func(data_x, *popt)) / data_err
            chi2 = np.sum(residuals**2)
            n = len(data_y)
            k = len(popt)
            ndof = n - k

            # Log-likelihood (Gaussian errors)
            log_L = -0.5 * chi2 - 0.5 * n * np.log(2*np.pi) - np.sum(np.log(data_err))

            aic = 2*k - 2*log_L
            bic = k*np.log(n) - 2*log_L

            results.append({
                'name': name, 'k': k, 'chi2': chi2,
                'chi2_red': chi2/ndof, 'AIC': aic, 'BIC': bic
            })
        except RuntimeError:
            results.append({'name': name, 'k': 0, 'chi2': np.inf,
                           'chi2_red': np.inf, 'AIC': np.inf, 'BIC': np.inf})

    # Print comparison
    print(f"{'Model':<20} {'k':<4} {'χ²/ndof':<10} {'AIC':<10} {'BIC':<10}")
    print("-" * 54)
    for r in sorted(results, key=lambda x: x['AIC']):
        print(f"{r['name']:<20} {r['k']:<4} {r['chi2_red']:<10.3f} {r['AIC']:<10.2f} {r['BIC']:<10.2f}")

    return results

# Example: compare exponential vs power law
def power_law(t, A, n, C):
    return A * t**(-n) + C

models = [
    ('Exponential', exponential_decay, [10, 3, 0.1]),
    ('Power law', power_law, [10, 1, 0.1]),
]
model_comparison(models, t_data, y_data, y_err)

4. Error Propagation

def error_propagation(func, params, cov_matrix, *args):
    """
    Propagate parameter uncertainties through a function.
    Uses the Jacobian: σ²_f = J^T · Σ · J
    """
    eps = 1e-8
    f0 = func(params, *args)
    n_params = len(params)

    # Compute Jacobian numerically
    J = np.zeros((np.size(f0), n_params))
    for i in range(n_params):
        p_up = params.copy()
        p_up[i] += eps
        J[:, i] = (func(p_up, *args) - f0) / eps

    # Propagate: Σ_f = J Σ_p J^T
    cov_f = J @ cov_matrix @ J.T

    return f0, np.sqrt(np.diag(cov_f))

# Example: compute half-life from decay constant
def half_life(params):
    tau = params[1]  # decay time
    return np.array([tau * np.log(2)])

t_half, dt_half = error_propagation(half_life, popt, pcov)
print(f"Half-life: {t_half[0]:.3f} ± {dt_half[0]:.3f}")

Goodness-of-Fit Reference

χ²/ndof Interpretation
≈ 1 Good fit — model matches data within uncertainties
≪ 1 Overfitting or overestimated uncertainties
≫ 1 Poor fit — model inadequate or underestimated uncertainties
0.5 - 2.0 Acceptable range for most physics analyses

Common Pitfalls

Pitfall Fix
absolute_sigma=False (default!) Always set absolute_sigma=True when you have real error bars
Bad initial guess → wrong minimum Try multiple starting points or use lmfit bounds
Correlated parameters Check off-diagonal elements of covariance matrix
Non-Gaussian residuals Plot residual histogram, consider robust fitting
Overfitting (too many parameters) Use AIC/BIC for model selection
Ignoring systematic errors Report systematics separately from statistical errors

04 同仓库更多 Skills

fadrienne
fadrienne/MyGitHub

statistical-power

Sample size calculation, power analysis, and effect size conversion for scientific studies. Use BEFORE data collection (a priori) to determine required N, or after (post-hoc) to compute achieved power. Covers parametric tests (t-test, ANOVA, chi-square, proportions, correlation, regression), simulation-based power for complex/clustered/nested designs, and power curves. Use this skill when someone asks 'how many samples do I need', 'what is my power', 'what effect size can I detect', or any variant. Pairs with /experimental-design (choose design first, then compute power) and /statistical-analysis (analyze data after collection).

Skill与智能体开发
★ 0
fadrienne
fadrienne/MyGitHub

statistical-analysis

Guided statistical analysis with test selection and reporting. Use when you need help choosing appropriate tests for your data, assumption checking, power analysis, and APA-formatted results. Best for academic research reporting, test selection guidance. For implementing specific models programmatically use statsmodels.

测试与质量
★ 0
fadrienne
fadrienne/MyGitHub

scientific-writing

Core skill for the deep research and writing tool. Write scientific manuscripts in full paragraphs (never bullet points). Use two-stage process with (1) section outlines with key points using research-lookup then (2) convert to flowing prose. IMRAD structure, citations (APA/AMA/Vancouver), figures/tables, reporting guidelines (CONSORT/STROBE/PRISMA), for research papers and journal submissions.

内容创作者写作与文案Skill与智能体开发
★ 0
fadrienne
fadrienne/MyGitHub

scientific-visualization

Meta-skill for publication-ready figures. Use when creating journal submission figures requiring multi-panel layouts, significance annotations, error bars, colorblind-safe palettes, and specific journal formatting (Nature, Science, Cell). Orchestrates matplotlib/seaborn/plotly with publication styles. For quick exploration use seaborn or plotly directly.

分析与可视化Skill与智能体开发
★ 0
fadrienne
fadrienne/MyGitHub

research-code

Debug, profile, review, and restructure Python research and analysis code. Use when analysis scripts crash, produce wrong results, run too slowly, or need a correctness review. Covers: reading tracebacks and diagnosing root causes, hypothesis-driven debugging, reviewing code for common statistical/numerical errors, profiling data pipelines, improving reproducibility (seeds, environments, determinism), and structuring analysis scripts for sharing. Distinct from /exploratory-data-analysis (which understands data) and /statistical-analysis (which chooses and runs tests) — this skill focuses on the code itself.

开发工程师资料检索与研究
★ 0
fadrienne
fadrienne/MyGitHub

markdown-mermaid-writing

Comprehensive markdown and Mermaid diagram writing skill. Use when creating any scientific document, report, analysis, or visualization. Establishes text-based diagrams as the default documentation standard with full style guides (markdown + mermaid), 24 diagram type references, and 9 document templates.

内容创作者文档处理写作与文案
★ 0