สุ่มสัญญาณให้ถูก: Nyquist aliasing และ ring buffer
โมดูล 3 — แสดงผลเซนเซอร์บน HMI · สไลด์: slides.md · ภาพรวมโมดูล · หน้าหลักสูตร
เข้าใจว่ากราฟบนจอคือจุดที่เราเลือกสุ่มมาแล้วลากเส้นต่อกัน สุ่มไม่ทันจะได้คลื่นปลอมที่ดูน่าเชื่อ (aliasing) แล้วเรียนรู้ว่า ui.Chart เป็น ring buffer 50 ช่องที่รับแต่จำนวนเต็ม และทำไมกราฟที่วิ่งอยู่ตัวเดียวบนจอจึงวาดช้าที่สุด
เป้าหมาย
หัวข้อที่มีชื่อว่า “เป้าหมาย”เมื่อจบบทเรียนนี้ คุณจะ:
- คำนวณขีดจำกัด Nyquist และความถี่ปลอมได้ถูกต้อง (ลูป 200 ms ได้ fs 5 Hz เห็นได้ไม่เกิน 2.5 Hz · เขย่า 6 Hz จะเห็น |6 − 5| = 1 Hz · ใน 03_aliasing_nyquist.py คลื่น 30 Hz ที่สุ่ม 40 Hz จะเห็นเป็น 10 Hz) และอธิบายว่าทำไม aliasing กรองทิ้งทีหลังไม่ได้
- ป้อนค่าทศนิยมจาก motion() เข้า ui.Chart ด้วย int() ได้ถูก บอกได้ว่า int() ตัดทศนิยมทิ้งไม่ใช่ปัดเศษ (0.9 และ −0.9 เป็น 0) และเลือกตัวคูณกับช่วงแกน Y ให้ได้ความละเอียดที่ต้องการ เช่น คูณ 100 กับช่วง ±2000 ได้ 0.01 m/s²
- คำนวณความกว้างของหน้าต่างเวลาบนกราฟจากจำนวนช่องกับคาบลูป (50 × 0.2 s = 10 s) และบอกได้ว่าอยากเห็นย้อนหลังนานขึ้นมีสองปุ่ม คือยืดคาบลูปหรือเพิ่มจำนวนจุด และปุ่มไหนถูกกว่า
- อธิบายได้ว่าทำไมลูปที่มีแต่ set_next() วาดช้ากว่าลูปที่มี .text() อยู่ด้วยราว 40 เท่า (ตัวจับเวลาปกติ 80 คำสั่งต่อวินาที เทียบกับโหมดเร่ง 3,200) และแก้ด้วยการส่ง .text() ข้อความเดิมทุกรอบ
ก่อนเริ่ม
หัวข้อที่มีชื่อว่า “ก่อนเริ่ม”ทบทวนบทเรียน 3.1–3.3: เราอ่าน sensors.bmi270.motion() แล้วแปลงเป็นมุม ขึ้นจอด้วย ui.Bar บน ui.Scale กับ ui.Seg7 ซึ่งตอบได้ดีว่า “ตอนนี้เท่าไร”
ทบทวนเรื่อง quantization จากบทเรียน 2.7–2.9 ด้วย เพราะวันนี้เราจะเป็นคนสร้างมันเองตอนป้อนกราฟ
ชุดบทเรียน 3.4–3.6 จบที่แล็บกราฟความเร่งสามแกนในบทเรียน 3.6 บทเรียนนี้วางพื้นว่ากราฟนั้นเชื่อถือได้แค่ไหน
- อุปกรณ์: บอร์ด Eva Kit หรือ TESAIoT Dev Kit ที่ลงเฟิร์มแวร์ MicroPython ของ BENTO แล้ว หรือ BENTO Emulator ใน BENTO IDE
- เรียนมาก่อน: บทเรียน 3.3 — ลงมือทำ: เครื่องวัดระดับดิจิทัล
ดูของจริงก่อน
หัวข้อที่มีชื่อว่า “ดูของจริงก่อน”เปิดเมนู Sensor Dashboard บนบอร์ด กราฟ accel สามแกนที่วิ่งอยู่ตรงนั้นมีมาตั้งแต่บทเรียนแรก ลองสามอย่างตามลำดับ: วางนิ่ง เส้น Z ลอยสูงกว่าเพื่อน · เขย่าเบา ๆ รอยกระเพื่อมเลื่อนไปทางซ้าย · เอียงค้าง เส้นยกตัวแล้วค้างที่ระดับใหม่ ชุดบทเรียนนี้เราจะสร้างหน้าแบบนี้ขึ้นเอง บทเรียน 3.1–3.3 วัด “ตอนนี้เอียงกี่องศา” ส่วนชุดนี้เก็บ “สิบวินาทีที่ผ่านมาเป็นยังไง”
ตัวเลขบอกว่าตอนนี้เท่าไร กราฟบอกว่ามันกำลังจะไปทางไหน แถบกับ Seg7 ตอบ “ตอนนี้เอียงกี่องศา” ได้ทันที แต่ตอบไม่ได้เลยว่าเมื่อ 5 วินาทีที่แล้วสั่นไหม การสั่นถี่ขึ้นหรือเบาลง หรือมีค่ากระโดดแวบเดียวหรือเปล่า ข้อมูลที่แต่ละค่ามีเวลากำกับและเรียงตามเวลาเรียกว่า time series คอมพิวเตอร์เก็บสัญญาณต่อเนื่องไม่ได้ มันแอบมองเป็นระยะแล้วจดค่าไว้ (sampling) โดย fs = 1/Ts ลูปของเราหลับ 200 ms จึงได้ราว 5 Hz กราฟบนจอจึงไม่ใช่สัญญาณจริง มันคือจุดที่เราจดไว้แล้วลากเส้นตรงเชื่อมกัน ระหว่างสองจุดเกิดอะไรขึ้น เราไม่มีทางรู้จากกราฟนี้
เงื่อนไข Nyquist บอกว่าจะเห็นคลื่นความถี่ f ได้ ต้องสุ่มเร็วกว่าสองเท่าของมัน (fs > 2f) ที่ fs 5 Hz เราเห็นได้ไม่เกิน 2.5 Hz และอัตราสุ่มของเราไม่ได้ตั้งด้วยฮาร์ดแวร์ แต่เกิดจากความเร็วลูป Python (T_loop = T_sleep + T_work) งานในลูปหนักขึ้นเมื่อไร อัตราสุ่มตกลงเงียบ ๆ จึงต้องวัดคาบลูปจริง สัญญาณที่เร็วเกินไม่ได้หายไป มันปลอมตัวเป็นคลื่นที่ช้ากว่า f_alias = |f − k·fs| เขย่าบอร์ดราว 6 Hz ขณะสุ่ม 5 Hz กราฟจะโชว์คลื่นช้า ๆ 1 Hz ที่ไม่มีอยู่จริง ไม่มี error ไม่มีคำเตือน และดูน่าเชื่อถือด้วย เหตุผลเดียวกับล้อรถในหนังที่ดูเหมือนหมุนถอยหลัง เพราะกล้องสุ่มที่ 24 เฟรมต่อวินาที
ui.Chart เก็บค่าเป็นจำนวนเต็มเท่านั้น chart.set_next(0, ax) ที่ ax เป็น 9.78 จะได้ TypeError ต้องเขียน int(ax)
และ int() ตัดทศนิยมทิ้ง ไม่ใช่ปัดเศษ 0.9 กับ −0.9 กลายเป็น 0 ทั้งคู่ กราฟช่วง ±20 จึงหยาบเป็นขั้นละ 1 m/s²
วิธีแก้ในงานจริงคือ map ช่วงค่าจริงลงช่วงแกนก่อน เช่น ui.Chart(..., min=-2000, max=2000) กับ set_next(0, int(ax * 100))
ได้ความละเอียด 0.01 m/s² โดยไม่แตะเซนเซอร์เลย ตัวเลขบนแกนไม่จำเป็นต้องเป็นหน่วยจริง ขอแค่เรากับคนอ่านรู้ตรงกันว่าคูณอะไรไว้
set_next() ไม่ได้ “วาดกราฟ” Chart คือ ring buffer ค่าใหม่ดันเข้าทางขวา ค่าเก่าที่สุดหล่นหายทางซ้าย ไม่มีใครเก็บให้
ค่าปริยายคือ 50 ช่องต่อ series และกราฟหนึ่งใบมีได้สูงสุด 4 series หน้าต่างเวลาจึงกว้าง 50 × 0.2 s = 10 วินาที
อยากเห็นย้อนหลังนานขึ้นมีสองปุ่ม คือยืดคาบลูป หรือเพิ่มจุดด้วย ch.prop(ui.PROP_CHART_POINTS, n) ตั้งได้ 10–400
(เฟิร์มแวร์ 2026-08-20 ขึ้นไป รุ่นก่อนหน้า 50 ตายตัว) แต่ทุกจุดที่เพิ่มคือข้อความข้ามคอร์และเวลาวาดที่เพิ่มขึ้น การยืดคาบลูปจึงถูกกว่าเสมอ
สุดท้ายคือเหตุผลที่กราฟช้าทั้งที่ลูปเร็ว โค้ด Python อยู่บน CM33 แต่ CM55 เป็นคนวาด set_next() แค่ฝากคำสั่งลงคิว IPC
ฝั่ง CM55 มีตัวจับเวลาสองความเร็ว: ปกติ 200 ms หยิบได้ 16 คำสั่งต่อครั้ง ได้ 80 คำสั่งต่อวินาที โหมดเร่ง 5 ms ได้ 3,200 คำสั่งต่อวินาที
คำสั่งที่ปลุกโหมดเร่งคือการสร้าง widget, .text(), .pos() .size() .color() และคำสั่งของ collection อย่าง .cell() .add_row() .prop()
ส่วน .value() ทุกตัว set_next() และ .show()/.hide() ไม่ปลุก กราฟที่วิ่งอยู่ตัวเดียวบนจอจึงเป็นกรณีที่ช้าที่สุดพอดี
โหมดเร่งค้างอยู่ 500 ms หลังคำสั่งล่าสุด ลูป 200 ms ที่มี lbl_rec.text(rec_msg) ทุกรอบจึงไม่มีวันหลุดโหมดเร่ง
ส่งข้อความเดิมซ้ำได้ เพราะเฟิร์มแวร์ไม่วาดซ้ำถ้าข้อความไม่เปลี่ยน โหมดเร่งไม่ได้ทำให้เซนเซอร์หรือ Python เร็วขึ้น
มันแค่ทำให้คำสั่งที่ส่งไปแล้วถูกวาดออกจอเร็วขึ้น
ตัวอย่างสมบูรณ์
หัวข้อที่มีชื่อว่า “ตัวอย่างสมบูรณ์”03_aliasing_nyquist.py (ราว 15 นาที) ไฟล์นี้ตรึงอัตราสุ่มไว้ที่ 40 Hz (Nyquist 20 Hz) แล้วเปลี่ยนเฉพาะความถี่ของคลื่นจริงทีละขั้น 5, 18, 20, 30, 39 และ 41 Hz
- ทำนาย ก่อนกดเดินหน้า: เขียนลงบันทึกการเรียนว่าแต่ละขั้นเครื่องจะ “เห็น” กี่ Hz ด้วยสูตร |f − k·fs|
- รัน แล้วกดปุ่ม “เดินหน้า >” ทีละขั้น ขั้นแรกเส้นฟ้า (คลื่นจริง) กับเส้นเขียว (ที่เครื่องคิดว่าเห็น) ทับกันสนิท เส้นแดงคือค่าที่ ADC เก็บได้ แตะทั้งสองเส้นที่จุดสุ่มทุกจุด พอเกิน 20 Hz สองเส้นแยกกัน แล้วเทียบตัวเลขบน Seg7 กับที่ทายไว้
- สำรวจ ขั้น 20 Hz ที่อยู่บน Nyquist พอดี กฎคือ fs > 2f ไม่ใช่ fs ≥ 2f ตรงที่เท่ากันอาจสุ่มโดนจุดตัดศูนย์ทุกครั้งแล้วได้เส้นแบน แล้วเปิด serial ดูตารางเก้าแถวที่ไฟล์พิมพ์ไว้ ที่จุดสุ่มทุกจุด sin 30 Hz กับ sin 10 Hz มีขนาดเท่ากัน ต่างกันแค่เครื่องหมาย ข้อมูลที่ต้องใช้แยกสองคลื่นไม่ได้ถูกเก็บมาตั้งแต่แรก aliasing จึงไม่ใช่ noise และกรองทิ้งทีหลังไม่ได้ ทางแก้มีทางเดียวคือ anti-aliasing low-pass filter ก่อนถึง ADC ซึ่งบนบอร์ดนี้คือ C204 ที่ wiper ของ pot (fc ราว 637 Hz)
- ดัดแปลง เพิ่มความถี่ของคุณเองลงใน
FREQSแล้วทายผลก่อนรัน
| ไฟล์ | ไฟล์นี้สอน |
|---|---|
| examples/03_aliasing_nyquist.py | สุ่มช้าเกินไป แล้วได้ความถี่ที่ไม่เคยมีอยู่จริง |
สไลด์ของบทเรียนนี้อ้างถึงไฟล์ที่อยู่ในบทเรียนอื่นด้วย:
ภาพจอจาก BENTO Emulator ของตัวอย่างในบทนี้ (คลิกชื่อไฟล์เพื่อเปิดโค้ด)

03_aliasing_nyquist.py สุ่มช้าเกินไป แล้วได้ความถี่ที่ไม่เคยมีอยู่จริงเช็กความเข้าใจ
หัวข้อที่มีชื่อว่า “เช็กความเข้าใจ”คำถามชุดเดียวกันอยู่ใน quiz.yaml สำหรับระบบที่ตรวจอัตโนมัติ
-
ลูปอ่าน accel ทุก 200 ms (fs = 5 Hz) แล้วคุณเขย่าบอร์ดราว 6 ครั้งต่อวินาที กราฟจะแสดงอะไร (เลือกหนึ่งข้อ · เป้าหมายข้อ 1)
- ก) คลื่นช้า ๆ ราว 1 Hz ที่ไม่มีอยู่จริง โดยไม่มี error หรือคำเตือนใด ๆ
- ข) คลื่น 6 Hz ถูกต้อง แค่เส้นหยาบกว่าปกติ
- ค) เส้นแบนราบ เพราะสัญญาณที่เร็วเกินจะหายไปเฉย ๆ
- ง) ขึ้น error ว่าอัตราสุ่มไม่พอ
เฉลย
ก — f_alias = |6 − 1×5| = 1 Hz สัญญาณที่เร็วเกิน fs/2 ไม่ได้หายไป มันปลอมตัวเป็นคลื่นที่ช้ากว่าความจริง และดูน่าเชื่อถือ ซึ่งอันตรายกว่าการมองไม่เห็น
-
ข้อใดถูกเกี่ยวกับการสุ่มสัญญาณและ aliasing เลือกทุกข้อที่ถูก (เลือกได้หลายข้อ · เป้าหมายข้อ 1)
- ก) กฎคือ fs > 2f ไม่ใช่ fs ≥ 2f ตรงที่เท่ากันพอดีอาจสุ่มโดนจุดตัดศูนย์ทุกครั้งแล้วได้เส้นแบน
- ข) งานในลูปที่หนักขึ้นทำให้อัตราสุ่มของเราตกลงเงียบ ๆ เพราะ fs มาจากความเร็วลูป Python ไม่ได้ตั้งด้วยฮาร์ดแวร์
- ค) ถ้าเกิด aliasing แล้ว ใส่ dsp.EMA หลังการอ่านก็กรองคลื่นปลอมทิ้งได้
- ง) ทางแก้ aliasing คือ anti-aliasing low-pass filter ก่อนถึง ADC เช่น C204 ที่ wiper ของ pot บนบอร์ดนี้
เฉลย
ก, ข, ง — aliasing คือความถี่จริงที่ถูกพับลงมาทับย่านที่เราสนใจตั้งแต่ตอนสุ่ม ที่จุดสุ่มทุกจุดคลื่นปลอมกับคลื่นจริงให้ข้อมูลที่แยกกันไม่ได้ ตัวกรองหลังการอ่านจึงช่วยไม่ได้ ต้องกรองก่อนถึง ADC
-
กราฟความเร่งตั้งช่วง ±20 และป้อน int(ax) ได้เส้นหยาบเป็นขั้นละ 1 m/s² ถ้าต้องการความละเอียด 0.01 m/s² ควรทำอย่างไร (เลือกหนึ่งข้อ · เป้าหมายข้อ 2)
- ก) สร้างกราฟด้วย min=-2000, max=2000 แล้วป้อน chart.set_next(0, int(ax * 100))
- ข) ป้อน chart.set_next(0, ax) ตรง ๆ เพื่อเก็บทศนิยมไว้
- ค) ป้อน chart.set_next(0, round(ax, 2))
- ง) คงช่วง ±20 ไว้แล้วป้อน int(ax * 100)
เฉลย
ก — Chart เก็บเฉพาะจำนวนเต็ม ส่ง float ได้ TypeError และ int() ตัดทศนิยมทิ้ง จึงต้องคูณค่าแล้วขยายช่วงแกนตามกัน ถ้าคูณ 100 แต่คงช่วง ±20 เส้นจะทะลุขอบ
-
กราฟใช้ค่าปริยาย 50 ช่อง และลูปหมุนทุก 200 ms หน้าจอแสดงย้อนหลังได้กี่วินาที และถ้าอยากเห็นนานขึ้น ทางไหนถูกกว่า (เลือกหนึ่งข้อ · เป้าหมายข้อ 3)
- ก) 10 วินาที · ยืดคาบลูปให้ห่างขึ้นถูกกว่าการเพิ่มจำนวนจุด
- ข) 10 วินาที · เพิ่มจุดเป็น 400 ด้วย PROP_CHART_POINTS ถูกกว่าเสมอ
- ค) 50 วินาที · ไม่ต้องทำอะไรเพิ่ม
- ง) ไม่จำกัด เพราะกราฟเก็บทุกค่าที่เคยป้อนไว้
เฉลย
ก — T_window = 50 × 0.2 s = 10 s ค่าที่เก่ากว่านั้นหล่นหายจาก ring buffer การเพิ่มจุดทำได้ (10–400 บนเฟิร์มแวร์ 2026-08-20 ขึ้นไป) แต่ทุกจุดคือข้อความข้ามคอร์และเวลาวาดที่เพิ่มขึ้น
-
ลูปของคุณมีแค่ set_next() สามเส้นกับ led.value() แล้วกราฟกระตุกเหมือนวาดไม่ทัน ทางแก้ที่ถูกคืออะไร (เลือกหนึ่งข้อ · เป้าหมายข้อ 4)
- ก) เพิ่ม lbl_rec.text(rec_msg) ทุกรอบ ส่งข้อความเดิมซ้ำก็ได้ เพื่อปลุกโหมดเร่งของตัวจับเวลาฝั่ง CM55
- ข) เรียก led.value() ถี่ขึ้น เพื่อปลุกฝั่งจอ
- ค) ลด sleep_ms ให้ลูป Python หมุนเร็วขึ้น
- ง) อ่านเซนเซอร์ให้เร็วขึ้น เพราะกราฟรอค่าจากเซนเซอร์
เฉลย
ก — set_next() และ .value() ไม่ปลุกโหมดเร่ง ฝั่ง CM55 จึงระบายคำสั่งแค่ 80 ต่อวินาที .text() ปลุกโหมดเร่ง (3,200 ต่อวินาที) และค้างไว้ 500 ms ลูป 200 ms จึงไม่หลุดโหมดเลย ส่วนข้อความที่ไม่เปลี่ยน เฟิร์มแวร์ไม่วาดซ้ำ
บทเรียน 3.5 ลงมือกับ ui.Chart หลาย series และวัดคาบเวลาของลูปจริงด้วย time.ticks_ms() กับ time.ticks_diff() เพื่อพิสูจน์ว่าลูปของเราสุ่มที่ 5 Hz จริงอย่างที่คิด
บทเรียนถัดไป: บทเรียน 3.5 — ui.Chart: กราฟหลาย series และคาบเวลาของลูปจริง
สะท้อนคิด
หัวข้อที่มีชื่อว่า “สะท้อนคิด”- สัญญาณในงานของคุณเร็วแค่ไหน และลูป 200 ms เร็วพอสำหรับมันหรือเปล่า
- ถ้ากราฟโชว์คลื่นช้า ๆ ที่ดูสมเหตุสมผล คุณจะพิสูจน์อย่างไรว่ามันไม่ใช่คลื่นปลอม
- ถ้าต้องเห็นย้อนหลัง 30 วินาที คุณจะหมุนปุ่มไหน และเสียอะไรไปบ้าง
คำถามทบทวน
ลองตอบเองก่อน แล้วค่อยเปิดดูเฉลย
-
ลูปอ่าน accel ทุก 200 ms (fs = 5 Hz) แล้วคุณเขย่าบอร์ดราว 6 ครั้งต่อวินาที กราฟจะแสดงอะไร (เป้าหมายข้อ 1)
- คลื่นช้า ๆ ราว 1 Hz ที่ไม่มีอยู่จริง โดยไม่มี error หรือคำเตือนใด ๆ
- คลื่น 6 Hz ถูกต้อง แค่เส้นหยาบกว่าปกติ
- เส้นแบนราบ เพราะสัญญาณที่เร็วเกินจะหายไปเฉย ๆ
- ขึ้น error ว่าอัตราสุ่มไม่พอ
ดูเฉลย
คำตอบ: A. คลื่นช้า ๆ ราว 1 Hz ที่ไม่มีอยู่จริง โดยไม่มี error หรือคำเตือนใด ๆ
f_alias = |6 − 1×5| = 1 Hz สัญญาณที่เร็วเกิน fs/2 ไม่ได้หายไป มันปลอมตัวเป็นคลื่นที่ช้ากว่าความจริง และดูน่าเชื่อถือ ซึ่งอันตรายกว่าการมองไม่เห็น
-
ข้อใดถูกเกี่ยวกับการสุ่มสัญญาณและ aliasing เลือกทุกข้อที่ถูก (เป้าหมายข้อ 1)
- กฎคือ fs > 2f ไม่ใช่ fs ≥ 2f ตรงที่เท่ากันพอดีอาจสุ่มโดนจุดตัดศูนย์ทุกครั้งแล้วได้เส้นแบน
- งานในลูปที่หนักขึ้นทำให้อัตราสุ่มของเราตกลงเงียบ ๆ เพราะ fs มาจากความเร็วลูป Python ไม่ได้ตั้งด้วยฮาร์ดแวร์
- ถ้าเกิด aliasing แล้ว ใส่ dsp.EMA หลังการอ่านก็กรองคลื่นปลอมทิ้งได้
- ทางแก้ aliasing คือ anti-aliasing low-pass filter ก่อนถึง ADC เช่น C204 ที่ wiper ของ pot บนบอร์ดนี้
ดูเฉลย
คำตอบ: A. กฎคือ fs > 2f ไม่ใช่ fs ≥ 2f ตรงที่เท่ากันพอดีอาจสุ่มโดนจุดตัดศูนย์ทุกครั้งแล้วได้เส้นแบน · B. งานในลูปที่หนักขึ้นทำให้อัตราสุ่มของเราตกลงเงียบ ๆ เพราะ fs มาจากความเร็วลูป Python ไม่ได้ตั้งด้วยฮาร์ดแวร์ · D. ทางแก้ aliasing คือ anti-aliasing low-pass filter ก่อนถึง ADC เช่น C204 ที่ wiper ของ pot บนบอร์ดนี้
aliasing คือความถี่จริงที่ถูกพับลงมาทับย่านที่เราสนใจตั้งแต่ตอนสุ่ม ที่จุดสุ่มทุกจุดคลื่นปลอมกับคลื่นจริงให้ข้อมูลที่แยกกันไม่ได้ ตัวกรองหลังการอ่านจึงช่วยไม่ได้ ต้องกรองก่อนถึง ADC
-
กราฟความเร่งตั้งช่วง ±20 และป้อน int(ax) ได้เส้นหยาบเป็นขั้นละ 1 m/s² ถ้าต้องการความละเอียด 0.01 m/s² ควรทำอย่างไร (เป้าหมายข้อ 2)
- สร้างกราฟด้วย min=-2000, max=2000 แล้วป้อน chart.set_next(0, int(ax * 100))
- ป้อน chart.set_next(0, ax) ตรง ๆ เพื่อเก็บทศนิยมไว้
- ป้อน chart.set_next(0, round(ax, 2))
- คงช่วง ±20 ไว้แล้วป้อน int(ax * 100)
ดูเฉลย
คำตอบ: A. สร้างกราฟด้วย min=-2000, max=2000 แล้วป้อน chart.set_next(0, int(ax * 100))
Chart เก็บเฉพาะจำนวนเต็ม ส่ง float ได้ TypeError และ int() ตัดทศนิยมทิ้ง จึงต้องคูณค่าแล้วขยายช่วงแกนตามกัน ถ้าคูณ 100 แต่คงช่วง ±20 เส้นจะทะลุขอบ
-
กราฟใช้ค่าปริยาย 50 ช่อง และลูปหมุนทุก 200 ms หน้าจอแสดงย้อนหลังได้กี่วินาที และถ้าอยากเห็นนานขึ้น ทางไหนถูกกว่า (เป้าหมายข้อ 3)
- 10 วินาที · ยืดคาบลูปให้ห่างขึ้นถูกกว่าการเพิ่มจำนวนจุด
- 10 วินาที · เพิ่มจุดเป็น 400 ด้วย PROP_CHART_POINTS ถูกกว่าเสมอ
- 50 วินาที · ไม่ต้องทำอะไรเพิ่ม
- ไม่จำกัด เพราะกราฟเก็บทุกค่าที่เคยป้อนไว้
ดูเฉลย
คำตอบ: A. 10 วินาที · ยืดคาบลูปให้ห่างขึ้นถูกกว่าการเพิ่มจำนวนจุด
T_window = 50 × 0.2 s = 10 s ค่าที่เก่ากว่านั้นหล่นหายจาก ring buffer การเพิ่มจุดทำได้ (10–400 บนเฟิร์มแวร์ 2026-08-20 ขึ้นไป) แต่ทุกจุดคือข้อความข้ามคอร์และเวลาวาดที่เพิ่มขึ้น
-
ลูปของคุณมีแค่ set_next() สามเส้นกับ led.value() แล้วกราฟกระตุกเหมือนวาดไม่ทัน ทางแก้ที่ถูกคืออะไร (เป้าหมายข้อ 4)
- เพิ่ม lbl_rec.text(rec_msg) ทุกรอบ ส่งข้อความเดิมซ้ำก็ได้ เพื่อปลุกโหมดเร่งของตัวจับเวลาฝั่ง CM55
- เรียก led.value() ถี่ขึ้น เพื่อปลุกฝั่งจอ
- ลด sleep_ms ให้ลูป Python หมุนเร็วขึ้น
- อ่านเซนเซอร์ให้เร็วขึ้น เพราะกราฟรอค่าจากเซนเซอร์
ดูเฉลย
คำตอบ: A. เพิ่ม lbl_rec.text(rec_msg) ทุกรอบ ส่งข้อความเดิมซ้ำก็ได้ เพื่อปลุกโหมดเร่งของตัวจับเวลาฝั่ง CM55
set_next() และ .value() ไม่ปลุกโหมดเร่ง ฝั่ง CM55 จึงระบายคำสั่งแค่ 80 ต่อวินาที .text() ปลุกโหมดเร่ง (3,200 ต่อวินาที) และค้างไว้ 500 ms ลูป 200 ms จึงไม่หลุดโหมดเลย ส่วนข้อความที่ไม่เปลี่ยน เฟิร์มแวร์ไม่วาดซ้ำ
อ้างอิงบทเรียนนี้
ถ้านำบทเรียนนี้ไปสอน ทำสไลด์ หรือทำเอกสารต่อ ให้อ้างอิงด้วยข้อความนี้ ถ้าดัดแปลงเนื้อหา ให้เติม (ดัดแปลง)ต่อท้ายชื่อบทเรียน
"สุ่มสัญญาณให้ถูก: Nyquist aliasing และ ring buffer" จาก TESA Open Knowledge โดยสมาคมสมองกลฝังตัวไทย (Thai Embedded Systems Association: TESA) https://github.com/tesaiot/tesa-qualification-program สัญญาอนุญาต CC BY-NC 4.0
ข้อความอ้างอิงภาษาอังกฤษ: "Sampling right: Nyquist, aliasing and the ring buffer" 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/aiot-micropython/m03-sensor-hmi/l04-sampling/
บทเรียนนี้ดัดแปลงจากต้นฉบับด้านล่าง เมื่ออ้างอิงให้คงเครดิตต้นฉบับไว้ด้วย
https://github.com/Advance-Innovation-Centre-AIC/embedded-systems-for-aiot-developer/blob/a80bbe88a34bcb9bb8d991f42f9252b77cdab079/session-07.html (slides 1–14)
TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · CC BY-NC 4.0
เนื้อหาเผยแพร่ภายใต้ CC BY-NC 4.0 นำไปใช้ต่อในงานที่ไม่ใช่เพื่อการค้าได้ โปรดอ้างอิงสมาคมสมองกลฝังตัวไทย (TESA) ทุกครั้ง · วิธีอ้างอิง TESA