adctoolbox.aout.rearrange_error_by_value 源代码

"""Core computation for value-binned error analysis."""

import numpy as np
from typing import Any
from adctoolbox.fundamentals.fit_sine_4param import fit_sine_4param
from adctoolbox.aout._infer_signal_range import _infer_signal_range

[文档] def rearrange_error_by_value( signal: np.ndarray, norm_freq: float = None, n_bins: int = 100, clip_percent: float = 0.01, value_range: tuple[float, float | None] = None, ) -> dict[str, Any]: """ Compute value-binned error metrics. Maps input signal linearly to [0, n_bins-1]. """ signal = np.asarray(signal).flatten() if n_bins is None: n_bins = 100 # Determine boundaries v_min, v_max = _infer_signal_range(signal, value_range) # Map physical values to bin indices [0, n_bins-1] scale_range = v_max - v_min if scale_range == 0: scale = 0.0 else: scale = (n_bins - 1) / scale_range raw_indices = (signal - v_min) * scale bin_indices = np.round(raw_indices).astype(int) bin_indices = np.clip(bin_indices, 0, n_bins - 1) # Fit sine wave and compute residuals if norm_freq is None or np.isnan(norm_freq): fit_res = fit_sine_4param(signal) norm_freq = fit_res['frequency'] else: fit_res = fit_sine_4param(signal, frequency_estimate=norm_freq) fitted_signal = fit_res['fitted_signal'] error = signal - fitted_signal # Filter out edges if requested if clip_percent > 0: margin = int(n_bins * clip_percent) valid_mask = (bin_indices >= margin) & (bin_indices <= n_bins - 1 - margin) else: valid_mask = np.ones(len(bin_indices), dtype=bool) valid_indices = bin_indices[valid_mask] valid_error = error[valid_mask] # Compute statistics using vectorized operations count_per_bin = np.bincount(valid_indices, minlength=n_bins) sum_err_per_bin = np.bincount(valid_indices, weights=valid_error, minlength=n_bins) sum_sq_err_per_bin = np.bincount(valid_indices, weights=valid_error**2, minlength=n_bins) with np.errstate(divide='ignore', invalid='ignore'): # INL Profile error_mean = np.where(count_per_bin > 0, sum_err_per_bin / count_per_bin, np.nan) # Noise Profile error_rms = np.where(count_per_bin > 0, np.sqrt(sum_sq_err_per_bin / count_per_bin), np.nan) return { 'error_mean': error_mean, 'error_rms': error_rms, 'bin_centers': np.arange(n_bins), 'bin_indices': bin_indices, 'error': error, 'fitted_signal': fitted_signal, 'n_bins': n_bins, 'norm_freq': float(norm_freq), }