NetworkAnalysis

Trait NetworkAnalysis 

Source
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§

Source

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.

Source

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, see Resistances.
  • current_src: Current excitation of the network, see CurrentSources.
  • voltage_src: Voltage excitation of the network, see VoltageSources.

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 point initial_edge_resistances for further information.
  • jacobian: See JacobianData.

Lastly, the Newton-Raphson algorithm requires some configuration parameters:

  • config: See SolverConfig. This struct provides reasonable defaults via its Default 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);
}
Source

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.

Implementors§