gpu_fft/
utils.rs

1use std::f32::consts::PI;
2
3/// Generates a sine wave signal based on the specified frequency, sample rate, and duration.
4///
5/// This function creates a vector of samples representing a sine wave. The sine wave is generated
6/// using the formula: `sin(2 * π * frequency * time)`, where `time` is calculated based on the
7/// sample rate and the sample index.
8///
9/// # Parameters
10///
11/// - `frequency`: The frequency of the sine wave in Hertz (Hz).
12/// - `sample_rate`: The number of samples per second (samples/second).
13/// - `duration`: The duration of the sine wave in seconds.
14///
15/// # Returns
16///
17/// A vector of `f32` values representing the samples of the generated sine wave. The length of the
18/// output vector will be equal to the number of samples calculated as `sample_rate * duration`.
19///
20/// # Example
21///
22/// ```rust
23/// let frequency = 440.0; // A4 note
24/// let sample_rate = 44100.0; // CD quality
25/// let duration = 1.0; // 1 second
26/// let sine_wave = generate_sine_wave(frequency, sample_rate, duration);
27/// ```
28pub fn generate_sine_wave(frequency: f32, sample_rate: f32, duration: f32) -> Vec<f32> {
29    let num_samples = (sample_rate * duration) as usize;
30    let mut sine_wave = Vec::with_capacity(num_samples);
31
32    for n in 0..num_samples {
33        let sample = (2.0 * PI * frequency * (n as f32 / sample_rate)).sin();
34        sine_wave.push(sample);
35    }
36
37    sine_wave
38}
39
40/// Calculates the frequency values corresponding to the given number of samples and sample rate.
41///
42/// This function generates a vector of frequency values based on the number of samples and the
43/// sample rate. The frequencies are calculated as `k * sample_rate / n`, where `k` is the index
44/// of the frequency bin.
45///
46/// # Parameters
47///
48/// - `n`: The number of frequency bins (samples).
49/// - `sample_rate`: The sample rate in Hertz (Hz).
50///
51/// # Returns
52///
53/// A vector of `f32` values representing the frequency values for each bin. The length of the
54/// output vector will be equal to `n`.
55///
56/// # Example
57///
58/// ```rust
59/// let n = 1024; // Number of frequency bins
60/// let sample_rate = 44100.0; // Sample rate in Hz
61/// let frequencies = calculate_frequencies(n, sample_rate);
62/// ```
63pub fn calculate_frequencies(n: usize, sample_rate: f32) -> Vec<f32> {
64    (0..n).map(|k| k as f32 * sample_rate / n as f32).collect()
65}
66
67/// Finds the dominant frequencies in the Power Spectral Density (PSD) based on a threshold.
68///
69/// This function identifies the dominant frequencies in the provided PSD by checking for peaks
70/// in the PSD values that exceed a specified threshold. A peak is defined as a point that is
71/// greater than its immediate neighbors.
72///
73/// # Parameters
74///
75/// - `psd`: A vector of `f32` values representing the Power Spectral Density of the signal.
76/// - `frequencies`: A vector of `f32` values representing the frequency values corresponding to
77///   the PSD.
78/// - `threshold`: A threshold value for identifying dominant frequencies. Only peaks above this
79///   threshold will be considered.
80///
81/// # Returns
82///
83/// A vector of tuples, where each tuple contains a dominant frequency and its corresponding PSD
84/// value. The first element of the tuple is the frequency, and the second element is the PSD value.
85///
86/// # Example
87///
88/// ```rust
89/// let psd = vec![0.1, 0.5, 0.3, 0.7, 0.2]; // Example PSD values
90/// let frequencies = vec![0.0, 100.0, 200.0, 300.0, 400.0]; // Corresponding frequencies
91/// let threshold = 0.4; // Threshold for dominance
92/// let dominant_freqs = find_dominant_frequencies(psd, frequencies, threshold);
93/// ```
94pub fn find_dominant_frequencies(
95    psd: Vec<f32>,
96    frequencies: Vec<f32>,
97    threshold: f32,
98) -> Vec<(f32, f32)> {
99    let mut dominant_frequencies = Vec::new();
100
101    for i in 1..(psd.len() - 1) {
102        // Check if the current point is a peak
103        if psd[i] > psd[i - 1] && psd[i] > psd[i + 1] && psd[i] > threshold {
104            dominant_frequencies.push((frequencies[i], psd[i]));
105        }
106    }
107
108    dominant_frequencies
109}