171 lines
5.5 KiB
Markdown
171 lines
5.5 KiB
Markdown
---
|
|
name: fft-analyse
|
|
description: >
|
|
Performs FFT spectrum analysis on IQ data files (CSV, TXT, TSV). Use this skill
|
|
whenever the user asks to analyse IQ data, plot a spectrum, check OBW (occupied
|
|
bandwidth), look at FFT output, run spectrum analysis, or verify a filter's
|
|
frequency response from simulation output. Also triggers for phrases like
|
|
"分析频谱", "频谱分析", "查看IQ数据", "FFT分析", "OBW". Runs headless — no GUI
|
|
required. Auto-installs missing Python dependencies.
|
|
---
|
|
|
|
# FFT Spectrum Analyser Skill
|
|
|
|
Analyse IQ data from CSV/TXT/TSV files, produce a 3-panel spectrum plot, and
|
|
report 90 %/99 % occupied bandwidth plus top spectral peaks.
|
|
|
|
## Bundled Script
|
|
|
|
`scripts/fft_analyse.py` — general-purpose CLI analyser.
|
|
|
|
**Python requirement:** Python ≥ 3.8
|
|
**Dependencies:** `numpy >= 1.20`, `matplotlib >= 3.4`
|
|
The script calls `_ensure_deps()` at startup and auto-installs any missing
|
|
package via `pip` — no manual setup needed.
|
|
|
|
---
|
|
|
|
## Workflow
|
|
|
|
### 1. Find a working Python interpreter
|
|
|
|
On Windows, the default `python` / `python3` commands may resolve to the
|
|
Microsoft Store stub (exit code 49, not a real interpreter).
|
|
Search in this order until one works (`python --version` returns something):
|
|
|
|
```
|
|
D:\ProgramData\anaconda3\python.exe
|
|
C:\ProgramData\anaconda3\python.exe
|
|
D:\Anaconda3\python.exe
|
|
C:\Anaconda3\python.exe
|
|
D:\miniconda3\python.exe
|
|
C:\miniconda3\python.exe
|
|
%LOCALAPPDATA%\Programs\Python\Python3*\python.exe
|
|
python3 (system PATH)
|
|
python (system PATH)
|
|
```
|
|
|
|
If none found, tell the user to install Python 3.8+ (Anaconda recommended) and
|
|
provide a download link. Do not proceed without a working interpreter.
|
|
|
|
On Linux/macOS `python3` normally works directly.
|
|
|
|
### 2. Understand the input file
|
|
|
|
Ask the user (or infer from context):
|
|
|
|
| Question | Why |
|
|
|----------|-----|
|
|
| File path? | Required |
|
|
| Sample rate (fs)? | Affects frequency axis. Script auto-detects from filename keywords (e.g. `120m` → 122.88 MHz, `240m` / `245` → 245.76 MHz, `491` → 491.52 MHz). Ask if ambiguous. |
|
|
| Bit width? | Sets full-scale reference (dBFS). Common: 8 / 12 / 16 / 24 / 32. Default: 16-bit. |
|
|
| I and Q column names? | Script auto-detects common patterns (`data_i`, `m_i`, `i_dec`, `i[`, etc.). If auto-detection might be wrong, confirm or pass `--i-col` / `--q-col`. |
|
|
| Rows to skip? | Use `--skip N` to drop FIR startup zeros or header-less data. |
|
|
| Frequency display range? | Optional `--xlim -10,10` (MHz). Defaults to ±fs/2. |
|
|
|
|
### 3. Run the analyser
|
|
|
|
```bash
|
|
<python> <skill_dir>/scripts/fft_analyse.py \
|
|
"<input_file>" \
|
|
--fs <sample_rate_hz> \
|
|
--bits <bit_width> \
|
|
[--i-col <col>] [--q-col <col>] \
|
|
[--skip <N>] \
|
|
[--xlim <lo_mhz>,<hi_mhz>] \
|
|
[--out <output_dir>] \
|
|
[--prefix <name>]
|
|
```
|
|
|
|
**Examples**
|
|
|
|
```bash
|
|
# 16-bit IQ at 122.88 MHz, auto-detect columns, output next to input
|
|
python scripts/fft_analyse.py data.csv --fs 122.88e6 --bits 16
|
|
|
|
# 24-bit signed hex output from xsim, 245.76 MHz, specific columns
|
|
python scripts/fft_analyse.py output_iq.txt \
|
|
--fs 245.76e6 --bits 24 \
|
|
--i-col m_i_dec --q-col m_q_dec \
|
|
--skip 50 --xlim -70,70
|
|
|
|
# Full-scale override instead of bit-width
|
|
python scripts/fft_analyse.py ila_data.csv --fs 120e6 --fs-val 32768
|
|
```
|
|
|
|
### 4. Report results to the user
|
|
|
|
After the script finishes, tell the user:
|
|
|
|
- Path(s) of saved files: `*_analysis.png`, `*_analysis.svg`, `*_spectrum.csv`, `*_summary.txt`
|
|
- Key numbers from the summary: **90 % OBW**, **99 % OBW**, **top peak** (frequency + dBFS)
|
|
- Any warnings printed by the script (column auto-detection, skipped rows, etc.)
|
|
|
|
If the script errors, show the full traceback and diagnose the issue before
|
|
asking the user to retry.
|
|
|
|
---
|
|
|
|
## Column Auto-Detection Reference
|
|
|
|
The script matches column names case-insensitively using these patterns:
|
|
|
|
| Channel | Matched names (examples) |
|
|
|---------|--------------------------|
|
|
| I | `data_i`, `iq_i`, `ch_i`, `m_i`, `i_dec`, `i_data`, `i_val`, `i[…]` |
|
|
| Q | `data_q`, `iq_q`, `ch_q`, `m_q`, `q_dec`, `q_data`, `q_val`, `q[…]` |
|
|
|
|
If auto-detection picks the wrong columns (e.g. file has unusual names), pass
|
|
`--i-col` / `--q-col` explicitly.
|
|
|
|
---
|
|
|
|
## Output File Naming
|
|
|
|
All outputs share a timestamp suffix:
|
|
`<prefix>_<YYYYMMDD_HHMMSS>_analysis.png`
|
|
`<prefix>_<YYYYMMDD_HHMMSS>_spectrum.csv`
|
|
`<prefix>_<YYYYMMDD_HHMMSS>_summary.txt`
|
|
|
|
Default `<prefix>` = input filename stem (special chars → `_`).
|
|
Default output directory = same folder as input file.
|
|
Override with `--out <dir>` and `--prefix <name>`.
|
|
|
|
---
|
|
|
|
## Interpreting the Three-Panel Plot
|
|
|
|
| Panel | Content |
|
|
|-------|---------|
|
|
| Top: I/Q waveform | First 512 samples of I and Q after skip — checks data looks sane |
|
|
| Middle: Magnitude | Full-length `\|I+jQ\|` with RMS line — checks for amplitude variation / dropouts |
|
|
| Bottom: Spectrum | Hann-windowed FFT in dBFS, OBW markers, top-5 peak labels |
|
|
|
|
---
|
|
|
|
## Handling Hex IQ Data (xsim / ILA output)
|
|
|
|
Simulation output often stores 24-bit samples as unsigned hex strings, e.g.:
|
|
|
|
```
|
|
time_ns,m_i_24b_hex,m_q_24b_hex,m_i_dec,m_q_dec
|
|
163,000000,000000,0,0
|
|
...
|
|
3277,03f200,03f200,258560,258560
|
|
```
|
|
|
|
The script handles both hex (`m_i_24b_hex`) and decimal (`m_i_dec`) columns.
|
|
Prefer the `_dec` (signed decimal) columns when available — they are already
|
|
sign-extended and require no bit-width guess. When using hex columns, pass
|
|
`--bits 24` (or appropriate width) so two's-complement conversion is correct.
|
|
|
|
---
|
|
|
|
## Skill Script Location
|
|
|
|
```
|
|
C:\Users\bowei\.claude\skills\fft-analyse\scripts\fft_analyse.py
|
|
```
|
|
|
|
Always use the **absolute path** when invoking from any working directory.
|