2026年1月15日 星期四

RFID 負載調變

 RFID 負載調變

在 RFID(特別是 ISO/IEC 14443 標準)中,13.56 MHz 是載波(Carrier),而 212 kHz 的**副載波(Subcarrier)**則是用於從卡片(PICC)回傳資料到讀卡機(PCD)時的負載調變。

  • 載波 (f_c)13.56MHz

  • 副載波 (f_s)212kHz}f_c / 64)。

  • 調變方式:資料(Bit Stream)先調變在副載波上(通常是 BPSK 或 OOK),然後副載波再透過負載調變掛載到載波上。

Python Tkinter 模擬程式

為了能在螢幕上清楚看見波形,我們在繪圖時會按比例縮小頻率(否則13.56 MHz 的波紋太密會變成色塊),但保持運算邏輯正確。




import tkinter as tk

from tkinter import messagebox

import numpy as np

import matplotlib.pyplot as plt

from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg

import platform


# --- 中文與環境設定 ---

def setup_matplotlib_fonts():

    sys_plat = platform.system()

    if sys_plat == "Windows":

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

    elif sys_plat == "Darwin":

        plt.rcParams['font.sans-serif'] = ['Heiti TC']

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


setup_matplotlib_fonts()


class RFIDModulationApp:

    def __init__(self, root):

        self.root = root

        self.root.title("RFID 13.56MHz 副載波調變模擬器 (212kHz)")

        self.root.geometry("1100x850")

        

        self.create_widgets()


    def create_widgets(self):

        # 控制面板

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

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


        tk.Label(ctrl, text="資料位元 (例如 101):").pack(anchor=tk.W)

        self.ent_bits = tk.Entry(ctrl, width=15)

        self.ent_bits.insert(0, "101")

        self.ent_bits.pack(pady=5)


        tk.Label(ctrl, text="載波頻率 (fc) MHz:").pack(anchor=tk.W, pady=(10,0))

        self.ent_fc = tk.Entry(ctrl, width=15)

        self.ent_fc.insert(0, "13.56") # 僅作顯示參考

        self.ent_fc.pack(pady=5)


        tk.Label(ctrl, text="副載波頻率 (fs) kHz:").pack(anchor=tk.W, pady=(10,0))

        self.ent_fs = tk.Entry(ctrl, width=15)

        self.ent_fs.insert(0, "212")

        self.ent_fs.pack(pady=5)


        tk.Button(ctrl, text="生成調變波形", command=self.update_plot, 

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


        # 說明

        note = ("【RFID 物理層說明】\n"

                "1. 副載波 fs = fc / 64\n"

                "2. 卡片回傳資料時,會以\n"

                "   212kHz 切換負載阻抗。\n"

                "3. 下圖示範副載波如何\n"

                "   調變 13.56MHz 的振幅。")

        tk.Label(ctrl, text=note, justify=tk.LEFT, fg="#666").pack(side=tk.BOTTOM)


        # 繪圖區

        self.fig, self.axs = plt.subplots(3, 1, figsize=(8, 10))

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

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


    def update_plot(self):

        try:

            bits = [int(b) for b in self.ent_bits.get() if b in '01']

            if not bits: raise ValueError("請輸入有效位元")


            # 為方便視覺觀察,對頻率進行比例縮放 (13.56Mhz太高無法在畫面上繪圖)

            # 我們假設 fc = 1000Hz, fs = 1000/8 = 125Hz 進行演示

            fs_val = 212  # kHz

            bit_rate = 106 # kbps (RFID標準速率)

            

            t_bit = 1.0 # 每個位元的標準化時間

            fs_visual = 16 # 在一個位元內的副載波週數

            fc_visual = 128 # 在一個位元內的載波週數

            

            samples = 2000

            t = np.linspace(0, len(bits), len(bits) * samples)

            

            carrier_wave = np.sin(2 * np.pi * fc_visual * t)

            subcarrier_signal = np.zeros_like(t)

            modulated_wave = np.zeros_like(t)


            for i, bit in enumerate(bits):

                start = i * samples

                end = (i + 1) * samples

                

                # 1. 生成副載波 (在該位元區間內)

                # RFID 常見的副載波調變:如果 bit=1,副載波發送;bit=0,副載波暫停 (OOK範例)

                if bit == 1:

                    subcarrier_signal[start:end] = np.sign(np.sin(2 * np.pi * fs_visual * t[start:end]))

                else:

                    subcarrier_signal[start:end] = 0

                

                # 2. 負載調變效果 (副載波改變載波的振幅深淺)

                # 振幅變化量約為 10% (RFID 典型負載調變深度)

                modulation_depth = 0.3 # 為了視覺效果加強到 0.3

                amplitude = 1.0 + modulation_depth * subcarrier_signal[start:end]

                modulated_wave[start:end] = amplitude * carrier_wave[start:end]


            # 繪圖

            for ax in self.axs: ax.clear()


            # 子圖 1: 原始資料與副載波

            self.axs[0].plot(t, subcarrier_signal, color='blue', lw=1)

            self.axs[0].set_title(f"副載波信號 (212kHz 邏輯代表)")

            self.axs[0].set_ylabel("振幅")


            # 子圖 2: 載波

            self.axs[1].plot(t[:500], carrier_wave[:500], color='gray', alpha=0.5)

            self.axs[1].set_title("13.56MHz 載波 (局部放大)")


            # 子圖 3: 最終調變信號 (負載調變)

            self.axs[2].plot(t, modulated_wave, color='red', lw=0.8)

            self.axs[2].set_title("RFID 負載調變結果 (副載波掛載於載波振幅上)")

            self.axs[2].set_xlabel("位元時間")


            for ax in self.axs: ax.grid(True, alpha=0.3)

            

            self.fig.tight_layout()

            self.canvas.draw()


        except Exception as e:

            messagebox.showerror("錯誤", f"參數錯誤: {e}")


if __name__ == "__main__":

    root = tk.Tk()

    app = RFIDModulationApp(root)

    root.mainloop()


沒有留言:

張貼留言

CRC(循環冗餘檢查)

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