CDMA (碼分多址) 與 DSSS (直接序列擴頻) 的防碰撞方法
在 RFID 系統中,結合 CDMA (碼分多址) 與 DSSS (直接序列擴頻) 的防碰撞方法,是一種實體層(Physical Layer)的解決方案。與前面的「樹狀」或「時槽」演算法不同,它允許標籤在同一時間、同一頻率發送訊號。
CDMA / DSSS 防碰撞原理
正交碼 (Orthogonal Codes):每個標籤被分配一個唯一的「碼片序列」(Chipping Sequence),例如 Walsh Code。
擴頻 (Spreading):標籤將原始資料位元(0 或 1)與擴頻碼進行 XOR 運算。
疊加 (Superposition):多個標籤的擴頻訊號在空氣中疊加。
解擴 (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 演算法特點分析:
真正的併行處理:
不像 ALOHA 或 Tree-based 需要在時間或邏輯上排隊,CDMA 讓標籤「同時說話」,閱讀器透過「聽力(解碼)」來區分。
抗干擾能力:
由於使用了 DSSS,訊號被擴展到更寬的頻帶,對於窄頻噪聲有很強的魯棒性(Robustness)。
複雜度與代價:
容量限制:
可同時識別的標籤數量受限於 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()
沒有留言:
張貼留言