2026年1月15日 星期四

ASK (振幅鍵移) FSK (頻率鍵移)PSK (相位鍵移)

 ASK (振幅鍵移) FSK (頻率鍵移)PSK (相位鍵移)

一個結合 tkintermatplotlib 的數位調變(Digital Modulation)模擬程式。

為了實現這個功能,我們需要用到三個主要的庫:

  1. tkinter: 建立視窗介面。

  2. numpy: 進行訊號的數學運算。

  3. matplotlib: 將波形繪製成圖表並嵌入到視窗中。

1. 安裝必要套件

若尚未安裝,請執行:

Bash
pip install numpy matplotlib

2. 數位調變模擬程式碼

這個程式允許你輸入二進制序列(例如 10110),並自定義載波的震幅 (Amplitude)頻率 (Frequency)

3. 功能解析

  • ASK (振幅鍵移):

    當位元為 1 時,輸出載波波形;當位元為 0 時,輸出為 0。公式:s(t) = A  ▪️ bit▪️sin(2pi f1 t)。

  • FSK (頻率鍵移):

    當位元為 1 時使用頻率 f1,位元為 0 時切換到另一個頻率f2。這在無線電通訊中非常常見。

  • PSK (相位鍵移):

    頻率與震幅保持不變。當位元從 1 變為 0 時,波形的相位會旋轉 180°(反相),這在現代數位通訊(如 Wi-Fi、4G)中是更進階調變(如 QAM)的基礎。

操作提示:

  1. 您可以修改「數位序列」來觀察不同長度的訊號。

  2. FSK 第二頻率 設得比 f1 大很多,可以更明顯地看出頻率密度的變化。

  3. 載波頻率 建議設在 520 之間,視覺效果最好。




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


class ModulationApp:

    def __init__(self, root):

        self.root = root

        self.root.title("數位調變模擬器 (ASK, FSK, PSK)")

        self.root.geometry("1000x700")


        self.create_widgets()

        self.plot_initial()


    def create_widgets(self):

        # --- 左側參數控制區 ---

        control_frame = tk.LabelFrame(self.root, text="參數設定", padx=10, pady=10)

        control_frame.pack(side=tk.LEFT, fill=tk.Y, padx=10, pady=10)


        # 二進制序列

        tk.Label(control_frame, text="數位序列 (例如 1011):").pack(anchor=tk.W)

        self.entry_bits = tk.Entry(control_frame)

        self.entry_bits.insert(0, "10110")

        self.entry_bits.pack(fill=tk.X, pady=5)


        # 震幅

        tk.Label(control_frame, text="載波震幅 (A):").pack(anchor=tk.W)

        self.entry_amp = tk.Entry(control_frame)

        self.entry_amp.insert(0, "1")

        self.entry_amp.pack(fill=tk.X, pady=5)


        # 頻率

        tk.Label(control_frame, text="載波頻率 (f1, Hz):").pack(anchor=tk.W)

        self.entry_freq1 = tk.Entry(control_frame)

        self.entry_freq1.insert(0, "5")

        self.entry_freq1.pack(fill=tk.X, pady=5)


        # FSK 專用頻率

        tk.Label(control_frame, text="FSK 第二頻率 (f2, Hz):").pack(anchor=tk.W)

        self.entry_freq2 = tk.Entry(control_frame)

        self.entry_freq2.insert(0, "12")

        self.entry_freq2.pack(fill=tk.X, pady=5)


        # 更新按鈕

        tk.Button(control_frame, text="生成波形", command=self.update_plot, 

                  bg="#4CAF50", fg="white", font=('Arial', 10, 'bold')).pack(fill=tk.X, pady=20)


        # --- 右側繪圖區 ---

        self.plot_frame = tk.Frame(self.root, bg="white")

        self.plot_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True, padx=10, pady=10)


    def plot_initial(self):

        self.fig, (self.ax_bit, self.ax_ask, self.ax_fsk, self.ax_psk) = plt.subplots(4, 1, figsize=(8, 10), constrained_layout=True)

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

        self.canvas.get_tk_widget().pack(fill=tk.BOTH, expand=True)

        self.update_plot()


    def update_plot(self):

        try:

            # 獲取輸入

            bits_str = self.entry_bits.get().strip()

            bits = [int(b) for b in bits_str if b in '01']

            A = float(self.entry_amp.get())

            f1 = float(self.entry_freq1.get())

            f2 = float(self.entry_freq2.get())


            if not bits:

                raise ValueError("請輸入有效的 0 與 1 序列")


            # 時間軸設定

            t_bit = np.linspace(0, 1, 100) # 每一個位元的細分時間

            t_total = np.array([])

            bit_signal = np.array([])

            ask_signal = np.array([])

            fsk_signal = np.array([])

            psk_signal = np.array([])


            for i, bit in enumerate(bits):

                t = t_bit + i

                t_total = np.concatenate([t_total, t])

                

                # 原始數位訊號

                bit_signal = np.concatenate([bit_signal, np.full_like(t, bit)])

                

                # ASK: 1 有震幅, 0 無震幅

                ask_signal = np.concatenate([ask_signal, A * bit * np.sin(2 * np.pi * f1 * t)])

                

                # FSK: 1 使用 f1, 0 使用 f2

                freq = f1 if bit == 1 else f2

                fsk_signal = np.concatenate([fsk_signal, A * np.sin(2 * np.pi * freq * t)])

                

                # PSK: 1 使用 0 相位, 0 使用 180 度反相 (相位差 pi)

                phase = 0 if bit == 1 else np.pi

                psk_signal = np.concatenate([psk_signal, A * np.sin(2 * np.pi * f1 * t + phase)])


            # 清除舊圖並繪製新圖

            for ax in [self.ax_bit, self.ax_ask, self.ax_fsk, self.ax_psk]: ax.clear()


            self.ax_bit.step(t_total, bit_signal, where='post', color='black', lw=2)

            self.ax_bit.set_title(f"Original Bits: {bits_str}")

            self.ax_bit.set_ylim(-0.2, 1.2)


            self.ax_ask.plot(t_total, ask_signal, color='blue')

            self.ax_ask.set_title("ASK (Amplitude Shift Keying)")


            self.ax_fsk.plot(t_total, fsk_signal, color='red')

            self.ax_fsk.set_title("FSK (Frequency Shift Keying)")


            self.ax_psk.plot(t_total, psk_signal, color='green')

            self.ax_psk.set_title("PSK (Phase Shift Keying)")


            for ax in [self.ax_bit, self.ax_ask, self.ax_fsk, self.ax_psk]:

                ax.grid(True, alpha=0.3)


            self.canvas.draw()


        except Exception as e:

            messagebox.showerror("輸入錯誤", f"請確認數值格式是否正確!\n{e}")


if __name__ == "__main__":

    root = tk.Tk()

    app = ModulationApp(root)

    root.mainloop()


沒有留言:

張貼留言

CRC(循環冗餘檢查)

  CRC(循環冗餘檢查) 完整的 CRC(循環冗餘檢查)逐步演示器 。它支援自定義 生成多項式 與 資料位元流 ,並透過「下一步」按鈕展示二進制長除法(XOR 運算)的過程。 二進制長除法模擬 : CRC 的核心是模二除法(Modulo-2 Division),實務上就是不斷進...