pub trait NetworkAnalysis: Sized {
// Required methods
fn new(network: &Network) -> Self;
fn solve<'a>(
&'a mut self,
resistances: Resistances<'_>,
current_src: CurrentSources<'_>,
voltage_src: VoltageSources<'_>,
initial_edge_resistances: Option<&[f64]>,
initial_edge_currents: Option<&[f64]>,
jacobian: Option<&mut (dyn for<'b> FnMut(JacobianData<'b>) + 'a)>,
config: &SolverConfig,
) -> Result<Solution<'a>, SolveError>;
fn edge_types(&self) -> &[Type];
}
Expand description
Trait which defines functionality shared between
MeshAnalysis
and NodalAnalysis
.
Required Methods§
Sourcefn new(network: &Network) -> Self
fn new(network: &Network) -> Self
Create a new MeshAnalysis
or NodalAnalysis
instance from the given network.
Since the network has already been checked during its creation, this operation is infallible.
Sourcefn solve<'a>(
&'a mut self,
resistances: Resistances<'_>,
current_src: CurrentSources<'_>,
voltage_src: VoltageSources<'_>,
initial_edge_resistances: Option<&[f64]>,
initial_edge_currents: Option<&[f64]>,
jacobian: Option<&mut (dyn for<'b> FnMut(JacobianData<'b>) + 'a)>,
config: &SolverConfig,
) -> Result<Solution<'a>, SolveError>
fn solve<'a>( &'a mut self, resistances: Resistances<'_>, current_src: CurrentSources<'_>, voltage_src: VoltageSources<'_>, initial_edge_resistances: Option<&[f64]>, initial_edge_currents: Option<&[f64]>, jacobian: Option<&mut (dyn for<'b> FnMut(JacobianData<'b>) + 'a)>, config: &SolverConfig, ) -> Result<Solution<'a>, SolveError>
Try to solve the network for the given excitations and resistances.
This is the central method of NetworkAnalysis
which tries to calculate a Solution
which satisfies the given
constraints (excitations and resistance).
Depending on the chosen method (MeshAnalysis
or NodalAnalysis
),
the problem is transformed into a matrix equation of the type A * x = b
using the mesh
or nodal methods.
Such a system can be solved directly if A
and b
(resistances and excitations) are constant. If they aren’t, the system
is solved iteratively with the Newton-Raphson algorithm.
This method expects the following mandatory information:
resistances
: EdgeValueInputs of the network, seeResistances
.current_src
: Current excitation of the network, seeCurrentSources
.voltage_src
: Voltage excitation of the network, seeVoltageSources
.
Additionally, the iteration can be sped up with the following optional arguments:
initial_edge_resistances
: If provided, these values will be used for the initial guess of the edge resistances (in further iterations, the Newton-Raphson algorithm calculates the edge resistances). If not provided, the initial guess is 1 for all edges. Providing a reasonable guess here (e.g. stemming from further knowledge of the system) can reduce the number of iterations and therefore speed up the solution process. The argument has no influence if the system can be solved directly.initial_edge_currents
: If provided, these values will be used for the initial guess of the edge currents (in further iterations, the Newton-Raphson algorithm calculates the edge currents). If not provided, the initial guess is 0 for all edges. See bullet pointinitial_edge_resistances
for further information.jacobian
: SeeJacobianData
.
Lastly, the Newton-Raphson algorithm requires some configuration parameters:
config
: SeeSolverConfig
. This struct provides reasonable defaults via itsDefault
implementation.
§Examples
The following example shows how to solve a network with both current and voltage source and a resistance value which depends on the current going through it.
use std::collections::HashMap;
use approx; // Needed for result assertion
use network_analysis::*;
// Problem definition
// =====================================================================
/*
This creates the following network with a current source at 0 and a voltage source at 3
┌─[1]─┬─[2]─┐
[0] [6] [3]
└─[5]─┴─[4]─┘
*/
let mut edges: Vec<EdgeListEdge> = Vec::new();
edges.push(EdgeListEdge::new(vec![5], vec![1], Type::Current));
edges.push(EdgeListEdge::new(vec![0], vec![2, 6], Type::Resistance));
edges.push(EdgeListEdge::new(vec![1, 6], vec![3], Type::Resistance));
edges.push(EdgeListEdge::new(vec![2], vec![4], Type::Voltage));
edges.push(EdgeListEdge::new(vec![3], vec![5, 6], Type::Resistance));
edges.push(EdgeListEdge::new(vec![4, 6], vec![0], Type::Resistance));
edges.push(EdgeListEdge::new(vec![1, 2], vec![4, 5], Type::Resistance));
let network = Network::from_edge_list_edges(&edges).expect("valid network");
/*
Resistance 6 is the square root of the current going through it plus an
offset of 1. All other resistances are 1.
*/
let resistances = Resistances::Function(&|mut args: FunctionArgs<'_>| {
for (idx, val) in args.edge_value_and_type.iter_mut() {
if idx == 6 {
*val = 1.0 + args.edge_currents[6].abs().sqrt();
} else {
*val = 1.0;
}
}
});
let voltages = VoltageSources::Slice(&[0.0, 0.0, 0.0, -5.0, 0.0, 0.0, 0.0]);
let currents = CurrentSources::Slice(&[2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]);
let config = SolverConfig::default();
// Solving and analyzing the solution
// =====================================================================
let mut mesh_analysis = MeshAnalysis::new(&network);
let solution_mesh = mesh_analysis.solve(resistances, currents, voltages, None, None, None, &config).expect("can be solved");
// How many iterations were needed?
assert_eq!(solution_mesh.iter_count(), 7);
let mut nodal_analysis = NodalAnalysis::new(&network);
let solution_nodal = nodal_analysis.solve(resistances, currents, voltages, None, None, None, &config).expect("can be solved");
// How many iterations were needed?
assert_eq!(solution_nodal.iter_count(), 7);
for solution in [solution_mesh, solution_nodal].into_iter() {
// Check the resistances
let r: HashMap<_, _> = solution.resistances_and_indices().iter().collect();
assert_eq!(r[&1], 1.0);
approx::assert_abs_diff_eq!(r[&6], 1.532, epsilon = 1e-3);
// Edge currents of 0, 1 and 5 are forced to be equal to the value of the current excitation
assert_eq!(solution.currents()[0], 2.0);
assert_eq!(solution.currents()[1], 2.0);
assert_eq!(solution.currents()[5], 2.0);
// Edge currents of 2, 3 and 4 are identical because of Kirchhoffs's law
approx::assert_abs_diff_eq!(solution.currents()[2], 2.283, epsilon = 1e-3);
approx::assert_abs_diff_eq!(solution.currents()[3], 2.283, epsilon = 1e-3);
approx::assert_abs_diff_eq!(solution.currents()[4], 2.283, epsilon = 1e-3);
// Kirchhoff's current law is fulfilled: Current through edge 6 is the difference
// between the current through the edges 0, 1 and 5 and the current through the
// edges 2, 3 and 4
approx::assert_abs_diff_eq!(solution.currents()[6], -0.283, epsilon = 1e-3);
}
Sourcefn edge_types(&self) -> &[Type]
fn edge_types(&self) -> &[Type]
Returns the edge types.
Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.