RFID Slotted ALOHA
Slotted ALOHA 的核心在於引入「時間槽」(Time Slots)的概念。在 Slotted ALOHA 中,時間被劃分為等長的區段,標籤只能在每個時間槽的起始點發送資料。
這種機制減少了碰撞發生的時間窗(從 2T 降至 1T),理論上能將最大吞吐量從 18.4% 提升至 36.8%。
時間槽管理 (Slot Manager):
不同於 Pure ALOHA 每個標籤亂跳,Slotted 版使用一個
slot_clock_manager。這像是一個指揮家,確保所有標籤在同一個時間點(Slot 開始)決定是否發送。
手動模式邏輯變更:
點擊「下一時間槽」時,程式會計算該槽位內的發送狀況。
你會發現,標籤現在是「整齊劃一」地變色(發送或碰撞),這正是 Slotted ALOHA 的特性。
狀態回饋:
增加了
Slot Marker顯示目前槽位的狀態(空閒、成功或碰撞)。標籤顏色:白色(閒置)、黃色(傳輸中)、綠色(成功)、紅色(碰撞)。
import tkinter as tk
import random
import time
from threading import Thread, Event
class SlottedALOHASimulator:
def __init__(self, root):
self.root = root
self.root.title("RFID Slotted ALOHA 模擬器")
# 參數設置
self.num_tags = 5
self.is_running = False
self.manual_mode = tk.BooleanVar(value=False)
self.slot_event = Event() # 控制時間槽同步
self.success_count = 0
self.collision_count = 0
self.current_slot = 0
self.active_transmissions = []
self.setup_ui()
def setup_ui(self):
# 畫布
self.canvas = tk.Canvas(self.root, width=600, height=280, bg="#f0f0f0")
self.canvas.pack(pady=10)
# 繪製 Reader
self.reader = self.canvas.create_rectangle(250, 20, 350, 70, fill="#bbdefb", outline="#1976d2")
self.canvas.create_text(300, 45, text="RFID Reader", font=("Arial", 10, "bold"))
# 繪製時間槽指示器 (Slot Indicator)
self.slot_marker = self.canvas.create_text(300, 100, text="等待開始...", font=("Courier", 12, "bold"), fill="#555")
self.tags = []
for i in range(self.num_tags):
x = 100 + (i * 100)
tag = self.canvas.create_oval(x-20, 180, x+20, 220, fill="white", outline="grey")
self.canvas.create_text(x, 235, text=f"Tag {i+1}")
self.tags.append(tag)
# 控制區
ctrl_frame = tk.Frame(self.root)
ctrl_frame.pack(pady=10)
self.btn_start = tk.Button(ctrl_frame, text="開始模擬", command=self.start_simulation, width=10, bg="#c8e6c9")
self.btn_start.pack(side=tk.LEFT, padx=5)
self.btn_stop = tk.Button(ctrl_frame, text="停止", command=self.stop_simulation, state=tk.DISABLED, width=10)
self.btn_stop.pack(side=tk.LEFT, padx=5)
tk.Checkbutton(ctrl_frame, text="手動模式 (逐槽控制)", variable=self.manual_mode).pack(side=tk.LEFT, padx=10)
self.btn_next = tk.Button(ctrl_frame, text="下一時間槽 >>", command=self.next_slot, state=tk.DISABLED, bg="#e1f5fe")
self.btn_next.pack(side=tk.LEFT, padx=5)
# 數據面板
self.stat_label = tk.Label(self.root, text="Slot: 0 | 成功: 0 | 碰撞: 0", font=("Consolas", 11))
self.stat_label.pack(pady=5)
def slot_clock_manager(self):
"""時間槽管理器:負責同步所有標籤的發送時機"""
while self.is_running:
if self.manual_mode.get():
self.slot_event.wait() # 等待手動點擊
else:
time.sleep(1.5) # 自動模式下的槽位間隔
if not self.is_running: break
self.current_slot += 1
self.update_slot_ui(f"Slot {self.current_slot} 開始發送!")
# 觸發標籤嘗試發送 (邏輯與 Pure 不同:所有標籤在同一瞬間判斷)
self.active_transmissions = []
results = []
# 模擬標籤隨機決定本槽位是否發送 (假設發送機率 p=0.3)
for i in range(self.num_tags):
if random.random() < 0.3:
self.active_transmissions.append(i)
self.canvas.itemconfig(self.tags[i], fill="#fff176") # 黃色:準備
time.sleep(0.5) # 模擬傳輸中
# 碰撞檢測
if len(self.active_transmissions) == 0:
self.update_slot_ui(f"Slot {self.current_slot}: 空閒 (Idle)")
elif len(self.active_transmissions) == 1:
idx = self.active_transmissions[0]
self.success_count += 1
self.canvas.itemconfig(self.tags[idx], fill="#81c784") # 綠色:成功
self.update_slot_ui(f"Slot {self.current_slot}: 成功讀取 Tag {idx+1}")
else:
self.collision_count += 1
for idx in self.active_transmissions:
self.canvas.itemconfig(self.tags[idx], fill="#e57373") # 紅色:碰撞
self.update_slot_ui(f"Slot {self.current_slot}: 發生碰撞 ({len(self.active_transmissions)} 個標籤)")
self.update_stats()
time.sleep(0.8) # 讓使用者看清楚結果
# 重設標籤顏色準備進入下一個槽位
for i in range(self.num_tags):
self.canvas.itemconfig(self.tags[i], fill="white")
if self.manual_mode.get():
self.slot_event.clear()
def next_slot(self):
self.slot_event.set()
def update_slot_ui(self, msg):
self.root.after(0, lambda: self.canvas.itemconfig(self.slot_marker, text=msg))
def update_stats(self):
self.root.after(0, lambda: self.stat_label.config(
text=f"Slot: {self.current_slot} | 成功: {self.success_count} | 碰撞: {self.collision_count}"))
def start_simulation(self):
self.is_running = True
self.success_count = 0
self.collision_count = 0
self.current_slot = 0
self.update_stats()
self.btn_start.config(state=tk.DISABLED)
self.btn_stop.config(state=tk.NORMAL)
self.btn_next.config(state=tk.NORMAL)
# 啟動時脈執行緒
Thread(target=self.slot_clock_manager, daemon=True).start()
def stop_simulation(self):
self.is_running = False
self.slot_event.set()
self.btn_start.config(state=tk.NORMAL)
self.btn_stop.config(state=tk.DISABLED)
self.btn_next.config(state=tk.DISABLED)
self.update_slot_ui("模擬已停止")
if __name__ == "__main__":
root = tk.Tk()
app = SlottedALOHASimulator(root)
root.mainloop()
在 Slotted ALOHA 中,最關鍵的變數就是每個標籤在一個槽位中發送的機率 p。
如果 p 太高,會不斷發生碰撞 (Collision)。
如果 p 太低,通道會一直處於空閒 (Idle),浪費頻寬。
測試低負載:將 p 調到 0.05。你會發現大多數時間都是「空閒」,成功率很低。
測試高負載:將 p 調到 0.6 以上。你會發現畫面上經常是一片紅色,因為標籤都在搶著發送,導致碰撞嚴重。
尋找最佳值:理論上,當 $G = 1$(即平均每槽位有 1 個標籤發送)時效率最高。在 8 個標籤的情況下,將 $p$ 設定在 0.125 ($1/8$) 左右,您會觀察到最高的成功率。

沒有留言:
張貼留言