วันนี้เป็นชุดบทเรียนที่สามของ Analysis (Pillar 3) — ขั้นที่ 3 ของวงจรชีวิตข้อมูล เป็นจุดที่สัญญาณกลายเป็น "สิ่งที่โมเดลกินได้"
บทเรียน 4.1–4.2 เราขัดสัญญาณให้สะอาด (filter) · บทเรียน 4.3–4.4 เราแปลงไปโดเมนความถี่ (FFT) · วันนี้ บทเรียน 4.5–4.6 เราเอาสองอันนั้นมาบีบเป็น feature vector ที่โมเดลใช้จริง
จบชุดบทเรียนนี้เราจะเดินครบ 4 เรื่อง แล้วปิดท้ายด้วยการทำ feature front-end ด้วยมือเอง:
ปลายทางของวันนี้: จากสัญญาณ IMU ดิบ 50 จุด สร้าง feature vector 6 ตัวที่ เปลี่ยนตามการเคลื่อนไหวจริง ขึ้นจอ
วันนี้เราไม่ฝึกโมเดลนะ เราสร้าง "สิ่งที่โมเดลจะเห็น" ต่างหาก — พอถึงบทเรียน Training (บทเรียน 5.1–5.2) คุณจะเก็บ feature vector พวกนี้เป็น dataset จริง
ลองนึกถึงเสียง "ไอ" หนึ่งครั้ง หรือท่า "เขย่า" หนึ่งที — มันไม่ใช่ค่า ณ จุดเดียว มันคือ รูปร่างของสัญญาณช่วงเวลาหนึ่ง
นี่คือหลักเดียวกับหูคน: เราแยก "เสียงไอ" กับ "เสียงพูด" ไม่ได้จากคลื่นเสียง 1/1000 วินาที ต้องฟังทั้งช่วงถึงจะรู้ โมเดลก็เหมือนกัน
หน้าต่างเลื่อนทีละก้าว (stride) บีบ sample หลายจุดให้เป็น feature หนึ่งชุดที่โมเดลกินได้
Windowing คือการตัดสัญญาณที่ไหลมาเรื่อย ๆ ให้เป็นก้อนความยาวคงที่ (WIN จุด) ทีละก้อน แล้วประมวลผลทีละหน้าต่าง
WIN = 50 — ยาวหนึ่งหน้าต่าง (1 วินาทีที่ 50 Hz)HOP = 25 — เลื่อนหน้าต่างทีละ 25 จุด (ครึ่งหนึ่งของ WIN)ค่าพวกนี้ไม่ได้ตั้งมั่ว โมเดลถูกฝึกมาด้วยขนาดหน้าต่างเท่าไร ตอนใช้งานจริงก็ต้อง feed หน้าต่างขนาดเดียวกัน ไม่งั้น "สิ่งที่โมเดลเห็น" จะไม่ตรงกับตอนฝึก
ถ้าตัดหน้าต่างชนกันพอดี (hop = win) เหตุการณ์สั้น ๆ อาจตกร่องระหว่างหน้าต่างพอดีจนพลาด — การซ้อนช่วยไม่ให้พลาด
hop เล็ก = ตอบไว แต่เปลือง · hop ใหญ่ = ประหยัด แต่ตอบช้าและอาจพลาด — เราเลือก 50% เป็นค่ากลางที่โมเดลเสียง/IMU ส่วนใหญ่ใช้
หน้าต่างหนึ่งมี 50 จุด แต่เราไม่ได้ป้อน 50 จุดนั้นตรง ๆ เข้าโมเดล เราบีบมันเป็น feature vector สั้น ๆ ที่สรุป "ลักษณะเด่น" ของหน้าต่างไว้
"โมเดลดีแค่ไหน ขึ้นกับ feature ที่ป้อนมันมากพอ ๆ กับตัวโมเดลเอง" — วิศวกร Edge AI ใช้เวลากับ feature front-end นี้เยอะกว่าที่คนคิด
ตัวอย่างวันนี้บีบหนึ่งหน้าต่าง (แกน Z ของ accel) เป็น 6 ตัว สองกลุ่ม:
| feature | สูตร (ในโค้ด) | บอกอะไร |
|---|---|---|
mean |
sum(win)/n |
ระดับ DC / ทิศแรงโน้มถ่วงของแกนนี้ |
std |
sqrt(Σ(x-mean)²/n) |
ความแรงของการสั่น — นิ่ง=ต่ำ เขย่า=สูง |
band0..3 |
variance ของแต่ละช่วงเวลา | การสั่นกระจุกอยู่ต้น/กลาง/ท้ายหน้าต่าง |
mean กับ std เป็น feature เชิงสถิติ ของทั้งหน้าต่าง — เบา คำนวณเร็ว แต่ทรงพลังband0..3 แบ่งหน้าต่างเป็น 4 ช่วงเวลาแล้ววัด variance แต่ละช่วง — จับ "รูปร่างตามเวลา" ได้หยาบ ๆ
stdตัวเดียวแยก "นิ่ง/ขยับ" ได้เกือบหมดแล้ว — ในฉบับเต็มเราเอาstdมาตัดสิน "นิ่ง/ขยับ" ตรง ๆ เป็นตัวอย่างของ "การจำแนกคลาสเวอร์ชันมือทำ"
std (ส่วนเบี่ยงเบนมาตรฐาน) วัดว่าสัญญาณ "แกว่ง" ห่างจากค่าเฉลี่ยแค่ไหน — มันคือรากของ variance ที่เราเจอมาตั้งแต่โมดูล 3 (Processing)
std เล็กstd ใหญ่จำ variance จากบทเรียน Processing (บทเรียน 3.1–3.2) ได้ไหม — วันนี้เราเอามันกลับมาใช้เป็น feature โดยตรง แนวคิดเก่าไม่เคยหายไป มันแค่เปลี่ยนบทบาท
band0..3 แบ่งหน้าต่างเป็น 4 ช่วงเวลา แล้ววัดพลังงาน (variance) แต่ละช่วง — จับได้ว่าการสั่นแรงตอนไหนของหน้าต่าง
band0 แรง, band3 เบาในโลกจริงของ เสียง เราไม่แบ่งตามเวลาอย่างเดียว เราแบ่งตาม ความถี่ (เอา FFT จาก บทเรียน 4.3–4.4 มาจัดเป็นย่าน) — นั่นแหละคือ mel spectrogram ที่หน้าถัดไปจะเล่า
โมเดลเสียงบนบอร์ด (Baby Cry, Cough, Alarm, Siren) ไม่ได้กินคลื่นเสียงดิบ มันกิน spectrogram — ภาพความถี่ต่อเวลา
วันนี้เราทำเวอร์ชัน IMU ที่เห็นด้วยตาง่ายกว่า แต่พอเข้าใจ "window → feature" แล้ว spectrogram ของเสียงก็คือเรื่องเดียวกัน แค่ย่านเป็นความถี่
ก่อนเอาหน้าต่างไปทำ FFT เราไม่ตัดขอบตรง ๆ แต่ค่อย ๆ ลดขอบให้เรียบ ด้วยตัวคูณรูประฆังที่ชื่อ Hann window:
อ่านสัญลักษณ์ทีละตัวแบบง่าย ๆ:
WIN = 50)ค่าที่ได้: ขอบซ้าย · กลางหน้าต่าง · ขอบขวา — เหมือนกดเสียงให้เบาลงตอนต้นและปลาย
ทำไมสำคัญกับชุดบทเรียนนี้: ตอนตัดหน้าต่างแข็ง ๆ ขอบที่ขาดกระทันหันจะสร้างความถี่ปลอมใน FFT (เรียก spectral leakage) พอคูณ Hann ให้ขอบค่อย ๆ จางลง สเปกตรัมสะอาดขึ้น — mel spectrogram ของเสียงทุกตัวบนบอร์ดใช้ trick นี้ก่อนทำ FFT เสมอ
รวมทุกอย่างในหน้าที่แล้วเป็นสูตรเดียว คือสิ่งที่โมเดลเสียง "เห็น" จริง ๆ:
ไล่จากในสุดออกมานอกสุด — อ่านเหมือนสายพาน:
ทำไมสำคัญกับชุดบทเรียนนี้:
band0..3ที่เราทำวันนี้คือรุ่นย่อของสูตรนี้ — เราแบ่งเป็นย่านเวลาและวัด variance ส่วนเสียงแบ่งเป็นย่านความถี่ (Mel) แล้วใส่ log แค่นั้น โครงwindow → transform → รวมย่านอันเดียวกันเป๊ะ
จับใจความสำคัญที่สุดของชุดบทเรียนนี้ให้แน่น:
เพราะฉะนั้นการเข้าใจ feature front-end จึงสำคัญพอ ๆ กับตัวโมเดล — ชุดบทเรียนนี้คือรากฐานที่ทำให้โมดูล 5 (Training) ไม่ใช่กล่องดำ
ไฟล์ตัวอย่างใช้ของที่เราคุ้นแล้ว บวก math เข้ามาช่วยคำนวณ:
| คำสั่ง | ทำอะไร |
|---|---|
sensors.bmi270.motion() |
คืน (ax,ay,az,gx,gy,gz) — เราใช้ az เป็นสัญญาณ |
math.sqrt(x) |
รากที่สอง (สำหรับ std) |
ui.Bar(...) / .value(v) |
แท่งแสดงค่า feature แต่ละตัว |
ui.Label(...) / .text(s) |
ป้ายชื่อ feature + ตัวนับหน้าต่าง |
lcd.console(...) |
พิมพ์ feature vector เป็นข้อความ (ดูค่าจริง) |
time.sleep_ms(20) |
เว้นจังหวะให้ได้อัตราสุ่ม 50 Hz |
sensors.bmi270.motion()คืน 6 ค่า เราแตกเป็นax,ay,az,gx,gy,gzแล้วหยิบแค่azมาทำสัญญาณตัวอย่าง — แกนอื่นทำแบบเดียวกันได้หมด