reda_spice/probe/analysis/
ac.rs1use 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 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}