2025年10月29日 星期三

調變技術 (Modulation) --Python

調變技術 (Modulation) 

源自於 https://haolongtelecom.home.blog/2019/02/12/%E7%A7%BB%E5%8B%95%E9%80%9A%E8%A8%8A-1-%E6%8A%80%E8%A1%93%E7%AF%87/

調變 (Modulation):通訊設備的發射端將「低頻訊號 (聲音)」處理成「高頻訊號 (電磁波)」之後,再傳送出去的過程,稱為「調變」。

解調 (Demodulation):通訊設備的接收端將「高頻訊號 (電磁波)」接收了之後,再還原成「低頻訊號 (聲音)」的過程,稱為「解調」。

ASK (Amplitude Shift Keying)

振幅位移鍵送 ASK,使電磁波跟隨數位訊號的「振幅大小」變化,載著數位訊號一起發射出去。當電磁波振幅大時,代表 1;振幅小時,代表 0。ASK 的技術最簡單,抗雜訊能力最差,較少使用在無線通訊上,而多使用在光纖通訊。

FSK (Frequency Shift Keying)

頻率位移鍵送 FSK,使電磁波跟隨數位訊號的「頻率高低」變化,載著數位訊號一起發射出去。當電磁波頻率高時,代表 1;頻率低時,代表 0。FSK 在頻率改變的瞬間可能使電磁波不連續,造成頻譜的特性變差。技術複雜,但抗雜訊能力比 ASK 好,錯誤率低,可使用在無線通訊上。

PSK (Phase Shift Keying)

相位位移鍵送 PSK,使電磁波跟隨數位訊號的「波形不同」變化,載著數位訊號一起發射出去。當電磁波相位為 180°(先下後上振動)時,代表 1;相位為 0°(先上後下振動)時,代表 0。技術最複雜,但抗雜訊能力最好,因此較常用在無線通訊上,例如無線網路。





Tkinter 介面: 用於接收 10-bit 的二進制輸入。

Matplotlib 邏輯: 根據輸入的 10-bit 數據,生成 ASK、FSK、PSK 的波形數據。

Tkinter 整合: 將 Matplotlib 圖表嵌入到 Tkinter 視窗中。

(使用 Matplotlib 整合至 Tkinter)


 import tkinter as tk

from tkinter import ttk, messagebox

import numpy as np

import matplotlib.pyplot as plt

from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg


# --- 核心邏輯:波形生成函式 ---


def generate_modulation_signals(data_bits, fc=10, fs=1000):

    """

    根據輸入的二進制數據,生成 ASK, FSK, PSK 訊號。

    fc: 載波頻率 (Carrier Frequency)

    fs: 採樣頻率 (Sampling Frequency)

    """

    

    # 計算總時間長度 (假設每個 bit 持續 1 秒)

    T_bit = 1

    T_total = len(data_bits) * T_bit

    

    # 創建時間軸

    time = np.linspace(0, T_total, int(fs * T_total), endpoint=False)

    

    # 初始化訊號

    ask_signal = np.zeros_like(time)

    fsk_signal = np.zeros_like(time)

    psk_signal = np.zeros_like(time)

    

    # 載波 (Carrier)

    carrier = np.cos(2 * np.pi * fc * time)

    

    # 循環處理每個 bit

    for i, bit in enumerate(data_bits):

        t_start = i * T_bit

        t_end = (i + 1) * T_bit

        

        # 找出當前 bit 區間的索引

        idx = (time >= t_start) & (time < t_end)

        

        # 1. ASK (Amplitude Shift Keying)

        # '1' = 載波振幅 A1 (設為 1.0)

        # '0' = 載波振幅 A0 (設為 0.2, 避免完全為零,以便觀察)

        amplitude = 1.0 if bit == '1' else 0.2

        ask_signal[idx] = amplitude * np.cos(2 * np.pi * fc * time[idx])

        

        # 2. FSK (Frequency Shift Keying)

        # '1' = 頻率 f1 (設為 1.5 * fc)

        # '0' = 頻率 f0 (設為 0.5 * fc)

        freq = 1.5 * fc if bit == '1' else 0.5 * fc

        fsk_signal[idx] = np.cos(2 * np.pi * freq * time[idx])

        

        # 3. PSK (Phase Shift Keying)

        # '1' = 相位 φ1 (設為 0)

        # '0' = 相位 φ0 (設為 pi/2, 即 90度相移,與圖片中180度相移略有不同,但能清楚顯示相位變化)

        phase = 0 if bit == '1' else np.pi # 180度相移 (π)

        psk_signal[idx] = np.cos(2 * np.pi * fc * time[idx] + phase)

    

    # 模擬基頻訊號 (Baseband)

    baseband = np.zeros_like(time)

    for i, bit in enumerate(data_bits):

        t_start = i * T_bit

        t_end = (i + 1) * T_bit

        idx = (time >= t_start) & (time < t_end)

        baseband[idx] = 1.0 if bit == '1' else 0.0


    return time, baseband, carrier, ask_signal, fsk_signal, psk_signal, T_total


# --- Tkinter 應用程式類 ---


class ModulationApp:

    def __init__(self, master):

        self.master = master

        master.title("數位調變波形產生器")


        # 設定 Tkinter 介面

        main_frame = ttk.Frame(master, padding="10")

        main_frame.pack(fill='both', expand=True)


        input_frame = ttk.LabelFrame(main_frame, text="輸入 (10-bit 二進制)", padding="10")

        input_frame.pack(fill='x', pady=5)


        ttk.Label(input_frame, text="請輸入 10 個二進制位元 (例如: 1010101010):").pack(side='left', padx=10)

        

        self.bit_input = ttk.Entry(input_frame, width=15)

        self.bit_input.pack(side='left', padx=10)

        self.bit_input.insert(0, "1010111001") # 預設值


        ttk.Button(input_frame, text="產生波形", command=self.plot_signals).pack(side='left')


        # Matplotlib 繪圖區域

        self.fig, self.axs = plt.subplots(5, 1, sharex=True, figsize=(10, 8))

        self.fig.tight_layout(pad=3.0) # 調整佈局

        

        self.canvas = FigureCanvasTkAgg(self.fig, master=main_frame)

        self.canvas_widget = self.canvas.get_tk_widget()

        self.canvas_widget.pack(fill='both', expand=True, pady=10)

        

        # 初始繪圖

        self.plot_signals(initial=True)


    def plot_signals(self, initial=False):

        """

        根據輸入繪製 ASK, FSK, PSK 波形。

        """

        data_str = self.bit_input.get().strip()

        

        if initial:

            # 初始時使用預設值

            data_str = "1010111001"

            

        if len(data_str) != 10 or not all(c in '01' for c in data_str):

            messagebox.showerror("輸入錯誤", "請輸入剛好 10 個二進制位元 (0 或 1)。")

            return


        data_bits = list(data_str)


        # 1. 生成數據

        time, baseband, carrier, ask_signal, fsk_signal, psk_signal, T_total = \

            generate_modulation_signals(data_bits)


        # 2. 清除舊圖表

        for ax in self.axs:

            ax.clear()


        # 3. 繪製

        titles = ["(a) BASEBAND", "(b) CARRIER", "(c) ASK", "(d) FSK", "(e) PSK"]

        signals = [baseband, carrier, ask_signal, fsk_signal, psk_signal]

        

        for i, ax in enumerate(self.axs):

            ax.plot(time, signals[i])

            ax.set_title(titles[i], loc='left', fontsize=12)

            ax.set_yticks([]) # 隱藏 Y 軸標籤

            ax.set_xlim(0, T_total)

            ax.grid(True, linestyle='--', alpha=0.6)

            

            # 特別處理基頻訊號,使其看起來更像方波

            if i == 0:

                 ax.step(time, signals[i], where='post')

                 ax.set_ylim(-0.2, 1.2) # 調整 y 軸範圍以顯示 0 和 1

                 # 標記 1 和 0

                 for bit_idx, bit in enumerate(data_bits):

                     ax.text(bit_idx + 0.5, 0.5, bit, fontsize=18, ha='center', va='center', color='red')


        # 設置底部 X 軸標籤

        self.axs[-1].set_xlabel("Time (sec)")


        # 4. 更新 Canvas

        self.canvas.draw()


# --- 執行主程式 ---

if __name__ == "__main__":

    root = tk.Tk()

    app = ModulationApp(root)

    root.mainloop()

沒有留言:

張貼留言

ESP32 (ESP-IDF in VS Code) MFRC522 + MQTT + PYTHON TKinter +SQLite

 ESP32 (ESP-IDF in VS Code) MFRC522 + MQTT + PYTHON TKinter +SQLite  ESP32 VS Code 程式 ; PlatformIO Project Configuration File ; ;   Build op...