2026年1月19日 星期一

CDMA (碼分多址) 與 DSSS (直接序列擴頻) 的防碰撞方法

 CDMA (碼分多址) 與 DSSS (直接序列擴頻) 的防碰撞方法

在 RFID 系統中,結合 CDMA (碼分多址)DSSS (直接序列擴頻) 的防碰撞方法,是一種實體層(Physical Layer)的解決方案。與前面的「樹狀」或「時槽」演算法不同,它允許標籤在同一時間、同一頻率發送訊號。

CDMA / DSSS 防碰撞原理

  1. 正交碼 (Orthogonal Codes):每個標籤被分配一個唯一的「碼片序列」(Chipping Sequence),例如 Walsh Code

  2. 擴頻 (Spreading):標籤將原始資料位元(0 或 1)與擴頻碼進行 XOR 運算。

  3. 疊加 (Superposition):多個標籤的擴頻訊號在空氣中疊加。

  4. 解擴 (Despreading):閱讀器使用特定標籤的碼片與接收到的混合訊號進行「內積(Inner Product)」運算,利用正交性過濾掉其他標籤的干擾,提取出目標資料。



import tkinter as tk

from tkinter import messagebox

import numpy as np


class CDMASim:

    def __init__(self, root):

        self.root = root

        self.root.title("RFID CDMA/DSSS 防碰撞模擬器")

        self.root.geometry("700x750")


        # 定義 4-bit Walsh Codes (相互正交)

        self.codes = {

            "Tag_A": np.array([1, 1, 1, 1]),

            "Tag_B": np.array([1, -1, 1, -1]),

            "Tag_C": np.array([1, 1, -1, -1]),

            "Tag_D": np.array([1, -1, -1, 1])

        }

        

        self.setup_ui()


    def setup_ui(self):

        tk.Label(self.root, text="CDMA Direct Sequence Spread Spectrum", font=("Arial", 14, "bold")).pack(pady=10)


        # 輸入區

        input_frame = tk.Frame(self.root)

        input_frame.pack(pady=10)


        tk.Label(input_frame, text="標籤 A 資料 (0 or 1):").grid(row=0, column=0)

        self.val_a = tk.Entry(input_frame, width=5); self.val_a.insert(0, "1")

        self.val_a.grid(row=0, column=1, padx=5)


        tk.Label(input_frame, text="標籤 B 資料 (0 or 1):").grid(row=1, column=0)

        self.val_b = tk.Entry(input_frame, width=5); self.val_b.insert(0, "0")

        self.val_b.grid(row=1, column=1, padx=5)


        # 按鈕

        self.btn_run = tk.Button(self.root, text="執行編碼與疊加", bg="#c8e6c9", command=self.simulate_cdma)

        self.btn_run.pack(pady=10)


        # 日誌與結果

        self.log_box = tk.Text(self.root, width=85, height=25, font=("Consolas", 10))

        self.log_box.pack(pady=10, padx=10)


    def log(self, msg, color="black"):

        self.log_box.insert(tk.END, msg + "\n")

        self.log_box.see(tk.END)


    def simulate_cdma(self):

        self.log_box.delete("1.0", tk.END)

        

        try:

            # 1. 取得原始資料並轉換 (0 -> -1, 1 -> 1)

            d_a = 1 if self.val_a.get() == "1" else -1

            d_b = 1 if self.val_b.get() == "1" else -1

            

            self.log(f"--- 步驟 1: 原始資料轉換 ---")

            self.log(f"Tag A: {self.val_a.get()} -> {d_a}")

            self.log(f"Tag B: {self.val_b.get()} -> {d_b}")


            # 2. 擴頻 (Spreading)

            code_a = self.codes["Tag_A"]

            code_b = self.codes["Tag_B"]

            spread_a = d_a * code_a

            spread_b = d_b * code_b

            

            self.log(f"\n--- 步驟 2: 擴頻 (Data * Walsh Code) ---")

            self.log(f"Tag A Walsh: {code_a} -> Spread: {spread_a}")

            self.log(f"Tag B Walsh: {code_b} -> Spread: {spread_b}")


            # 3. 疊加 (Superposition - 碰撞發生)

            combined_signal = spread_a + spread_b

            self.log(f"\n--- 步驟 3: 訊號疊加 (空氣中的碰撞訊號) ---")

            self.log(f"Combined Signal (A+B): {combined_signal}", "red")


            # 4. 解擴 (Despreading - 閱讀器分離訊號)

            self.log(f"\n--- 步驟 4: 閱讀器解擴 (Inner Product) ---")

            

            # 提取 A

            decode_a = np.sum(combined_signal * code_a) / len(code_a)

            self.log(f"Decode A: (Sum({combined_signal} * {code_a})) / 4 = {decode_a}")

            result_a = "1" if decode_a > 0 else "0"

            

            # 提取 B

            decode_b = np.sum(combined_signal * code_b) / len(code_b)

            self.log(f"Decode B: (Sum({combined_signal} * {code_b})) / 4 = {decode_b}")

            result_b = "1" if decode_b > 0 else "0"


            self.log(f"\n--- 最終識別結果 ---")

            self.log(f"成功分離!標籤 A = {result_a}, 標籤 B = {result_b}", "blue")


        except Exception as e:

            messagebox.showerror("錯誤", "請輸入 0 或 1")


if __name__ == "__main__":

    root = tk.Tk()

    app = CDMASim(root)

    root.mainloop()


CDMA/DSSS 演算法特點分析:

  1. 真正的併行處理: 不像 ALOHA 或 Tree-based 需要在時間或邏輯上排隊,CDMA 讓標籤「同時說話」,閱讀器透過「聽力(解碼)」來區分。

  2. 抗干擾能力: 由於使用了 DSSS,訊號被擴展到更寬的頻帶,對於窄頻噪聲有很強的魯棒性(Robustness)。

  3. 複雜度與代價

    • 標籤端:需要額外的電路來處理擴頻碼(Walsh Generator),成本比純 QT 標籤高。

    • 閱讀器端:需要強大的運算能力來執行同步(Synchronization)與多用戶檢測(Multi-user Detection)。

  4. 容量限制: 可同時識別的標籤數量受限於 Walsh 碼的長度。如果是 4-bit 碼,理論上最多只能同時識別 4 個標籤。


模擬器會展示資料如何從原始位元轉變為擴頻訊號,然後在空氣中疊加(碰撞),最後被閱讀器還原


import tkinter as tk
from tkinter import messagebox
import numpy as np
import random

class CDMAStepSim:
    def __init__(self, root):
        self.root = root
        self.root.title("RFID CDMA/DSSS 防碰撞逐步模擬")
        self.root.geometry("700x750")

        # 定義 4-bit 正交 Walsh Codes
        self.walsh_codes = {
            "Tag_A": np.array([1, 1, 1, 1]),
            "Tag_B": np.array([1, -1, 1, -1])
        }
        
        self.reset_data()
        self.setup_ui()

    def reset_data(self):
        # 隨機產生 0 或 1 作為標籤資料
        self.data_a = random.randint(0, 1)
        self.data_b = random.randint(0, 1)
        self.current_step = 0
        self.steps = [
            self.step_show_raw,
            self.step_spreading,
            self.step_superposition,
            self.step_despreading,
            self.step_final
        ]

    def setup_ui(self):
        # 標題與標籤資訊
        tk.Label(self.root, text="CDMA/DSSS 逐步演示", font=("Arial", 16, "bold")).pack(pady=10)
        
        self.info_frame = tk.Frame(self.root, relief=tk.GROOVE, bd=2)
        self.info_frame.pack(pady=10, padx=20, fill=tk.X)
        
        self.info_text = tk.Label(self.info_frame, text="點擊 [下一步] 開始模擬", font=("Consolas", 11), justify=tk.LEFT)
        self.info_text.pack(pady=10)

        # 訊號視覺化區
        self.canvas = tk.Canvas(self.root, width=600, height=150, bg="black")
        self.canvas.pack(pady=10)

        # 執行日誌
        self.log_box = tk.Listbox(self.root, width=80, height=15, font=("Consolas", 10), bg="#f4f4f4")
        self.log_box.pack(pady=10)

        # 控制鈕
        btn_frame = tk.Frame(self.root)
        btn_frame.pack(pady=10)

        self.btn_next = tk.Button(btn_frame, text="下一步 (Next)", width=15, bg="#e3f2fd", command=self.next_step)
        self.btn_next.pack(side=tk.LEFT, padx=10)

        tk.Button(btn_frame, text="重新開始 (Reset)", width=15, command=self.restart).pack(side=tk.LEFT, padx=10)

    def log(self, msg, color="black"):
        self.log_box.insert(tk.END, msg)
        self.log_box.itemconfig(tk.END, fg=color)
        self.log_box.see(tk.END)

    def restart(self):
        self.reset_data()
        self.log_box.delete(0, tk.END)
        self.info_text.config(text=f"重新生成資料:Tag A = {self.data_a}, Tag B = {self.data_b}")
        self.canvas.delete("all")
        self.btn_next.config(state=tk.NORMAL)
        self.log("--- 模擬已重置 ---")

    def next_step(self):
        if self.current_step < len(self.steps):
            self.steps[self.current_step]()
            self.current_step += 1
        else:
            self.btn_next.config(state=tk.DISABLED)
            messagebox.showinfo("完成", "CDMA 辨識流程演示完畢")

    # --- 各個步驟的邏輯 ---

    def step_show_raw(self):
        self.log(f"[步驟 1] 原始資料轉換 (0 -> -1, 1 -> 1)")
        self.val_a = 1 if self.data_a == 1 else -1
        self.val_b = 1 if self.data_b == 1 else -1
        self.log(f"  Tag A: {self.data_a} -> {self.val_a} | Tag B: {self.data_b} -> {self.val_b}")

    def step_spreading(self):
        self.log(f"[步驟 2] 擴頻 (Spreading)")
        self.spread_a = self.val_a * self.walsh_codes["Tag_A"]
        self.spread_b = self.val_b * self.walsh_codes["Tag_B"]
        self.log(f"  Tag A 擴頻後: {self.spread_a}")
        self.log(f"  Tag B 擴頻後: {self.spread_b}")
        self.draw_signal(self.spread_a, "cyan", 30, "Tag A Signal")
        self.draw_signal(self.spread_b, "lime", 90, "Tag B Signal")

    def step_superposition(self):
        self.log(f"[步驟 3] 訊號疊加 (Superposition / Collision)")
        self.combined = self.spread_a + self.spread_b
        self.log(f"  空氣中的混合訊號: {self.combined}", "red")
        self.canvas.delete("all")
        self.draw_signal(self.combined, "yellow", 60, "Combined Air Signal")

    def step_despreading(self):
        self.log(f"[步驟 4] 閱讀器解擴 (Despreading)")
        # 計算內積
        self.decode_val_a = np.sum(self.combined * self.walsh_codes["Tag_A"]) / 4
        self.decode_val_b = np.sum(self.combined * self.walsh_codes["Tag_B"]) / 4
        self.log(f"  A 解碼計算: Sum({self.combined} * {self.walsh_codes['Tag_A']}) / 4 = {self.decode_val_a}")
        self.log(f"  B 解碼計算: Sum({self.combined} * {self.walsh_codes['Tag_B']}) / 4 = {self.decode_val_b}")

    def step_final(self):
        res_a = 1 if self.decode_val_a > 0 else 0
        res_b = 1 if self.decode_val_b > 0 else 0
        self.log(f"[最終結果] 識別成功!", "blue")
        self.log(f"  辨識結果 -> Tag A: {res_a}, Tag B: {res_b}")
        self.info_text.config(text=f"識別完成!\n原始:A={self.data_a} B={self.data_b}\n解碼:A={res_a} B={res_b}")

    def draw_signal(self, data, color, y_offset, label):
        w = 500 / len(data)
        self.canvas.create_text(50, y_offset, text=label, fill="white", anchor=tk.W)
        for i, val in enumerate(data):
            h = val * 20
            self.canvas.create_rectangle(150 + i*w, y_offset - h, 150 + (i+1)*w, y_offset, fill=color, outline="white")

if __name__ == "__main__":
    root = tk.Tk()
    app = CDMAStepSim(root)
    root.mainloop()

沒有留言:

張貼留言

Dynamic Framed Slotted ALOHA (DFSA) 防撞方法

 Dynamic Framed Slotted ALOHA (DFSA)防撞方法 DFSA 的核心邏輯: 動態框長 (Dynamic Frame Size) :閱讀器會根據上一輪的結果(碰撞次數、空閒次數)來 動態調整 下一輪的時槽數(框長 $L$ )。 效率優化 :當標籤很多時...