1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
//! Static spectrum analysis: print to PNG file.

use crate::util::png::write_png_file_rgb_tuples;
use std::collections::BTreeMap;
use std::path::PathBuf;

pub fn spectrum_static_png_visualize(
    frequency_spectrum: &BTreeMap<u32, f32>,
    directory: &str,
    filename: &str,
    highlighted_frequencies: &[f32],
) {
    // assert no NAN
    assert!(!frequency_spectrum.iter().any(|(_, f)| f.is_nan()), "There are NAN-values in the spectrum!");

    let image_width = 5000;
    let image_height = 3000;

    let mut rgb_img = vec![vec![(255, 255, 255); image_width]; image_height];

    // find maximum for graphics scaling
    let mut max = 0.0;
    for (_fr, mag) in frequency_spectrum {
        if *mag > max {
            max = *mag;
        }
    }

    let x_step = image_width as f64 / frequency_spectrum.len() as f64;
    let mut i = 0;
    for (frequency, mag) in frequency_spectrum {
        let mag = mag / max * image_height as f32;

        let x = (i as f64 * x_step) as usize;

        for j in 0..mag as usize {
            let mut color = (0, 0, 0);

            let highlight = highlighted_frequencies
                .iter()
                .any(|f| (*frequency as f32 - *f).abs() < 5.0);
            if highlight {
                color = (255, 0, 0);
            }

            // make it wider
            if x > 2 && highlight {
                rgb_img[image_height - 1 - j][x - 1] = color;
                rgb_img[image_height - 1 - j][x - 2] = color;
            }
            rgb_img[image_height - 1 - j][x] = color;
        }
        i += 1;
    }

    let mut path = PathBuf::new();
    path.push(directory);
    path.push(filename);
    write_png_file_rgb_tuples(&path, &rgb_img);
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::test_support::TEST_OUT_DIR;
    use std::f32::NAN;

    #[test]
    fn test_visualize_sine_waves_spectrum() {
        let mut spectrum = BTreeMap::new();
        spectrum.insert(0, 0.0);
        spectrum.insert(10, 5.0);
        spectrum.insert(20, 20.0);
        spectrum.insert(30, 40.0);
        spectrum.insert(40, 80.0);
        spectrum.insert(50, 120.0);
        spectrum.insert(55, 130.0);
        spectrum.insert(60, 140.0);
        spectrum.insert(65, 130.0);
        spectrum.insert(70, 120.0);
        spectrum.insert(80, 80.0);
        spectrum.insert(90, 40.0);
        spectrum.insert(100, 20.0);
        spectrum.insert(110, 5.0);
        spectrum.insert(120, 0.0);
        spectrum.insert(130, 0.0);

        // Do FFT + get spectrum
        spectrum_static_png_visualize(
            &spectrum,
            TEST_OUT_DIR,
            "spectrum_60hz_peak_basic_visualization.png",
            &[60.0],
        );
    }

    #[allow(non_snake_case)]
    #[test]
    #[should_panic]
    fn test_panic_on_NAN() {
        let mut spectrum = BTreeMap::new();
        spectrum.insert(0, NAN);

        spectrum_static_png_visualize(
            &spectrum,
            TEST_OUT_DIR,
            "spectrum_60hz_peak_plotters_visualization_NAN.png",
            &[],
        );
    }
}