تابعی که فقط «عدد را به دسی‌بل تبدیل می‌کند»، هنوز قرارداد کافی ندارد. باید بدانیم ورودی دامنه است یا توان، مرجع چیست و صفر چه رفتاری دارد. این تصمیم‌ها برای گزارش ویژگی‌های سیگنال در یک برنامهٔ مهندسی یا مسیر آماده‌سازی دادهٔ هوش مصنوعی مهم‌اند. در این درس یک تابع خالص با داده‌های ساختگی و مرجع عددی مستقل می‌سازیم؛ طیف‌سنج، حسگر یا مدل یادگیری ماشین اجرا نمی‌شود.

۱. دسی‌بل بدون نوع کمیت و مرجع کامل نیست

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

برای نسبت دامنه، سطح برابر 20log10(A/Aref) و برای نسبت توان برابر 10log10(P/Pref) است. تعریف mag2db ضریب بیست و تعریف pow2db ضریب ده را توضیح می‌دهند. ورودی لگاریتم یک نسبت بی‌بعد است؛ ولتاژ را به مرجع ولتاژ و توان را به مرجع توان تقسیم می‌کنیم. این دو فرمول روی همان عدد خام، پاسخ یکسانی نمی‌دهند.

دامنه در این مثال مقدار RMS مثبتِ ولتاژ با واحد V است؛ نمونهٔ لحظه‌ایِ منفی را خودکار قدرمطلق نمی‌گیریم. توان هم مقدار مثبت با واحد W است. برچسب رایج dBV را با مرجع یک ولت RMS و dBm را با مرجع یک میلی‌وات توان به کار می‌بریم. تابع عمومی مرجع را صریح می‌گیرد و از اسم متغیر یا بزرگی عدد حدس نمی‌زند.

بخش ۸٫۷ راهنمای NIST تأکید می‌کند کمیت و مرجع گزارش معلوم باشند؛ همچنین دربارهٔ افزودن پسوندهایی مانند dBm به نماد واحد، توصیهٔ نگارشی محدودتری دارد. اینجا نام رایج را همراه مرجع کامل می‌آوریم و ادعای انطباق آن پسوند با شیوهٔ نگارش NIST نداریم. صفر دسی‌بل یعنی برابر بودن مقدار و مرجع، نه نبود سیگنال.

۲. نسبت ولتاژ چه زمانی نسبت توان را توضیح می‌دهد؟

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

برای بار مقاومتی خالص، توان متوسط از V_RMS²/R به دست می‌آید. مستندات db در MathWorks نیز نقش مقاومت در تبدیل ولتاژ به توان را مشخص می‌کند. اگر مقاومت دو حالت یکسان باشد، نسبت توان مربع نسبت ولتاژ است و دو فرمول سطح سازگار می‌شوند. این شرط را نمی‌توان برای بارهای نامعلوم یا مختلط حذف کرد.

دو ولت نسبت به یک ولت RMS روی همان بار پنجاه‌اهمی، نسبت دامنهٔ دو و نسبت توان چهار دارد؛ هر دو سطح تقریباً ۶٫۰۲۰۶ دسی‌بل می‌دهند. اگر بار حالت اول صد اهم و مرجع پنجاه اهم باشد، نسبت توان دو و سطح آن حدود ۳٫۰۱۰۳ دسی‌بل می‌شود. نسبت ولتاژ هنوز دو است؛ پس برابری خودکارِ سطح‌های دامنه و توان از بین می‌رود.

یک ولت RMS نسبت به مرجع یک ولت، صفر dBV است. همان ولتاژ در فرض پنجاه اهم، ۰٫۰۲ وات می‌دهد که نسبت به یک میلی‌وات حدود ۱۳٫۰۱۰۳ دسی‌بل است. بنابراین تبدیل میان dBV و dBm بدون اطلاعات بار، یک تغییر برچسب ساده نیست. اعداد این بخش فرض آموزشی‌اند؛ بار واقعی، کالیبراسیون و عدم قطعیت اندازه‌گیری بررسی نشده‌اند.

۳. کد کامل با سیاست صفر و محاسبهٔ دوشاخه

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

کد با Python 3.14.5 اجرا شده و فقط int یا float دقیق، مثبت و متناهی را برای مقدار و مرجع می‌پذیرد. bool، NaN، بی‌نهایت، رشته و مرجع نامثبت رد می‌شوند. واحد دقیقِ دامنه V و توان W است؛ mV یا mW بدون تبدیل پذیرفته نمی‌شوند. سیاست تابع برای صفر، ValueError است؛ حد ریاضیِ سطح با مقدارِ رو به صفر، منفی بی‌نهایت است و صفر دسی‌بل نیست.

"""Original finite dB reference lesson; no instrument/MATLAB execution."""
from decimal import Decimal, localcontext
import json
import math
import platform


def _positive(value, field):
    if type(value) not in (int, float):
        raise TypeError(field + ' must be exact int or float')
    try:
        value = float(value)
    except OverflowError as error:
        raise ValueError(field + ' cannot be represented as finite float') from error
    if not math.isfinite(value) or value <= 0:
        raise ValueError(field + ' must be finite and strictly positive')
    return value


def level_db(value, reference, kind, unit):
    if type(kind) is not str or kind not in ('amplitude', 'power'):
        raise ValueError('kind must be amplitude or power')
    expected_unit = 'V' if kind == 'amplitude' else 'W'
    if type(unit) is not str or unit != expected_unit:
        raise ValueError('value and reference require the same declared unit ' + expected_unit)
    value, reference = _positive(value, 'value'), _positive(reference, 'reference')
    scale = 20.0 if kind == 'amplitude' else 10.0
    delta = value - reference
    if -0.5 * reference <= delta <= reference:
        # Close represented values: avoid subtracting almost equal logarithms.
        log_ratio = math.log1p(delta / reference) / math.log(10.0)
    else:
        # Wide range: do not construct value/reference, which may overflow/underflow.
        log_ratio = math.log10(value) - math.log10(reference)
    result = scale * log_ratio
    if not math.isfinite(result):
        raise ArithmeticError('nonfinite dB result')
    return result


def reference_decimal(value, reference, scale):
    """Independent 80-digit log10 of the exact represented float ratio."""
    with localcontext() as context:
        context.prec = 80
        ratio = Decimal.from_float(float(value)) / Decimal.from_float(float(reference))
        return float(Decimal(scale) * ratio.log10())


def _close(actual, expected, *, abs_tol=1e-10, rel_tol=1e-12):
    return math.isclose(actual, expected, abs_tol=abs_tol, rel_tol=rel_tol)


def _raises(expected, function, *args):
    try:
        function(*args)
    except expected:
        return True
    return False


def run_example():
    voltages = [0.01, 0.1, 1.0, 10.0, 100.0]
    powers = [1e-5, 1e-4, 1e-3, 1e-2, 1e-1]
    voltage_levels = [level_db(value, 1.0, 'amplitude', 'V') for value in voltages]
    power_levels = [level_db(value, 0.001, 'power', 'W') for value in powers]
    near_value, near_reference = 1e16 + 2.0, 1e16
    near = level_db(near_value, near_reference, 'amplitude', 'V')
    naive_near = 20 * (math.log10(near_value) - math.log10(near_reference))
    minimum = math.ulp(0.0)
    pairs = [(1.0, 0.001), (3.0, 2.0), (0.25, 0.125), (1e308, 1e-308),
             (1e-308, 1e308), (near_value, near_reference), (minimum, 2 * minimum)]
    reference_comparisons = [
        _close(level_db(value, reference, kind, unit), reference_decimal(value, reference, scale))
        for value, reference in pairs
        for kind, unit, scale in (('amplitude', 'V', 20), ('power', 'W', 10))]
    # Synthetic purely resistive loads; RMS voltage to mean power is V_rms**2/R.
    same_r_amplitude = level_db(2.0, 1.0, 'amplitude', 'V')
    same_r_power = level_db(4.0 / 50.0, 1.0 / 50.0, 'power', 'W')
    unequal_r_power = level_db(4.0 / 100.0, 1.0 / 50.0, 'power', 'W')
    one_volt_dbv = level_db(1.0, 1.0, 'amplitude', 'V')
    one_volt_50ohm_dbm = level_db(1.0 / 50.0, 0.001, 'power', 'W')
    invalid_numbers = (True, '1', None, 1j, float('nan'), float('inf'), -float('inf'), 2**10000)
    checks = {
        'hand_voltage_powers_of_ten': all(_close(a, b) for a, b in zip(voltage_levels, [-40, -20, 0, 20, 40])),
        'hand_power_one_milliwatt_reference': all(_close(a, b) for a, b in zip(power_levels, [-20, -10, 0, 10, 20])),
        'equal_positive_values_zero_db': all(level_db(value, value, kind, unit) == 0.0
            for value in (minimum, 0.001, 1.0, 1e308) for kind, unit in (('amplitude', 'V'), ('power', 'W'))),
        'factor_ten_amplitude_twenty_power_ten': _close(level_db(10, 1, 'amplitude', 'V'), 20)
            and _close(level_db(10, 1, 'power', 'W'), 10),
        'factor_two_amplitude_hand_value': _close(same_r_amplitude, 6.020599913279624),
        'factor_two_power_hand_value': _close(level_db(2, 1, 'power', 'W'), 3.010299956639812),
        'voltage_power_equivalence_only_equal_resistance': _close(same_r_amplitude, same_r_power)
            and not _close(same_r_amplitude, unequal_r_power),
        'independent_decimal_ratio_reference': len(reference_comparisons) == 14 and all(reference_comparisons),
        'wide_range_without_building_ratio': math.isinf(1e308 / 1e-308) and 1e-308 / 1e308 == 0.0
            and _close(level_db(1e308, 1e-308, 'amplitude', 'V'), 12320)
            and _close(level_db(1e-308, 1e308, 'amplitude', 'V'), -12320),
        'near_unity_log1p_retains_represented_difference': naive_near == 0.0 and near > 0
            and _close(near, reference_decimal(near_value, near_reference, 20), abs_tol=1e-27),
        'exact_fixture_common_scale_invariance': all(_close(
            level_db(value * 8, reference * 8, 'amplitude', 'V'), level_db(value, reference, 'amplitude', 'V'))
            for value, reference in ((0.125, 1.0), (3.0, 2.0), (8.0, 0.5))),
        'reciprocal_levels_negate': all(_close(level_db(a, b, 'power', 'W'), -level_db(b, a, 'power', 'W'))
            for a, b in pairs),
        'finite_fixture_chain_rule': _close(level_db(2, 10, 'amplitude', 'V'),
            level_db(2, 3, 'amplitude', 'V') + level_db(3, 10, 'amplitude', 'V')),
        'positive_input_order_is_monotonic': voltage_levels == sorted(voltage_levels)
            and len(set(voltage_levels)) == len(voltages),
        'dbv_and_dbm_references_are_not_interchangeable': one_volt_dbv == 0.0
            and _close(one_volt_50ohm_dbm, 13.010299956639813),
        'zero_negative_values_and_references_rejected': all(
            _raises(ValueError, level_db, value, 1, 'amplitude', 'V')
            and _raises(ValueError, level_db, 1, value, 'amplitude', 'V')
            for value in (0, -0.0, -1, -1e-308)),
        'invalid_types_nonfinite_kinds_and_units_rejected': all(
            _raises((TypeError, ValueError), level_db, value, 1, 'amplitude', 'V')
            and _raises((TypeError, ValueError), level_db, 1, value, 'power', 'W') for value in invalid_numbers)
            and all(_raises(ValueError, level_db, 1, 1, kind, unit)
                    for kind, unit in (('voltage', 'V'), (None, 'V'), ('amplitude', 'mV'),
                                       ('power', 'V'), ('amplitude', b'V'))),
        'positive_subnormal_pair_is_valid': _close(level_db(minimum, 2 * minimum, 'amplitude', 'V'), -6.020599913279624)
            and _close(level_db(2 * minimum, minimum, 'amplitude', 'V'), 6.020599913279624),
    }
    assert len(checks) == 18 and all(type(value) is bool and value for value in checks.values())
    return {'runtime': {'python': platform.python_version(), 'libraries': ['stdlib math and decimal'], 'decimal_reference_precision': 80},
            'contract': {'amplitude': '20*log10(value/reference), both positive RMS V',
                         'power': '10*log10(value/reference), both positive W',
                         'zero_policy': 'ValueError; limit is -infinity, not finite zero dB',
                         'labels': 'dBV uses 1 V RMS; dBm is common shorthand for explicit 1 mW power reference'},
            'metrics': {'voltages_V_RMS': voltages, 'voltage_reference_V_RMS': 1.0, 'voltage_levels_db': voltage_levels,
                        'powers_W': powers, 'power_reference_W': 0.001, 'power_levels_db': power_levels,
                        'same_R_50ohm_amplitude_db': same_r_amplitude, 'same_R_50ohm_power_db': same_r_power,
                        'unequal_R_power_db': unequal_r_power, 'one_V_RMS_at_50ohm_level_re_1mW_db': one_volt_50ohm_dbm,
                        'near_unity_value': near_value, 'near_unity_reference': near_reference,
                        'near_unity_db': near, 'plain_log_difference_db': naive_near,
                        'wide_range_amplitude_db': level_db(1e308, 1e-308, 'amplitude', 'V'),
                        'decimal_reference_comparisons': len(reference_comparisons)},
            'checks': checks,
            'limitations': ['No MATLAB, analyzer, sensor, spectrum, microphone, sound-pressure or noise measurement executed.',
                            'RMS voltage/power relation assumes explicitly stated purely resistive equal loads when comparing ratios.',
                            'All math is on represented finite float inputs; no recovery of lost input precision, universal accuracy or uncertainty guarantee.',
                            'dBV/dBm common labels must keep their explicit references; not a claim that appended symbols follow NIST SI notation recommendations.']}


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

ساخت مستقیم نسبتِ عدد بسیار بزرگ به عدد بسیار کوچک ممکن است سرریز کند. در فاصلهٔ زیاد، اختلاف log10 دو مقدار را می‌گیریم تا نسبت کامل ساخته نشود. اما همین تفریق نزدیک برابری می‌تواند اختلاف کوچکی را از دست بدهد. در شاخهٔ نزدیک، delta برابر مقدار منهای مرجع است و با log1p، لگاریتم 1+delta/reference محاسبه می‌شود. این دو شاخه برای هدف‌های عددی متفاوت‌اند.

شرط شاخهٔ نزدیک، قرارگرفتن delta بین منفی نصف مرجع و خود مرجع است؛ در نتیجه آرگومان log1p از دامنهٔ مجاز بیرون نمی‌رود. داده‌ها ابتدا به float تبدیل می‌شوند و تابع دقت ازدست‌رفتهٔ ورودی را برنمی‌گرداند. موفقیت این راه روی fixtureها، اثبات دقت همگانی یا برآورد خطای فیزیکی نیست. MATLAB اجرا نشده و مستندات آن مرجع تعریف کمیت‌هاست.

۴. پاسخ دستی، Decimal و هجده گروه بررسی

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

ولتاژهای ۰٫۰۱، ۰٫۱، یک، ده و صد ولت نسبت به یک ولت RMS، سطح‌های منفی چهل، منفی بیست، صفر، بیست و چهل دسی‌بل دارند. توان‌های ده میکرووات تا صد میلی‌وات با گام ده‌برابری، نسبت به یک میلی‌وات، منفی بیست تا بیست دسی‌بل می‌دهند. این پاسخ‌های دستی، انتخاب اشتباه ضریب ده یا بیست و مرجع اشتباه را آشکار می‌کنند.

{
  "runtime": {
    "python": "3.14.5",
    "libraries": [
      "stdlib math and decimal"
    ],
    "decimal_reference_precision": 80
  },
  "contract": {
    "amplitude": "20*log10(value/reference), both positive RMS V",
    "power": "10*log10(value/reference), both positive W",
    "zero_policy": "ValueError; limit is -infinity, not finite zero dB",
    "labels": "dBV uses 1 V RMS; dBm is common shorthand for explicit 1 mW power reference"
  },
  "metrics": {
    "voltages_V_RMS": [
      0.01,
      0.1,
      1.0,
      10.0,
      100.0
    ],
    "voltage_reference_V_RMS": 1.0,
    "voltage_levels_db": [
      -40.0,
      -20.0,
      0.0,
      20.0,
      40.0
    ],
    "powers_W": [
      1e-05,
      0.0001,
      0.001,
      0.01,
      0.1
    ],
    "power_reference_W": 0.001,
    "power_levels_db": [
      -20.0,
      -10.0,
      0.0,
      10.0,
      20.0
    ],
    "same_R_50ohm_amplitude_db": 6.020599913279623,
    "same_R_50ohm_power_db": 6.020599913279623,
    "unequal_R_power_db": 3.0102999566398116,
    "one_V_RMS_at_50ohm_level_re_1mW_db": 13.010299956639813,
    "near_unity_value": 1.0000000000000002e+16,
    "near_unity_reference": 1e+16,
    "near_unity_db": 1.7371779276130068e-15,
    "plain_log_difference_db": 0.0,
    "wide_range_amplitude_db": 12320.0,
    "decimal_reference_comparisons": 14
  },
  "checks": {
    "hand_voltage_powers_of_ten": true,
    "hand_power_one_milliwatt_reference": true,
    "equal_positive_values_zero_db": true,
    "factor_ten_amplitude_twenty_power_ten": true,
    "factor_two_amplitude_hand_value": true,
    "factor_two_power_hand_value": true,
    "voltage_power_equivalence_only_equal_resistance": true,
    "independent_decimal_ratio_reference": true,
    "wide_range_without_building_ratio": true,
    "near_unity_log1p_retains_represented_difference": true,
    "exact_fixture_common_scale_invariance": true,
    "reciprocal_levels_negate": true,
    "finite_fixture_chain_rule": true,
    "positive_input_order_is_monotonic": true,
    "dbv_and_dbm_references_are_not_interchangeable": true,
    "zero_negative_values_and_references_rejected": true,
    "invalid_types_nonfinite_kinds_and_units_rejected": true,
    "positive_subnormal_pair_is_valid": true
  },
  "limitations": [
    "No MATLAB, analyzer, sensor, spectrum, microphone, sound-pressure or noise measurement executed.",
    "RMS voltage/power relation assumes explicitly stated purely resistive equal loads when comparing ratios.",
    "All math is on represented finite float inputs; no recovery of lost input precision, universal accuracy or uncertainty guarantee.",
    "dBV/dBm common labels must keep their explicit references; not a claim that appended symbols follow NIST SI notation recommendations."
  ]
}

برای شاهد مستقل، از Decimal.from_float و log10 با دقت هشتادرقمی استفاده می‌کنیم. مقدار دقیقِ همان float نمایش‌یافته به مرجع منتقل می‌شود؛ رشتهٔ اعشاریِ ایدئال جای آن قرار نمی‌گیرد. چهارده مقایسه یک گروه از هجده گروه‌اند. تحمل عمومیِ مقایسه، مطلق 1e−10 دسی‌بل و نسبی 1e−12 است؛ برای نمونهٔ نزدیک برابری، تحمل مطلق جداگانهٔ 1e−27 داریم.

در نمونهٔ 1e308 نسبت به 1e−308، نسبت مستقیم به بی‌نهایت می‌رسد، اما سطح دامنه ۱۲۳۲۰ دسی‌بل متناهی است. در جهت معکوس، نسبت مستقیم به صفر کم‌ریزی می‌کند ولی سطح منفی ۱۲۳۲۰ است. از طرف دیگر، مقدارهای 1e16+2 و 1e16 با تفریق سادهٔ لگاریتم‌ها صفر می‌دهند؛ شاخهٔ نزدیک حدود 1.737e−15 دسی‌بلِ مثبت را مطابق مرجع حفظ می‌کند.

آزمون RMS ولتاژ به ساخت دامنهٔ مؤثر کمک می‌کند و آزمون دامنهٔ FFT قرارداد دیگری برای استخراج دامنه دارد. تبدیل دسی‌بل، درستی مرحلهٔ قبلی را ثابت نمی‌کند. آزمون واحد برای این تابع خالص مناسب است، چون مرجع و دامنهٔ ورودی معلوم‌اند؛ اعتبار کل زنجیرهٔ اندازه‌گیری به بررسی‌های دیگری نیاز دارد.

۵. چهار پرسش پاسخ‌دار دربارهٔ مرجع و خطا

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

پرسش اول: دو برابر شدن دامنه و توان یک سطح می‌دهد؟ پاسخ: خیر؛ نسبت دامنهٔ دو حدود ۶٫۰۲۰۶ و نسبت توان دو حدود ۳٫۰۱۰۳ دسی‌بل می‌دهد. تنها با رابطهٔ مربع و بار برابر می‌توان مقایسهٔ متناظر ساخت.

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

پرسش سوم: چرا همیشه اختلاف دو log10 کافی نیست؟ پاسخ: نزدیک برابری ممکن است دو لگاریتم به یک float گرد شوند. نمونهٔ 1e16+2 اختلاف مثبت دارد و شاخهٔ log1p آن را در این آزمایش حفظ می‌کند.

پرسش چهارم: یک ولت روی پنجاه اهم، صفر dBm است؟ پاسخ: خیر؛ توان فرضی ۲۰ میلی‌وات و سطح حدود ۱۳٫۰۱۰۳ دسی‌بل نسبت به یک میلی‌وات است. منابع در ۲۴ مهر ۱۴۰۵ خوانده شدند؛ هجده بررسی، تأیید ابزار واقعی نیست.

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

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