บทเรียน 4.3 — FFT และโดเมนความถี่: bin, Nyquist, DC, leakage และ Hann window

อ่านสเปกตรัมของสัญญาณจริง

โมดูล 4 — วิเคราะห์สัญญาณ

Pillar 3 — Analysis (วิเคราะห์สัญญาณ)

คาถาประจำบทเรียน: "สัญญาณเดียวกัน มองได้สองแบบ — คลื่นดิบในโดเมนเวลา กับสเปกตรัมในโดเมนความถี่ และโมเดลเสียงมองแบบหลัง"

MicroPython บนบอร์ด BENTO (PSoC Edge · Cortex-M55 + Ethos-U55 NPU)

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก Edge AI Developer (รศ.วิรุฬห์ ศรีบริรักษ์, BUU) · CC BY-NC 4.0

เปิดบทเรียนด้วยของจริงก่อน

เหมือนทุกบทเรียน เราเริ่มแบบ กลับด้าน — รันของที่ทำงานได้ก่อน แล้วค่อยแกะว่าทำไม วันนี้ของจริงคือ สเปกตรัมสด: เขย่าบอร์ด แล้วดูพลังงานความถี่ขยับบนจอ

รันสเปกตรัมก่อน เขย่าแล้วดูแท่งขยับ แกะดูข้างใน FFT ทำอะไร เติม/แก้เอง pipeline 4 ขั้น อยากต่อยอด feature เสียง 4.5–4.6

เราใช้แนว PRIMM เหมือนเดิม (Predict–Run–Investigate–Modify–Make) — เห็นสเปกตรัมขยับก่อน แล้วจะสงสัยเองว่า "ตัวเลขพวกนี้มาจากไหน" นั่นแหละคือแรงจูงใจที่ดีที่สุด

ชุดบทเรียนนี้ไม่ต้องเข้าใจ FFT ทุกบรรทัดในทีเดียว ขอแค่เขย่าบอร์ดแล้วเห็น "พลังงานย้ายความถี่" ตามจังหวะ แล้วเริ่มอยากรู้ว่ามันรู้ได้ยังไง

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก Edge AI Developer (รศ.วิรุฬห์ ศรีบริรักษ์, BUU) · CC BY-NC 4.0

เป้าหมายของชุดบทเรียนนี้

จบชุดบทเรียนนี้เราจะเดินครบ แล้วปิดท้ายด้วยการรันสเปกตรัมสด:

  1. โดเมนเวลา vs โดเมนความถี่ — สัญญาณเดียวกัน สองมุมมอง มุมไหนบอกอะไร
  2. FFT คืออะไร — แปลงคลื่นดิบ N จุด เป็นขนาดของแต่ละความถี่ (ไม่ใช่กล่องดำ)
  3. สองศัตรูของสเปกตรัม — DC/แรงโน้มถ่วง (bin 0) กับ spectral leakage และวิธีจัดการ (ตัดค่าเฉลี่ย + Hann window)
  4. bin ความถี่ + Nyquist — FS/N คุมความละเอียด, FS/2 คือเพดานความถี่
  5. ลงมือ: เติม pipeline 4 ขั้น อ่านสเปกตรัมสดจาก IMU ด้วยตาตัวเอง

ปลายทางของวันนี้: เขย่าบอร์ด แล้วแท่งสเปกตรัมขึ้น พร้อมความถี่เด่น (peak) ที่เปลี่ยนตามจังหวะที่เขย่าเร็ว-ช้า

วันนี้เราเน้น "เห็นสเปกตรัม + อ่าน peak เป็น" — ส่วน mel-spectrogram ที่โมเดลเสียงใช้จริง เก็บไว้ต่อยอดในบทเรียน 4.5–4.6

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก Edge AI Developer (รศ.วิรุฬห์ ศรีบริรักษ์, BUU) · CC BY-NC 4.0

ชุดบทเรียนนี้อยู่ตรงไหนของวงจร

เราอยู่ Pillar 3 (Analysis) — ขั้นที่เปลี่ยนสัญญาณดิบให้กลายเป็น "สิ่งที่โมเดลเห็นจริง" บทเรียน 4.1–4.2 เราทำ filter ในโดเมนเวลา วันนี้เปิดมุมมองใหม่: โดเมนความถี่

1 · DAQ โมดูล 2 2 · Processing โมดูล 3 3 · Analysis (เราอยู่นี่) 4.1–4.2 filter · 4.3–4.4 FFT · 4.5–4.6 feature วันนี้ = 4.3–4.4 4 · Training โมดูล 5 5 · Apps โมดูล 6

ทำไม Analysis ถึงสำคัญกับ Edge AI: โมเดลไม่ได้ฉลาดกว่าสิ่งที่มันเห็น ถ้า feature ที่ป้อนเข้าไปดี โมเดลเล็ก ๆ ก็แม่นได้ FFT คือหนึ่งในเครื่องมือหลักที่ทำให้ feature เสียง/การสั่นสะเทือน "อ่านง่าย" สำหรับโมเดล

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก Edge AI Developer (รศ.วิรุฬห์ ศรีบริรักษ์, BUU) · CC BY-NC 4.0

โดเมนเวลา vs โดเมนความถี่

สัญญาณคลื่นเดียวกัน มองได้สองแบบ ทั้งสองถูกต้อง แต่บอกคนละเรื่อง:

โดเมนเวลา (time domain) แกน X = เวลา · แกน Y = ค่าที่วัดได้ "ตอนไหนสูงตอนไหนต่ำ" — แต่ดูยากว่าความถี่เท่าไร โดเมนความถี่ (frequency domain) แกน X = ความถี่ · แกน Y = ความแรงของความถี่นั้น "ความถี่ไหนแรง" — เห็นทันทีว่ามี 1 ยอดเด่น

ลองนึกถึงเสียงเปียโน: โดเมนเวลาคือ "คลื่นความดันอากาศที่สั่น" ส่วนโดเมนความถี่คือ "โน้ตอะไรถูกกด" — หูเราชอบคิดแบบหลัง และโมเดลเสียงก็เช่นกัน

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก Edge AI Developer (รศ.วิรุฬห์ ศรีบริรักษ์, BUU) · CC BY-NC 4.0

ทำไมโมเดลเสียงดูสเปกตรัม ไม่ดูคลื่นดิบ

คลื่นเสียงดิบเปลี่ยนเร็วมากและ "หน้าตา" ต่างกันทุกครั้งแม้จะเป็นเสียงเดียวกัน แต่ สเปกตรัม ของมันคงรูปกว่ามาก

  • เสียงไอสองครั้งไม่มีทางเหมือนกันเป๊ะในโดเมนเวลา แต่ การกระจายพลังงานตามความถี่ คล้ายกัน — โมเดลจับตรงนี้ได้ง่ายกว่า
  • สเปกตรัมบีบข้อมูลให้สั้นลง: คลื่นดิบ 16000 จุด/วินาที กลายเป็นสเปกตรัมไม่กี่สิบค่า — โมเดลเล็กลง เร็วขึ้น
  • ความถี่มีความหมายทางกายภาพ: เสียงสูง/ต่ำ, การสั่นเร็ว/ช้า — เป็น feature ที่ "อ่านออก" ทั้งกับคนและโมเดล

นี่คือเหตุผลที่ front-end ของโมเดลเสียงเกือบทุกตัว เริ่มด้วย FFT (แล้วต่อด้วย mel/log ในบทเรียน 4.5–4.6) — เราไม่ได้ส่งคลื่นดิบเข้าโมเดลตรง ๆ เราส่ง "ภาพความถี่" ของมัน

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก Edge AI Developer (รศ.วิรุฬห์ ศรีบริรักษ์, BUU) · CC BY-NC 4.0

สัญญาณคือผลรวมของไซน์หลายความถี่

หัวใจของ Fourier: สัญญาณไหน ๆ ก็เขียนเป็นผลบวกของคลื่นไซน์/โคไซน์ที่ความถี่ต่าง ๆ ได้ FFT แค่ถามกลับว่า "ในสัญญาณนี้ มีไซน์ความถี่ไหนบ้าง แต่ละอันแรงแค่ไหน"

ไซน์ความถี่ต่ำ + ไซน์ความถี่สูง = สัญญาณจริง (ดูยุ่ง) FFT ทำงานย้อนกลับ: จากสัญญาณจริง แยกกลับเป็นไซน์แต่ละความถี่ ผลลัพธ์ = สเปกตรัม: แท่งสูง = ความถี่นั้นมีอยู่มาก

พูดง่าย ๆ: FFT คือ "เครื่องแยกส่วนผสม" ของสัญญาณ ป้อนคลื่นที่ดูยุ่ง ๆ เข้าไป มันบอกกลับว่า "จริง ๆ แล้วเธอประกอบจากไซน์ความถี่พวกนี้ ในสัดส่วนนี้"

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก Edge AI Developer (รศ.วิรุฬห์ ศรีบริรักษ์, BUU) · CC BY-NC 4.0

ภาพเคลื่อนไหว — FFT: โดเมนเวลา → โดเมนความถี่

ภาพเคลื่อนไหว: คลื่นผสมในโดเมนเวลาผ่าน FFT แล้วกลายเป็นแท่งสเปกตรัมในโดเมนความถี่

▸ ลองเล่นสด (GeoGebra): เปิด Interactive Math Lab — ลากจุด/เลื่อนสไลเดอร์ดูสมการขยับตาม

คลื่นผสมทางซ้ายถูกแยกเป็นแท่งความถี่ทางขวา — แท่งที่เด่นคือความถี่หลักที่ซ่อนอยู่

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก Edge AI Developer (รศ.วิรุฬห์ ศรีบริรักษ์, BUU) · CC BY-NC 4.0

FFT — จากคลื่นดิบ สู่สเปกตรัม

FFT (Fast Fourier Transform) รับสัญญาณ N จุดในโดเมนเวลา แล้วคืน N ค่าเชิงซ้อนในโดเมนความถี่ — หนึ่งค่าต่อหนึ่ง "bin" ความถี่

input: N จุด (เวลา) accel Z ที่สุ่มมา N ค่า fft(re, im) radix-2 Cooley-Tukey output: N ค่าเชิงซ้อน re[k] + i·im[k] ต่อ bin ใช้จริงแค่ครึ่งแรก (ความถี่บวก) "ดูยาก" "อ่านออก: ความถี่ไหนแรง"
  • ทำไมต้อง N เป็นเลขยกกำลัง 2 (เช่น 32, 64, 128)? เพราะ radix-2 แบ่งครึ่งซ้ำ ๆ ได้ลงตัว ทำให้เร็ว — เวลา N log N แทนที่จะเป็น N² แบบคำนวณตรง ๆ (นี่คือที่มาของคำว่า "Fast")
  • ผลลัพธ์เป็นเลขเชิงซ้อน re[k] + i·im[k] เดี๋ยวเราจะแปลงเป็น "ขนาด" ให้อ่านง่าย

ในไฟล์ฝึก ฟังก์ชัน fft() เขียนไว้ให้ครบแล้ว (เหมือน models() ในบทเรียน 1.1–1.3 ที่ให้มา) เราไม่ต้องแก้ตัว FFT แต่ควรอ่านให้เห็นว่ามันเป็นแค่การบวก-คูณเป็นระเบียบ ไม่ใช่เวทมนตร์

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก Edge AI Developer (รศ.วิรุฬห์ ศรีบริรักษ์, BUU) · CC BY-NC 4.0

คณิตเบื้องหลัง FFT — สูตร DFT ในหนึ่งบรรทัด

FFT เป็นแค่วิธีคำนวณ เร็ว ของสูตรตั้งต้นที่ชื่อ DFT (Discrete Fourier Transform) หน้าตาแบบนี้:

X[k]=∑n=0N−1x[n]  e−j 2πkn/NX[k]=\sum_{n=0}^{N-1} x[n]\;e^{-j\,2\pi k n / N}

อ่านทีละสัญลักษณ์แบบภาษาคน — ไม่ต้องจำ แค่รู้ว่าตัวไหนคืออะไร:

  • x[n]x[n] = สัญญาณดิบจุดที่ nn (คือ az ที่เราเก็บใส่ buf)
  • NN = จำนวนจุดในหน้าต่าง (ชุดบทเรียนนี้ใช้ 32)
  • kk = หมายเลข bin ความถี่ (0, 1, 2, … , N−1N-1)
  • X[k]X[k] = เลขเชิงซ้อน re[k] + i·im[k] บอกว่า "ความถี่ของ bin kk มีอยู่แรงแค่ไหน"
  • e−j 2πkn/Ne^{-j\,2\pi k n / N} = คลื่นอ้างอิงความถี่ kk ที่เอาไป "เทียบ" กับสัญญาณของเรา
สัญญาณ x[n] (N จุด) คลื่นดิบในโดเมนเวลา เทียบกับคลื่นอ้างอิง คูณ + บวก ตามสูตร DFT ทำซ้ำทุกค่า k X[k] ต่อทุก bin "ความถี่ไหนแรง" อ่านออก

ทำไมสำคัญกับชุดบทเรียนนี้: สูตรนี้คือสิ่งที่ฟังก์ชัน fft() ในไฟล์ฝึกทำให้เราแบบเร็ว ๆ เราไม่ต้องคำนวณเอง แต่พอเห็นว่ามันคือ "คูณคลื่นอ้างอิงแล้วบวก" ก็จะเลิกกลัวว่ามันเป็นกล่องดำ — มันคือเลขคณิตเป็นระเบียบเท่านั้น

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก Edge AI Developer (รศ.วิรุฬห์ ศรีบริรักษ์, BUU) · CC BY-NC 4.0

แต่ละ bin คือหนึ่งความถี่ — แปลงเป็น Hz

X[k] ให้ค่ามาเป็น "หมายเลข bin" (kk) ยังไม่ใช่ Hz ที่คนอ่านออก สูตรแปลงกลับสั้นนิดเดียว:

fk=k FSNf_k = \frac{k\,F_S}{N}

  • FSF_S = อัตราสุ่ม (ชุดบทเรียนนี้ FS=50F_S = 50 Hz), N=32N = 32 → หนึ่ง bin กว้าง FS/N=1.5625F_S/N = 1.5625 Hz
  • ลองแทนค่าจริง ให้เห็นภาพ:
bin kk fk=k FS/Nf_k = k\,F_S/N หมายความว่า
0 00 Hz DC / แรงโน้มถ่วง (ตัวที่เราตัดทิ้ง)
1 1.561.56 Hz เขย่าช้ามาก ~1-2 ครั้ง/วินาที
3 4.694.69 Hz เขย่าปานกลาง
4 6.256.25 Hz ตรงกับไซน์ทดสอบในสไลด์ตรวจ FFT
N/2=16N/2 = 16 2525 Hz เพดาน Nyquist (FS/2F_S/2) อ่านเกินนี้ไม่ได้

ทำไมสำคัญกับชุดบทเรียนนี้: บรรทัด peak_hz = kmax * FS / N ในโค้ดของเรา ก็คือสูตรนี้เป๊ะ ๆ พอเขย่าเร็วขึ้น พลังงานย้ายไป bin ที่ kk สูงขึ้น สูตรก็คืน Hz ที่สูงขึ้นตาม — นี่คือเหตุผลที่ "เขย่า 3 ครั้ง/วินาที แล้วได้ peak ~3 Hz"

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก Edge AI Developer (รศ.วิรุฬห์ ศรีบริรักษ์, BUU) · CC BY-NC 4.0

bin ความถี่ · bin width · Nyquist

output ของ FFT เป็น "ช่อง" (bin) เรียงตามความถี่ แต่ละ bin แทนช่วงความถี่แคบ ๆ สองสูตรที่ต้องจำ:

bin 0 DC (0 Hz) bin 1 bin 2 bin 3 · · · bin N/2−1 ~Nyquist แต่ละ bin ห่างกัน = bin width; bin สุดท้ายที่ใช้ได้ ≈ Nyquist

bin width=FSNNyquist=FS2\text{bin width}=\frac{FS}{N}\qquad\qquad \text{Nyquist}=\frac{FS}{2}

  • bin width FS/N = ความละเอียดความถี่ ยิ่ง N มาก bin ยิ่งแคบ แยกสองความถี่ที่ใกล้กันได้ดีขึ้น (แต่เก็บ N จุดใช้เวลานานขึ้น)
  • Nyquist FS/2 = ความถี่สูงสุดที่อ่านได้ถูก ที่ FS=50 Hz เราเห็นได้ถึง 25 Hz เท่านั้น
  • แปลง bin เป็น Hz: f = k * FS / N (เช่น N=32, FS=50 → bin 4 = 6.25 Hz)

ถ้าสัญญาณจริงมีความถี่ เกิน Nyquist มันจะ "พับ" กลับมาโผล่ผิดที่ (aliasing) — นี่คือเหตุผลที่อัตราสุ่มต้องสูงพอเสมอ เราจะเจอเรื่องนี้อีกตอนทำ feature เสียง

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก Edge AI Developer (รศ.วิรุฬห์ ศรีบริรักษ์, BUU) · CC BY-NC 4.0

เลือก N ยังไง — ความละเอียด vs ความไว

N (จำนวนจุดต่อหน้าต่าง) เป็นปุ่มปรับที่แลกกันสองด้าน ไม่มีค่าที่ "ดีที่สุด" ตายตัว ขึ้นกับงาน:

N bin width (FS/N) ที่ FS=50 เก็บ N จุดใช้เวลา เหมาะกับ
16 3.13 Hz (หยาบ) ~0.32 s (ไว) ดูคร่าว ๆ ตอบเร็ว
32 1.56 Hz ~0.64 s ชุดบทเรียนนี้ (สมดุลดี)
64 0.78 Hz (ละเอียด) ~1.28 s (หน่วง) แยกความถี่ใกล้กัน
128 0.39 Hz (ละเอียดมาก) ~2.56 s (ช้า) วิเคราะห์นิ่ง ๆ
  • N มาก → bin แคบ แยกสองความถี่ที่ใกล้กันได้ดี แต่ ต้องเก็บจุดนานขึ้น = สเปกตรัมอัปเดตช้าลง (ไม่ทันเหตุการณ์เร็ว)
  • N น้อย → อัปเดตไว ตอบสนองทันที แต่ ความถี่ที่ใกล้กันจะรวมร่างอยู่ bin เดียว แยกไม่ออก
  • ต้องเป็นเลขยกกำลัง 2 เสมอ (radix-2): 16, 32, 64, 128, …

นี่คือ การตัดสินใจเชิงวิศวกรรม ที่เจอตลอดในงาน DSP: "ละเอียดในความถี่" กับ "ไวในเวลา" แลกกันเสมอ (หลักความไม่แน่นอนของ time-frequency) เราเลือก N=32 เพราะพอดีกับการเขย่ามือ

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก Edge AI Developer (รศ.วิรุฬห์ ศรีบริรักษ์, BUU) · CC BY-NC 4.0

ศัตรูที่ 1 — DC / แรงโน้มถ่วง (bin 0)

accel ที่วางนิ่งอ่านได้ ~1g จากแรงโน้มถ่วง เป็นค่า คงที่ — ในโลกความถี่ ค่าคงที่คือความถี่ 0 Hz พอดี = bin 0 (DC)

ไม่ตัด DC bin 0 bin 0 พุ่ง กลบทุกอย่าง ตัด DC แล้ว (ลบค่าเฉลี่ย) bin เขย่า เห็นความถี่การเขย่าจริง
  • วิธีแก้ง่ายมาก: ลบค่าเฉลี่ยของหน้าต่างออก ก่อน FFT → mean = sum(buf)/N แล้วใช้ buf[i] - mean
  • นี่คือ ช่องเติมที่ 1 ในไฟล์ฝึก ถ้าลืมตัด: วางบอร์ดนิ่ง ๆ ก็เห็น bin 0 พุ่งเด่น กลบสเปกตรัมของการเขย่า

"ตัด DC" ที่จริงคือการเอา "ระดับพื้น" ที่ไม่สั่นออก เหลือแต่ส่วนที่แกว่ง — เพราะเราสนใจ "การเปลี่ยนแปลง" ไม่ใช่ "ค่าคงที่"

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก Edge AI Developer (รศ.วิรุฬห์ ศรีบริรักษ์, BUU) · CC BY-NC 4.0

ศัตรูที่ 2 — spectral leakage + Hann window

เราตัดสัญญาณเป็นท่อน ๆ ยาว N จุด ปัญหาคือขอบของท่อนมัก "ไม่พอดีคาบ" ทำให้พลังงานของความถี่หนึ่ง รั่ว ไปเปื้อน bin ข้างเคียง เรียก spectral leakage

สัญญาณดิบ (ขอบกระโดด) ขอบชน = รั่ว × Hann window กดขอบให้เป็น 0 = ผล: ขอบนุ่ม รั่วน้อยลง สเปกตรัมคมขึ้น

w[i]=0.5−0.5cos⁡ ⁣(2πiN−1)w[i]=0.5-0.5\cos\!\left(\frac{2\pi i}{N-1}\right)

  • Hann window คือ "ผ้าคลุม" รูประฆัง คูณเข้ากับสัญญาณ กดค่าที่ขอบให้ค่อย ๆ เป็น 0 → ไม่มีการกระโดดที่ขอบ → รั่วน้อยลง
  • นี่คือ ช่องเติมที่ 2: re = [(buf[i]-mean) * (0.5 - 0.5*math.cos(2*math.pi*i/(N-1))) for i in range(N)]

ราคาที่จ่าย: ยอด peak จะ "อ้วน" ขึ้นเล็กน้อย แลกกับการรั่วที่น้อยลงมาก ในงาน feature เสียงจริง Hann (หรือญาติ ๆ ของมัน) เป็นมาตรฐาน

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก Edge AI Developer (รศ.วิรุฬห์ ศรีบริรักษ์, BUU) · CC BY-NC 4.0

ศัตรูที่ 3 (จริง ๆ คือขั้นอ่านผล) — magnitude

output ของ FFT ต่อ bin เป็นเลขเชิงซ้อน re[k] + i·im[k] เราไม่สนเฟส สนแค่ "ความถี่นี้แรงแค่ไหน" = ขนาด (magnitude) ของเลขเชิงซ้อน

re im re[k] im[k] mag[k] mag[k] = √(re[k]² + im[k]²) = ความยาวลูกศร = "ความถี่ k แรงเท่าไร"
  • นี่คือ ช่องเติมที่ 3: mag = [math.sqrt(re[k]*re[k] + im[k]*im[k]) for k in range(HALF)]
  • เราเอาแค่ ครึ่งแรก (HALF = N//2) เพราะครึ่งหลังเป็นภาพสะท้อนของสัญญาณจริง (สมมาตร) ไม่ให้ข้อมูลเพิ่ม

sqrt(re² + im²) คือทฤษฎีบทพีทาโกรัสตรง ๆ — re กับ im เป็นสองด้านของสามเหลี่ยม magnitude คือด้านตรงข้ามมุมฉาก นั่นคือ "ขนาด" ของความถี่นั้น

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก Edge AI Developer (รศ.วิรุฬห์ ศรีบริรักษ์, BUU) · CC BY-NC 4.0

ขั้นสุดท้าย — หา peak แล้วแปลงเป็น Hz

มีสเปกตรัมแล้ว คำถามที่คนอยากรู้ที่สุดคือ "ความถี่ไหนเด่นสุด" = bin ที่ magnitude สูงสุด (ข้าม bin 0 ที่เป็น DC ที่ยังหลงเหลือ)

kmax = max(range(1, HALF), key=lambda k: mag[k])   # bin เด่น (ข้าม bin 0)
peak_hz = kmax * FS / N                              # แปลง bin -> Hz
  • นี่คือ ช่องเติมที่ 4: หา kmax ด้วย max(..., key=lambda k: mag[k])
  • แปลงกลับเป็นความถี่จริงด้วย f = k * FS / N — เขย่าเร็ว kmax เลื่อนไปทางขวา (Hz สูง), เขย่าช้า kmax เลื่อนซ้าย (Hz ต่ำ)

เริ่มจาก range(1, HALF) ไม่ใช่ range(0, ...) เพราะ bin 0 คือ DC ถ้ายังตัดไม่หมดเกลี้ยง มันอาจแอบชนะ เราเลยข้ามมันไปเลยเพื่อความชัวร์

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก Edge AI Developer (รศ.วิรุฬห์ ศรีบริรักษ์, BUU) · CC BY-NC 4.0