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

ฟิลเตอร์ DSP: EMA, Median, Kalman และ radar range profile

โมดูล 4 — วิเคราะห์สัญญาณ · สไลด์: slides.md · ภาพรวมโมดูล · หน้าหลักสูตร

เปิดเสาที่ 3 (Analysis) ด้วยฟิลเตอร์ตามเวลา รู้ว่าสัญญาณรบกวนมีหลายหน้า เลือก EMA, Median หรือ Kalman1D ให้ตรงกับหน้าของ noise ใช้ API ร่วม update/value/reset และเห็น radar range profile ที่ฝั่ง C ทำให้แล้ว

เมื่อจบบทเรียนนี้ คุณจะ:

  1. แยกชนิดของสัญญาณรบกวน (white noise, spike, drift) และเลือกฟิลเตอร์ที่เหมาะกับแต่ละชนิดได้ พร้อมเหตุผล
  2. คำนวณ EMA หนึ่งก้าวด้วย y = αx + (1−α)y_prev และค่ากลางของหน้าต่าง Median ด้วยมือ แล้วอธิบายข้อแลกเปลี่ยนระหว่างความเรียบกับการตอบสนองเมื่อปรับ α
  3. อธิบาย Kalman gain K = P/(P+R) ว่าคือน้ำหนักที่ให้กับการวัด และบอกผลของการเพิ่ม r หรือ q
  4. สร้างฟิลเตอร์ของ dsp ด้วย keyword argument ครั้งเดียวนอกลูป แล้วป้อนทีละค่าด้วย update() และอธิบายได้ว่าทำไมสร้างในลูปแล้วไม่เรียบ

ผ่านโมดูล 3 มาแล้ว เคยเห็นเกจสั่นทั้งที่วางบอร์ดนิ่งในบทเรียน 3.2 บทเรียนนี้คือคำตอบของอาการนั้น เปิด s08_filters_full.py (อยู่ในบทเรียน 4.2) ไว้ลองเล่นก่อนแกะ

รัน s08_filters_full.py ก่อนอ่านโค้ด กราฟบนคือสัญญาณดิบ (ขนาดความเร่งสามแกน) กราฟล่างคือค่าเดียวกันหลังกรอง เขย่าบอร์ดเบา ๆ แล้วสลับฟิลเตอร์ใน dropdown ดูว่าเส้นล่างเปลี่ยนนิสัยอย่างไร และแถบ noise down % บอกว่าลดการกระตุกได้กี่เปอร์เซ็นต์

ไม่มีเซนเซอร์ตัวไหนให้ค่าเรียบ สัญญาณรบกวนมีหลายหน้า: white noise หนามเล็กกระจายจากความร้อนหรือ ADC (เหมาะกับ EMA/SMA), spike/outlier ค่าโดดเป็นครั้งคราวจาก multipath หรือการชนสัญญาณ (เหมาะกับ Median), drift ค่าเลื่อนช้า ๆ (เหมาะกับ HPF) และแบบผสม (เหมาะกับ Kalman) ไม่มีฟิลเตอร์ตัวเทพ ต้องมองศัตรูก่อนหยิบเครื่องมือ Analysis มาก่อน Training เสมอ เพราะถ้าป้อนสัญญาณสกปรก โมเดลจะเรียน “หนาม” ไปด้วย

ฟิลเตอร์ตามเวลาคือ ความจำ มันถ่วงค่าใหม่กับอดีต ฟิลเตอร์ใน dsp ทำงานแบบ streaming บน CM33 ทุกตัวใช้ API เดียวกัน: สร้างครั้งเดียวนอกลูป → y = f.update(x) ทุกรอบ → f.value() อ่านค่าล่าสุด → f.reset() ล้าง state พารามิเตอร์ทุกตัวเป็น keyword argument (alpha=, window=, q=, r=) ส่งแบบ positional เช่น dsp.EMA(0.15) จะโยน TypeError ถ้าเผลอสร้างฟิลเตอร์ในลูป ความจำจะถูกลบทุกรอบ เส้นจะไม่มีวันเรียบ

EMA: $y[n] = \alpha x[n] + (1-\alpha) y[n-1]$ α เล็กเรียบแต่ตามช้า α ใหญ่ไวแต่หนามยังโผล่ ค่า EMA_ALPHA = 0.15 คือเชื่อของใหม่ 15% Median เรียงค่าล่าสุด N ตัวแล้วเอาค่ากลาง ค่าโดดจึงไม่มีสิทธิ์ชนะ (เช่น 98, 101, 240, 99, 100 ได้ 100 แต่ค่าเฉลี่ยได้ 127.6) เฟิร์มแวร์บังคับ window เป็นเลขคี่ไม่เกิน 15 Kalman1D เก็บทั้งค่าประมาณและความไม่มั่นใจ P ทุกก้าวคำนวณ $K = P/(P+R)$ แล้ว $x \leftarrow x + K(z - x)$ r สูง (ไม่เชื่อเซนเซอร์) ทำให้ K เล็กจึงเรียบ q สูงยอมให้ค่าจริงขยับเร็ว มองได้ว่า Kalman คือ EMA ที่ปรับ α ของตัวเองได้

ตัวอย่างของจริงคือ radar range profile: sensors.radar_range() คืน distance_m, peak_db, resolution_m, target, seq ฝั่ง C ทำ HPF → FFT → dB → หา peak ให้หมด ความละเอียดราว 0.33 เมตรต่อ bin และระยะชอบกระโดดเพราะ multipath ซึ่งคือ spike แท้ ๆ ฟิลเตอร์ที่เหมาะจึงเป็น Median และในงานจริงเรามักต่อฟิลเตอร์กัน เช่น Median กัน spike ก่อนแล้ว EMA เกลี่ยต่อ

05_radar_distance.py คือไม้วัดระยะด้วยเรดาร์ที่ใช้ Median กันระยะกระโดด ลองทาย (Predict) ก่อนรันว่าถ้าเดินเข้าออกหน้าบอร์ด ตัวเลขจะนิ่งหรือกระโดด แล้วรันเทียบบนบอร์ด

ไฟล์ ไฟล์นี้สอน
examples/05_radar_distance.py Radar Range: ไม้วัดระยะบนจอ (Bar + Seg7 + กราฟ)

สไลด์ของบทเรียนนี้อ้างถึงไฟล์ที่อยู่ในบทเรียนอื่นหรือใน shared/ ด้วย:

คำถามชุดเดียวกันอยู่ใน quiz.yaml สำหรับระบบที่ตรวจอัตโนมัติ

  1. ระยะจากเรดาร์กระโดดเป็นครั้งคราวเพราะการสะท้อนหลายทาง ควรเลือกฟิลเตอร์ใดเป็นลำดับแรก (เลือกหนึ่งข้อ · เป้าหมายข้อ 1)

    • ก) EMA
    • ข) Median
    • ค) HPF
    • ง) ไม่ต้องกรอง
    เฉลย

    ข — การกระโดดเป็น spike แท้ ๆ Median โหวตค่ากลางจึงตัด spike ทิ้งได้ ส่วน EMA จะเกลี่ยให้เป็นโหนกที่ยังเห็นอยู่

  2. y_prev = 10, x = 20 และ α = 0.25 ค่า EMA รอบนี้เป็นเท่าไร (เลือกหนึ่งข้อ · เป้าหมายข้อ 2)

    • ก) 12.5
    • ข) 15
    • ค) 17.5
    • ง) 20
    เฉลย

    ก — y = 0.25 × 20 + 0.75 × 10 = 5 + 7.5 = 12.5 ค่าใหม่ได้น้ำหนักแค่หนึ่งในสี่ เส้นจึงตามช้าแต่เรียบ

  3. หน้าต่าง Median ห้าค่าคือ 98 101 240 99 100 ผลลัพธ์คืออะไร (เลือกหนึ่งข้อ · เป้าหมายข้อ 2)

    • ก) 127.6
    • ข) 100
    • ค) 240
    • ง) 98
    เฉลย

    ข — เรียงได้ 98 99 100 101 240 ค่ากลางคือ 100 spike 240 ถูกดันไปขอบ ขณะที่ค่าเฉลี่ย 127.6 ถูก spike ลาก

  4. ใน Kalman1D ถ้าเพิ่ม r (ไม่เชื่อเซนเซอร์มากขึ้น) โดย q คงเดิม ผลคืออะไร (เลือกหนึ่งข้อ · เป้าหมายข้อ 3)

    • ก) K โตขึ้น ค่ากระโดดตามการวัด
    • ข) K เล็กลง ค่าขยับทีละน้อย เรียบขึ้นแต่ตามช้าลง
    • ค) ไม่มีผลเพราะ K คงที่
    • ง) ฟิลเตอร์หยุดทำงาน
    เฉลย

    ข — K = P/(P+R) เมื่อ R โต K เล็กลง x += K(z − x) จึงขยับน้อย ได้ความเรียบแลกกับการตอบสนองแบบเดียวกับ α เล็กของ EMA

  5. โค้ดนี้สร้าง f = dsp.EMA(alpha=0.15) ไว้ในลูปทุกรอบแล้วเรียก f.update(x) ผลบนกราฟคืออะไร (เลือกหนึ่งข้อ · เป้าหมายข้อ 4)

    • ก) เส้นเรียบมากเพราะ α เล็ก
    • ข) เส้นกรองเหมือนเส้นดิบ เพราะฟิลเตอร์ที่เพิ่งสร้างคืนค่าแรกที่ป้อนตรง ๆ และความจำถูกลบทุกรอบ
    • ค) โปรแกรมโยน TypeError
    • ง) เส้นเป็นศูนย์ตลอด
    เฉลย

    ข — state อยู่ในอ็อบเจกต์ การสร้างใหม่ทุกรอบคือการเริ่มต้นใหม่ทุกครั้ง ฟิลเตอร์จึงไม่มีอดีตให้ถ่วง ต้องสร้างครั้งเดียวนอกลูป

  • คำนวณ EMA ด้วยมือสามก้าวจาก x = 10, 10, 20 เริ่ม y = 10 ที่ α = 0.5 และ α = 0.1 แล้วเทียบว่าตัวไหนตามทันกว่า
  • หาค่ากลางของหน้าต่าง [5, 7, 90, 6, 5] เทียบกับค่าเฉลี่ย แล้วจดลงบันทึกการเรียนว่าทำไมต่างกัน
  • ใน REPL ลองเรียก dsp.EMA(0.15) ดูข้อความ error แล้วแก้เป็น dsp.EMA(alpha=0.15)

บทเรียน 4.2 เราจะเติมไฟล์ s08_filters.py ให้สร้างฟิลเตอร์จากชื่อ กรองสัญญาณจริง และวัดผลเป็น noise down %

บทเรียนถัดไป: บทเรียน 4.2 — ลงมือทำ: ฟิลเตอร์ทำสัญญาณให้สะอาดสด ๆ

  • งานที่คุณสนใจเจอสัญญาณรบกวนหน้าไหนมากที่สุด และคุณยอมช้าได้แค่ไหนเพื่อแลกความเรียบ
  • ทำไมการวัดความเรียบด้วยการกระตุกระหว่างเฟรมจึงใช้กับเซนเซอร์จริงได้ แม้ไม่มี “เฉลย” ว่าค่าจริงคือเท่าไร

คำถามทบทวน

ลองตอบเองก่อน แล้วค่อยเปิดดูเฉลย

  1. ระยะจากเรดาร์กระโดดเป็นครั้งคราวเพราะการสะท้อนหลายทาง ควรเลือกฟิลเตอร์ใดเป็นลำดับแรก (เป้าหมายข้อ 1)

    1. EMA
    2. Median
    3. HPF
    4. ไม่ต้องกรอง
    ดูเฉลย

    คำตอบ: B. Median

    การกระโดดเป็น spike แท้ ๆ Median โหวตค่ากลางจึงตัด spike ทิ้งได้ ส่วน EMA จะเกลี่ยให้เป็นโหนกที่ยังเห็นอยู่

  2. y_prev = 10, x = 20 และ α = 0.25 ค่า EMA รอบนี้เป็นเท่าไร (เป้าหมายข้อ 2)

    1. 12.5
    2. 15
    3. 17.5
    4. 20
    ดูเฉลย

    คำตอบ: A. 12.5

    y = 0.25 × 20 + 0.75 × 10 = 5 + 7.5 = 12.5 ค่าใหม่ได้น้ำหนักแค่หนึ่งในสี่ เส้นจึงตามช้าแต่เรียบ

  3. หน้าต่าง Median ห้าค่าคือ 98 101 240 99 100 ผลลัพธ์คืออะไร (เป้าหมายข้อ 2)

    1. 127.6
    2. 100
    3. 240
    4. 98
    ดูเฉลย

    คำตอบ: B. 100

    เรียงได้ 98 99 100 101 240 ค่ากลางคือ 100 spike 240 ถูกดันไปขอบ ขณะที่ค่าเฉลี่ย 127.6 ถูก spike ลาก

  4. ใน Kalman1D ถ้าเพิ่ม r (ไม่เชื่อเซนเซอร์มากขึ้น) โดย q คงเดิม ผลคืออะไร (เป้าหมายข้อ 3)

    1. K โตขึ้น ค่ากระโดดตามการวัด
    2. K เล็กลง ค่าขยับทีละน้อย เรียบขึ้นแต่ตามช้าลง
    3. ไม่มีผลเพราะ K คงที่
    4. ฟิลเตอร์หยุดทำงาน
    ดูเฉลย

    คำตอบ: B. K เล็กลง ค่าขยับทีละน้อย เรียบขึ้นแต่ตามช้าลง

    K = P/(P+R) เมื่อ R โต K เล็กลง x += K(z − x) จึงขยับน้อย ได้ความเรียบแลกกับการตอบสนองแบบเดียวกับ α เล็กของ EMA

  5. โค้ดนี้สร้าง f = dsp.EMA(alpha=0.15) ไว้ในลูปทุกรอบแล้วเรียก f.update(x) ผลบนกราฟคืออะไร (เป้าหมายข้อ 4)

    1. เส้นเรียบมากเพราะ α เล็ก
    2. เส้นกรองเหมือนเส้นดิบ เพราะฟิลเตอร์ที่เพิ่งสร้างคืนค่าแรกที่ป้อนตรง ๆ และความจำถูกลบทุกรอบ
    3. โปรแกรมโยน TypeError
    4. เส้นเป็นศูนย์ตลอด
    ดูเฉลย

    คำตอบ: B. เส้นกรองเหมือนเส้นดิบ เพราะฟิลเตอร์ที่เพิ่งสร้างคืนค่าแรกที่ป้อนตรง ๆ และความจำถูกลบทุกรอบ

    state อยู่ในอ็อบเจกต์ การสร้างใหม่ทุกรอบคือการเริ่มต้นใหม่ทุกครั้ง ฟิลเตอร์จึงไม่มีอดีตให้ถ่วง ต้องสร้างครั้งเดียวนอกลูป

อ้างอิงบทเรียนนี้

ถ้านำบทเรียนนี้ไปสอน ทำสไลด์ หรือทำเอกสารต่อ ให้อ้างอิงด้วยข้อความนี้ ถ้าดัดแปลงเนื้อหา ให้เติม (ดัดแปลง)ต่อท้ายชื่อบทเรียน

"ฟิลเตอร์ DSP: EMA, Median, Kalman และ radar range profile" จาก TESA Open Knowledge โดยสมาคมสมองกลฝังตัวไทย (Thai Embedded Systems Association: TESA) https://github.com/tesaiot/tesa-qualification-program สัญญาอนุญาต CC BY-NC 4.0

ข้อความอ้างอิงภาษาอังกฤษ: "DSP filters: EMA, Median, Kalman and the radar range profile" from TESA Open Knowledge by the Thai Embedded Systems Association (TESA), https://github.com/tesaiot/tesa-qualification-program, licensed under CC BY-NC 4.0

ลิงก์บทเรียน: https://tesaiot.github.io/tesa-qualification-program/courses/edge-ai-developer/m04-analysis/l01-dsp-filters/

วิธีอ้างอิง TESA ฉบับเต็ม

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · CC BY-NC 4.0

เนื้อหาเผยแพร่ภายใต้ CC BY-NC 4.0 นำไปใช้ต่อในงานที่ไม่ใช่เพื่อการค้าได้ โปรดอ้างอิงสมาคมสมองกลฝังตัวไทย (TESA) ทุกครั้ง · วิธีอ้างอิง TESA