รูปปกบทความ

1. 🎯 ตอนที่ 20: ความสำคัญของอัตราการสุ่ม (Sampling Time) ใน Digital Control

2. 📖 เปิดฉาก (The Hook)

สวัสดีครับน้องๆ และนักพัฒนาทุกท่าน! กลับมาพบกันอีกครั้งในซีรีส์ เจาะลึกวิศวกรรมระบบควบคุม (Control Systems) จาก 101 ถึง Advance สไตล์วิศวกรรุ่นพี่ครับ

ในตอนที่แล้ว เราได้เปลี่ยนผ่านจากโลกของอนาล็อกเข้าสู่โลกดิจิทัล (Digital Control) กันไปแล้ว สมองกลอย่างไมโครคอนโทรลเลอร์ไม่สามารถรับรู้โลกแบบต่อเนื่องได้ มันจึงต้องใช้วิธี “สุ่มมอง (Sampling)” เป็นจังหวะๆ

ลองจินตนาการว่าน้องกำลังขับรถด้วยความเร็วสูง แต่โดนบังคับให้ “หลับตา แล้วลืมตาขึ้นมามองถนนแค่แวบเดียว” ถ้าน้องลืมตาทุกๆ 1 วินาทีอย่างสม่ำเสมอ สมองของน้องจะสามารถกะระยะและคาดเดาความเร็วของรถคันหน้าได้อย่างแม่นยำ (Deterministic) แต่ถ้าจู่ๆ น้องเกิดกะพริบตาแบบผิดจังหวะ เดี๋ยวลืมตาถี่ๆ 0.1 วินาที เดี๋ยวเผลอหลับตาไป 2 วินาที… สมองของน้องจะรวนทันที! น้องอาจจะตกใจคิดว่ารถคันหน้าเบรกกะทันหัน และเผลอกระทืบเบรกรถตัวเองจนเกิดอุบัติเหตุได้เลย

ในโลกของการเขียนโค้ดระบบควบคุมก็เช่นกันครับ! วิศวกรมือใหม่หลายคนมักจะเอาสมการ PID ไปยัดไว้ใน while(1) loop ธรรมดาที่เวลาหน่วงไม่แน่นอน วันนี้พี่จะพาไปชำแหละให้ดูว่า การที่ลูปเวลาทำงานไม่คงที่ หรือที่ทางวิศวกรรมเรียกว่าปรากฏการณ์ “Sampling Jitter” นั้น มันเข้าไปทำลายล้างการคำนวณในโหมด Integral (I) และ Derivative (D) จนทำให้เครื่องจักรของเราสั่นเป็นเจ้าเข้าได้อย่างไรครับ!

3. 🧠 แก่นวิชา (Core Concepts)

ในระบบควบคุมดิจิทัล (Discrete-time control systems) เรามีตัวแปรเวลาที่สำคัญที่สุดคือ Sampling Time ($T_s$) ซึ่งคือระยะห่างระหว่างรอบการคำนวณแต่ละครั้ง

หลักการทางคณิตศาสตร์ทั้งหมดของการควบคุมดิจิทัล (เช่น Z-Transform หรือ Discrete PID) ถูกสร้างขึ้นบนสมมติฐานศักดิ์สิทธิ์ข้อหนึ่ง นั่นคือ: “เวลาในการสุ่มต้องคงที่เป๊ะๆ และคาดเดาได้ (Deterministic)”

แต่ในโลกความจริง การประมวลผลของซอฟต์แวร์อาจเจอทางแยก (if-else), การเรียกใช้ฟังก์ชันย่อย, หรือถูกขัดจังหวะจากงานอื่น ทำให้เกิดความคลาดเคลื่อนของเวลาในการสุ่ม เรียกว่า Sampling Jitter สมการของการเกิด Jitter คือ: $$ t_k = k T_s + \epsilon_k $$ โดยที่:

  • $t_k$ คือ เวลาที่ซอฟต์แวร์ทำงานจริง
  • $k T_s$ คือ เวลาในอุดมคติที่ควรจะทำ
  • $\epsilon_k$ คือ ค่าความคลาดเคลื่อน (Jitter error) แบบสุ่ม

คำถามคือ… แล้วอีเจ้า $\epsilon_k$ นิดๆ หน่อยๆ ในซอฟต์แวร์ มันไปสร้างหายนะให้กับระบบควบคุมได้อย่างไร? ไปดูคณิตศาสตร์กันครับ!

รูปประกอบบล็อกไดอะแกรมแสดงผลกระทบของ Sampling Jitter ต่อสมการ PID

4. 🧮 ร่ายมนต์สมการและโค้ดควบคุม (The Math & Implementation)

เรามายกสมการ Discrete PID (แบบ Position Form) ที่อิงจากวิธีประมาณค่าแบบ Euler มาดูกันครับ: $$ u(k) = K_p e(k) + K_i T_s \sum_{i=1}^{k} e(i) + K_d \frac{e(k) - e(k-1)}{T_s} $$

สังเกตตัวแปร $T_s$ ในสมการให้ดีนะครับ มันโผล่มา 2 จุด ซึ่งเป็นจุดตายทั้งคู่:

1. หายนะในพจน์ Derivative (The Derivative Disaster): โหมด D ทำหน้าที่หา “ความชัน (Rate of change)” โดยเอาผลต่างของ Error หารด้วยเวลา $T_s$ สมมติว่าเซ็นเซอร์ไม่ได้ขยับเลย แต่โค้ดของคุณเกิด Jitter (ทำงานเร็วผิดปกติ) ทำให้เวลา $\Delta t$ จริงๆ เล็กลงกว่า $T_s$ ที่ตั้งไว้ในตัวแปรคณิตศาสตร์ ผลลัพธ์คือสมองกลจะหารด้วยค่าคงที่ $T_s$ ตัวเดิม แต่ได้ค่าการเปลี่ยนแปลงที่เพี้ยนไป หากระบบของคุณมีการใช้ Derivative Gain ($K_d$) ที่สูง การกระตุกของเวลาเพียงเล็กน้อยจะถูก “ขยาย (Amplify)” ให้กลายเป็นยอดแหลม (Noise Spike) มหาศาล ส่งผลให้มอเตอร์ของคุณครางเสียงแหลม กระตุก และร้อนจัด!

2. ความเพี้ยนในพจน์ Integral (The Integral Drift): โหมด I ทำหน้าที่หา “พื้นที่ใต้กราฟ” โดยเอา Error มาคูณกับ $T_s$ เพื่อบวกสะสมเป็นสี่เหลี่ยมผืนผ้าทีละแผ่น ถ้ารอบเวลาทำงานจริงยืดเยื้อ (ลูปหน่วง) แผ่นสี่เหลี่ยมในโลกความจริงจะมีขนาดกว้างกว่าในสมการ ทำให้พื้นที่สะสมผิดพลาดไปเรื่อยๆ จนระบบเกิด Offset และไม่มีวันเข้าเป้าหมายได้นิ่งสนิท

ตัวอย่างโค้ดมือใหม่ (ที่ทำให้เครื่องพัง):

// ตัวอย่างแบบนี้ "ห้ามทำ" ในงาน Control!
float Ts = 0.01; // หวังใจว่าจะทำงานทุกๆ 10ms

void main() {
    while(1) {
        float e = read_sensor() - setpoint;
        
        // หากในลูปนี้มีฟังก์ชันอื่นที่เวลาประมวลผลไม่แน่นอน (เช่น การพริ้นต์จอ LCD)
        update_LCD_display(); // บางทีใช้ 2ms บางทีใช้ 15ms!
        
        // สมการคำนวณที่อิงจากตัวแปร Ts แบบตายตัว จะเพี้ยนทันที
        integral += e * Ts; 
        derivative = (e - prev_e) / Ts;
        
        output = Kp*e + Ki*integral + Kd*derivative;
        prev_e = e;
        
        delay(10); // หวังว่าจะหน่วงเวลาให้ได้ 10ms แต่มันไม่เป๊ะ!
    }
}

5. 🛡️ เคล็ดลับจากคัมภีร์ลับ (Under the Hood / Pro-Tips)

แล้ววิศวกรระดับโปรเขารับมือกับปัญหานี้กันอย่างไร? คำตอบเดียวเลยครับ: “ทิ้ง delay() ไปซะ แล้วจงใช้ Hardware Timer Interrupt!”

ในไมโครคอนโทรลเลอร์ (เช่น STM32 หรือ PIC) เราจะมีวงจรที่เรียกว่า Timer ซึ่งทำงานแยกอิสระจาก CPU หลักด้วยความถี่ของสัญญาณนาฬิกา (Hardware Clock) แบบเป๊ะๆ เราสามารถตั้งค่าให้ Timer ตัวนี้สร้างจังหวะขัดจังหวะที่เรียกว่า Timer Service Routine (ISR) ได้ตามคาบเวลา $T_s$ ที่ต้องการเป๊ะๆ ในระดับไมโครวินาที!

การแก้ปัญหาด้วย Timer ISR:

// ตัวแปรในระบบ
float Ts = 0.01; // 10ms
volatile float output = 0.0;

// ฟังก์ชันนี้จะถูกฮาร์ดแวร์เรียกทำงานทุกๆ 10ms เป๊ะ! ไม่ว่า CPU กำลังทำอะไรอยู่
void Timer_ISR_Handler() {
    float e = read_sensor() - setpoint;
    
    // คำนวณ PID ตรงนี้ มั่นใจได้เลยว่า Ts = 0.01 วินาทีเสมอ
    integral += e * Ts;
    derivative = (e - prev_e) / Ts;
    
    output = Kp*e + Ki*integral + Kd*derivative;
    write_actuator(output);
    
    prev_e = e;
}

void main() {
    setup_Hardware_Timer_Interrupt(10_ms); // เริ่มนับเวลาจาก Hardware
    while(1) {
        // เอาฟังก์ชันที่เวลาไม่แน่นอนมาใส่ใน main() ได้เลย
        // เช่น อัปเดตหน้าจอ, รับส่ง Wi-Fi, สื่อสาร UART
        update_LCD_display(); 
        send_data_to_server();
    }
}

Pro-Tip: แม้เราจะใช้ Interrupt แล้ว แต่ถ้าเรามี Interrupt หลายตัวแย่งกันทำงาน (Nesting Interrupts) ก็ยังอาจเกิด Jitter เล็กน้อยได้ ดังนั้น กฎเหล็กอีกข้อคือ “โค้ดคำนวณ PID ใน ISR ต้องสั้น กระชับ และคำนวณให้เสร็จไวที่สุดเสมอ!” ห้ามใส่คำสั่งพริ้นต์หรือวนลูปหนักๆ ใน ISR เด็ดขาดครับ!

6. 🏁 บทสรุป (To be continued…)

Sampling Time ($T_s$) ไม่ใช่แค่ตัวเลขค่าคงที่โง่ๆ ในสมการคณิตศาสตร์ แต่มันคือ “จังหวะหัวใจ” ของระบบควบคุมดิจิทัล หากจังหวะหัวใจนี้เต้นผิดพลาด (Sampling Jitter) มันจะไปบิดเบือนการรับรู้อดีต (Integral) และบ่อนทำลายการพยากรณ์อนาคต (Derivative) ทันที การใช้ Timer Interrupt จึงเป็นภาคบังคับในการเขียนเฟิร์มแวร์ระดับอุตสาหกรรมครับ

ตอนนี้เราได้เห็นข้อควรระวังในการแปลงสมการ PID สู่โลกดิจิทัลกันอย่างครบถ้วนแล้ว! ตั้งแต่การแก้สมการ (ตอนที่ 13), โครงสร้าง Topology (ตอนที่ 15), Anti-windup (ตอนที่ 16), กรอง Noise (ตอนที่ 18), มาจนถึงความสำคัญของเวลา (ตอนที่ 20)

ในตอนต่อไป เราจะเข้าสู่เนื้อหาคลายปมปัญหาที่หลายคนรอคอย: “แล้วเราจะหาค่า $K_p, K_i, K_d$ ได้อย่างไรโดยไม่ต้องนั่งเดา?” เตรียมพบกับคัมภีร์การจูนระดับตำนานอย่าง Ziegler-Nichols Method กันแบบเจาะลึก รอติดตามนะครับ!


ต้องการที่ปรึกษาด้านการออกแบบระบบควบคุม (Control Systems), หุ่นยนต์อัตโนมัติ (Robotics) หรือพัฒนาระบบ Automation ขั้นสูงให้กับโรงงานของคุณ? ทีมงาน WP Solution พร้อมให้บริการออกแบบและติดตั้งระบบแบบครบวงจร ดูรายละเอียดบริการของเราได้ที่: www.wpsolution2017.com หรือพูดคุยปรึกษาเบื้องต้นได้ที่ Line: wisit.p