ข้ามไปยังเนื้อหา
Tayakorn

คู่มือ Mesh Networking — สื่อสารในที่ที่ไม่มีเสาสัญญาณ

LEVEL 4 · ระดับเทพ

ทดสอบโดยไม่มีวิทยุสักตัว

ถ้าอ่านมาถึงตรงนี้แล้วอยากลองทำจริง อุปสรรคแรกคือคุณไม่มีวิทยุสิบตัวและไม่มีภูเขาให้เดินขึ้น บทนี้บอกว่าไม่จำเป็นต้องมี

14.1 ทำไมการจำลองถึงคุ้มกว่าที่คิด

ปัญหาสำคัญเกือบทั้งหมดในเล่มนี้ — flapping, count-to-infinity, ความจุที่หายไปกับตัวเอง, เส้นทางย้ายเมื่อโหนดขยับ — เป็นปัญหาเชิงตรรกะ ไม่ใช่ปัญหาเชิงคลื่น ⇒ ทดสอบได้บนโน้ตบุ๊กตัวเดียว

สิ่งที่จำลองไม่ได้คือคลื่นจริงในภูมิประเทศจริง แต่นั่นเป็นงานของขั้นถัดไป ไม่ใช่ข้ออ้างที่จะไม่ทดสอบตรรกะก่อน

14.2 ตัวจำลองทั้งตัว

import math, heapq

RANGE_M = 300.0          # ระยะที่ยังคุยกันพอได้

class Node:
    def __init__(self, name, x, y, vx, vy):
        self.name, self.x, self.y, self.vx, self.vy = name, x, y, vx, vy
    def step(self, dt):
        self.x += self.vx*dt; self.y += self.vy*dt

def etx_between(a, b):
    """ระยะ -> ETX · เกินระยะ = ไม่มีลิงก์"""
    d = math.hypot(a.x-b.x, a.y-b.y)
    if d > RANGE_M: return None
    ratio = max(0.05, 1.0 - (d/RANGE_M)**2)      # ใกล้ = ส่งถึงเกือบทุกใบ
    return round(1.0/(ratio*ratio), 2)

def route(nodes, src, dst):
    idx = {n.name: n for n in nodes}
    dist = {src: 0.0}; prev = {}; pq = [(0.0, src)]
    while pq:
        d, u = heapq.heappop(pq)
        if u == dst: break
        if d > dist.get(u, float("inf")): continue
        for n in nodes:
            if n.name == u: continue
            w = etx_between(idx[u], n)
            if w is None: continue
            nd = d + w
            if nd < dist.get(n.name, float("inf")):
                dist[n.name] = nd; prev[n.name] = u; heapq.heappush(pq, (nd, n.name))
    if dst not in dist: return None, None
    p = [dst]
    while p[-1] in prev: p.append(prev[p[-1]])
    return list(reversed(p)), dist[dst]

nodes = [Node("A",   0,    0, 0, 0),      # ฐาน อยู่กับที่
         Node("B", 250,    0, 0, 8),      # เดินขึ้นเหนือ 8 เมตรต่อวินาที
         Node("E", 240, -120, 0, 0),      # อยู่กับที่ เป็นทางสำรอง
         Node("C", 470,  -60, 0, 0),
         Node("D", 690,  -80, 0, 0)]

for t in range(0, 61, 10):
    p, cost = route(nodes, "A", "D")
    shown = " -> ".join(p) if p else "ส่งไม่ถึง"
    print(f"{t:>3} วิ  {shown:<22} ETX {round(cost,2) if cost else '-'}")
    for n in nodes: n.step(10)

ผลรันจริง

  0 วิ  A -> B -> C -> D       ETX 21.09
 10 วิ  A -> B -> E -> C -> D  ETX 33.43
 20 วิ  A -> E -> C -> D       ETX 36.99
 30 วิ  A -> E -> C -> D       ETX 36.99
 40 วิ  A -> E -> C -> D       ETX 36.99
 50 วิ  A -> E -> C -> D       ETX 36.99
 60 วิ  A -> E -> C -> D       ETX 36.99

อ่านผลทีละบรรทัด: วินาทีที่ 0 เส้นทางวิ่งผ่าน B ตรง ๆ · วินาทีที่ 10 B เดินห่างจนลิงก์แย่ลง เส้นทางยาวขึ้นเป็น 4 hop เพื่อเลี่ยงลิงก์ที่กำลังเสื่อม · วินาทีที่ 20 B หลุดออกนอกระยะ เครือข่ายย้ายไปใช้ E เป็นการถาวรและนิ่งตั้งแต่นั้น

เครือข่ายซ่อมเส้นทางตัวเองโดยไม่มีใครสั่ง — และคุณเพิ่งเห็นมันเกิดขึ้นบนหน้าจอตัวเองโดยไม่ต้องมีวิทยุสักตัว

14.3 ต่อยอดจากตรงนี้ยังไง

ตัวจำลองข้างบนคือโครงที่เติมได้ทีละชั้น และแต่ละชั้นคือบทหนึ่งในเล่มนี้:

  • เพิ่มการหลุดหายของแพ็กเก็ตแบบสุ่มตามค่า ETX แล้ววัดว่าส่งถึงจริงกี่เปอร์เซ็นต์ (บทที่ 4)
  • เพิ่ม hello กับเส้นตาย แล้วดูว่ากว่าจะรู้ว่า B หายใช้เวลากี่วินาที (บทที่ 5)
  • เพิ่ม hysteresis แล้วนับจำนวนครั้งที่เส้นทางเปลี่ยนตลอดการทดลอง (บทที่ 9)
  • เพิ่มช่องคลื่นแล้ววัดความจุตามสูตรบทที่ 11 — และลองปรับ REUSE_GAP ดูว่าเพดานขยับตามไหม (บทที่ 10–11)

เคล็ดลับ: เพิ่มทีละชั้นและวัดผลทุกครั้ง ถ้าเพิ่มสองชั้นพร้อมกันแล้วผลเปลี่ยน คุณจะไม่รู้ว่าชั้นไหนทำ

อ่านแบบเต็มเล่ม