Skip to main content

reda_spice/probe/analysis/
ac.rs

1use std::{collections::HashMap, path::Path};
2use reda_unit::{Complex, CurrentPhasor, Frequency, VoltagePhasor};
3
4use crate::probe::Drawer;
5
6use super::AnalysisError;
7
8#[derive(Debug, Clone, Default)]
9pub struct AcAnalysis {
10    pub frequency: Vec<Frequency>,
11    pub nodes: HashMap<String, Vec<VoltagePhasor>>,
12    pub branches: HashMap<String, Vec<CurrentPhasor>>,
13    pub internal_parameters: HashMap<String, Vec<Complex>>,
14}
15
16impl AcAnalysis {
17    pub fn get_node(&self, name: &str) -> Option<&Vec<VoltagePhasor>> {
18        self.nodes.get(name)
19    }
20
21    pub fn get_branch(&self, name: &str) -> Option<&Vec<CurrentPhasor>> {
22        self.branches.get(name)
23    }    
24}
25
26impl AcAnalysis {
27    pub fn draw_gain<P: AsRef<Path>>(
28        &self, 
29        drawer: &Drawer, 
30        input_node: &str,
31        output_node: &str,
32        path: P
33    ) -> Result<(), AnalysisError> {
34        let frequency: Vec<_> = self.frequency.iter().map(|t| t.to_f64().log10()).collect();
35        
36        let input = self.get_node(input_node)
37            .ok_or_else(|| AnalysisError::NoExitNode(input_node.into()))?;
38        let output = self.get_node(output_node)
39            .ok_or_else(|| AnalysisError::NoExitNode(output_node.into()))?;
40
41        let mut values = Vec::new();
42        for (vin, vout) in input.iter().zip(output.iter()) {
43            let db = 20.0 * (vout.abs() / vin.abs()).log10();
44            values.push(db.to_f64());
45        }
46
47        drawer.draw("frequency", "Gain",  &frequency, &[("Gain".into(), values)], path).map_err(|e| AnalysisError::PlotError(e))
48    }
49
50    pub fn draw_phase<P: AsRef<Path>>(
51        &self, 
52        drawer: &Drawer, 
53        input_node: &str,
54        output_node: &str,
55        path: P
56    ) -> Result<(), AnalysisError> {
57        let frequency: Vec<_> = self.frequency.iter().map(|t| t.to_f64().log10()).collect();
58        
59        let input = self.get_node(input_node)
60            .ok_or_else(|| AnalysisError::NoExitNode(input_node.into()))?;
61        let output = self.get_node(output_node)
62            .ok_or_else(|| AnalysisError::NoExitNode(output_node.into()))?;
63
64        let mut values = Vec::new();
65        for (vin, vout) in input.iter().zip(output.iter()) {
66            // let db = 20.0 * (vout.abs() / vin.abs()).log10();
67            let relative = vout.arg() - vin.arg();
68            values.push(relative.to_f64());
69        }
70
71        drawer.draw("frequency", "Phase",  &frequency, &[("Phase".into(), values)], path).map_err(|e| AnalysisError::PlotError(e))
72    }
73}