Skip to content

Prajuab Riabroy's Blog

Survey Application – GNSS – UAV – Programing – Python – Dart&Flutter – Rust

Menu
  • Home
  • About Us
  • Survey Application
    • Surveyor Pocket Tools
    • Traverse Pro
    • XSection Plot
    • Geoid Height Pro
    • Spot Fire
    • โปรแกรมงานสำรวจสำหรับเครื่องคิดเลข Casio fx-5800P
    • โปรแกรมงานสำรวจสำหรับเครื่องคิดเลข Casio fx-9860G II SD
  • Download
  • Privacy Policy
Menu

ทดสอบคำนวณหาความสูงจีออยด์ TGM2017 ด้วยไลบรารี Proj.4

Posted on 30/01/2019

ไม่นานมานี้มีผมดาวน์โหลดไฟล์โปรแกรมและข้อมูลของ TGM2017 เรียกเต็มๆคือ Thailand Geoid Model 2017 ที่เป็นโครงการร่วมมือจากหลายๆฝ่ายของทางราชการ ผมยังไม่มีโอกาสได้นำไปใช้งาน โดยเฉพาะจะนำมาประยุกต์ใช้ในงานรังวัด GNSS ถือว่าเป็นสิ่งที่พวกเรารอคอยมานานที่จะได้มี local geoid model มาใช้งานกัน

โดยเฉพาะงานรังวัด GNSS เมื่อคำนวณแล้วจะได้ค่าพิกัดทางราบ และทางดิ่งจะได้ความสูง (h – Ellipsoid height) ที่เทียบกับทรงรี WGS84 ถ้าเรามีแบบจำลองความสูงจีออยด์สามารถคำนวณหาความสูง (H – Orthometric height) หรือระดับน้ำทะเลปานกลางได้ จากสูตร h = H + N โดยที่ไม่ต้องมีการเดินระดับไปหาจุดที่รังวัด GNSS แต่อย่างใด โดยที่โปรแกรมคำนวณหาค่าความสูงจีออยด์ (N – Geoid Height หรือ Geoid Separation) ที่ผมจะมาลองเขียนโปรแกรมเล็กๆเพื่อหาค่า N นี้ด้วยภาษาไพทอนในลำดับต่อไป

ในตอนนี้ผมจะใช้ไลบรารี Proj.4 เรียกไลบรารีในเวอร์ชั่นภาษาไพทอนนี้ว่า PyProj ตัวไลบรารี Proj.4 เองก็เพิ่งสนับสนุนการคำนวณ Vertical Datum ไปไม่นานนี้เอง สมมติว่าถ้าไม่ได้ใช้ไลบรารีตัวนี้เป็นตัวช่วยคงเป็นงานหนักหนาสาหัสเหมือนกัน

แปลงรูปแบบไฟล์ของแบบจำลองความสูงจีออยด์ TGM2017

ไฟล์แบบจำลองความสูงจีออยด์ TGM2017 ที่ผมดาวน์โหลดได้มานั้นเป็นแอสกี้ (Text file) ขนาดประมาณ 10.7 MB และมีโปรแกรมคำนวณมาด้วยชื่อไฟล์ execute คือ “TGM2017.EXE” สำหรับไฟล์แอสกี้ในคู่มือแสดงรายละเอียดดังนี้

  • ค่าละติจูด (Latitude) เริ่มต้น : 3 องศา
  • ค่าลองจิจูด (Longitude) เริ่มต้น : 95 องศา
  • ความละเอียดเชิงพื้นที่ : 1 ลิปดา
  • จานวนหลัก (Column) : 780 หลัก
  • จานวนแถว (Row) : 1200 แถว
TGM2017 layout

สำหรับไลบรารี PyProj นั้นถ้าต้องการคำนวณ Vertical Datum ต้องการไฟล์ในรูปแบบ gtx ที่กำหนดมาตรฐานโดย NOAA เพื่อให้การใช้งานมีประสิทธิภาพมาก ทางนี้แนะนำให้ใช้ไฟล์ไบนารีเพื่อประหยัดเมมโมรี สำหรับรูปแบบไฟล์ gtx นั้นไม่มีอะไรมาก กำหนดให้มีไฟล์ header เพื่อบอกจุดเริ่มต้นขอบเขตการใช้งาน ระยะห่างของละติจูดและลองจิจูดของแต่ละจุดในแนวตั้งและแนวนอน จำนวนแถวและจำนวนคอลัมน์ ที่เหลือจะเป็นความสูงจีออยด์ในแต่ละจุดมีขนาดเท่ากับ จำนวณแถวคูณจำนวนคอลัมน์ ตัวหัวไฟล์ผมสามารถเขียนได้ดังนี้

3.0 95.0 0.01666666666 0.01666666666 1200 780

อธิบาย : ละติจูดของมุมล่างซ้าย ลองจิจูดของมุมล่างซ้าย ระยะห่างของจุดในแนวละติจูด ระยะห่างของจุดในแนวลองจิจูด จำนวนแถว จำนวนคอลัมน์

ผมตรวจสอบไฟล์แอสกี้แล้วพบว่า ความสูงจีออยด์ถูกปูเรียงมาแล้วตามข้อกำหนดของ NOAA ดังนั้นผมจะอ่านไฟล์แอสกี้นี้แล้วแปลงเป็นไบนารี เพียงแต่เพิ่มส่วนหัวเข้าไป

ตัวอย่างโปรแกรมไพทอนสำหรับแปลงไฟล์แบบจำลองความสูงจีออยด์

ผมเขียนสคริปต์ภาษาไพทอน เผื่อมีใครสนใจ ผมตึ้งชื่อไฟล์ว่า “rtsd2gtx.py” โปรแกรมมีขนาดเล็กมากๆ ไม่กี่บรรทัด หลักการคืออ่านไฟล์แอสกี้ “tgm2017.asc” มาแล้วเขียนไฟล์ไบนารีในรูปแบบ gtx ข้อควรระวังคือไฟล์ไบนารี ต้องเป็นแบบ Big Endian ในโมดูล struct ผมจึงใส่เครื่องหมาย “>” ไปด้วย

ตัวอย่างเขียนขนิดข้อมูลเป็น double ใช้คำสั่ง f.write(struct.pack(“>d”, 3.0))
เขียนข้อมูลเป็น integer ใช้คำสั่ง f.write(struct.pack(“>i”, 1200))

<import struct
def readRTSDAsciiFile():
    geoid = []
    with open('tgm2017.asc', 'r') as f:
        geoid = [[float(n) for n in line.split()] for line in f] #2D list, one list contain one row.
    #TGM2017 was organized already from lowest row (min latitude) to highest row (max latitude).
    #No need to reverse.	
    return geoid

def writeGTXBinaryFile(geoid):
    with open('tgm2017.gtx', 'wb') as f:
        # pack with ">" for big endian.
		# write Header of file
        f.write(struct.pack(">d", 3.0))  #lower left Latitude
        f.write(struct.pack(">d", 95.0)) #lower left Longtitude		
        f.write(struct.pack(">d", 1.0/60.0)) #delta Latitude = 1 second
        f.write(struct.pack(">d", 1.0/60.0)) #delta Longitude = 1 second	
        f.write(struct.pack(">i", 1200)) #number of rows
        f.write(struct.pack(">i", 780))	#number of columns
		# write height values.
        for row in geoid:
            for c in row:
                f.write(struct.pack(">f", c))

# main program	
g = readRTSDAsciiFile()
writeGTXBinaryFile(g)

ณ ตอนนี้ผมสร้างโฟลเดอร์ เอาไฟล์ tgm2017.asc มาวางไว้ และมีโปรแกรมสคริปต์ “rtsd2gtx.py” อยู่ในโฟลเดอร์เดียวกัน

โฟลเดอร์ที่เก็บไฟล์

จากนั้นทำการรันโปรแกรมด้วยคำสั่งที่คอมมานด์ไลน์ python rtsd2gtx.py รอแป๊ปหนึ่งไฟล์ gtx ที่เก็บแบบจำลองความสูงจีออยด์จะถูกสร้าง และมีขนาดเล็กลงจากไฟล์แอสกี้ดั้งเดิมประมาณ 3 เท่า

ไฟล์ tgm2017.gtx ขนาดประมาณ 3.57 MB

ตัวอย่างโปรแกรมไพทอนสำหรับคำนวณหาความสูงจีออยด์

ต่อไปโปรแกรมไพทอนที่จะนำมาทดสอบคำนวณหาความสูงจีออยด์ ผมตั้งชื่อง่ายๆว่า “test.py” ถ้าจะลองรันโปรแกรมนี้เพื่อทดสอบต้องติดตั้งไลบรารี pyproj ให้เรียบร้อยก่อน

โค้ดโปรแกรมเริ่มต้นจากสร้าง projection ต้นทาง (ตัวแปร wgs84 egm) โดยที่กำหนด +geoidgrids=tgm2017.gtx และสร้าง projection ปลายทาง (ตัวแปร wgs84) โดยที่เว้นไม่ใส่แบบจำลองความสูงจีออยด์

import pyproj # Import the pyproj module
# Define source coordinate system with TGM2017.
wgs84egm = pyproj.Proj("+init=EPSG:4326 +geoidgrids=tgm2017.gtx") 
# Define target coordinate system without geoid model.
wgs84 = pyproj.Proj("+init=EPSG:4326")

lat, lon = 18.3353398540, 99.371215293000
x, y, z = pyproj.transform(wgs84egm, wgs84, lon, lat, 0.0)
print("1) Latitude = %.8f, Longitude = %.8f, Geoid Height = %.5f" % (y, x, z))

lat, lon = 7.75906518100, 98.303594340000
x, y, z = pyproj.transform(wgs84egm, wgs84, lon, lat, 0.0)
print("2) Latitude = %.8f, Longitude = %.8f, Geoid Height = %.5f" % (y, x, z))

lat, lon = 9.18558870000, 99.843706600000
x, y, z = pyproj.transform(wgs84egm, wgs84, lon, lat, 0.0)
print("3) Latitude = %.8f, Longitude = %.8f, Geoid Height = %.5f" % (y, x, z))

lat, lon = 6.96243169, 99.77398865
x, y, z = pyproj.transform(wgs84egm, wgs84, lon, lat, 0.0)
print("4) Latitude = %.8f, Longitude = %.8f, Geoid Height = %.5f" % (y, x, z))

lat, lon = 7.20852844, 99.72353542
x, y, z = pyproj.transform(wgs84egm, wgs84, lon, lat, 0.0)
print("5) Latitude = %.8f, Longitude = %.8f, Geoid Height = %.5f" % (y, x, z))

lat, lon = 7.35631365, 100.12797020
x, y, z = pyproj.transform(wgs84egm, wgs84, lon, lat, 0.0)
print("6) Latitude = %.8f, Longitude = %.8f, Geoid Height = %.5f" % (y, x, z))

lat, lon = 7.23806984, 100.55255020
x, y, z = pyproj.transform(wgs84egm, wgs84, lon, lat, 0.0)
print("7) Latitude = %.8f, Longitude = %.8f, Geoid Height = %.5f" % (y, x, z))

lat, lon = 7.09316728, 100.56368280
x, y, z = pyproj.transform(wgs84egm, wgs84, lon, lat, 0.0)
print("8) Latitude = %.8f, Longitude = %.8f, Geoid Height = %.5f" % (y, x, z))

lat, lon = 6.99643503, 100.43034140
x, y, z = pyproj.transform(wgs84egm, wgs84, lon, lat, 0.0)
print("9) Latitude = %.8f, Longitude = %.8f, Geoid Height = %.5f" % (y, x, z))

lat, lon = 13.0+42.0/60+38.64/3600, 100+29.0/60+13.02/3600
x, y, z = pyproj.transform(wgs84egm, wgs84, lon, lat, 0.0)
print("10) Latitude = %.8f, Longitude = %.8f, Geoid Height = %.5f" % (y, x, z))

เมื่อจัดเก็บไฟล์เรียบร้อย ในตอนนี้ ถ้าดูที่โฟล์เดอร์จะเห็นไฟล์ดังนี้

จุดทดสอบ

ถ้าดูในโค้ดจะเห็นจุดทดสอบทั้งหมด 10 จุด โดยที่ 9 จุดแรกผมนำมาจากไฟล์ INPUT.DAT ที่ติดมากับโปรแกรม TGM2017.EXE ถ้าเปิดดูด้วย Notepad จะเห็นดังนี้

จุดทดสอบ

ส่วนจุดที่ 10 ได้มาจากสไลด์ ชื่อ BM11SP Latitude = 13° 42′ 38.64″ N Longitude = 100° 29′ 13.02″E

คำนวณ

จากนั้นทำการรันโปรแกรมบนคอมมานด์ไลน์ ใช้้คำสั่ง python test.py จะได้ผลลัพธ์ดังนี้

คำนวณหาความสูงจีออยด์

ผมนำผลลัพธ์มาเปรียบเทียบกับที่คำนวณด้วย TGM2017.EXE พบว่ามีความต่างกันเล็กน้อยที่หลักมิลลิเมตร สาเหตุน่าจะเกิดตอน interpolation โดยการนำจุดรอบๆจากแบบจำลองความสูงจีออยด์ ซึ่งโปรแกรมอาจจะเลือกใช้แบบ BiCubic หรือ BiLinear ผมไม่แน่ใจว่า Proj.4 ใช้แบบไหน ตอนนี้ยังไม่มีโอกาสไปดูโค้ดต้นฉบับ

เปรียบเทียบผลลัพธ์การคำนวณ

การพัฒนาโปรแกรมสำหรับการใช้งานในอนาคต

ผมวางแผนว่าจะนำแบบจำลองความสูงจีออยด์ TGM2017 ไปคำนวณในโปรแกรมรวมเครื่องมือฉบับกระเปาสำหรับช่างสำรวจ Surveyor Pocket Tools ได้แก่การคำนวณความสูงจีออยด์ การคำนวณหาสเกลแฟคเตอร์

สรุป

ขอขอบคุณดร.พุทธิพล ดำรงชัยและคณะผู้จัดทำโครงการนี้ทุกๆท่าน สำหรับการจัดทำแบบจำลองความสูงจีออยด์ความละเอียดสูงสำหรับประเทศไทย อันจะเป็นประโยชน์เอนกอนันต์ต่อการประยุกต์ใช้ในแวดวงงานด้านสำรวจและด้านอื่นๆอีกมากในปัจจุบันและอนาคตอันใกล้นี้ ผมเองยังมีความหวังลึกๆว่าน่าจะมีการพัฒนาปรับปรุงให้แบบจำลองนี้ให้มึความถูกต้องมากๆยิ่งขึ้นในอนาคต

Related

4 thoughts on “ทดสอบคำนวณหาความสูงจีออยด์ TGM2017 ด้วยไลบรารี Proj.4”

  1. Pathompong Senayai says:
    31/01/2019 at 19:56

    เยี่ยมครับ

    Reply
    1. priabroy says:
      31/01/2019 at 20:38

      ขอบคุณที่แนะนำ TGM2017 มาครับ

      Reply
  2. ประสงค์ says:
    09/05/2019 at 09:53

    ช่างสามารถทำ TGM2017 ให้อยู่ในรูปแบบนามสกุล .ggf เพื่อใช้กับโปรแกรม TBC ได้ไหมครับ

    Reply
    1. priabroy says:
      09/05/2019 at 12:00

      ขอบคุณครับที่ทักทายกันมา ผมลองแปลงรูปแบบเป็น GGF ไปลองใช้ใน Trimble Business Center สามารถใช้งานได้ ไปอ่านได้ในบล็อกตามลิ๊งค์นี้ ไฟล์ไปดาวน์โหลดได้ตามลี๊งค์นี้

      Reply

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

November 2026
M T W T F S S
 1
2345678
9101112131415
16171819202122
23242526272829
30  
« Oct    

Blog Stats

There was an issue retrieving stats. Please try again later.

Recent Posts

  • เร็วแรงทะลุนรกกับ POCUT (POint Cloud UTils)
  • อัพเดทแอพ “SurveyStar LDP Thailand” เพื่อรับกับยกร่างมาตรฐาน “TH-LDP”
  • ออกแอพใหม่ SurveyStar Traverse Pro สืบสานงานคำนวณวงรอบ ตอนที่ 2
  • ออกแอพใหม่ SurveyStar Traverse Pro สืบสานงานคำนวณวงรอบ ตอนที่ 1
  • โปรแกรมอรรถประโยชน์ Pocut (POint Cloud Utils)
  • โปรแกรมแปลงไฟล์แคดข้ามระบบพิกัด (Drawing Transformer)
  • มาตรฐานระบบพิกัดแผนที่แบบแอลดีพีของประเทศไทยสำหรับงานวิศวกรรมและการก่อสร้าง (Thailand Low Distortion Map Coordinate System for Engineering and Construction)
  • ประสบการณ์ใช้งาน Kimi K3 Code เขมือบแบบสยอง
  • สร้างแพลตฟอร์มดู Point Cloud บนเว็บด้วย Potree + CesiumJS — เรื่องเล่าจากสนามบินอู่ตะเภา
  • เมื่อวิศวกรสำรวจคำนวณเรื่องน้ำ – วิเคราะห์ระบบระบายน้ำบริเวณ RESA
  • แนะนำหนังสือ “จีออเดซี” ที่ยอดเยี่ยมของดร.พุทธิพล
  • ESPrtk ทำให้ ESP32 ใช้ไม่ได้? วิธีกู้คืน
  • กรณีศึกษา – คืนชีพ SDL30 ปี 2000 ด้วย ESP32 และแอพทำเอง SDL30 Collector
  • DIY RTK Base Station (survey-grade) รุ่น V3.21 ด้วย Raspberry Pi 2B + UM980 เมื่อคุณปู่กลับมาเป็นฮีโร่ ตอนที่ 4
  • รีวิวกูปรี (CoPre2) โปรแกรมประมวลผลไลดาร์จากค่าย CHCNav
  • DIY RTK Base Station (survey-grade) รุ่น V3.2 ด้วย Orange Pi 3 Zero + UM980 ตอนที่ 3
  • DIY RTK Base Station (survey-grade) รุ่น V3 ด้วย Orange Pi 3 Zero + UM980 ตอนที่ 2
  • เส้นทางและไทม์ไลน์ของใบรับรองความรู้ความชำนาญในการประกอบอาชีพวิศวกรรม(สำรวจ)ระดับวิศวกรวิชาชีพ
  • มัดแหนมรวมสามโปรแกรมไปใช้บนสโตร์ Snap ฝั่งลีนุกซ์
  • ปัดฝุ่น Traverse Pro เพิ่มรายละเอียดรายการคำนวณใหม่แบบแนวนอน (Landscape) และธีมมืด
  • DIY RTK Base Station (Survey-Grade) ด้วยชิป UM980 และบอร์ด ESP32 ตอนที่ 1
  • สร้าง NTRIP Caster ด้วย BNC บนคลาวด์แบบ DIY สำหรับ RTK Base Station ใช้ CHCNav P5
  • จับ AI มาไตรกรีฬา สร้างตัวติดตั้ง Snap สำหรับ Surveyor Pocket Tools กับประเด็นแฝงเร้นความเป็นส่วนตัวของผู้ใช้
  • ทดสอบรีด QGIS แบบโหดสัสด้วยชุดข้อมูล Open Building V3 โพลีกอน 74 ล้านหลัง
  • เมื่อ AI เป็นพิษชักจูงผู้ใช้ด้วยข้อมูลผิดๆ

Subscribe to Blog via Email

Enter your email address to subscribe to this blog and receive notifications of new posts by email.

Join 117 other subscribers

Archives

  • October 2026
  • September 2026
  • August 2026
  • July 2026
  • May 2026
  • April 2026
  • March 2026
  • January 2026
  • December 2025
  • November 2025
  • September 2025
  • August 2025
  • July 2025
  • June 2025
  • May 2025
  • January 2025
  • December 2024
  • November 2024
  • October 2024
  • September 2024
  • July 2024
  • May 2024
  • April 2024
  • January 2024
  • November 2023
  • October 2023
  • September 2023
  • July 2023
  • June 2023
  • May 2023
  • March 2023
  • February 2023
  • January 2023
  • November 2022
  • October 2022
  • September 2022
  • July 2022
  • May 2022
  • December 2021
  • October 2021
  • September 2021
  • August 2021
  • May 2021
  • February 2021
  • January 2021
  • December 2020
  • November 2020
  • October 2020
  • September 2020
  • July 2020
  • June 2020
  • May 2020
  • April 2020
  • March 2020
  • February 2020
  • January 2020
  • December 2019
  • November 2019
  • September 2019
  • August 2019
  • July 2019
  • May 2019
  • April 2019
  • March 2019
  • February 2019
  • January 2019
  • November 2018
  • October 2018
  • September 2018
  • August 2018
  • July 2018
  • June 2018
  • May 2018
  • April 2018
  • March 2018
  • January 2018
  • November 2017
  • July 2017
  • June 2017
  • May 2017
  • April 2017
  • March 2017
  • February 2017
  • January 2017
  • December 2016
  • November 2016
  • October 2016
  • August 2016
  • November 2015
  • March 2015
  • August 2014
  • March 2014
  • January 2014
  • December 2013
  • February 2012
  • January 2012
  • November 2011
  • October 2011
  • August 2011
  • April 2011
  • February 2011
  • December 2010
  • November 2010
  • October 2010
  • September 2010
  • June 2010
  • April 2010
  • March 2010
  • January 2010
  • December 2009
  • November 2009
  • October 2009
  • September 2009
  • August 2009

Recent Comments

  • priabroy on DIY RTK Base Station (survey-grade) รุ่น V3.21 ด้วย Raspberry Pi 2B + UM980 เมื่อคุณปู่กลับมาเป็นฮีโร่ ตอนที่ 4
  • priabroy on DIY RTK Base Station (survey-grade) รุ่น V3.21 ด้วย Raspberry Pi 2B + UM980 เมื่อคุณปู่กลับมาเป็นฮีโร่ ตอนที่ 4
  • richard on DIY RTK Base Station (survey-grade) รุ่น V3.21 ด้วย Raspberry Pi 2B + UM980 เมื่อคุณปู่กลับมาเป็นฮีโร่ ตอนที่ 4
  • priabroy on ออกแอพใหม่ SurveyStar Traverse Pro สืบสานงานคำนวณวงรอบ ตอนที่ 1
  • Konexana Yomleuangsa on ออกแอพใหม่ SurveyStar Traverse Pro สืบสานงานคำนวณวงรอบ ตอนที่ 1
©2026 Prajuab Riabroy's Blog | Design: Newspaperly WordPress Theme