{"id":1240,"date":"2025-11-25T20:32:36","date_gmt":"2025-11-25T17:02:36","guid":{"rendered":"https:\/\/ilk.ir\/sahifa\/?p=1240"},"modified":"2025-11-25T20:32:37","modified_gmt":"2025-11-25T17:02:37","slug":"%da%a9%d8%af-%da%a9%d8%a7%d9%85%d9%84-%d8%b4%d8%a8%db%8c%d9%87%d8%b3%d8%a7%d8%b2-dds-%d8%a8%d8%a7-%d8%ae%d8%b7%d8%a7%db%8c-r-2r","status":"publish","type":"post","link":"https:\/\/ilk.ir\/sahifa\/world\/%d8%a7%d9%84%da%a9%d8%aa%d8%b1%d9%88%d9%86%db%8c%da%a9\/%da%a9%d8%af-%da%a9%d8%a7%d9%85%d9%84-%d8%b4%d8%a8%db%8c%d9%87%d8%b3%d8%a7%d8%b2-dds-%d8%a8%d8%a7-%d8%ae%d8%b7%d8%a7%db%8c-r-2r\/","title":{"rendered":"\u06a9\u062f \u06a9\u0627\u0645\u0644 \u0634\u0628\u06cc\u0647\u200c\u0633\u0627\u0632 DDS \u0628\u0627 \u062e\u0637\u0627\u06cc R-2R"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">\u0645\u0646\u0637\u0642 \u0645\u062f\u0627\u0631 R-2R\u060c \u0631\u0627\u0628\u0637 \u06a9\u0627\u0631\u0628\u0631\u06cc \u06af\u0631\u0627\u0641\u06cc\u06a9\u06cc\u060c \u0648 \u062a\u0648\u0644\u06cc\u062f \u0645\u0648\u062c \u0633\u06cc\u0646\u0648\u0633\u06cc \u0648 \u0627\u0636\u0627\u0641\u0647 \u06a9\u0631\u062f\u0646 \u0622\u0646\u0627\u0644\u06cc\u0632 \u0637\u06cc\u0641\u06cc (FFT)\u060c \u0627\u06cc\u0646 \u06a9\u062f \u06cc\u06a9 <strong>\u0634\u0628\u06cc\u0647\u200c\u0633\u0627\u0632 \u06a9\u0627\u0645\u0644 DDS<\/strong> \u0628\u0627 \u0642\u0627\u0628\u0644\u06cc\u062a \u0628\u0631\u0631\u0633\u06cc \u062e\u0637\u0627\u06cc \u0645\u0642\u0627\u0648\u0645\u062a\u200c\u0647\u0627 \u0627\u0633\u062a.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u0627\u06cc\u0646 \u0628\u0631\u0646\u0627\u0645\u0647 \u0628\u0647 \u0634\u0645\u0627 \u0646\u0634\u0627\u0646 \u0645\u06cc\u200c\u062f\u0647\u062f \u06a9\u0647 \u062e\u0637\u0627\u06cc \u0645\u0642\u0627\u0648\u0645\u062a\u200c\u0647\u0627 \u0686\u0637\u0648\u0631 \u06a9\u06cc\u0641\u06cc\u062a \u062e\u0631\u0648\u062c\u06cc \u0633\u06cc\u0646\u0648\u0633\u06cc \u0631\u0627 \u0627\u0632 \u0646\u0638\u0631 \u0647\u0627\u0631\u0645\u0648\u0646\u06cc\u06a9 (THD) \u062a\u062d\u062a \u062a\u0627\u062b\u06cc\u0631 \u0642\u0631\u0627\u0631 \u0645\u06cc\u200c\u062f\u0647\u062f.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">\ud83d\udcbb \u06a9\u062f \u06a9\u0627\u0645\u0644 \u0634\u0628\u06cc\u0647\u200c\u0633\u0627\u0632 DDS \u0628\u0627 \u062e\u0637\u0627\u06cc R-2R<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>import tkinter as tk\nfrom tkinter import ttk\nimport numpy as np\nimport random\nimport matplotlib.pyplot as plt\nfrom matplotlib.backends.backend_tkagg import FigureCanvasTkAgg\nfrom matplotlib.figure import Figure\n\n# --- \u0645\u0646\u0637\u0642 \u0645\u062d\u0627\u0633\u0628\u0627\u062a\u06cc \u0645\u062f\u0627\u0631 R-2R (\u06a9\u0627\u0645\u0644\u0627\" \u0627\u0632 \u0642\u0628\u0644) ---\nclass Real_R2R_DAC:\n    \"\"\"\u06a9\u0644\u0627\u0633 \u0634\u0628\u06cc\u0647\u200c\u0633\u0627\u0632\u06cc \u0645\u062f\u0627\u0631 R-2R \u0628\u0627 \u0642\u0627\u0628\u0644\u06cc\u062a \u062e\u0637\u0627\u06cc \u0645\u0642\u0627\u0648\u0645\u062a\u200c\u0647\u0627\"\"\"\n    def __init__(self, resolution_bits, v_ref, r_base, tolerance_percent):\n        self.n = resolution_bits\n        self.v_ref = v_ref\n        \n        # \u062a\u0648\u0644\u06cc\u062f \u0645\u0642\u0627\u0648\u0645\u062a\u200c\u0647\u0627 \u0628\u0627 \u062e\u0637\u0627\u06cc \u062a\u0635\u0627\u062f\u0641\u06cc\n        def get_resistor(ideal_value):\n            return ideal_value * (1 + random.uniform(-tolerance_percent\/100, tolerance_percent\/100))\n\n        self.resistors_shunt = &#91;get_resistor(2 * r_base) for _ in range(self.n)]\n        self.resistors_series = &#91;get_resistor(r_base) for _ in range(self.n - 1)]\n        self.r_terminator = get_resistor(2 * r_base)\n\n    def solve_circuit(self, digital_input):\n        \"\"\"\u062d\u0644 \u0645\u062f\u0627\u0631 \u0628\u0631\u0627\u06cc \u06cc\u06a9 \u06a9\u062f \u0648\u0631\u0648\u062f\u06cc \u062e\u0627\u0635 \u0628\u0627 \u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u0627\u0632 \u0631\u0648\u0634 \u062a\u0648\u0646\u0646 \u062a\u06a9\u0631\u0627\u0631\u06cc\"\"\"\n        # \u062a\u0628\u062f\u06cc\u0644 \u0648\u0631\u0648\u062f\u06cc \u0628\u0647 \u0644\u06cc\u0633\u062a \u0628\u06cc\u062a\u200c\u0647\u0627 (LSB \u062f\u0631 \u0627\u0646\u062f\u06cc\u0633 0)\n        bits = &#91;(digital_input &gt;&gt; i) &amp; 1 for i in range(self.n)]\n        \n        r_looking_down = self.r_terminator\n        v_looking_down = 0.0\n\n        # \u062d\u0644 \u0645\u062f\u0627\u0631 \u0627\u0632 LSB \u0628\u0647 MSB\n        for i in range(self.n):\n            v_in_bit = self.v_ref if bits&#91;i] == 1 else 0.0\n            r_shunt = self.resistors_shunt&#91;i]\n            \n            denom = r_looking_down + r_shunt\n            v_node = (v_in_bit * r_looking_down + v_looking_down * r_shunt) \/ denom\n            r_node = (r_looking_down * r_shunt) \/ denom\n            \n            if i == self.n - 1:\n                return v_node\n            \n            r_series = self.resistors_series&#91;i]\n            v_looking_down = v_node\n            r_looking_down = r_node + r_series\n        return 0.0\n\n# --- \u0631\u0627\u0628\u0637 \u06a9\u0627\u0631\u0628\u0631\u06cc \u06af\u0631\u0627\u0641\u06cc\u06a9\u06cc (GUI) \u0648 \u0645\u0646\u0637\u0642 DDS ---\nclass DDS_Simulator_App:\n    def __init__(self, root):\n        self.root = root\n        self.root.title(\"\u0634\u0628\u06cc\u0647\u200c\u0633\u0627\u0632 \u06a9\u0627\u0645\u0644 DDS \u0648 \u062a\u062d\u0644\u06cc\u0644 \u0647\u0627\u0631\u0645\u0648\u0646\u06cc\u06a9\")\n        self.root.geometry(\"1200x850\")\n        \n        self.r_base = 10000 # 10k Ohm \u062b\u0627\u0628\u062a\n\n        # --- \u067e\u0646\u0644 \u06a9\u0646\u062a\u0631\u0644 (\u0633\u0645\u062a \u0686\u067e) ---\n        control_frame = ttk.LabelFrame(root, text=\"\u062a\u0646\u0638\u06cc\u0645\u0627\u062a \u0645\u062f\u0627\u0631 \u0648 \u0633\u06cc\u06af\u0646\u0627\u0644\", padding=\"15\")\n        control_frame.pack(side=tk.LEFT, fill=tk.Y, padx=10, pady=10)\n\n        # 1. \u062a\u0639\u062f\u0627\u062f \u0628\u06cc\u062a\u200c\u0647\u0627 (Resolution)\n        ttk.Label(control_frame, text=\"\u06f1. \u0631\u0632\u0648\u0644\u0648\u0634\u0646 (\u0628\u06cc\u062a):\").pack(anchor=\"w\", pady=5)\n        self.var_bits = tk.IntVar(value=8)\n        scale_bits = ttk.Scale(control_frame, from_=4, to=12, orient=tk.HORIZONTAL, variable=self.var_bits, command=self.update_plot)\n        scale_bits.pack(fill=tk.X, pady=5)\n        self.lbl_bits_val = ttk.Label(control_frame, text=\"8 bits\")\n        self.lbl_bits_val.pack(anchor=\"e\")\n\n        # 2. \u0648\u0644\u062a\u0627\u0698 \u0645\u0631\u062c\u0639 (Vref)\n        ttk.Label(control_frame, text=\"\u06f2. \u0648\u0644\u062a\u0627\u0698 \u0645\u0631\u062c\u0639 (V):\").pack(anchor=\"w\", pady=5)\n        self.var_vref = tk.DoubleVar(value=5.0)\n        scale_vref = ttk.Scale(control_frame, from_=1.0, to=10.0, orient=tk.HORIZONTAL, variable=self.var_vref, command=self.update_plot)\n        scale_vref.pack(fill=tk.X, pady=5)\n        self.lbl_vref_val = ttk.Label(control_frame, text=\"5.0 V\")\n        self.lbl_vref_val.pack(anchor=\"e\")\n\n        # 3. \u062f\u0631\u0635\u062f \u062e\u0637\u0627 (Tolerance)\n        ttk.Label(control_frame, text=\"\u06f3. \u062e\u0637\u0627\u06cc \u0645\u0642\u0627\u0648\u0645\u062a (%):\").pack(anchor=\"w\", pady=5)\n        self.var_tol = tk.DoubleVar(value=0.0)\n        scale_tol = ttk.Scale(control_frame, from_=0.0, to=10.0, orient=tk.HORIZONTAL, variable=self.var_tol, command=self.update_plot)\n        scale_tol.pack(fill=tk.X, pady=5)\n        self.lbl_tol_val = ttk.Label(control_frame, text=\"0.0 %\")\n        self.lbl_tol_val.pack(anchor=\"e\")\n        \n        # 4. \u0641\u0631\u06a9\u0627\u0646\u0633 \u0633\u06cc\u0646\u0648\u0633\u06cc (Number of Cycles)\n        ttk.Label(control_frame, text=\"\u06f4. \u062a\u0639\u062f\u0627\u062f \u0633\u06cc\u06a9\u0644 (\u062f\u0631 \u0646\u0645\u0648\u0646\u0647):\").pack(anchor=\"w\", pady=5)\n        self.var_cycles = tk.IntVar(value=3)\n        scale_cycles = ttk.Scale(control_frame, from_=1, to=8, orient=tk.HORIZONTAL, variable=self.var_cycles, command=self.update_plot)\n        scale_cycles.pack(fill=tk.X, pady=5)\n        self.lbl_cycles_val = ttk.Label(control_frame, text=\"3 Cycles\")\n        self.lbl_cycles_val.pack(anchor=\"e\")\n\n        # \u062f\u06a9\u0645\u0647 \u062a\u0648\u0644\u06cc\u062f \u0645\u062c\u062f\u062f (\u0628\u0631\u0627\u06cc \u0645\u0634\u0627\u0647\u062f\u0647 \u062a\u063a\u06cc\u06cc\u0631 \u0645\u0642\u0627\u0648\u0645\u062a\u200c\u0647\u0627\u06cc \u062a\u0635\u0627\u062f\u0641\u06cc)\n        ttk.Separator(control_frame, orient='horizontal').pack(fill='x', pady=15)\n        self.btn_regen = ttk.Button(control_frame, text=\"\u062a\u0648\u0644\u06cc\u062f \u0645\u062c\u062f\u062f \u0645\u0642\u0627\u0648\u0645\u062a\u200c\u0647\u0627 \u0648 \u0634\u0628\u06cc\u0647\u200c\u0633\u0627\u0632\u06cc\", command=self.force_update)\n        self.btn_regen.pack(fill=tk.X, pady=5)\n\n        # \u0648\u0636\u0639\u06cc\u062a \u0648 \u0646\u062a\u0627\u06cc\u062c\n        ttk.Separator(control_frame, orient='horizontal').pack(fill='x', pady=15)\n        self.lbl_status = tk.Label(control_frame, text=\"\u0648\u0636\u0639\u06cc\u06cc\u062a: \u0646\u0631\u0645\u0627\u0644\", font=(\"Arial\", 12, \"bold\"), fg=\"green\", wraplength=200)\n        self.lbl_status.pack(pady=5)\n        self.lbl_thd = tk.Label(control_frame, text=\"THD: N\/A\", font=(\"Arial\", 12, \"bold\"), wraplength=200)\n        self.lbl_thd.pack(pady=5)\n\n\n        # --- \u0646\u0627\u062d\u06cc\u0647 \u0646\u0645\u0648\u062f\u0627\u0631 (\u0633\u0645\u062a \u0631\u0627\u0633\u062a) ---\n        plot_frame = ttk.Frame(root)\n        plot_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True, padx=10, pady=10)\n\n        # \u0627\u06cc\u062c\u0627\u062f \u0634\u06a9\u0644 Matplotlib \u0628\u0627 \u0633\u0647 \u0646\u0645\u0648\u062f\u0627\u0631\n        self.fig = Figure(figsize=(8, 7), dpi=100)\n        self.ax1 = self.fig.add_subplot(311) # \u0632\u0645\u0627\u0646\n        self.ax2 = self.fig.add_subplot(312, sharex=self.ax1) # \u062e\u0637\u0627\n        self.ax3 = self.fig.add_subplot(313) # FFT\n        self.fig.subplots_adjust(hspace=0.45, top=0.95, bottom=0.08)\n\n        self.canvas = FigureCanvasTkAgg(self.fig, master=plot_frame)\n        self.canvas.get_tk_widget().pack(fill=tk.BOTH, expand=True)\n\n        # \u0631\u0633\u0645 \u0627\u0648\u0644\u06cc\u0647\n        self.force_update()\n\n    def force_update(self):\n        \"\"\"\u0641\u0631\u0627\u062e\u0648\u0627\u0646\u06cc \u0628\u0631\u0627\u06cc \u062a\u0648\u0644\u06cc\u062f \u0645\u0642\u0627\u062f\u06cc\u0631 \u062a\u0635\u0627\u062f\u0641\u06cc \u062c\u062f\u06cc\u062f \u0645\u0642\u0627\u0648\u0645\u062a \u0648 \u0631\u0633\u0645\"\"\"\n        self.update_plot(None)\n\n    def calculate_thd(self, signal):\n        \"\"\"\u0645\u062d\u0627\u0633\u0628\u0647 THD (Total Harmonic Distortion) \u0628\u0631 \u0627\u0633\u0627\u0633 FFT\"\"\"\n        N = len(signal)\n        fft_result = np.fft.fft(signal)\n        magnitude = np.abs(fft_result&#91;:N\/\/2])\n        \n        # \u067e\u06cc\u062f\u0627 \u06a9\u0631\u062f\u0646 \u0641\u0631\u06a9\u0627\u0646\u0633 \u0627\u0635\u0644\u06cc (\u0628\u0639\u062f \u0627\u0632 DC)\n        # DC (\u0641\u0631\u06a9\u0627\u0646\u0633 \u0635\u0641\u0631) \u0631\u0627 \u062d\u0630\u0641 \u0645\u06cc\u200c\u06a9\u0646\u06cc\u0645\u060c \u0686\u0648\u0646 \u0645\u0648\u062c \u0645\u0627 \u0627\u0632 0 \u062a\u0627 Vref \u0627\u0633\u062a \u0648 \u0628\u0627\u06cc\u0627\u0633 \u062f\u0627\u0631\u062f\n        fundamental_index = np.argmax(magnitude&#91;1:]) + 1 \n        V_f1 = magnitude&#91;fundamental_index]\n        \n        # \u0645\u062c\u0645\u0648\u0639 \u062f\u0627\u0645\u0646\u0647 \u062a\u0648\u0627\u0646\u200c\u0647\u0627\u06cc \u0647\u0627\u0631\u0645\u0648\u0646\u06cc\u06a9 (\u0627\u0632 \u0647\u0627\u0631\u0645\u0648\u0646\u06cc\u06a9 \u062f\u0648\u0645 \u0628\u0647 \u0628\u0639\u062f)\n        # THD \u0645\u0639\u0645\u0648\u0644\u0627\u064b \u0628\u0631 \u0627\u0633\u0627\u0633 10 \u0647\u0627\u0631\u0645\u0648\u0646\u06cc\u06a9 \u0627\u0648\u0644 \u0645\u062d\u0627\u0633\u0628\u0647 \u0645\u06cc\u200c\u0634\u0648\u062f\n        harmonic_power_sum = 0\n        for h in range(2, 11): # \u0647\u0627\u0631\u0645\u0648\u0646\u06cc\u06a9\u200c\u0647\u0627\u06cc 2 \u062a\u0627 10\n            harmonic_index = h * fundamental_index\n            if harmonic_index &lt; N \/\/ 2:\n                harmonic_power_sum += magnitude&#91;harmonic_index]**2\n        \n        if V_f1 == 0: return float('inf')\n        \n        # THD = sqrt(\u0645\u062c\u0645\u0648\u0639 \u062a\u0648\u0627\u0646 \u0647\u0627\u0631\u0645\u0648\u0646\u06cc\u06a9\u200c\u0647\u0627) \/ \u062a\u0648\u0627\u0646 \u0641\u0631\u06a9\u0627\u0646\u0633 \u0627\u0635\u0644\u06cc\n        thd = np.sqrt(harmonic_power_sum) \/ V_f1\n        return thd * 100 # \u0628\u0631 \u062d\u0633\u0628 \u062f\u0631\u0635\u062f\n\n    def update_plot(self, event=None):\n        # \u062e\u0648\u0627\u0646\u062f\u0646 \u067e\u0627\u0631\u0627\u0645\u062a\u0631\u0647\u0627\n        bits = int(self.var_bits.get())\n        v_ref = self.var_vref.get()\n        tol = self.var_tol.get()\n        cycles = self.var_cycles.get()\n        r_base = self.r_base\n        \n        self.lbl_bits_val.config(text=f\"{bits} bits\")\n        self.lbl_vref_val.config(text=f\"{v_ref:.1f} V\")\n        self.lbl_tol_val.config(text=f\"{tol:.1f} %\")\n        self.lbl_cycles_val.config(text=f\"{cycles} Cycles\")\n\n        # --- \u06f1. \u062a\u0648\u0644\u06cc\u062f \u0633\u06cc\u06af\u0646\u0627\u0644 DDS (\u0648\u0631\u0648\u062f\u06cc \u0633\u06cc\u0646\u0648\u0633\u06cc \u06a9\u0648\u0627\u0646\u062a\u0627\u06cc\u0632 \u0634\u062f\u0647) ---\n        num_samples = 2**bits\n        # t = \u0641\u0627\u0632 \u0633\u06cc\u06af\u0646\u0627\u0644\n        t = np.linspace(0, cycles * 2 * np.pi, num_samples, endpoint=False) \n        \n        # \u0645\u0648\u062c \u0633\u06cc\u0646\u0648\u0633\u06cc (\u0628\u0627\u06cc\u0627\u0633 \u0634\u062f\u0647 \u0628\u0631\u0627\u06cc DDS\u060c \u0627\u0632 0 \u062a\u0627 1)\n        sine_wave_analog = (np.sin(t) + 1) \/ 2 \n        \n        # \u06a9\u0648\u0627\u0646\u062a\u0627\u06cc\u0632 \u06a9\u0631\u062f\u0646 (\u062a\u0628\u062f\u06cc\u0644 \u0628\u0647 \u06a9\u062f \u062f\u06cc\u062c\u06cc\u062a\u0627\u0644 LUT)\n        max_code = 2**bits - 1\n        digital_inputs = np.round(sine_wave_analog * max_code).astype(int)\n\n        # --- \u06f2. \u062d\u0644 \u0645\u062f\u0627\u0631 DAC \u0628\u0627 \u0648\u0631\u0648\u062f\u06cc \u0633\u06cc\u0646\u0648\u0633\u06cc ---\n        ideal_dac = Real_R2R_DAC(bits, v_ref, r_base, 0.0)\n        real_dac = Real_R2R_DAC(bits, v_ref, r_base, tol)\n        \n        # \u062d\u0644 DAC \u0628\u0627 \u0648\u0631\u0648\u062f\u06cc LUT \u0633\u06cc\u0646\u0648\u0633\u06cc\n        y_ideal = np.array(&#91;ideal_dac.solve_circuit(i) for i in digital_inputs])\n        y_real = np.array(&#91;real_dac.solve_circuit(i) for i in digital_inputs])\n        \n        # \u0645\u062d\u0627\u0633\u0628\u0647 \u062e\u0637\u0627 \u0648 \u06cc\u06a9\u0646\u0648\u0627\u06cc\u06cc\n        y_real_diff = np.diff(y_real)\n        is_monotonic = not np.any(y_real_diff &lt; 0)\n\n        # --- \u06f3. \u0622\u0646\u0627\u0644\u06cc\u0632 \u0637\u06cc\u0641\u06cc (FFT) \u0648 THD ---\n        # \u0633\u06cc\u06af\u0646\u0627\u0644 \u0631\u0627 \u0627\u0632 \u0628\u0627\u06cc\u0627\u0633 DC \u062e\u0627\u0631\u062c \u0645\u06cc\u200c\u06a9\u0646\u06cc\u0645\n        signal_for_fft = y_real - np.mean(y_real)\n        \n        thd_percent = self.calculate_thd(signal_for_fft)\n        \n        N = len(signal_for_fft)\n        fft_result = np.fft.fft(signal_for_fft)\n        fft_magnitude = np.abs(fft_result&#91;:N\/\/2])\n        fft_magnitude_db = 20 * np.log10(fft_magnitude \/ np.max(fft_magnitude)) # \u0646\u0631\u0645\u0627\u0644\u0627\u06cc\u0632 \u0628\u0647 dBc\n        \n        fft_freq_axis = np.fft.fftfreq(N, 1\/N)&#91;:N\/\/2] # \u0645\u062d\u0648\u0631 \u0641\u0631\u06a9\u0627\u0646\u0633 \u0646\u0631\u0645\u0627\u0644 \u0634\u062f\u0647\n\n        # --- \u06f4. \u0631\u0633\u0645 \u0646\u0645\u0648\u062f\u0627\u0631\u0647\u0627 ---\n        self.ax1.clear()\n        self.ax2.clear()\n        self.ax3.clear()\n\n        # \u0646\u0645\u0648\u062f\u0627\u0631 \u06f1: \u0632\u0645\u0627\u0646 (\u062e\u0631\u0648\u062c\u06cc DDS)\n        self.ax1.plot(t, y_ideal, linestyle='--', color='gray', label='Ideal', alpha=0.7)\n        self.ax1.plot(t, y_real, color='blue', label='Real', linewidth=1.5)\n        self.ax1.set_ylabel('Voltage (V)')\n        self.ax1.set_title(f'Time Domain Output (DDS Signal)')\n        self.ax1.legend()\n        self.ax1.grid(True, alpha=0.3)\n\n        # \u0646\u0645\u0648\u062f\u0627\u0631 \u06f2: \u062e\u0637\u0627 (INL\/DNL - \u0628\u0647 \u062f\u0644\u06cc\u0644 \u063a\u06cc\u0631\u062e\u0637\u06cc \u0628\u0648\u062f\u0646)\n        error_val = y_real - y_ideal\n        self.ax2.plot(t, error_val, color='red')\n        self.ax2.axhline(0, color='black', linewidth=0.8)\n        self.ax2.set_ylabel('Error (V)')\n        self.ax2.set_title('Error\/Distortion in Time Domain')\n        self.ax2.grid(True, alpha=0.3)\n\n        # \u0646\u0645\u0648\u062f\u0627\u0631 \u06f3: \u0637\u06cc\u0641 \u0641\u0631\u06a9\u0627\u0646\u0633\u06cc (FFT)\n        self.ax3.plot(fft_freq_axis, fft_magnitude_db, color='purple')\n        self.ax3.set_xlabel('Normalized Frequency Index')\n        self.ax3.set_ylabel('Magnitude (dBc)')\n        self.ax3.set_title('Frequency Spectrum (FFT)')\n        self.ax3.set_ylim(-100, 0) # \u0646\u0645\u0627\u06cc\u0634 \u0627\u0632 0 \u062a\u0627 -100 dB\n        self.ax3.grid(True, alpha=0.3)\n        \n        # --- \u06f5. \u0628\u0631\u0648\u0632\u0631\u0633\u0627\u0646\u06cc \u0648\u0636\u0639\u06cc\u062a ---\n        if is_monotonic:\n            self.lbl_status.config(text=\"\u0648\u0636\u0639\u06cc\u062a: \u06cc\u06a9\u0646\u0648\u0627 (Monotonic)\", fg=\"green\")\n        else:\n            self.lbl_status.config(text=\"\u0647\u0634\u062f\u0627\u0631: \u063a\u06cc\u0631\u06cc\u06a9\u0646\u0648\u0627 (Non-Monotonic)!\", fg=\"red\")\n        \n        self.lbl_thd.config(text=f\"THD: {thd_percent:.3f} %\")\n\n        self.canvas.draw()\n\n# --- \u0627\u062c\u0631\u0627\u06cc \u0628\u0631\u0646\u0627\u0645\u0647 ---\nif __name__ == \"__main__\":\n    root = tk.Tk()\n    try:\n        default_font = ('Tahoma', 10)\n        root.option_add(\"*Font\", default_font)\n    except:\n        pass\n    app = DDS_Simulator_App(root)\n    root.mainloop()\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">\u0631\u0627\u0647\u0646\u0645\u0627\u06cc \u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u0648 \u062a\u062d\u0644\u06cc\u0644 \u0646\u062a\u0627\u06cc\u062c:<\/h3>\n\n\n\n<ol start=\"1\" class=\"wp-block-list\">\n<li><strong>\u062e\u0637\u0627\u06cc \u0635\u0641\u0631 (Tolerance 0%)<\/strong>:\n<ul class=\"wp-block-list\">\n<li><code>THD<\/code> \u0628\u0633\u06cc\u0627\u0631 \u067e\u0627\u06cc\u06cc\u0646 \u0627\u0633\u062a (\u06a9\u0645\u062a\u0631 \u0627\u0632 \u06f0.\u06f1\u066a) \u0648 \u0641\u0642\u0637 \u0628\u0647 \u062f\u0644\u06cc\u0644 <strong>\u06a9\u0648\u0627\u0646\u062a\u0627\u06cc\u0632\u06cc\u0634\u0646 (Quantization)<\/strong> \u0627\u0633\u062a\u060c \u0646\u0647 \u062e\u0637\u0627\u06cc \u0645\u0642\u0627\u0648\u0645\u062a.<\/li>\n\n\n\n<li>\u062f\u0631 \u0646\u0645\u0648\u062f\u0627\u0631 FFT\u060c \u0642\u0644\u0647 \u0627\u0635\u0644\u06cc \u0633\u06cc\u06af\u0646\u0627\u0644 \u0628\u0633\u06cc\u0627\u0631 \u063a\u0627\u0644\u0628 \u0627\u0633\u062a.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>\u062e\u0637\u0627\u06cc \u0628\u0627\u0644\u0627 (Tolerance 5% \u06cc\u0627 \u0628\u06cc\u0634\u062a\u0631)<\/strong>:\n<ul class=\"wp-block-list\">\n<li><code>THD<\/code> \u0628\u0647 \u0634\u062f\u062a \u0627\u0641\u0632\u0627\u06cc\u0634 \u0645\u06cc\u200c\u06cc\u0627\u0628\u062f (\u0645\u0645\u06a9\u0646 \u0627\u0633\u062a \u0628\u0647 \u0628\u0627\u0644\u0627\u06cc \u06f1\u066a \u0628\u0631\u0633\u062f).<\/li>\n\n\n\n<li>\u062f\u0631 \u0646\u0645\u0648\u062f\u0627\u0631 FFT\u060c \u0686\u0646\u062f\u06cc\u0646 \u0642\u0644\u0647 \u06a9\u0648\u0686\u06a9 (\u0647\u0627\u0631\u0645\u0648\u0646\u06cc\u06a9) \u062f\u0631 \u06a9\u0646\u0627\u0631 \u0642\u0644\u0647 \u0627\u0635\u0644\u06cc \u0638\u0627\u0647\u0631 \u0645\u06cc\u200c\u0634\u0648\u0646\u062f \u06a9\u0647 \u0646\u0634\u0627\u0646\u200c\u062f\u0647\u0646\u062f\u0647 \u0622\u0644\u0648\u062f\u06af\u06cc \u0633\u06cc\u06af\u0646\u0627\u0644 \u0627\u0633\u062a.<\/li>\n\n\n\n<li>\u0627\u06cc\u0646 \u062f\u0642\u06cc\u0642\u0627\u064b \u0646\u0634\u0627\u0646 \u0645\u06cc\u200c\u062f\u0647\u062f \u06a9\u0647 \u0686\u0631\u0627 \u0633\u0627\u0632\u0646\u062f\u06af\u0627\u0646 DDS \u0627\u0632 \u0634\u0628\u06a9\u0647\u200c\u0647\u0627\u06cc \u0645\u0642\u0627\u0648\u0645\u062a\u06cc \u0628\u0633\u06cc\u0627\u0631 \u062f\u0642\u06cc\u0642 \u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u0645\u06cc\u200c\u06a9\u0646\u0646\u062f.<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n","protected":false},"excerpt":{"rendered":"<p>\u0645\u0646\u0637\u0642 \u0645\u062f\u0627\u0631 R-2R\u060c \u0631\u0627\u0628\u0637 \u06a9\u0627\u0631\u0628\u0631\u06cc \u06af\u0631\u0627\u0641\u06cc\u06a9\u06cc\u060c \u0648 \u062a\u0648\u0644\u06cc\u062f \u0645\u0648\u062c \u0633\u06cc\u0646\u0648\u0633\u06cc \u0648 \u0627\u0636\u0627\u0641\u0647 \u06a9\u0631\u062f\u0646 \u0622\u0646\u0627\u0644\u06cc\u0632 \u0637\u06cc\u0641\u06cc (FFT)\u060c \u0627\u06cc\u0646 \u06a9\u062f \u06cc\u06a9 \u0634\u0628\u06cc\u0647\u200c\u0633\u0627\u0632 \u06a9\u0627\u0645\u0644 DDS \u0628\u0627 \u0642\u0627\u0628\u0644\u06cc\u062a \u0628\u0631\u0631\u0633\u06cc \u062e\u0637\u0627\u06cc \u0645\u0642\u0627\u0648\u0645\u062a\u200c\u0647\u0627 \u0627\u0633\u062a. \u0627\u06cc\u0646 \u0628\u0631\u0646\u0627\u0645\u0647 \u0628\u0647 \u0634\u0645\u0627 \u0646\u0634\u0627\u0646 \u0645\u06cc\u200c\u062f\u0647\u062f \u06a9\u0647 \u062e\u0637\u0627\u06cc \u0645\u0642\u0627\u0648\u0645\u062a\u200c\u0647\u0627 \u0686\u0637\u0648\u0631 \u06a9\u06cc\u0641\u06cc\u062a \u062e\u0631\u0648\u062c\u06cc \u0633\u06cc\u0646\u0648\u0633\u06cc \u0631\u0627 \u0627\u0632 \u0646\u0638\u0631 \u0647\u0627\u0631\u0645\u0648\u0646\u06cc\u06a9 (THD) \u062a\u062d\u062a \u062a\u0627\u062b\u06cc\u0631 \u0642\u0631\u0627\u0631 \u0645\u06cc\u200c\u062f\u0647\u062f. \ud83d\udcbb \u06a9\u062f \u06a9\u0627\u0645\u0644 \u0634\u0628\u06cc\u0647\u200c\u0633\u0627\u0632 DDS &hellip;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[13],"tags":[],"class_list":["post-1240","post","type-post","status-publish","format-standard","","category-13"],"_links":{"self":[{"href":"https:\/\/ilk.ir\/sahifa\/wp-json\/wp\/v2\/posts\/1240","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/ilk.ir\/sahifa\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/ilk.ir\/sahifa\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/ilk.ir\/sahifa\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/ilk.ir\/sahifa\/wp-json\/wp\/v2\/comments?post=1240"}],"version-history":[{"count":1,"href":"https:\/\/ilk.ir\/sahifa\/wp-json\/wp\/v2\/posts\/1240\/revisions"}],"predecessor-version":[{"id":1241,"href":"https:\/\/ilk.ir\/sahifa\/wp-json\/wp\/v2\/posts\/1240\/revisions\/1241"}],"wp:attachment":[{"href":"https:\/\/ilk.ir\/sahifa\/wp-json\/wp\/v2\/media?parent=1240"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/ilk.ir\/sahifa\/wp-json\/wp\/v2\/categories?post=1240"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/ilk.ir\/sahifa\/wp-json\/wp\/v2\/tags?post=1240"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}