Skip to main content

pedalkernel_validate/
lib.rs

1// Pre-existing lint suppressions for technical debt in this crate.
2#![allow(dead_code)]
3#![allow(unused_variables)]
4#![allow(unused_mut)]
5#![allow(unused_imports)]
6#![allow(clippy::redundant_closure)]
7#![allow(clippy::ptr_arg)]
8#![allow(clippy::redundant_field_names)]
9#![allow(clippy::unnecessary_map_or)]
10#![allow(clippy::io_other_error)]
11#![allow(clippy::manual_is_multiple_of)]
12//! # PedalKernel Validation Library
13//!
14//! A toolkit for validating WDF (Wave Digital Filter) circuit simulations against
15//! reference implementations (analytical, SPICE, or hardware measurements).
16//!
17//! ## Library Usage
18//!
19//! This crate can be used as a dependency for writing custom validation tests:
20//!
21//! ```toml
22//! [dependencies]
23//! pedalkernel-validate = { path = "../pedalkernel-validate" }
24//! ```
25//!
26//! ### Signal Generation
27//!
28//! Generate deterministic test signals for audio processing validation:
29//!
30//! ```rust
31//! use pedalkernel_validate::signals;
32//!
33//! let sample_rate = 48000.0;
34//!
35//! // Unit impulse (100ms duration)
36//! let impulse = signals::impulse(4800, 1.0);
37//!
38//! // 1kHz sine wave, 100ms duration, amplitude 0.5
39//! let sine = signals::sine(sample_rate, 1000.0, 0.1, 0.5);
40//!
41//! // Two-tone IMD test signal
42//! let two_tone = signals::two_tone(sample_rate, 1000.0, 1100.0, 0.1, 0.5);
43//!
44//! // Exponential frequency sweep 20Hz-20kHz over 1 second
45//! let sweep = signals::exp_sweep(sample_rate, 20.0, 20000.0, 1.0, 0.8);
46//!
47//! // Tone burst for attack/release testing
48//! let burst = signals::tone_burst(sample_rate, 1000.0, 0.5, 10.0, 90.0, 5);
49//!
50//! // Level sweep for gain curve measurement
51//! let levels = signals::level_sweep(sample_rate, 1000.0, &[-20.0, -10.0, 0.0, 10.0], 0.5);
52//! ```
53//!
54//! ### Comparison Metrics
55//!
56//! Compare two audio signals with various metrics:
57//!
58//! ```rust
59//! use pedalkernel_validate::metrics;
60//!
61//! let wdf_output: Vec<f64> = vec![/* your WDF output */];
62//! let reference: Vec<f64> = vec![/* golden reference */];
63//! let sample_rate = 48000.0;
64//!
65//! // Normalized RMS error in dB (lower is better, -60dB = 0.1% error)
66//! let rms_err = metrics::normalized_rms_error_db(&wdf_output, &reference);
67//!
68//! // Peak error in dB
69//! let peak_err = metrics::peak_error_db(&wdf_output, &reference);
70//!
71//! // THD (Total Harmonic Distortion) in dB
72//! let thd = metrics::thd_db(&wdf_output, 1000.0, sample_rate, 10);
73//!
74//! // THD difference between WDF and reference
75//! let thd_err = metrics::thd_error_db(&wdf_output, &reference, 1000.0, sample_rate);
76//!
77//! // Even/odd harmonic ratio (for push-pull validation)
78//! let ratio = metrics::even_odd_ratio_db(&wdf_output, 1000.0, sample_rate, 10);
79//!
80//! // Spectral error in dB
81//! let spectral_err = metrics::spectral_error_db(&wdf_output, &reference, sample_rate, None);
82//!
83//! // DC drift measurement
84//! let dc_drift = metrics::dc_drift_mv(&wdf_output, sample_rate, 100.0);
85//!
86//! // Or use the combined comparison function:
87//! let result = metrics::compare(&wdf_output, &reference, sample_rate, Some(1000.0));
88//! println!("RMS error: {:.1} dB", result.normalized_rms_error_db);
89//! println!("Peak error: {:.1} dB", result.peak_error_db);
90//! ```
91//!
92//! ### Analytical References
93//!
94//! Generate mathematically exact references for linear circuits:
95//!
96//! ```rust
97//! use pedalkernel_validate::analytical;
98//!
99//! let r = 10_000.0;  // 10k ohms
100//! let c = 10e-9;     // 10nF
101//! let sample_rate = 48000.0;
102//!
103//! // Impulse response of RC lowpass (bilinear transform)
104//! let ir = analytical::rc_lowpass_impulse_response(r, c, sample_rate, 1000);
105//!
106//! // Filter a signal through ideal RC lowpass
107//! let input = vec![1.0; 1000];
108//! let output = analytical::rc_lowpass_filter(&input, r, c, sample_rate);
109//!
110//! // Frequency response calculations
111//! let mag = analytical::rc_lowpass_magnitude(r, c, 1000.0);  // magnitude at 1kHz
112//! let phase = analytical::rc_lowpass_phase(r, c, 1000.0);    // phase at 1kHz
113//! ```
114//!
115//! ### NumPy File I/O
116//!
117//! Read/write NumPy .npy files for interoperability with Python:
118//!
119//! ```rust,ignore
120//! use pedalkernel_validate::npy;
121//!
122//! // Write test data
123//! let data = vec![1.0, 2.0, 3.0, 4.0];
124//! npy::write_f64("output.npy", &data).unwrap();
125//!
126//! // Read reference data
127//! let reference = npy::read_f64("golden.npy").unwrap();
128//! ```
129//!
130//! ### Custom Test Runner
131//!
132//! Build custom validation pipelines:
133//!
134//! ```rust,ignore
135//! use pedalkernel_validate::{signals, metrics, npy};
136//! use pedalkernel_validate::config::PassCriteria;
137//!
138//! fn validate_my_circuit(
139//!     circuit_path: &str,
140//!     golden_path: &str,
141//!     sample_rate: f64,
142//! ) -> bool {
143//!     // Generate test signal
144//!     let input = signals::sine(sample_rate, 1000.0, 0.1, 1.0);
145//!
146//!     // Process through your circuit (pseudocode)
147//!     // let output = my_circuit.process(&input);
148//!     let output = input.clone(); // placeholder
149//!
150//!     // Load golden reference
151//!     let golden = npy::read_f64(golden_path).unwrap();
152//!
153//!     // Compare
154//!     let result = metrics::compare(&output, &golden, sample_rate, Some(1000.0));
155//!
156//!     // Check against criteria
157//!     let criteria = PassCriteria {
158//!         normalized_rms_error_db: Some(-60.0),
159//!         peak_error_db: Some(-40.0),
160//!         thd_error_db: Some(1.0),
161//!         ..Default::default()
162//!     };
163//!
164//!     result.passes(&criteria)
165//! }
166//! ```
167//!
168//! ## CLI Usage
169//!
170//! The crate also provides a CLI for running predefined test suites:
171//!
172//! ```bash
173//! # List available tests
174//! pedalkernel-validate list
175//!
176//! # Run all validation suites
177//! pedalkernel-validate run --suite all
178//!
179//! # Run specific suite
180//! pedalkernel-validate run --suite nonlinear
181//!
182//! # Quick validate a single circuit
183//! pedalkernel-validate quick my_circuit.pedal
184//!
185//! # Bootstrap golden references from current WDF output
186//! pedalkernel-validate bootstrap --suite all
187//!
188//! # Generate analytical golden references
189//! pedalkernel-validate generate-linear
190//! ```
191//!
192//! ## Module Overview
193//!
194//! - [`signals`] - Deterministic test signal generators
195//! - [`metrics`] - Audio comparison metrics (RMS, THD, spectral, etc.)
196//! - [`analytical`] - Mathematically exact references for linear circuits
197//! - [`spice`] - ngspice integration for golden reference generation
198//! - [`npy`] - NumPy .npy file I/O
199//! - [`config`] - YAML-based test configuration
200//! - [`runner`] - Test orchestration
201//! - [`report`] - JSON and terminal reporting
202
203// ============================================================================
204// Public modules
205// ============================================================================
206
207pub mod analytical;
208pub mod pro_pedal;
209pub mod config;
210pub mod metrics;
211pub mod npy;
212pub mod report;
213pub mod runner;
214pub mod signals;
215pub mod spice;
216
217// ============================================================================
218// Top-level re-exports for convenience
219// ============================================================================
220
221// Config types
222pub use config::{
223    ConfigError, GlobalConfig, MetricConfig, PassCriteria, SignalConfig, TestCase, TestSuite,
224    ValidationConfig, ValidationProfile,
225};
226
227// Metrics types
228pub use metrics::ComparisonResult;
229
230// Runner types
231pub use runner::{RunnerConfig, RunnerError, ValidationRunner};
232
233// Report types
234pub use report::{
235    ComparisonMetrics, ReportSummary, SignalResult, SuiteResult, TestResult, ValidationReport,
236};
237
238// Signal types
239pub use signals::SignalSpec;
240
241// SPICE types
242pub use spice::{SpiceConfig, SpiceError, SpiceRunner};
243
244/// Prelude module - import everything commonly needed
245///
246/// ```rust
247/// use pedalkernel_validate::prelude::*;
248/// ```
249pub mod prelude {
250    // Signal generation
251    pub use crate::signals::{
252        dbvu_to_peak, exp_sweep, impulse, level_sweep, silence, sine, tone_burst, two_tone,
253        SignalSpec,
254    };
255
256    // Metrics
257    pub use crate::metrics::{
258        compare, dc_drift_mv, even_odd_ratio_db, normalized_rms_error_db, peak_error_db,
259        spectral_error_db, thd_db, thd_error_db, ComparisonResult,
260    };
261
262    // Analytical references
263    pub use crate::analytical::{
264        rc_highpass_filter, rc_highpass_impulse_response, rc_lowpass_filter,
265        rc_lowpass_impulse_response, rc_lowpass_magnitude, rc_lowpass_phase, rlc_bandpass_filter,
266        twin_t_notch_filter,
267    };
268
269    // Config
270    pub use crate::config::{
271        GlobalConfig, MetricConfig, PassCriteria, SignalConfig, TestCase, TestSuite,
272        ValidationConfig, ValidationProfile,
273    };
274
275    // NPY I/O
276    pub use crate::npy::{exists as npy_exists, read_f64 as npy_read, write_f64 as npy_write};
277
278    // Runner
279    pub use crate::runner::{quick_validate, RunnerConfig, ValidationRunner};
280
281    // Report
282    pub use crate::report::{SignalResult, SuiteResult, TestResult, ValidationReport};
283
284    // SPICE
285    pub use crate::spice::{SpiceConfig, SpiceRunner};
286}