กลับไปหน้ารวมไฟล์
using-splines-for-charts-with-smooth-graph-33d030.md

ไอเดีย

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

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

ทฤษฎีเบื้องต้น

เส้นโค้งเบซิเยร์ (Bezier Curves)

เส้นโค้งเบซิเยร์คือเส้นโค้งที่นิยามด้วยคณิตศาสตร์ มักใช้ในงานคอมพิวเตอร์กราฟิกส์ และถูกนำมาใช้ใน Splines เพื่อสร้างเส้นโค้งที่เนียนและต่อเนื่องได้ง่ายๆ โดยการกำหนดรูปร่างผ่านชุดของจุดควบคุม (control points)

เส้นโค้งเบซิเยร์ลูกบาศก์ (Cubic Bezier curves) อาศัยการประมาณค่าเชิงเส้นระหว่างจุดควบคุม และสามารถเขียนเป็นฟังก์ชันที่คำนวณพิกัด x และ y ของจุดบนเส้นโค้งที่ค่า t ใดๆ ได้ เพื่อให้เข้าใจการทำงานของฟังก์ชันนี้ ลองนึกถึงเส้นโค้งเบซิเยร์ลูกบาศก์ที่กำหนดด้วยจุดควบคุมสี่จุด: P0, P1, P2 และ P3 เส้นโค้งจะเริ่มที่ P0 และสิ้นสุดที่ P3 โดยรูปร่างถูกกำหนดโดยจุดควบคุมกลาง P1 และ P2 ที่ t=0 ฟังก์ชันจะคืนค่าเป็นจุดเริ่มต้น P0 และที่ t=1 จะคืนค่าเป็นจุดสิ้นสุด P3 จุดต่างๆ บนเส้นโค้งระหว่างนั้นคำนวณมาจากการประมาณค่าเชิงเส้นระหว่างจุดควบคุม โดยน้ำหนักของการประมาณค่าถูกกำหนดโดยค่า t พูดให้ชัดคือ ที่ t=0.5 จุดที่ได้จะอยู่บนส่วนของเส้นตรงที่เชื่อมระหว่างจุดกึ่งกลางของส่วนเส้นตรงระหว่างจุดควบคุมแรกและสุดท้าย (P0 กับ P3) ไปยังจุดกึ่งกลางของส่วนเส้นตรงระหว่างจุดควบคุมที่สองและสาม (P1 กับ P2)

https://en.wikipedia.org/wiki/File:B%C3%A9zier_3_big.gif

GIF ด้านบนแสดงให้เห็นภาพว่าเส้นโค้งเบซิเยร์ลูกบาศก์ถูกกำหนดรูปร่างโดยจุดควบคุมอย่างไร และการประมาณค่าเชิงเส้นระหว่างจุดเหล่านั้นมารวมกันสร้างเป็นเส้นโค้งได้อย่างไร

ฟังก์ชันสำหรับเส้นโค้งเบซิเยร์ลูกบาศก์คือการรวมกันของการประมาณค่าเชิงเส้นเหล่านี้ ซึ่งมีสูตรดังนี้:

B(t) = (1-t)^3 * P0 + 3(1-t)^2 * t * P1 + 3(1-t) * t^2 * P2 + t^3 * P3

B(t) คือจุดบนเส้นโค้งที่ค่า t

P0 คือจุดเริ่มต้นของเส้นโค้ง

P1 และ P2 คือจุดควบคุมกลางที่กำหนดรูปร่างเส้นโค้ง

P3 คือจุดสิ้นสุดของเส้นโค้ง

ฟังก์ชันนี้คำนวณค่า x และ y ของจุดบนเส้นโค้งโดยใช้ค่า t และจุดควบคุม มันคำนวณส่วนประกอบจาก P0, P1, P2 และ P3 ตามลำดับเพื่อกำหนดเส้นโค้ง เราสามารถใช้ฟังก์ชันนี้สร้างจุดหลายๆ จุดบนเส้นโค้งได้โดยการวนลูปค่า t จาก 0 ถึง 1 เมื่อพลอตจุดเหล่านี้ทั้งหมด มันจะกลายเป็นเส้นโค้งที่เนียนและต่อเนื่อง

สไปน์ (Splines)

ในสไปน์ จุดต่อ (knots หรือ joints) คือตำแหน่งที่เส้นโค้งสองเส้นหรือมากกว่ามาบรรจบกัน และจุดควบคุม (control points) จะกำหนดรูปร่างของเส้นโค้งระหว่างจุดต่อเหล่านั้น เพื่อให้แน่ใจว่ามีความต่อเนื่องที่เนียนระหว่างเส้นโค้งที่อยู่ติดกัน จุดควบคุมที่ตำแหน่งต่อต้องถูกวางในลักษณะที่เวกเตอร์แทนเจนต์ของเส้นโค้งที่อยู่ติดกันมีค่าเท่ากันที่จุดต่อนั้น ดังนั้นจุดควบคุมก่อนและหลังจุดต่อ ต้องอยู่บนเส้นตรงเดียวกันซึ่งลากผ่านจุดต่อที่อยู่ตรงกลางด้วย วิธีนี้ทำให้สไปน์ดูเป็นเส้นโค้งที่เนียนและต่อเนื่อง แทนที่จะเป็นเส้นโค้งหลายๆ เส้นแยกจากกัน ซึ่งนั่นคือสิ่งที่เราต้องการพอดีเลย

แม้ว่า Bezier Curves จะเป็นวิธีที่เจ๋งในการหาค่าที่อยู่ระหว่างจุดควบคุม (control points) แต่ก็ยังมีคำถามอยู่ว่า "แล้วเราจะมั่นใจได้ไงว่าเส้น Spline ที่ได้จะเนียนลื่น?" โดยเฉพาะเมื่อมีเงื่อนไขว่า จุดควบคุมก่อนและหลังจุดต่อ (joint) ต้องอยู่บนเส้นตรงเดียวกันที่ลากผ่านจุดต่อตรงกลางนั่นแหละ เพราะความชัน (slope) ของเส้นตรงนั้นมันเปลี่ยนแปลงได้นี่นา

เพื่อจัดการกับเรื่องนี้ Spline ประเภทต่างๆ เช่น Cardinal Splines, Catmull-Rom Splines, และ Hermite Splines จึงกำหนดจุดควบคุมสองจุดระหว่างจุดต่อ (ซึ่งแทนข้อมูลที่เรารู้) ขึ้นมา ทำให้แต่ละประเภทมีฟังก์ชันเฉพาะตัวที่สามารถเขียนในรูปเมทริกซ์ได้แบบนี้:

สำหรับ Cardinal และ Catmull-Rom Splines นั้น ความชันของเส้นที่ลากผ่านจุดควบคุมและจุดต่อจะถูกตั้งให้เท่ากับเส้นที่ลากผ่านจุดต่อที่อยู่ติดกัน ซึ่งนี่แหละที่กำหนดตำแหน่งของจุดควบคุมและเส้นสัมผัส (tangent) ที่จุดต่อ สำหรับ Cardinal Splines นั่นหมายความว่า เวกเตอร์แทนเจนต์จากจุดต่อไปยังจุดควบคุม จะเท่ากับเวกเตอร์ระหว่างจุดต่อที่อยู่ติดกัน เวกเตอร์พวกนี้สามารถปรับขนาดได้ด้วยการคูณกับเมทริกซ์ ส่วน Catmull-Rom Spline ก็คือ Cardinal Spline ประเภทหนึ่งที่ตั้งค่าตัวคูณปรับขนาด (scaling factor) เป็น 0.5 พอดี

Cardinal Spline:

[ -s 2-s s-2 s ]

[ 2s s-3 3-2s -s ]

[ -s 0 s 0 ]

[ 0 1 0 0 ]

Catmull-Rom Spline (สำหรับ s = 0.5):

1/2 * (

[-1 3 -3 1 ]

[ 2 -5 4 -1 ]

[-1 0 1 0 ]

[ 0 2 0 0 ] )

ในที่นี้ แต่ละแถวสอดคล้องกับเซตของจุดควบคุมสี่จุด และแต่ละคอลัมน์แทนน้ำหนัก (weights) ของฟังก์ชันพื้นฐาน (basis functions) ที่เกี่ยวข้อง

Hermite Spline:

[ 2 -2 1 1 ] * จุดต่อเริ่มต้น (start joint)

[-3 3 -2 -1 ] * เวกเตอร์แทนเจนต์จากจุดต่อเริ่มต้น

[ 0 0 1 0 ] * จุดต่อสิ้นสุด (end joint)

[ 1 0 0 0 ] * เวกเตอร์แทนเจนต์จากจุดต่อสิ้นสุด

ในที่นี้ สองแถวแรกสอดคล้องกับจุดควบคุมและเวกเตอร์แทนเจนต์สำหรับจุดเริ่มต้นของเส้นโค้ง ส่วนสองแถวหลังสอดคล้องกับจุดควบคุมและเวกเตอร์แทนเจนต์สำหรับจุดสิ้นสุดของเส้นโค้ง

B-Spline :

1/6 * (

[ 1 4 1 0 ]

[-3 0 3 0 ]

[ 3 -6 3 0 ]

[-1 3 -3 1 ] )

ในที่นี้ แต่ละแถวสอดคล้องกับเซตของจุดควบคุมสี่จุด และแต่ละคอลัมน์แทนน้ำหนักของฟังก์ชันพื้นฐานที่เกี่ยวข้อง

โค้ดของโปรเจคนี้มีการนำ Spline ประเภทต่างๆ มาประยุกต์ใช้แบบง่ายๆ ไว้ให้แล้ว ไปลองเล่นกันได้

การทำให้ข้อมูลทางคณิตศาสตร์เรียบเนียน (Mathematical Data Smoothing)

ข้อมูลเซนเซอร์ดิบ (เช่น อุณหภูมิหรือระดับแก๊ส) มักจะ "ขรุขระ" เนื่องจากสัญญาณรบกวน โปรเจคนี้ใช้ Cubic Spline Interpolation ในการสร้างกราฟที่ดูเนียนลื่นและเป็นมืออาชีพ

  • ตรรกะของ Spline: แทนที่จะวาดเส้นตรงระหว่างจุดข้อมูล (Linear Interpolation) อัลกอริทึมจะคำนวณพหุนามดีกรีสามสำหรับแต่ละช่วงข้อมูล เพื่อให้แน่ใจว่าเส้นโค้งจะเนียนที่ทุกจุดต่อ
  • การจัดการทรัพยากร: เนื่องจากการคำนวณ spline อาจใช้ทรัพยากร CPU เยอะ ระบบจึงคำนวณ "K-vectors" ล่วงหน้าและเก็บไว้ในบัฟเฟอร์ชั่วคราว ทำให้ Arduino สามารถวาดกราฟเนียนๆ ได้แบบเรียลไทม์

การนำเสนอภาพ (Visual Presentation)

  • การแสดงผลบน LCD/OLED: พิกัดที่ถูกทำให้เรียบแล้วจะถูกแปลงเป็นตำแหน่งพิกเซลบนจอกราฟิก (เช่น SSD1306)
  • UI ความเที่ยงตรงสูง: เทคนิคนี้จำเป็นมากสำหรับแดชบอร์ดในอุตสาหกรรมหรืออุปกรณ์ติดตามทางการแพทย์ ที่ความชัดเจนของภาพและการวิเคราะห์แนวโน้มสำคัญกว่าการดูข้อมูลจุดดิบที่มีสัญญาณรบกวน จัดไปวัยรุ่น!

ข้อมูล Frontmatter ดั้งเดิม

title: "งานง่ายแต่หล่อ! วาดกราฟโค้งเนียนด้วย Splines"
description: "โปรเจค Arduino นี้จะโชว์ให้เห็นว่าเราจัดการข้อมูลจากเซนเซอร์ในโลกจริงมาแสดงผลบน E-paper screen แบบตึงๆ ได้ยังไง โดยใช้ Splines ทำให้กราฟโค้งเนียน ดูเทพๆ ไปเลยวัยรุ่น!"
author: "trialrunner"
category: "Lab Stuff"
tags:
  - "Environmental Sensing"
views: 1793
likes: 0
price: 1499
difficulty: "Easy"
components:
  - "1x ESP32"
tools: []
apps:
  - "1x Arduino IDE 2.0 (beta)"
  - "1x PlatformIO"
downloadableFiles: []
documentationLinks: []
passwordHash: "0cbba90bf5cfd27e970568268a18fd9a00fe68172de1ec57bb09d3ccdc636944"
encryptedPayload: "U2FsdGVkX1/PiEcOTtgbe4HpGiTiA/P2EEYOkVpLzSwgUP+xK9uRYgCYh2CcrHXm+Rw328BsaLzzHRTkI6PHN1fyQXdBcbnCoKoTcVXq1UhQTwTKI1nkOI9buSpah42X"
seoDescription: "Arduino project demonstrating Splines for smooth Graph charts and displaying real-world data on E-paper screens."
videoLinks: []
heroImage: "https://cdn.jsdelivr.net/gh/bigboxthailand/arduino-assets@main/images/projects/using-splines-for-charts-with-smooth-graph-33d030_cover.jpg"
lang: "en"