Behavior Analysis
เมื่อเรืออยู่ไกลสุดขอบฟ้า แต่ก็อยากจะบอกว่า แอบส่องเธออยู่นะจ๊ะ

สวัสดีเพื่อนๆ ชาวเรา และเหล่าผู้ดูแลระบบ (ทั้งระบบคอมและระบบนิเวศ) ก่อนเข้าเรื่องตามหัวข้อ เกริ่นก่อนกว่าการวิเคราะห์พฤติกรรมตามหัวข้อของเรานั้นมันมีหลากหลายรูปแบบมากกกก (ก.ไก่ ล้านตัว) แต่วันนี้ผมจะพาทุกคนดำดิ่งลงไปใต้ท้องทะเลลึก แต่เราไม่ได้จะไปดูปะการังกันนะฮะ เราจะไปดูสิ่งที่เชื่อมโยงพวกเราเข้าด้วยกันจริงๆ นั่นคือ สายเคเบิ้ลใต้น้ำ (Undersea Cables)
เคยสงสัยไหมว่า เวลาเราเล่นเกมเซิร์ฟเวอร์นอกแล้วปิงพุ่ง หรือดู _hub แล้วหมุนติ้วๆ บางทีมันไม่ใช่เพราะเน็ตบ้านเรากาก แต่มันอาจจะมี "พี่เบิ้ม" ลำไหนสักลำกำลังทำตัวล่อลับๆ เอ้ย ลับๆ ล่อๆ อยู่เหนือสายไฟเบอร์ยักษ์ใต้ทะเลที่พาดมาหาเราก็ได้ ซึ่งจะมาดูกันว่า Content Creator สาย Tech ที่ชอบหาเรื่องใส่ตัว (และหาเรื่องเขียนโค้ด) คนนี้ จะมาเล่าเรื่องการสร้างระบบ Behavioral Analysis เพื่อตรวจจับแขกไม่ได้รับเชิญ ที่เข้ามาป่วนสายเคเบิ้ลของเรากัน
เมื่อ "ทะเล" คือ Production Environment ที่ไม่มี Firewall
ถ้าเรามองว่า Internet คือ Network ขนาดใหญ่ สายเคเบิ้ลใต้น้ำก็คือ Physical Layer (Layer 1) ที่เปราะบางที่สุดครับ มันคือเส้นเลือดใหญ่ที่แบกรับ Data กว่า 95% ของโลกใบนี้ไว้ ถามว่าทำไมไม่ส่งผ่านดาวเทียมล่ะ งั้นก็ลองสักตั้งครับ ต่อเน็ตดาวเทียมเล่น ROV หรือ PUBG ดู แล้วจะหัวร้อน เพราะ Latency Time ก็คือระยะจากพื้นโลกที่เราๆ นั่งลงแรงค์กันอยู่กับอวกาศที่ดาวเทียมลอยอยู่มันไกลนะเออ และเมื่อถึงดาวเทียมแล้วก็ต้องกลับลงมาที่พื้นโลกในระยะทางพอๆ กัน มันก็เลยจะมีความช้าเชิงเวลาสูงกว่า Fiber Optic มหาศาล เพราะฉะนั้น สาย Fiber Optic ใต้ทะเลก็คือตัวแบก ณ ปัจจุบัน แต่ปัญหาก็คือ ทะเลมันกว้างมาก และเราไม่มีทางเอา Firewall ไปกั้นกลางมหาสมุทรได้
ภัยคุกคามที่น่ากลัวที่สุดไม่ใช่ฉลามกัดสาย (หรือมีวะ) แต่คือสมอเรือและอวนลากครับ โดยเฉพาะเรือที่จงใจเข้ามาทำกิจกรรมแปลกๆ ในเขตหวงห้าม การจะมานั่งเฝ้าหน้าจอตลอด 24 ชั่วโมง นั้นเป็นเรื่องที่เป็นไปไม่ได้สำหรับมนุษย์ เราจึงต้องทำ Automated Monitoring System เพื่อคัดกรองเรือนับหมื่นลำให้เหลือเฉพาะเคสที่น่าสงสัยจริงๆ

รู้จักกับ Dark Vessel และ Anomaly Detection (ฉบับโปรแกรมเมอร์)
ในโลกของเรือ เรามีสิ่งที่เรียกว่า AIS (Automatic Identification System) ตามที่เคยเขียนไปใน Maritime Sensors Integration (จิ้มที่นี่) ซึ่งมันก็เหมือนกับ Header ใน Packet ข้อมูลนั่นแหละครับ มันจะบอกว่า ฉันคือใคร อยู่ที่ไหน กำลังจะไปไหน แต่ในทางปฏิบัติ มันจะมีเรืออยู่ประเภทหนึ่งที่เราเรียกว่า Dark Vessel คือเรือที่จงใจ ปิด สัญญาณ AIS เพื่อหลบเลี่ยงการถูกตรวจจับ เหมือนการส่ง Request มาโดยไม่มี User-Agent หรือการมุด VPN มาทำเรื่องไม่ดีนั่นแหละ ส่วน Anomaly Detection คือการตรวจจับความผิดปกติ เช่น เรือทุกลำวิ่งเป็นเส้นตรงด้วยความเร็ว 20 knots แต่มีลำหนึ่งดันมาวนเวียน (Loitering) หรือหยุดนิ่งอยู่เหนือสายเคเบิ้ลด้วยความเร็ว 1 knot เป็นเวลาหลายชั่วโมง ฮั่นแน่...
ในการตรวจจับ Dark Vessel เรามักจะใช้ข้อมูลจากดาวเทียมแบบ SAR - Synthetic Aperture Radar หรือ EO - Electro Optical หรือ RADAR ตามบทความที่ผ่านมา (จิ้มที่นี่) มา Compare กับข้อมูล AIS ถ้าดาวเทียมหรือเรดาร์เห็นจุด แต่ในระบบ AIS ไม่มี Data ปรากฎออกมา แสดงว่าลำนั้นแหละ... สาย Dark
แล้วจะรู้ได้ไงกันน้า ว่าใครเข้ามาป้วนเปี้ยน
หัวใจสำคัญของการเขียนโปรแกรมเรื่องนี้คือ Spatial Analysis ครับโพ้ม อันดับแรกเราต้องเปลี่ยนพิกัดโลก Lat/Lon ให้กลายเป็น Vector และคำนวณระยะห่างระหว่างเรือกับสายเคเบิ้ล เสร็จแล้วเราก็ต้องออกแบบ Logic การตรวจจับเบื้องต้น โดยการใช้
- Geofencing สร้าง Buffer Zone รอบสายเคเบิ้ล (เช่น 500 เมตร)
- State Machine เรือทุกลำจะมี State เช่น TRANSIT, LOITERING, STOPPED, FISHING
- Heuristic Rules คือ ถ้าเรือเข้าโซน + ความเร็ว < 2 knots + มีการเปลี่ยนแปลง Heading บ่อยๆ = High Risk (อาจกำลังลากอวน ทิ้งสมอ หรือด้อมๆ มองๆ) ส่วนถ้าเรือหายไปจากระบบ (AIS Missing) ในโซนที่กำหนด ก็ให้เป็น Critical Alert อย่าง (ไม่) ต้องสงสัย
ข้อมูลล่ะ ข้อมูล ต้องมีอะไรบ้าง
ถ้าเราจะสร้างระบบนี้ เราก็จะต้องเตรียม Pipeline สำหรับรับ Data สำหรับการนำมาวิเคราะห์ ตามนี้ฮะ
- MMSI หรือเปรียบเสมือนเลขบัตรประชาชนของเรือ
- Latitude น่าจะรู้ว่าคืออัลไล
- Longitude อันนี้ด้วย
- SOG หรือ Speed Over Ground คือ ความเร็วเรือบนบนผิวโลก ใช้ตรวจสอบเรือวิ่งปกติหรือวิ่งชลอเพื่อทำอะไรน่ะ
- COG หรือ Course Over Ground คือ ทิศทางที่เรือแล่นไปบนผิวโลก ใช้คำนวณ Vector พฤติกรรม
- Vessel Type ประเภทเรือ จะได้ข้อมูลว่าเรือประมงมีความเสี่ยงสูงกว่าเรือบรรทุกน้ำมันขนาดใหญ่ เป็นต้น
เมื่อเห็นทุกสิ่งทุกอย่างเรียบร้อย ตะโกน... Coding Time!
แน่นอนว่าเราถนัด Python ก็ใช้ Go (เอ๊ะ -.-) ซึ่ง Python จะมี Library หลากหลายมากสำหรับการทำเรื่องเกี่ยวกับการทำ Data Analysis อย่าง Shapely และ GeoPandas ซึ่งในกรณีนี้ Implement เพื่อเช็คดูว่าเรือลำนี้เข้ามาเฉียดที่เส้นที่กำหนดหรือเปล่า
from shapely.geometry import Point, LineString
import math
TILE_SIZE:float = 256.0
ZOOM:float = 20.0
SCALE:float = 2**ZOOM
CIRCUMFERENCE:int = 40075016
# กำหนดพิกัดที่เป็นเส้นของสายเคเบิ้ล (สมมติว่าเป็นเส้นตรงง่ายๆ 2 จุด ไม่ต้องเยอะ)
CABLE_ROUTE:list[tuple] = [(100.0, 10.0), (101.0, 11.0)]
def longitudeToPixelX(longitude:float) -> float :
x:float = 0.5 + longitude/360.0
return x*SCALE*TILE_SIZE
def latitudeToPixelY(latitude:float) -> float :
sinY:float = math.sin(latitude*math.pi/180.0)
sinY = math.min(math.max(sinY, -0.9999), 0.9999)
y:float = 0.5 + math.log((1 + sinY)/(1 - sinY))/(-4*math.pi)
return y*SCALE*TILE_SIZE
# อ๊ะๆ อันนี้สำคัญโคตรๆ สำหรับการ Projection จาก WGS84 เป็น Mercator (เกาะไว้เลยฮะ รอบหน้า)
def projectRoute(route:list[tuple]) -> list[tuple] :
projected:list[tuple] = []
# ค่าสำหรับเปลี่ยนจาก Web Mercator เป็น Mercator (เมตร)
curcum:float = CIRCUMFERENCE/(TILE_SIZE*SCALE)
for position in route :
x:float = longitudeToPixelX(position[0])*curcum
y:float = latitudeToPixelY(position[1])*curcum
projected.append((x, y))
return projected
# แปลง WGS84 -> Mercator
PROJECTED_ROUTE = LineString(projectRoute(CABLE_ROUTE))
# สร้าง Buffer Zone 500 เมตร (หน่วยในที่นี้ต้องแปลงเป็น Degree หรือใช้ Projection ที่เหมาะสม)
DANGER_ZONE = PROJECTED_ROUTE.buffer(500)
# ฟังก์ชั่นหลักของเรา วิเคราะห์พฤติกรรมเรือเบื้องต้น
def analyzeBehavior(vesselId:str, currentPosition:tuple, speed:float, course:float) :
# ตรวจสอบว่าที่เรือปัจจุบันอยู่ในรัศมีของเคเบิ้ลมั้ย
isInside:bool = DANGER_ZONE.contains(Point(currentPosition))
# ตรวจสอบว่าทิศทางของเรือวิ่งเข้าหาเคเบิ้ลมั้ย
isCross:bool = True
# ตรวจสอบความเร็วต่ำมั้ย
isOperation:bool = speed < 2.0
if isInside and isCross and isOperation :
return f"ALERT: เรือรหัส MMSI {vesselId} กำลังยุ่งวุ่นวายกับสายเคเบิ้ลนะจ๊ะ"
elif isInside and isCross :
return f"INFO: เรือรหัส MMSI {vesselId} กำลังผ่านสายเคเบิ้ลเฉยๆ"
# elif ......
return f"OK: เรือรหัส MMSI {vesselId} ปกติ"
# ทดสอบระบบ
print(analyzeBehavior("123456", (100.5, 10.51), 1.5, 126.4))อันนี้ Code แบบง่ายๆ โคตรๆ ที่แทบจะช่วยอะไรไม่ได้สำหรับการใช้งานจริง แต่ทำให้แค่เห็นว่าจะต้องมี Parameter หรือ Library อะไรช่วยเบื้องต้นบ้าง ซึ่งในระบบจริง เราจะไม่ใช้แค่ Point ปัจจุบันด้วยฮะ แต่เราจะใช้ Historical Trajectory (เส้นทางย้อนหลัง) มาคำนวณหาค่าความโค้ง (Curvature) และความแปรปรวนของความเร็ว เพื่อดูว่าเขากำลังทิ้งสมอหรือเปล่า เพราะสมอเรือนี่แหละคือบอสตัวจริงที่ทำสายขาด หรือเป็นประเภทเรือประมงและกำลังทำประมงอยู่บริเวณนั้น หรือเป็นเรือสำรวจจากประเทศ... กำลังลดความเร็วขนานใกล้ๆ เคเบิ้ล (อันนี้โคตรโหด โคตรอันตราย) หรือจะเอาวิธีที่ปัจจุบันหน่อย ก็จับยัด Machine Learning แม่มเลย เพราะเราจะรู้พฤติกรรมอีกหลายๆ อย่างที่ Algorithm ธรรมดาๆ ออกแบบได้ยากด้วย
อีกอันนึงคืออันนี้เป็นแค่ข้อสังเกต เห็นมั้ยว่าปกติแล้วนักเดินเรือหรือคนที่อ่านค้าพิกัดจะอ่าน Lat/Lon แต่ทำไมในการจับไปคำนวณกลายเป็น Lon/Lat ก็เพราะเราต้องแปลงกลับไปเป็นพิกัด (x, y) ยังไงล่า พลาดกันมาเยอะแล้วพวกแกร แล้วก็ไหนจะเรื่อง Degree Decimal, Degree Minute Decimal, Degree Minute Second อีก
สุดท้ายละ การป้องกันดีกว่าการซ่อมแน่นอน
การวิเคราะห์พฤติกรรมเรือไม่ใช่แค่เรื่องของการจับผิด แต่มันคือการสร้าง Situational Awareness เพื่อให้หน่วยงานที่เกี่ยวข้อง สามารถส่งกำลังที่ออกไปตรวจการณ์ หรือส่งข้อความแจ้งเตือนผ่านวิทยุไปยังเรือลำนั้นได้ทันท่วงทีก่อนที่สายจะขาด ซึ่งในมุมของ Software Engineer แล้ว งานนี้คือความท้าทายเรื่อง Big Data และ Real-time Processing เพราะข้อมูล AIS ทั่วโลกมีปริมาณมหาศาล การเขียน Algorithm ที่แม่นยำและประหยัด Resource จึงเป็นหัวใจสำคัญสัสๆ
และหวังว่าบทความนี้จะช่วยให้มิตรรักแฟนบล็อค เห็นภาพว่ากฎหมายทางทะเล กับ Software Engineering มันมาบรรจบกันได้อย่างไรในโลกใต้สมุทรอันมืดมิด
Happy Coding, and Smooth Sailing นะคร้าบทุกโค้น สวัสดีโชคดี