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

۱. دامنهٔ مدل و قرارداد واحدهای SI

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

مقاومت، سلف و خازن به‌صورت سری، خطی و ایدئال فرض می‌شوند و تحلیل فقط برای حالت ماندگار سینوسی است. R، L و C مثبت‌اند و فرکانس ورودی بر حسب هرتز، نه رادیان‌برثانیه است. در کد، ω از ۲πf ساخته می‌شود. اثر مقاومت سیم‌پیچ، نشتی خازن، وابستگی قطعات به فرکانس و شرایط آغازین وارد مدل نشده‌اند؛ ثابت‌بودن جواب نرم‌افزار به معنای مطابقت آن با هر قطعهٔ واقعی نیست.

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

API آموزشی ما بازه‌های بستهٔ مشخص دارد: R از ده به توان منفی نه تا ده به توان نه اهم، L از ده به توان منفی نه تا هزار هانری، C از ده به توان منفی دوازده تا یک فاراد و f از ده به توان منفی شش تا ده به توان نه هرتز. این حدود انتخاب نرم‌افزاری‌اند تا واسطه‌های محاسبه وارد مقیاس‌های افراطی نشوند؛ مشخصات تجهیزات یا تمام مدارهای فیزیکیِ مجاز نیستند.

۲. امپدانس مختلط را از اندازه‌اش جدا کنیم

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

درس مدار RLC سری OpenStax جمع فازوری سهم‌ها را توضیح می‌دهد. در قرارداد مختلطِ ما، مقاومت R، سلف jωL و خازن ۱/(jωC) سهم دارند. بنابراین Z برابر R+j(ωL−۱/ωC) است. XL و XC هر دو اندازه‌های مثبتِ راکتانس‌اند؛ علامت اثر خازنی در تفاضلِ بخش موهومی ظاهر می‌شود.

خروجی Z یک عدد مختلط بر حسب اهم است و اندازهٔ آن از قدرمطلق مختلط گرفته می‌شود. برخی متن‌های آموزشی حرف Z را برای اندازه به کار می‌برند؛ ما در کد impedance و magnitude_ohm را جدا برمی‌گردانیم. جمع سادهٔ R+XL+XC پاسخ این مدل نیست. بخش موهومی منفی، در این قرارداد رفتار خازنیِ خالصِ ترکیب را نشان می‌دهد؛ مثبت، رفتار سلفی را.

مثال دستی R برابر سه اهم و L و C هرکدام ۰٫۵ در واحد SI است. فرکانس را ۱/(۲π) هرتز می‌گیریم تا ω یک رادیان‌برثانیه باشد. XL برابر ۰٫۵ و XC برابر دو اهم است؛ پس Z برابر ۳−j۱٫۵ اهم می‌شود. اندازه حدود ۳٫۳۵۴۱ اهم و زاویه حدود منفی ۲۶٫۵۶۵ درجه است. این مقادیر، جوابِ همین مدل‌اند و رتبه‌بندی یا طراحی قطعه نیستند.

۳. کد کامل و کنترل ورودی پیش از تقسیم

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

مثال با Python 3.14.5 و کتابخانهٔ استاندارد اجرا شده است. فقط int یا float دقیق و متناهی در بازهٔ هر پارامتر پذیرفته می‌شود؛ bool، NaN، بی‌نهایت، رشته و مقدار مختلط رد می‌شوند. واحدها باید همان tuple صریح باشند. برای زاویه، phase در مرجع cmath رادیان می‌دهد و کد آن را برای گزارش به درجه تبدیل می‌کند.

"""Original ideal series-RLC impedance contract with explicitly bounded SI inputs."""
import cmath
from fractions import Fraction
import itertools
import json
import math
import platform


RANGES = {'resistance': (1e-9, 1e9), 'inductance': (1e-9, 1e3),
          'capacitance': (1e-12, 1.0), 'frequency': (1e-6, 1e9)}


def _positive_in_range(value, name):
    if type(value) not in (int, float):
        raise TypeError(name + ' requires exact int or float')
    try:
        value = float(value)
    except OverflowError as error:
        raise ValueError(name + ' cannot be represented') from error
    low, high = RANGES[name]
    if not math.isfinite(value) or not low <= value <= high:
        raise ValueError(name + ' outside authored finite positive range')
    return value


def series_rlc(resistance, inductance, capacitance, frequency,
               units=('ohm', 'H', 'F', 'Hz')):
    if type(units) is not tuple or units != ('ohm', 'H', 'F', 'Hz'):
        raise ValueError('explicit tuple of SI unit tags required')
    r, l, c, f = (_positive_in_range(v, name) for v, name in zip(
        (resistance, inductance, capacitance, frequency), RANGES))
    omega = math.tau * f
    z_resistor, z_inductor, z_capacitor = complex(r, 0), 1j * omega * l, 1 / (1j * omega * c)
    impedance = z_resistor + z_inductor + z_capacitor
    magnitude = abs(impedance)
    f0 = 1 / (math.tau * math.sqrt(l * c))
    if not cmath.isfinite(impedance) or not all(math.isfinite(v) for v in (omega, magnitude, f0)):
        raise ValueError('computed quantity must be finite')
    return {'impedance': impedance, 'magnitude_ohm': magnitude,
            'phase_deg': math.degrees(cmath.phase(impedance)),
            'omega_rad_s': omega, 'xl_ohm': z_inductor.imag, 'xc_ohm': -z_capacitor.imag,
            'resonance_hz': f0}


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


def run_example():
    f = 1 / math.tau
    result = series_rlc(3, 0.5, 0.5, f)
    f0 = 1 / math.pi
    resonant = series_rlc(3, 0.5, 0.5, f0)
    above = series_rlc(3, 0.5, 0.5, 2 * f0)
    changed_r = series_rlc(6, 0.5, 0.5, f)
    scaled = series_rlc(6, 1, 0.25, f)
    changed_l = series_rlc(3, 1, 0.5, f)
    scan = [series_rlc(3, 0.5, 0.5, factor * f0)['impedance'].imag for factor in (0.25, 0.5, 1, 2, 4)]
    reference_results = []
    for r, l, c, angular in itertools.product((1, 3, 7), (Fraction(1, 4), Fraction(1, 2), Fraction(1)),
                                             (Fraction(1, 4), Fraction(1, 2), Fraction(1)), (1, 2, 4, 8)):
        observed = series_rlc(r, float(l), float(c), angular / math.tau)
        # Exact rational impedance from a separate scalar reactance formula.
        reactive = Fraction(angular) * l - 1 / (Fraction(angular) * c)
        expected = complex(r, float(reactive))
        reference_results.append(cmath.isclose(observed['impedance'], expected, rel_tol=1e-14, abs_tol=1e-13))
    baseline = [3, 0.5, 0.5, f]
    bad_types = []
    bad_finite = []
    for index in range(4):
        for value in (True, '1', 1 + 0j, None):
            values = baseline[:]
            values[index] = value
            bad_types.append(_raises(TypeError, series_rlc, *values))
        for value in (float('nan'), float('inf'), -float('inf'), 10 ** 400):
            values = baseline[:]
            values[index] = value
            bad_finite.append(_raises(ValueError, series_rlc, *values))
    ranges_results = []
    for index, (name, limits) in enumerate(RANGES.items()):
        for value in limits:
            values = baseline[:]
            values[index] = value
            ranges_results.append(cmath.isfinite(series_rlc(*values)['impedance']))
        for value in (limits[0] / 2, limits[1] * 2):
            values = baseline[:]
            values[index] = value
            ranges_results.append(_raises(ValueError, series_rlc, *values))
    current = 6 / result['impedance']  # hypothetical 6V RMS source, not a measured current
    checks = {
        'hand_impedance_three_minus_j_one_point_five_ohm': result['impedance'] == complex(3, -1.5),
        'hand_magnitude_and_capacitive_phase': math.isclose(result['magnitude_ohm'], math.sqrt(45) / 2)
            and math.isclose(result['phase_deg'], math.degrees(math.atan2(-1.5, 3))),
        'element_impedances_have_opposite_reactive_signs': result['xl_ohm'] == 0.5 and result['xc_ohm'] == 2
            and result['impedance'].real == 3 and result['impedance'].imag == result['xl_ohm'] - result['xc_ohm'],
        'resonance_hz_matches_hand_one_over_pi': math.isclose(result['resonance_hz'], f0, rel_tol=1e-15),
        'at_resonance_impedance_is_resistance_with_absolute_ohm_tolerance': cmath.isclose(resonant['impedance'], 3 + 0j, rel_tol=0, abs_tol=1e-12)
            and math.isclose(resonant['magnitude_ohm'], 3),
        'below_resonance_net_reactance_negative': result['impedance'].imag < 0 and f < result['resonance_hz'],
        'reciprocal_frequency_above_resonance_has_opposite_reactance': above['impedance'] == complex(3, 1.5)
            and math.isclose(above['magnitude_ohm'], result['magnitude_ohm']),
        'selected_frequency_scan_reactance_strictly_increasing': all(a < b for a, b in zip(scan, scan[1:])),
        'resistance_change_only_changes_real_part': changed_r['impedance'] - result['impedance'] == 3 + 0j,
        'simultaneous_component_scaling_doubles_impedance_preserves_resonance': cmath.isclose(scaled['impedance'], 2 * result['impedance'])
            and math.isclose(scaled['resonance_hz'], result['resonance_hz']),
        'doubling_inductance_reduces_resonant_frequency_by_sqrt_two': math.isclose(changed_l['resonance_hz'], f0 / math.sqrt(2)),
        'si_units_tuple_and_frequency_not_angular_tag': all(_raises(ValueError, series_rlc, *baseline, units=units) for units in (
            ('ohm', 'mH', 'F', 'Hz'), ('ohm', 'H', 'uF', 'Hz'), ('ohm', 'H', 'F', 'rad/s'), ['ohm', 'H', 'F', 'Hz']))
            and not cmath.isclose(series_rlc(3, 0.5, 0.5, 1)['impedance'], result['impedance']),
        'dc_and_negative_frequency_rejected_not_finite_dc_impedance': _raises(ValueError, series_rlc, 3, 0.5, 0.5, 0)
            and _raises(ValueError, series_rlc, 3, 0.5, 0.5, -1),
        'zero_or_negative_components_rejected_by_positive_domain': all(_raises(ValueError, series_rlc, *values) for values in (
            [0, 0.5, 0.5, f], [-1, 0.5, 0.5, f], [3, 0, 0.5, f], [3, 0.5, -1, f])),
        'nonreal_types_bool_and_nonfinite_numbers_rejected': all(bad_types) and all(bad_finite),
        'authored_range_endpoints_included_outside_rejected': len(ranges_results) == 16 and all(ranges_results),
        'independent_exact_fraction_oracle_108_cases': len(reference_results) == 108 and all(reference_results),
        'hand_rms_current_from_impedance_and_voltage_roundtrip': cmath.isclose(current, complex(float(Fraction(8, 5)), float(Fraction(4, 5))))
            and cmath.isclose(current * result['impedance'], 6 + 0j),
    }
    assert len(checks) == 18 and all(type(v) is bool and v for v in checks.values())
    return {'runtime': {'python': platform.python_version(), 'libraries': ['stdlib only, no physical circuit or simulator']},
            'contract': {'topology': 'ideal series positive R,L,C, sinusoidal steady state, phasor V=Z*I',
                         'units': ['ohm', 'H', 'F', 'Hz'], 'bounded_input_ranges': RANGES,
                         'frequency': 'positive Hz, omega=tau*f rad/s; DC rejected',
                         'complex_vs_magnitude': 'Zcomplex=R+j(omegaL-1/omegaC); |Z| in ohm'},
            'metrics': {'frequency_hz': f, 'omega_rad_s': result['omega_rad_s'], 'xl_ohm': result['xl_ohm'],
                        'xc_ohm': result['xc_ohm'], 'impedance_real_ohm': result['impedance'].real,
                        'impedance_imag_ohm': result['impedance'].imag, 'magnitude_ohm': result['magnitude_ohm'],
                        'phase_deg': result['phase_deg'], 'resonance_hz': result['resonance_hz'],
                        'at_resonance_imag_ohm': resonant['impedance'].imag,
                        'hypothetical_6v_rms_current_a': {'real': current.real, 'imag': current.imag},
                        'independent_fraction_reference_cases': len(reference_results)},
            'checks': checks,
            'limitations': ['No measured device, safe wiring instruction, power calculation, transient response, tolerances, parasitics or component rating claim.',
                            'Positive resistance excludes the lossless R=0 singular resonance; DC capacitor-blocking limit is not a finite impedance result here.',
                            'Authored positive SI bounds avoid extreme intermediate ranges in this lesson, not all valid circuits or universal numerical stability.',
                            'Near-resonance cancellation and ordinary float error remain; unit tags do not detect a value mislabeled in SI.']}


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

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

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

۴. رزونانس، مرجع کسری و آزمون‌های بازگشت

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

بر اساس رابطهٔ رزونانس جریان در مدار سری، ω۰ برابر ۱/رادیکال LC است. برای مثال ما ω۰ دو و f۰ برابر ۱/π هرتز می‌شود؛ دو راکتانس برابر و امپدانس همان مقاومت سه اهم است. این رزونانسِ حالت ماندگارِ تحریک‌شده است؛ فرکانس نوسان آزادِ میرا یا رفتار تمام مدارهای RLC را از آن نتیجه نمی‌گیریم.

{
  "runtime": {
    "python": "3.14.5",
    "libraries": [
      "stdlib only, no physical circuit or simulator"
    ]
  },
  "contract": {
    "topology": "ideal series positive R,L,C, sinusoidal steady state, phasor V=Z*I",
    "units": [
      "ohm",
      "H",
      "F",
      "Hz"
    ],
    "bounded_input_ranges": {
      "resistance": [
        1e-09,
        1000000000.0
      ],
      "inductance": [
        1e-09,
        1000.0
      ],
      "capacitance": [
        1e-12,
        1.0
      ],
      "frequency": [
        1e-06,
        1000000000.0
      ]
    },
    "frequency": "positive Hz, omega=tau*f rad/s; DC rejected",
    "complex_vs_magnitude": "Zcomplex=R+j(omegaL-1/omegaC); |Z| in ohm"
  },
  "metrics": {
    "frequency_hz": 0.15915494309189535,
    "omega_rad_s": 1.0,
    "xl_ohm": 0.5,
    "xc_ohm": 2.0,
    "impedance_real_ohm": 3.0,
    "impedance_imag_ohm": -1.5,
    "magnitude_ohm": 3.3541019662496847,
    "phase_deg": -26.56505117707799,
    "resonance_hz": 0.3183098861837907,
    "at_resonance_imag_ohm": 0.0,
    "hypothetical_6v_rms_current_a": {
      "real": 1.6,
      "imag": 0.8
    },
    "independent_fraction_reference_cases": 108
  },
  "checks": {
    "hand_impedance_three_minus_j_one_point_five_ohm": true,
    "hand_magnitude_and_capacitive_phase": true,
    "element_impedances_have_opposite_reactive_signs": true,
    "resonance_hz_matches_hand_one_over_pi": true,
    "at_resonance_impedance_is_resistance_with_absolute_ohm_tolerance": true,
    "below_resonance_net_reactance_negative": true,
    "reciprocal_frequency_above_resonance_has_opposite_reactance": true,
    "selected_frequency_scan_reactance_strictly_increasing": true,
    "resistance_change_only_changes_real_part": true,
    "simultaneous_component_scaling_doubles_impedance_preserves_resonance": true,
    "doubling_inductance_reduces_resonant_frequency_by_sqrt_two": true,
    "si_units_tuple_and_frequency_not_angular_tag": true,
    "dc_and_negative_frequency_rejected_not_finite_dc_impedance": true,
    "zero_or_negative_components_rejected_by_positive_domain": true,
    "nonreal_types_bool_and_nonfinite_numbers_rejected": true,
    "authored_range_endpoints_included_outside_rejected": true,
    "independent_exact_fraction_oracle_108_cases": true,
    "hand_rms_current_from_impedance_and_voltage_roundtrip": true
  },
  "limitations": [
    "No measured device, safe wiring instruction, power calculation, transient response, tolerances, parasitics or component rating claim.",
    "Positive resistance excludes the lossless R=0 singular resonance; DC capacitor-blocking limit is not a finite impedance result here.",
    "Authored positive SI bounds avoid extreme intermediate ranges in this lesson, not all valid circuits or universal numerical stability.",
    "Near-resonance cancellation and ordinary float error remain; unit tags do not detect a value mislabeled in SI."
  ]
}

در نصف این فرکانس، بخش موهومی منفی ۱٫۵ و در دو برابر آن مثبت ۱٫۵ اهم است؛ اندازه‌ها برابرند. تغییر فقط R، بخش حقیقی را تغییر می‌دهد. دوبرابرکردن هم‌زمان R و L و نصف‌کردن C، کل امپدانس را دوبرابر و فرکانس رزونانس را ثابت می‌گذارد. این ویژگی‌ها خطاهایی را آشکار می‌کنند که یک جوابِ منفرد ممکن است نشان ندهد؛ هر ویژگی با فرض‌های همین مدل معتبر است.

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

اگر منبع فرضی شش ولت RMS با فاز صفر به همین امپدانس اعمال شود، جریان از ۶/Z برابر ۱٫۶+j۰٫۸ آمپر می‌شود. ضرب دوبارهٔ I در Z باید ولتاژ مرجع را بازسازی کند. این آزمون واحد، اندازه‌گیری جریان یا آزمون توان نیست. قرارداد توان سه‌فاز به مسئلهٔ متفاوت توان و مزدوج می‌پردازد و اعتبارسنجی مدار RC نمونهٔ کنترل پاسخ عددی گذراست.

منابع در ۲۴ مهر ۱۴۰۵ خوانده شدند. تاریخ انتشار کتاب OpenStax، ششم اکتبر ۲۰۱۶ است؛ تاریخ حقوق درج‌شده در پایین صفحه را تاریخ بازنگری علمیِ این بخش حساب نکرده‌ایم. نسخهٔ مستندات پایتون 3.14.8 و نسخهٔ اجرای کد 3.14.5 جدا ثبت شده‌اند. این درس آموزش پایه و مثال تألیفی است، نه گزارش پژوهش یا آزمایش تازه.

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

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

پرسش اول: برای ω یک، R سه، L و C برابر ۰٫۵، امپدانس چند است؟ پاسخ: XL برابر ۰٫۵ و XC دو اهم است؛ Z برابر ۳−j۱٫۵ اهم و اندازهٔ آن رادیکال ۴۵ تقسیم بر دو، حدود ۳٫۳۵۴۱ اهم می‌شود.

پرسش دوم: در رزونانسِ همین مثال، امپدانس صفر است؟ پاسخ: خیر؛ f۰ برابر ۱/π هرتز است و سهم‌های راکتیو حذف می‌شوند، ولی مقاومت سه اهم باقی می‌ماند. R صفر خارج از قرارداد است.

پرسش سوم: مقدار یک را با واحد rad/s به frequency بدهیم؟ پاسخ: خیر؛ این ورودی هرتز است و کد خودش در ۲π ضرب می‌کند. برای ω یک، f باید ۱/(۲π) هرتز باشد؛ برچسب rad/s صریحاً رد می‌شود.

پرسش چهارم: برای DC عدد بزرگی جای Z برگردانیم؟ پاسخ: در این API خیر؛ f صفر خطاست. حدِ مدار ایدئال با خازن سری، امپدانس متناهیِ همین فرمول نیست و گذرا و شرایط اولیه هم محاسبه نشده‌اند.

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

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