شبیه ساز تعاملی مقایسه‌گر دو موج مثلثی

شبیه ساز تعاملی مقایسه‌گر طوریکه هر دو ورودی $V_+$ و $V_-$ از نوع موج مثلثی (Triangle Wave) باشند و فرکانس هر دو با اسلایدر و همچنین دامنه موج قابل تنظیم باشد.

این شبیه‌سازی، رفتار یک مقایسه‌گر را هنگام دریافت دو سیگنال مثلثی با فرکانس‌های متفاوت نشان می‌دهد که می‌تواند در مدارهای تولید پالس پیچیده کاربرد داشته باشد.

کد پایتون: مقایسه‌گر دو موج مثلثی تعاملی با امکان تغییر دامنه

import numpy as np
import matplotlib.pyplot as plt
from scipy import signal
from matplotlib.widgets import Slider, Button 

# ----------------- کلاس OpAmp (مقایسه‌گر) -----------------
# ولتاژهای اشباع ثابت می‌مانند
V_SUPPLY_POS = 5.5
V_SUPPLY_NEG = -5.5

class OpAmpComparator:
    def __init__(self, v_pos=V_SUPPLY_POS, v_neg=V_SUPPLY_NEG):
        self.v_pos = v_pos
        self.v_neg = v_neg

    def transfer(self, v_plus, v_minus):
        """خروجی بر اساس مقایسه V+ و V-"""
        if v_plus > v_minus:
            return self.v_pos
        elif v_plus < v_minus:
            return self.v_neg
        else:
            return 0

# ----------------- تنظیمات اولیه شبیه‌سازی -----------------
duration = 0.01  # 10 میلی‌ثانیه
sampling_rate = 10000 
time = np.linspace(0, duration, int(duration * sampling_rate), endpoint=False) # آرایه زمان (X data)

# تعریف OpAmp
opamp = OpAmpComparator()

# ----------------- تنظیمات نمودار و Handlers (مقداردهی اولیه) -----------------

# ایجاد یک پنجره نمودار (Figure)
fig, ax = plt.subplots(figsize=(10, 7))
# فضای لازم برای اسلایدرها
plt.subplots_adjust(left=0.1, bottom=0.35) 

# تعریف دستگیره‌های پلات (Handles) به صورت None
# این متغیرها به عنوان متغیرهای سراسری (global) در نظر گرفته می‌شوند.
line_plus = None
line_minus = None
line_out = None

# خطوط اشباع
ax.axhline(y=opamp.v_pos, color='gray', linestyle='-.', alpha=0.7)
ax.axhline(y=opamp.v_neg, color='gray', linestyle='-.', alpha=0.7, label='Supply Rails ($\pm 5.5V$)')

# ----------------- تابع اصلی تولید و رسم داده‌ها -----------------

def generate_and_plot(f_tri1, f_tri2, amplitude):
    """
    تولید دو موج مثلثی با فرکانس و دامنه متغیر و شبیه‌سازی خروجی.
    """
    
    # 1. تولید سیگنال‌های ورودی
    # V+ (ورودی غیرمعکوس‌کننده): موج مثلثی 1
    V_plus_signal = amplitude * signal.sawtooth(2 * np.pi * f_tri1 * time, width=0.5)
    
    # V- (ورودی معکوس‌کننده): موج مثلثی 2
    V_minus_signal = amplitude * signal.sawtooth(2 * np.pi * f_tri2 * time, width=0.5)

    # 2. شبیه‌سازی خروجی
    V_out_signal = []
    for v_plus, v_minus in zip(V_plus_signal, V_minus_signal):
        v_out = opamp.transfer(v_plus, v_minus)
        V_out_signal.append(v_out)
    
    return V_plus_signal, V_minus_signal, np.array(V_out_signal)

# ----------------- تعریف ویجت‌های اسلایدر -----------------

# فرکانس‌های اولیه
f_tri1_init = 500  
f_tri2_init = 500
amp_init = 4.0 # دامنه اولیه

# محورها برای اسلایدر فرکانس مثلثی 1 (V+)
ax_freq_tri1 = plt.axes([0.1, 0.25, 0.8, 0.03], facecolor='lightgoldenrodyellow')
slider_tri1 = Slider(ax_freq_tri1, 'Tri 1 Freq (Hz)', 50, 2000, valinit=f_tri1_init, valstep=25)

# محورها برای اسلایدر فرکانس مثلثی 2 (V-)
ax_freq_tri2 = plt.axes([0.1, 0.2, 0.8, 0.03], facecolor='lightgoldenrodyellow')
slider_tri2 = Slider(ax_freq_tri2, 'Tri 2 Freq (Hz)', 50, 1000, valinit=f_tri2_init, valstep=25)

# محورها برای اسلایدر دامنه (Amplitude)
ax_amp = plt.axes([0.1, 0.15, 0.8, 0.03], facecolor='lightcyan')
slider_amp = Slider(
    ax_amp, 
    'Amplitude (V)', 
    valmin=1.0, 
    valmax=6.0, 
    valinit=amp_init, 
    valstep=0.1
)

# ----------------- تابع به‌روزرسانی (Update Function) - بخش اصلی اصلاح شده -----------------

def update(val):
    """
    این تابع مقادیر جدید را از اسلایدرها گرفته و نمودار را به‌روز می‌کند.
    """
    # تعریف متغیرهای global برای دسترسی به Handlers خطوط
    global line_plus, line_minus, line_out 
    
    f_tri1_new = slider_tri1.val
    f_tri2_new = slider_tri2.val
    amp_new = slider_amp.val
    
    # تولید داده‌های جدید
    V_plus_new, V_minus_new, V_out_new = generate_and_plot(f_tri1_new, f_tri2_new, amp_new)
    
    # **منطق اصلاح شده:** بررسی می‌کند که آیا خطوط قبلاً ایجاد شده‌اند یا خیر
    if line_plus is None:
        # اگر اولین بار است (مقداردهی اولیه)، خطوط را ایجاد کنید
        line_plus, = ax.plot(time, V_plus_new, label='$V_+$ (Tri 1)', color='blue', linestyle='--')
        line_minus, = ax.plot(time, V_minus_new, label='$V_-$ (Tri 2)', color='green', linestyle=':')
        line_out, = ax.plot(time, V_out_new, label='Output ($V_{out}$)', color='red', linewidth=2)
    else:
        # در غیر این صورت، فقط داده‌های Y را به‌روزرسانی کنید
        line_plus.set_ydata(V_plus_new)
        line_minus.set_ydata(V_minus_new)
        line_out.set_ydata(V_out_new)
    
    # به‌روزرسانی عناوین (Labels) در Legend
    line_plus.set_label(f'$V_+$ (Tri 1: {f_tri1_new:.0f} Hz, {amp_new:.1f} V)')
    line_minus.set_label(f'$V_-$ (Tri 2: {f_tri2_new:.0f} Hz, {amp_new:.1f} V)')
    ax.legend()
    
    # تنظیم محور Y
    max_y = max(amp_new * 1.05, V_SUPPLY_POS * 1.05)
    min_y = min(-amp_new * 1.05, V_SUPPLY_NEG * 1.05)
    ax.set_ylim(min_y, max_y)
    
    # دستور رسم مجدد
    fig.canvas.draw_idle() 

# ----------------- اتصال اسلایدر به تابع به‌روزرسانی و نمایش اولیه -----------------
slider_tri1.on_changed(update)
slider_tri2.on_changed(update)
slider_amp.on_changed(update)

# اجرای به‌روزرسانی اولیه برای نمایش نمودار با مقادیر اولیه و رفع خطای اولیه
update(None)

# ----------------- تنظیمات نهایی نمودار و نمایش -----------------
ax.set_title('Interactive Op-Amp Comparator: Freq & Amplitude Control')
ax.set_xlabel('Time (s)') # اصلاح واحد زمان
ax.set_ylabel('Voltage (V)')
ax.set_xlim(0, duration) # تنظیم محور X

plt.show()

همچنین بررسی کنید

ساخت پروب اسیلوسکوپ برای اندازه گیری توان (قسمت دوم)

در قسمت یک، ما محدودیت های پهنای باند پروب های غیرفعال را پوشش دادیم و …

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *