# Bài 4: STFT, magnitude, power, phase và độ phân giải

[Bắt đầu](00-BAT-DAU-LOP-01.md) · Trước: [sampling](03-SAMPLING-ALIASING-RESAMPLING.md) · Tiếp: [mel và token](05-MEL-CEPSTRUM-CHUAN-HOA-TOKEN.md)

## Mục tiêu và tiền đề

Tính STFT nhỏ, giải thích window/hop/n_fft khác nhau, phân biệt power với PSD, và tính ba loại temporal span. Cần DFT bài 2, fs bài 3. Ở đây L_w là độ dài window tính bằng mẫu; H là hop bằng mẫu; N_FFT là FFT length; m là frame index; k là frequency index. Không dùng N đồng thời cho số FFT bin và số token.

## 1. Tại sao dùng Fourier trên đoạn ngắn?

Cả clip có thể chuyển từ nguyên âm sang /s/. DFT toàn clip phức vẫn giữ waveform, nhưng không có hàng riêng cho thời điểm chuyển. STFT cắt các đoạn chồng nhau rồi đo phổ từng đoạn: giả định trong một window, cấu trúc đủ ổn định để mô tả. [S8: Aalto, Short-time analysis, phần Windowing và Spectrogram](https://speechprocessingbook.aalto.fi/representations/short-time-analysis/).

Với frame bắt đầu tại mH, chọn phase theo chỉ số **cục bộ** r:

$$X[m,k]=\sum_{r=0}^{L_w-1}x[mH+r]w[r]e^{-j2\pi kr/N_{FFT}}.$$

Đọc lần lượt: lấy L_w mẫu → nhân window w → thêm zero nếu N_FFT>L_w → DFT. Cách dùng global index n trong số mũ khác một hệ số phase phụ thuộc m; magnitude không đổi. Phải giữ quy ước nếu so phase.

w giảm discontinuity tại biên window. Rectangular window giữ mọi mẫu hệ số 1 nhưng có sidelobes mạnh; tapered window như Hann giảm sidelobes với main lobe rộng hơn. Không có window giảm leakage mà tăng mọi dạng resolution miễn phí. [S8, Windowing functions và Accuracy](https://speechprocessingbook.aalto.fi/representations/short-time-analysis/).

## 2. Ví dụ STFT hoàn chỉnh

**Giả lập, không phải dữ liệu paper:** x=[1,0,−1,0,1,0], fs=8 Hz, L_w=N_FFT=4, H=2, w=[1,1,1,1], không padding. Có 1+floor((6−4)/2)=2 frames.

- m=0 lấy [1,0,−1,0], nên X[0,:]=[0,2,0,2] theo bài 2.
- m=1 lấy [−1,0,1,0]=−frame0, nên X[1,:]=[0,−2,0,−2].

Magnitude cả hai là [0,2,0,2]; squared magnitude là [0,4,0,4]. Phase ở bin1: frame0=0, frame1=π (−π tương đương modulo2π). Phase tại bin magnitude=0 không xác định về toán; đừng diễn giải giá trị 0 mà phần mềm trả cho arg(0) thành dấu vật lý.

Với input thực và window thực, phổ conjugate-symmetric: one-sided chỉ giữ k=0,1,2 ở ví dụ N_FFT=4. Shape có thể là [frequency,frame]=[3,2] trong thư viện, trong khi công thức lớp học là [frame,frequency]=[2,3]. Transpose đúng shape là cần thiết trước mel/patch.

## 3. Magnitude, squared magnitude, năng lượng và dB

| Đại lượng | Công thức | Đọc như thế nào |
|---|---|---|
| Magnitude | $A=\lvert X\rvert$ | Độ dài vector phức |
| Phase | φ=arg(X) | Góc, radian; không ổn định gần A=0 |
| Squared magnitude | $P=\lvert X\rvert^2$ | Thường được gọi power spectrogram; scale phụ thuộc DFT/window |
| Energy đoạn | $E=\sum_r\lvert x[r]w[r]\rvert^2$ | Bình phương biên độ cộng theo mẫu |
| PSD chuẩn hóa | Cần fs và window energy, quy ước một/hai phía | Đơn vị biên độ²/Hz; không mặc định bằng squared magnitude |

Với DFT không normalized, Parseval cho E=(1/N_FFT)Σ_k|X[k]|². Frame0 có E=1²+(−1)²=2, tổng squared spectrum=8, chia4 đúng2. Nếu cộng one-sided để lấy energy, phải nhân đôi các bin dương không phải DC/Nyquist đối với tín hiệu thực. [S26: Julius O. Smith, Rayleigh Energy Theorem / Parseval, công thức DFT không normalized](https://dsprelated.com/freebooks/mdft/Rayleigh_Energy_Theorem_Parseval_s.html).

Log không nhận một đại lượng có đơn vị nếu chưa chọn reference. Viết S=ln((P+ε)/P_ref) với P_ref cùng đơn vị và ε>0 là floor, thì S không thứ nguyên. Power dB=10log10(P/P_ref); magnitude dB=20log10(A/A_ref), vì P/P_ref=(A/A_ref)². **Ví dụ:** P=4, P_ref=1 cho 6,0206 dB; A=2, A_ref=1 cũng 6,0206 dB. Dùng20log10(P) sẽ thành12,0412 dB và sai quy ước power.

## 4. Window, hop, FFT length điều khiển ba việc khác nhau

Với fs=32 kHz, window25 ms=L_w=800 mẫu, hop10 ms=H=320 mẫu. Một window dài hơn thu nhiều chu kỳ hơn nên giúp phân biệt thành phần gần nhau, đồng thời làm mờ biến đổi ngắn. Hop nhỏ hơn cho frame centers dày hơn; không làm window có thêm bằng chứng phân biệt hai tần số gần.

N_FFT=1.024 cho spacing fs/N_FFT=31,25 Hz; N_FFT=2.048 cho15,625 Hz. Cùng 800 mẫu và cùng window, thêm zero chỉ lấy mẫu phổ dày hơn; main-lobe do window quyết định chưa hẹp lại. Thang 1/0,025=40 Hz gợi độ dài quan sát; **không phải** giới hạn phân giải chính xác phổ quát cho mọi estimator/window/SNR.

![Zero-padding cho phổ mịn hơn mà không tách hai tone gần; giả lập](assets/zero-padding-resolution.png)

Hình dùng hai cosine1.000/1.020 Hz, cùng25 ms Hann window. Điểm1.024 và đường zero-pad8.192 theo cùng envelope. Nó minh họa một trường hợp, không định lý mọi cặp20 Hz luôn bất khả phân biệt.

## 5. Frame count không chỉ do duration

Với L=81.920, H=320:

| Quy ước được khai báo | Frame count trước pad/truncate |
|---|---:|
| Cắt window800 mẫu, chỉ nhận cửa sổ đầy đủ, không center | 1+floor((81.920−800)/320)=254 |
| PyTorch STFT mặc định frame theo n_fft1.024, center=False, win_length800 | 1+floor((81.920−1.024)/320)=253 |
| Center=True, padding tiêu chuẩn, N_FFT chẵn1.024 | 1+floor(81.920/320)=257 |

PyTorch2.9 mô tả padding window lên n_fft và đếm frame theo n_fft khi không center; các tùy chọn alignment/version có thể cần kiểm riêng. [S9: torch.stft, Parameters và Returns](https://docs.pytorch.org/docs/2.9/generated/torch.stft.html).

Paper báo cáo **pad/truncate về256 frame**, không chỉ ra trong đoạn Method đã đọc mọi chi tiết n_fft/center/window type. Vì thế bảng trên là ba implementation minh họa có điều kiện, không tuyên bố code paper tạo253/254/257. Giá trị zero padding ở log-space cũng không tự đồng nghĩa im lặng: silent power với floor có log khác0 tùy reference.

## 6. Patch80 ms nhìn waveform bao dài?

Tám frame cách nhau10 ms có frame-start/center distance đầu-cuối là7×10=70 ms. Mỗi cửa sổ rộng25 ms; union danh nghĩa từ đầu cửa sổ đầu tới cuối cửa sổ cuối:

$$D_{union}=(8-1)\times10+25=95\ {\rm ms}.$$

Nominal patch span theo bước lưới là8×10=80 ms. Hai patch kề nhau bắt đầu cách80 ms nhưng window union có thể chồng15 ms. 95 ms giả định windows đủ ở nội vùng; centered edge có thể chứa padding, điểm window zero không đóng góp, nên không coi đó là95 ms bằng chứng audio thật ở mọi patch. Sau dense attention, token có thể nhận thông tin cả clip. **Đường truyền có thể** tồn tại không chứng minh effective causal dependence ở mọi vị trí.

Paper patch8time×32mel và128 tokens; đây là front-end geometry trước attention, không độ chính xác localization guaranteed. [Paper, mục3.1–3.2; bản đồ](../06-GIAI-PHAU-PAPER.md).

## 7. Bài tập

1. fs=16 kHz, window25 ms, hop10 ms: đổi ra mẫu.
2. X=3+4j. Tính magnitude/power/phase và power dB với P_ref=1.
3. Cùng window25 ms, tăng n_fft gấp đôi có thêm duration quan sát không? Giảm hop có tách hai tone gần hơn không?
4. Patch4 frames với hop10 ms/window25 ms: nominal span, first-last distance, union?
5. Tại sao không áp dụng công thức254 vô điều kiện cho torch.stft?

<details>
<summary>Đáp án</summary>

1. 400 và160 mẫu. Quy đổi ms sang s trước nhân fs.
2. A=5, P=25, φ=atan2(4,3)≈0,927295 rad;10log10(25)=13,9794 dB. Phase phải dùng atan2 để đúng góc phần tư.
3. Không. n_fft đổi lưới tần số; hop đổi lưới thời gian. Khả năng phân biệt còn phụ thuộc window, signal model và noise.
4.40 ms;30 ms;55 ms. Không gọi40 hoặc55 là receptive field toàn encoder.
5.254 dùng frame support length800 và không padding. PyTorch thường đóng frame length theo n_fft, còn center=True pad hai phía. Cần biết code/version và không nhầm win_length với n_fft.

</details>

## Đào sâu tự chọn

Từ Y[k]=e^(−jω_kD)X[k], phase unwrap theo k của một delay lý tưởng có slope−D; group delay là −dφ/dω, đơn vị mẫu nếu ω tính radian/mẫu. Không suy group delay ổn định tại spectral zero, không dùng wrapped phase để lấy derivative tùy tiện. STFT magnitude của nhiều frame chồng nhau có constraints phục hồi riêng; mất phase trực tiếp không có nghĩa không còn một chút thông tin nào liên quan phase.
