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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
//! Static spectrum analysis: print spectrum to PNG file.

use plotters::prelude::*;
use std::collections::BTreeMap;
use std::path::PathBuf;

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

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

    let max_frequency = *frequency_spectrum
        .iter()
        .skip(frequency_spectrum.len() - 2)
        .last()
        .unwrap()
        .0;

    let mut path = PathBuf::new();
    path.push(directory);
    path.push(filename);

    let mut width = frequency_spectrum.len() as u32;
    if width < 700 {
        width = 700;
    }

    let height = if width < 700 {
        (width as f32 / 0.8) as u32
    } else {
        700
    };

    let root = BitMapBackend::new(&path, (width, height)).into_drawing_area();
    root.fill(&WHITE).unwrap();
    let mut chart = ChartBuilder::on(&root)
        .caption("y=f magnitudes of sample", ("sans-serif", 20).into_font())
        .margin(5)
        .x_label_area_size(60)
        .y_label_area_size(60)
        .build_cartesian_2d(0.0..(max_frequency as f32) /*.log10()*/, 0.0..max)
        .unwrap();

    chart.configure_mesh().draw().unwrap();

    chart
        .draw_series(LineSeries::new(
            // (-50..=50).map(|x| x as f32 / 50.0).map(|x| (x, x * x)),
            frequency_spectrum
                .iter()
                .map(|(frequency, magnitude)| ((*frequency as f32) /*.log10()*/, *magnitude)),
            &RED,
        ))
        .unwrap()
        .label("frequency magnitude")
        .legend(|(x, y)| PathElement::new(vec![(x, y), (x + 20, y)], RED));

    chart
        .configure_series_labels()
        .background_style(WHITE.mix(0.8))
        .border_style(BLACK)
        .draw()
        .unwrap();
}

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

    #[test]
    fn test_visualize_sine_waves_spectrum_plotters() {
        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);

        spectrum_static_plotters_png_visualize(
            &spectrum,
            TEST_OUT_DIR,
            "spectrum_60hz_peak_plotters_visualization.png",
        );
    }

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

        spectrum_static_plotters_png_visualize(
            &spectrum,
            TEST_OUT_DIR,
            "spectrum_60hz_peak_plotters_visualization_NAN.png",
        );
    }
}