بازبینی تغییر یک فرمول، فقط مقایسهٔ دو عددِ ظاهراً معقول نیست. ممکن است نسخهٔ تازه، وابستگی به پهنای‌باند را اشتباه کند، ولی در یک ورودیِ خاص همان جواب قبلی را بدهد. در این درس، یک مقاومت ایدئال و سه پارامتر ساختگی انتخاب می‌کنیم تا واحد، پاسخ دستی و مرجع مستقل را کنار هم بگذاریم. هیچ نویز واقعی، فایل صوتی، حسگر یا تقویت‌کننده‌ای اندازه‌گیری نمی‌شود؛ خروجی، پیش‌بینیِ یک مدل محدود است.

۱. چگالی طیفی با ولتاژ کل یک کمیت نیست

تمایز چگالی طیفی نویز و کمیت انتگرال‌گرفته در یک باند
تصویر مفهومی: تمایز چگالی طیفی نویز و کمیت انتگرال‌گرفته در یک باند؛ بدون مقیاس عددی و مستقل از نتایج اجرای کد.

در قرارداد تک‌سویهٔ این مدل، چگالی طیفیِ توانِ ولتاژ برابر S_v=4k_BTR با واحد ولتِ مربع بر هرتز است. ریشهٔ آن، چگالی دامنه با واحد ولت بر رادیکال هرتز می‌شود. این دو را هر دو «چگالی نویز» بنامیم و واحد را حذف کنیم، بازبینی فرمول دشوار می‌شود. چگالی دامنه هنوز یک ولتاژ مؤثرِ کل در باندِ معلوم نیست.

بخش نویز حرارتی در یادداشت TI، مدل مقاومت ایدئال و وابستگی چگالی به دمای کلوین و مقاومت را توضیح می‌دهد. صفحهٔ دوم MT-047 از Analog Devices رابطهٔ مؤثر را صریحاً به شکل sqrt(4k_BTRB) می‌نویسد. این‌ها مراجع فنی سازندگان‌اند؛ در این نوشته، نتایج مستقلِ آزمونِ یک محصول محسوب نمی‌شوند.

برای بهرهٔ مرجعِ یک، مربع ولتاژ مؤثر از ضربِ PSD در پهنای‌باندِ معادل نویز به دست می‌آید؛ سپس ریشه می‌گیریم. بنابراین چگالی دامنه در ریشهٔ پهنای‌باند ضرب می‌شود، نه در خودِ آن. پاسخ، ولتاژ مدارِ باز است. مقاومت بار، تقسیم ولتاژ، نویز جریانِ تقویت‌کننده و سهمِ قطعات دیگر را در همین عدد پنهان نمی‌کنیم؛ آن‌ها مدل و محاسبهٔ دیگری لازم دارند.

۲. قرارداد کلوین، اهم و پهنای‌باند معادل

سه ورودی مستقل دما، مقاومت و پهنای‌باند معادل نویز
تصویر مفهومی: سه ورودی مستقل دما، مقاومت و پهنای‌باند معادل نویز؛ بدون مقیاس عددی و مستقل از نتایج اجرای کد.

ورودی نمونه، هزار اهم، ۳۰۰ کلوین و ده‌هزار هرتز است. ثابت بولتزمن در شرح NIST از SI دقیقاً 1.380649e-23 J/K است. دقیق‌بودن این مقدارِ تعریفی به معنی دقیق‌بودن دما، مقاومت یا دستگاه نیست. همچنین نوشتن آن در یک متغیر float، نمایش دودوییِ تقریب‌زده می‌سازد؛ مرجع اعشاریِ آزمون، مقدار دقیقِ رشته را جدا نگه می‌دارد.

پهنای‌باندِ ورودی را نویسنده مفروض می‌گیرد؛ کد آن را از فرکانس قطع، نرخ نمونه‌برداری یا تعداد نمونه‌ها محاسبه نمی‌کند. برای یک فیلتر مستطیلیِ ایدئال با بهرهٔ یک، پهنای باند عبور همان مقدار است. در حالت دیگر باید پهنای‌باندِ معادل نویزِ مناسب را مستقل به دست آورد. برابری با فرکانس قطعِ هر فیلتر، یک قاعدهٔ عمومی نیست و این تابع آن را تأیید نمی‌کند.

دامنهٔ آموزشی، مقاومت یک تا یک‌میلیون اهم و دمای ۲۰۰ تا ۴۰۰ کلوین است. پهنای‌باند یا صفر است یا در بازهٔ بستهٔ یک‌میلیونیم تا یک‌میلیون هرتز قرار دارد. این کران‌ها جلوی دامنه‌های عددیِ نامحدود را می‌گیرند؛ حدود فیزیکیِ تمام مقاومت‌ها نیستند. کاربرد مدل کلاسیکِ سفید در محدودهٔ فرکانسیِ مربوط نیز فرض جداست؛ کران عددیِ ورودی، معتبر بودن فیزیک یا حذف اثرهای فرکانسیِ قطعهٔ واقعی را اثبات نمی‌کند.

۳. کد کامل و مرجع اعشاری مستقل

مرجع عددی مستقل در کنار محاسبهٔ نظری مقاومت
تصویر مفهومی: مرجع عددی مستقل در کنار محاسبهٔ نظری مقاومت؛ بدون مقیاس عددی و مستقل از نتایج اجرای کد.

تابع، فقط int یا float دقیق را می‌پذیرد؛ bool، رشته، مختلط، NaN و بی‌نهایت رد می‌شوند. واحدها باید دقیقاً ('ohm','K','Hz') باشند. هزار اهم را با عدد یک و برچسب اهم نمی‌فرستیم و ۲۷ سلسیوس را بی‌صدا کلوین فرض نمی‌کنیم. اگر داده از مرز دیگری آمده، تبدیل و اعتبار واحد باید پیش از فراخوانی و با قراردادِ روشن انجام شود.

"""Bounded classical open-circuit resistor-noise calculation; no measurements."""
import json
import math
import platform
from decimal import Decimal, localcontext
from itertools import product

K_B = 1.380649e-23  # Rounded binary64 representation of exact SI decimal.


def bounded_number(value, lower, upper, name):
    if type(value) not in (int, float):
        raise TypeError(name + " must be int or float, not bool")
    if not lower <= value <= upper:
        raise ValueError(name + " outside the finite model range")
    return float(value)


def resistor_noise(resistance_ohm, temperature_k, noise_bandwidth_hz,
                   *, units=("ohm", "K", "Hz")):
    if type(units) is not tuple or units != ("ohm", "K", "Hz"):
        raise ValueError("units must be exactly ('ohm', 'K', 'Hz')")
    r = bounded_number(resistance_ohm, 1, 1_000_000, "resistance")
    t = bounded_number(temperature_k, 200, 400, "temperature")
    b = bounded_number(noise_bandwidth_hz, 0, 1_000_000, "bandwidth")
    if 0 < b < 1e-6:
        raise ValueError("positive bandwidth must be at least 1e-6 Hz")
    psd = 4 * K_B * t * r  # One-sided voltage PSD, V**2/Hz.
    mean_square = psd * b  # Ideal unity-gain noise-equivalent bandwidth.
    return {
        "one_sided_psd_v2_per_hz": psd,
        "amplitude_density_v_per_sqrt_hz": math.sqrt(psd),
        "mean_square_v2": mean_square,
        "rms_v": math.sqrt(mean_square),
    }


def decimal_reference(r, t, b):
    # Exact SI k and represented input floats, not the main binary constant.
    with localcontext() as ctx:
        ctx.prec = 80
        rr, tt, bb = (Decimal.from_float(float(x)) for x in (r, t, b))
        psd = Decimal(4) * Decimal("1.380649e-23") * tt * rr
        mean_square = psd * bb
        return tuple(float(x) for x in
                     (psd, psd.sqrt(), mean_square, mean_square.sqrt()))


def rejects(exception, function, *args, **kwargs):
    try:
        function(*args, **kwargs)
    except exception:
        return True
    return False


def close(a, b):
    return math.isclose(a, b, rel_tol=2e-15, abs_tol=0.0)


def run_example():
    checks = {}
    hand = resistor_noise(1000, 300, 10_000)
    checks["hand_mean_square_literal"] = close(hand["mean_square_v2"], 1.6567788e-13)
    checks["hand_psd_literal"] = close(hand["one_sided_psd_v2_per_hz"], 1.6567788e-17)
    checks["one_hz_density_equals_rms"] = close(
        resistor_noise(1000, 300, 1)["rms_v"],
        hand["amplitude_density_v_per_sqrt_hz"])
    fixtures = list(product((1, 1000.5, 1_000_000), (200, 300, 400),
                            (0, 1e-6, 10_000, 1_000_000)))
    checks["decimal_independent_36_fixtures_one_group"] = all(
        all(close(actual, expected) for actual, expected in
            zip(resistor_noise(r, t, b).values(), decimal_reference(r, t, b)))
        for r, t, b in fixtures)
    four_b = resistor_noise(1000, 300, 40_000)
    checks["bandwidth_fourfold_rms_twofold"] = (
        close(four_b["rms_v"], 2 * hand["rms_v"]) and
        close(four_b["mean_square_v2"], 4 * hand["mean_square_v2"]))
    four_r = resistor_noise(4000, 300, 10_000)
    checks["resistance_fourfold_density_twofold"] = close(
        four_r["amplitude_density_v_per_sqrt_hz"],
        2 * hand["amplitude_density_v_per_sqrt_hz"])
    low_t, high_t = (resistor_noise(1000, t, 10_000) for t in (200, 400))
    checks["kelvin_twofold_mean_square_twofold"] = (
        close(high_t["mean_square_v2"], 2 * low_t["mean_square_v2"]) and
        close(high_t["rms_v"], math.sqrt(2) * low_t["rms_v"]))
    checks["density_independent_of_bandwidth"] = (
        hand["amplitude_density_v_per_sqrt_hz"] ==
        four_b["amplitude_density_v_per_sqrt_hz"])
    zero = resistor_noise(1000, 300, 0)
    checks["zero_bandwidth_not_zero_density"] = (
        zero["rms_v"] == zero["mean_square_v2"] == 0 and
        zero["one_sided_psd_v2_per_hz"] > 0)
    wrong_numeric = hand["amplitude_density_v_per_sqrt_hz"] * 10_000
    checks["reject_linear_bandwidth_formula_by_witness"] = (
        not close(wrong_numeric, hand["rms_v"]) and
        close(wrong_numeric / hand["rms_v"], 100))
    checks["unit_profile_rejects_relabelling"] = all(
        rejects(ValueError, resistor_noise, 1000, 300, 10_000, units=u)
        for u in (("kohm", "K", "Hz"), ("ohm", "C", "Hz"),
                  ("ohm", "K", "kHz"), ["ohm", "K", "Hz"]))
    checks["non_numeric_and_bool_rejected"] = all(
        rejects(TypeError, resistor_noise, *args)
        for args in ((True, 300, 1), (1000, "300", 1),
                     (1000, 300, False), (1000, 300, 1j)))
    checks["nonfinite_in_each_position_rejected"] = all(
        rejects(ValueError, resistor_noise, *args)
        for bad in (math.nan, math.inf, -math.inf)
        for args in ((bad, 300, 1), (1000, bad, 1), (1000, 300, bad)))
    checks["physical_and_policy_bounds_rejected"] = all(
        rejects(ValueError, resistor_noise, *args)
        for args in ((0, 300, 1), (-1, 300, 1), (1_000_001, 300, 1),
                     (1000, 199, 1), (1000, 401, 1),
                     (1000, 300, -1), (1000, 300, 1_000_001),
                     (1000, 300, math.nextafter(1e-6, 0))))
    checks["declared_closed_bounds_accepted_finite"] = all(
        all(math.isfinite(x) and x >= 0 for x in
            resistor_noise(r, t, b).values())
        for r, t, b in ((1, 200, 1e-6), (1_000_000, 400, 1_000_000)))
    checks["disjoint_band_mean_squares_add"] = close(
        resistor_noise(1000, 300, 2500)["mean_square_v2"] +
        resistor_noise(1000, 300, 7500)["mean_square_v2"],
        hand["mean_square_v2"])
    assert all(type(v) is bool and v for v in checks.values()), checks
    return {
        "python_version": platform.python_version(),
        "data_origin": "synthetic model parameters; no acquired samples",
        "contract": "open-circuit ideal classical resistor; one-sided flat PSD; supplied unity-gain noise-equivalent bandwidth",
        "units": {"resistance": "ohm", "temperature": "K", "bandwidth": "Hz",
                  "psd": "V^2/Hz", "amplitude_density": "V/sqrt(Hz)",
                  "mean_square": "V^2", "rms": "V"},
        "hand_inputs": {"resistance_ohm": 1000, "temperature_k": 300,
                        "noise_bandwidth_hz": 10_000},
        "hand_result": hand,
        "fourfold_bandwidth_rms_v": four_b["rms_v"],
        "decimal_reference_precision": 80,
        "independent_fixture_count_in_one_group": len(fixtures),
        "comparison_tolerance": {"relative": 2e-15, "absolute": 0},
        "checks": checks,
        "unique_check_groups": len(checks),
    }


if __name__ == "__main__":
    print(json.dumps(run_example(), ensure_ascii=False, indent=2))

چهار خروجیِ نام‌دار، PSD تک‌سویه، چگالی دامنه، میانگین مربع و RMS هستند. برنامه نه نمونهٔ تصادفی تولید می‌کند و نه از میانگینِ تعداد محدودی نمونه، پارامترِ آماری برآورد می‌کند. از همین رو، درس RMS نمونه‌های ولتاژ مسئلهٔ دیگری دارد: آنجا دادهٔ نمونه‌برداری‌شده ورودی است؛ اینجا پارامترِ مدل و یک باندِ فرضی را به تابع می‌دهیم.

مرجع با Decimal و دقت هشتاد رقم ساخته شده است. ثابت را از رشتهٔ دقیق می‌گیرد و ورودی‌ها را با Decimal.from_float از مقدارِ واقعاً نمایش‌داده‌شده می‌سازد؛ این رفتار در مستندات Decimal مشخص است. مسیر اصلی حسابِ دودویی و ریشهٔ math دارد. این استقلالِ نمایش و دقت، شاهد مفیدی است، ولی مرجع هنوز همان مدل فیزیکی را فرض می‌کند و اندازه‌گیریِ مستقل نیست.

۴. شاهد تغییر فرمول و نتیجهٔ اجرا

اثر پهنای باند مفروض بر کمیت مربع و ریشهٔ آن
تصویر مفهومی: اثر پهنای باند مفروض بر کمیت مربع و ریشهٔ آن؛ بدون مقیاس عددی و مستقل از نتایج اجرای کد.

برای ورودی دستی، PSD برابر 1.6567788e-17 V²/Hz و میانگین مربع برابر 1.6567788e-13 V² است. چگالی دامنه حدود ۴٫۰۷۰۳۵ نانوولت بر رادیکال هرتز و ولتاژ مؤثر حدود ۴۰۷٫۰۳۵ نانوولت می‌شود. تفاوت رقم پایانیِ float در خروجی ثبت شده؛ آن را دقت واقعیِ یک وسیله یا تعداد رقمِ مجازِ اندازه‌گیری معرفی نمی‌کنیم.

{
  "python_version": "3.14.5",
  "data_origin": "synthetic model parameters; no acquired samples",
  "contract": "open-circuit ideal classical resistor; one-sided flat PSD; supplied unity-gain noise-equivalent bandwidth",
  "units": {
    "resistance": "ohm",
    "temperature": "K",
    "bandwidth": "Hz",
    "psd": "V^2/Hz",
    "amplitude_density": "V/sqrt(Hz)",
    "mean_square": "V^2",
    "rms": "V"
  },
  "hand_inputs": {
    "resistance_ohm": 1000,
    "temperature_k": 300,
    "noise_bandwidth_hz": 10000
  },
  "hand_result": {
    "one_sided_psd_v2_per_hz": 1.6567788e-17,
    "amplitude_density_v_per_sqrt_hz": 4.070354775692163e-09,
    "mean_square_v2": 1.6567787999999998e-13,
    "rms_v": 4.070354775692163e-07
  },
  "fourfold_bandwidth_rms_v": 8.140709551384326e-07,
  "decimal_reference_precision": 80,
  "independent_fixture_count_in_one_group": 36,
  "comparison_tolerance": {
    "relative": 2e-15,
    "absolute": 0
  },
  "checks": {
    "hand_mean_square_literal": true,
    "hand_psd_literal": true,
    "one_hz_density_equals_rms": true,
    "decimal_independent_36_fixtures_one_group": true,
    "bandwidth_fourfold_rms_twofold": true,
    "resistance_fourfold_density_twofold": true,
    "kelvin_twofold_mean_square_twofold": true,
    "density_independent_of_bandwidth": true,
    "zero_bandwidth_not_zero_density": true,
    "reject_linear_bandwidth_formula_by_witness": true,
    "unit_profile_rejects_relabelling": true,
    "non_numeric_and_bool_rejected": true,
    "nonfinite_in_each_position_rejected": true,
    "physical_and_policy_bounds_rejected": true,
    "declared_closed_bounds_accepted_finite": true,
    "disjoint_band_mean_squares_add": true
  },
  "unique_check_groups": 16
}

اکنون تغییرِ عمداً غلط را امتحان می‌کنیم: عدد چگالی دامنه را در ده‌هزار ضرب کنیم. حاصل عددی، صد برابرِ پاسخ درست می‌شود و از نظر واحد نیز ولتاژ نیست. آزمون با پهنای‌باند یک هرتز به‌تنهایی این خطا را آشکار نمی‌کرد، چون عامل عددیِ یک تغییری نمی‌دهد. انتخابِ شاهد باید تفاوتِ فرضِ درست و غلط را نمایان کند؛ تکرارِ همان ورودی، شاهدِ تازه نمی‌سازد.

شانزده گروه واقعی اجرا شده‌اند. سی‌وشش ترکیبِ محدود با مرجع اعشاری در یک گروه مقایسه می‌شوند؛ پاسخ‌های دستی، چهاربرابرشدن پهنای باند، تغییر مقاومت، تغییر دمای کلوین و خطاهای مرزی گروه‌های دیگرند. تلورانس نسبی دو ضرب‌در ده به توان منفی پانزده و مطلق صفر، فقط برای همین مقایسه‌های محاسباتی است. این تلورانس، بودجهٔ خطا یا عدم قطعیتِ مقاومت واقعی نیست.

با صفرشدن باند، میانگین مربع و RMS صفر می‌شوند، ولی چگالیِ خودِ مقاومت همچنان مثبت است؛ «نویز مقاومت حذف شد» نتیجهٔ درستی نیست. درس تفاوت مقدار دما و اختلاف دما هم دلیل استفاده از کلوین را در مرزِ تبدیل روشن می‌کند. اجرا فقط Python 3.14.5 است؛ منابع در ۲۵ مهر ۱۴۰۵ خوانده شدند و تاریخ اسناد از تاریخ اجرا جدا ثبت شده است.

۵. چهار پرسش با پاسخ کامل

بازبینی محدودیت‌های مدل پیش از تفسیر مقدار نویز
تصویر مفهومی: بازبینی محدودیت‌های مدل پیش از تفسیر مقدار نویز؛ بدون مقیاس عددی و مستقل از نتایج اجرای کد.

پرسش اول: پهنای‌باند از ده‌هزار به چهل‌هزار هرتز برسد، RMS چند برابر می‌شود؟ پاسخ: دو برابر، حدود ۸۱۴٫۰۷۱ نانوولت. میانگین مربع چهار برابر و چگالی دامنه بدون تغییر می‌ماند.

پرسش دوم: باند صفر یعنی مقاومت بدون نویز است؟ پاسخ: خیر؛ فقط مقدارِ انتگرال‌گرفته در باندِ صفر، حدِ صفر دارد. PSD این نمونه همچنان مثبت است؛ این حالت، مقاومتِ فیزیکیِ بی‌نویز نمی‌سازد.

پرسش سوم: می‌توان عدد ۳۰۰ را با واحد سلسیوس به همان تابع داد؟ پاسخ: خیر؛ دمای این رابطه مطلق و واحد قرارداد K است. کد برچسب C را رد می‌کند؛ تبدیلِ دما باید با سیاست جدا انجام شود.

پرسش چهارم: عبور آزمون‌ها نویز کلِ مدار را تأیید می‌کند؟ پاسخ: خیر؛ فقط حساب و مرز همین مدل ایدئال آزموده شده است. بارگذاری، پاسخ فرکانسی، منابع نویز دیگر، عدم قطعیت و اندازه‌گیریِ واقعی در برنامه وجود ندارند.

منابع و مطالعهٔ بیشتر

بررسی منابع: ۲۵ مهر ۱۴۰۵. تحلیل‌ها و پیشنهادهای اجرایی، جمع‌بندی نویسنده‌اند.