2025年11月5日 星期三

ASK調變方式

ASK調變方式

https://techweb.rohm.com.tw/product/wireless/wireless-communication/23710/ 

調變指傳輸資料時,變換成最佳功率訊號。

調變方式大致上可以分成類比調變、數位調變、脈波調變、頻譜擴散4種。
類比調變使用在AM和FM廣播、短波廣播上。
數位調變方式為傳送”1″ 和 “0”二進位訊號的方式。
可以細分成利用振幅和頻率、相位等單載波進行調變,以及將不同的訊號調變成多個載波後再傳送出去的多載波調變。
其他還有更動脈波寬度的脈波調變、訊號能量分散在寬頻的頻譜擴散方式。

調變方式的種類

說明調變方式

無線通訊中,是藉由將聲音和資料加載在一定頻率的電波上,傳送資料。
本文將說明典型的調變方式概要。

ASK (Amplitude Shift Keying)
利用變換有無類比訊號,來傳送資料的數位調變方式。
FSK (Frequency Shift Keying)
利用類比訊號振幅的不同,調變數位訊號的方式,對於二進位資料0和1,藉由切換低頻和高頻來進行調變。
【ASK和FSK】

ASK和FSK



import tkinter as tk

from tkinter import ttk

from matplotlib.figure import Figure

from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg

import numpy as np

import matplotlib.pyplot as plt 


# --- Matplotlib 中文設置 ---

try:

    plt.rcParams['font.sans-serif'] = ['Microsoft JhengHei', 'SimHei', 'sans-serif'] 

    plt.rcParams['axes.unicode_minus'] = False 

    CHINESE_FONT = 'Microsoft JhengHei'

except:

    CHINESE_FONT = 'sans-serif' 


# --- ASK 調變函數 ---


def generate_ask_waveform(fm_hz, fc_hz, modulation_percentage, duration_sec=0.01):

    """

    生成 ASK 調變波形數據。

    fm_hz: 基帶信號頻率 (例如 1 kHz)

    fc_hz: 載波信號頻率 (例如 2.45 GHz 或可視化頻率)

    modulation_percentage: 調變百分比 (0 到 100)

    duration_sec: 繪圖總時長

    """

    try:

        # 將百分比轉換為調變指數 m (0 到 1)

        m = modulation_percentage / 100.0

        

        # 為了清晰顯示,我們需要足夠的採樣點數。

        fs = max(20000, 100 * fc_hz) 

        

        # 限制採樣頻率以防止程式在極高頻率下消耗過多資源

        if fs > 1e6:

             fs = 1e6 

        

        t = np.linspace(0, duration_sec, int(fs * duration_sec), endpoint=False)

        

        # 1. 基帶信號 (數位信號 0 和 1)

        # 使用方波模擬,確保每個週期內有 0 和 1 的切換

        bit_duration = 1 / fm_hz

        digital_signal = np.where((t % bit_duration) < (bit_duration / 2), 1.0, 0.0)

        

        # 2. 載波信號

        carrier_signal = np.cos(2 * np.pi * fc_hz * t)

        

        # 3. ASK 調變

        # 振幅 A(t): 當 digital_signal=1 時,振幅為 1;當 digital_signal=0 時,振幅為 1-m

        amplitude_envelope = (1 - m) + m * digital_signal

        

        # 最終 ASK 信號

        ask_signal = amplitude_envelope * carrier_signal


        return t, digital_signal, carrier_signal, ask_signal, fs


    except Exception as e:

        print(f"調變計算錯誤: {e}")

        return None, None, None, None, None


# --- 繪圖函數 ---


def plot_waveform(t, digital_signal, carrier_signal, ask_signal, fs, ax_list):

    """繪製三個信號波形,並優化 Y 軸範圍。"""

    

    # 清除舊圖

    for ax in ax_list:

        ax.clear()


    # 1. 基帶信號 (數位信號)

    ax_list[0].plot(t * 1000, digital_signal, color='red', label='基帶數位信號')

    ax_list[0].set_title('基帶信號 ($f_m$)', fontproperties=CHINESE_FONT)

    ax_list[0].set_ylabel('振幅', fontproperties=CHINESE_FONT)

    # 優化 Y 軸範圍,讓 0 和 1 電平清晰顯示

    ax_list[0].set_ylim(-0.1, 1.1) 

    ax_list[0].grid(True, linestyle=':')

    ax_list[0].legend(loc='upper right')


    # 2. 載波信號 (用於視覺化,可能是模擬頻率)

    ax_list[1].plot(t * 1000, carrier_signal, color='blue', label='載波信號')

    ax_list[1].set_title(f'載波信號 ($f_c$ = {float(entry_fc_plot.get()):.2f} Hz)', fontproperties=CHINESE_FONT)

    ax_list[1].set_ylabel('振幅', fontproperties=CHINESE_FONT)

    # 設置 Y 軸範圍為標準的正負 1 振幅

    ax_list[1].set_ylim(-1.1, 1.1)

    ax_list[1].grid(True, linestyle=':')

    ax_list[1].legend(loc='upper right')


    # 3. ASK 調變信號

    ax_list[2].plot(t * 1000, ask_signal, color='purple', label='ASK 調變信號')

    ax_list[2].set_title(f'ASK 調變信號 (m={float(entry_m.get()):.1f}%)', fontproperties=CHINESE_FONT)

    ax_list[2].set_xlabel('時間 [ms]', fontproperties=CHINESE_FONT)

    ax_list[2].set_ylabel('振幅', fontproperties=CHINESE_FONT)

    # 設置 Y 軸範圍,略大於最大振幅

    max_amp = np.max(np.abs(ask_signal))

    ax_list[2].set_ylim(-max_amp * 1.1, max_amp * 1.1)

    ax_list[2].grid(True, linestyle=':')

    ax_list[2].legend(loc='upper right')


    # 調整佈局,確保子圖間無重疊,且利用整個 Figure 高度

    fig.tight_layout()

    # 重新繪製圖形

    canvas.draw()


# --- 主程式介面和執行 ---


def run_ask_modulation():

    """從輸入框獲取數值並執行計算與繪圖。"""

    try:

        fm_khz = float(entry_fm.get()) # 基帶信號頻率 (kHz)

        fc_input = float(entry_fc_input.get()) # 載波信號頻率 (MHz/GHz - 僅供輸入記錄)

        m = float(entry_m.get())       # 調變百分比 (%)

        

        # 單位轉換

        fm_hz = fm_khz * 1000  # 基帶信號 Hz

        

        # --- 載波頻率處理 (視覺化) ---

        # 如果輸入的載波頻率很高 (例如 >= 1000 MHz/GHz), 使用模擬載波頻率

        if fc_input >= 1000:

            # 使用基帶信號頻率的 50 倍作為視覺化載波,例如 1kHz -> 50kHz

            fc_plot_hz = 50 * fm_hz 

            

            # 更新視覺化頻率顯示,並發出警告

            entry_fc_plot.set(f"{fc_plot_hz:.2f}")

            result_text.set(

                f"⚠️ 警告: 輸入 $f_c$={fc_input} MHz/GHz 過高,\n"

                f"繪圖時使用模擬載波 $f_c$ = {fc_plot_hz/1000:.1f} kHz。"

            )

        else:

            # 假設輸入的是 kHz 或 MHz (如果數值不大)

            fc_plot_hz = fc_input * 1000 

            entry_fc_plot.set(f"{fc_plot_hz:.2f}")

            result_text.set("")


        if fm_hz <= 0 or fc_plot_hz <= 0 or m < 0 or m > 100:

            result_text.set("輸入值必須有效: 頻率 > 0, 調變百分比 0-100。")

            return


        # 計算波形數據

        t, digital_signal, carrier_signal, ask_signal, fs = generate_ask_waveform(fm_hz, fc_plot_hz, m)


        if t is not None:

            # 執行繪圖

            plot_waveform(t, digital_signal, carrier_signal, ask_signal, fs, [ax1, ax2, ax3])


    except ValueError:

        result_text.set("輸入值無效,請確保輸入數字。")

    except Exception as e:

        result_text.set(f"發生未預期錯誤: {e}")


# 設置 Tkinter 視窗

root = tk.Tk()

root.title("ASK 調變波形分析儀")


# 設置輸入框框架

input_frame = ttk.Frame(root, padding="10")

input_frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))


# --- 輸入控件 ---

# 信號頻率 fm (kHz)

ttk.Label(input_frame, text="信號 $f_m$ (kHz):").grid(row=0, column=0, sticky=tk.W, padx=5, pady=5)

entry_fm = ttk.Entry(input_frame, width=15)

entry_fm.grid(row=0, column=1, padx=5, pady=5)

entry_fm.insert(0, "1") # 預設值 1 kHz


# 載波頻率 fc (MHz/GHz - 僅供輸入記錄)

ttk.Label(input_frame, text="載波 $f_c$ (MHz/GHz):").grid(row=1, column=0, sticky=tk.W, padx=5, pady=5)

entry_fc_input = ttk.Entry(input_frame, width=15)

entry_fc_input.grid(row=1, column=1, padx=5, pady=5)

entry_fc_input.insert(0, "2450") # 預設值 2.45 GHz -> 2450 MHz/GHz


# 隱藏或用於顯示模擬頻率 (Hz)

entry_fc_plot = tk.StringVar(value="") 


# 調變百分比 m (%)

ttk.Label(input_frame, text="調變百分比 m (%):").grid(row=2, column=0, sticky=tk.W, padx=5, pady=5)

entry_m = ttk.Entry(input_frame, width=15)

entry_m.grid(row=2, column=1, padx=5, pady=5)

entry_m.insert(0, "80") # 預設值 80%


# 計算按鈕

ttk.Button(input_frame, text="執行 ASK 調變並繪圖", command=run_ask_modulation).grid(row=3, column=0, columnspan=2, pady=10)


# 結果/警告顯示

result_frame = ttk.Frame(root, padding="10")

result_frame.grid(row=0, column=1, sticky=(tk.W, tk.E, tk.N, tk.S))

result_text = tk.StringVar()

ttk.Label(result_frame, textvariable=result_text, justify=tk.LEFT, font=(CHINESE_FONT, 10), foreground='red').grid(row=0, column=0, sticky=tk.W) 


# 繪圖區設置 (Matplotlib)

# 增大 figure 尺寸以提供更多繪圖空間

fig = Figure(figsize=(10, 9), dpi=100) 

ax1 = fig.add_subplot(311) # 1. 基帶信號

ax2 = fig.add_subplot(312) # 2. 載波信號 (視覺化用)

ax3 = fig.add_subplot(313) # 3. ASK 調變信號


# 將 Matplotlib 圖形嵌入 Tkinter 介面

canvas = FigureCanvasTkAgg(fig, master=root)

canvas_widget = canvas.get_tk_widget()

canvas_widget.grid(row=1, column=0, columnspan=2, padx=10, pady=10)


# 執行一次初始計算和繪圖

run_ask_modulation()


# 啟動 Tkinter 主循環

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...