use clap::Parser;
use std::io::Write;
#[derive(Parser, Debug)]
#[command(about = "Generate synthetic EEG CSV for testing")]
struct Args {
#[arg(long, short, default_value = "data/sample.csv")]
output: String,
#[arg(long, default_value_t = 22)]
channels: usize,
#[arg(long, default_value_t = 10.0)]
duration: f32,
#[arg(long, default_value_t = 256.0)]
sfreq: f32,
}
const TUEG_NAMES: &[&str] = &[
"FP1-F7", "F7-T3", "T3-T5", "T5-O1", "FP2-F8", "F8-T4", "T4-T6", "T6-O2",
"T3-C3", "C3-CZ", "CZ-C4", "C4-T4", "FP1-F3", "F3-C3", "C3-P3", "P3-O1",
"FP2-F4", "F4-C4", "C4-P4", "P4-O2", "A1-T3", "T4-A2",
];
fn main() -> anyhow::Result<()> {
let args = Args::parse();
let n_ch = args.channels.min(TUEG_NAMES.len());
let n_t = (args.duration * args.sfreq) as usize;
let dt = 1.0 / args.sfreq;
if let Some(parent) = std::path::Path::new(&args.output).parent() {
std::fs::create_dir_all(parent)?;
}
let mut f = std::fs::File::create(&args.output)?;
writeln!(f, "# Generated by luna-rs gen_sample_eeg")?;
writeln!(f, "# sfreq={} channels={} duration={}s samples={}",
args.sfreq, n_ch, args.duration, n_t)?;
write!(f, "timestamp")?;
for name in TUEG_NAMES.iter().take(n_ch) {
write!(f, ",{name}")?;
}
writeln!(f)?;
let mut noise_state: u32 = 0xDEAD_BEEF;
for t in 0..n_t {
let time = t as f32 * dt;
write!(f, "{time:.9e}")?;
for ch in 0..n_ch {
let alpha = (2.0 * std::f32::consts::PI * (9.5 + ch as f32 * 0.3) * time).sin() * 20e-6;
let theta = (2.0 * std::f32::consts::PI * (5.0 + ch as f32 * 0.1) * time).sin() * 15e-6;
let beta = (2.0 * std::f32::consts::PI * (20.0 + ch as f32 * 0.7) * time).sin() * 5e-6;
noise_state ^= noise_state << 13;
noise_state ^= noise_state >> 17;
noise_state ^= noise_state << 5;
let noise = (noise_state as f32 / u32::MAX as f32 - 0.5) * 3e-6;
let val = alpha + theta + beta + noise;
write!(f, ",{val:.9e}")?;
}
writeln!(f)?;
}
let size = std::fs::metadata(&args.output)?.len();
println!("Generated {n_ch} channels × {n_t} samples ({:.1}s @ {} Hz)",
args.duration, args.sfreq);
println!(" → {} ({:.1} KB)", args.output, size as f64 / 1024.0);
Ok(())
}