extern crate sparsela;
use sparsela::SparseMatrix;
pub enum RspiceError {
InternalError,
CouldNotSolve,
}
impl std::fmt::Debug for RspiceError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
f.write_str(match self {
RspiceError::InternalError => "rspice: internal error",
RspiceError::CouldNotSolve => "rspice: no solution or underspecified",
})?;
Ok(())
}
}
#[derive(Clone, Copy)]
pub struct NetRef {
index: usize,
}
#[derive(Clone, Copy)]
pub struct ConnectionRef {
index: usize,
}
#[derive(Clone)]
pub struct ComponentRef {
connections: Vec<usize>,
}
impl ComponentRef {
pub fn connection(&self, index: usize) -> ConnectionRef {
ConnectionRef {
index: self.connections[index],
}
}
pub fn connection_count(&self) -> usize {
self.connections.len()
}
pub fn assemble(connections: &Vec<ConnectionRef>) -> Self {
let mut raw_connections = Vec::new();
for connection in connections {
raw_connections.push(connection.index);
}
Self {
connections: raw_connections,
}
}
}
#[derive(Clone, Copy)]
pub struct EquationRef {
index: usize,
}
pub struct TransientMatrix {
coefficient: SparseMatrix<f64>,
constant: Vec<f64>,
net_count: usize,
connection_count: usize,
}
impl std::fmt::Debug for TransientMatrix {
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
for y in 0..(self.net_count + self.connection_count) * 2 {
for x in 0..(self.net_count + self.connection_count) * 2 {
f.write_str(&format!("{:4} ", self.coefficient[(y, x)]))?;
}
f.write_str(&format!("| {:4}\n", self.constant[y]))?;
}
Ok(())
}
}
impl TransientMatrix {
fn new(net_count: usize, connection_count: usize) -> Self {
let total_size = (net_count + connection_count) * 2;
Self {
coefficient: SparseMatrix::new((total_size, total_size)),
constant: vec![0.0; total_size],
net_count: net_count,
connection_count: connection_count,
}
}
pub fn clear_equation(&mut self, equation: EquationRef) {
self.coefficient
.clear_row(self.net_count * 2 + equation.index);
self.constant[self.net_count * 2 + equation.index] = 0.0;
}
pub fn voltage_term(&mut self, equation: EquationRef, net: NetRef) -> &mut f64 {
&mut self.coefficient[(self.net_count * 2 + equation.index, net.index * 2)]
}
pub fn voltage_derivative_term(&mut self, equation: EquationRef, net: NetRef) -> &mut f64 {
&mut self.coefficient[(self.net_count * 2 + equation.index, net.index * 2 + 1)]
}
pub fn current_term(&mut self, equation: EquationRef, connection: ConnectionRef) -> &mut f64 {
&mut self.coefficient[(
self.net_count * 2 + equation.index,
(self.net_count + connection.index) * 2,
)]
}
pub fn current_derivative_term(
&mut self,
equation: EquationRef,
connection: ConnectionRef,
) -> &mut f64 {
&mut self.coefficient[(
self.net_count * 2 + equation.index,
(self.net_count + connection.index) * 2 + 1,
)]
}
pub fn constant_term(&mut self, equation: EquationRef) -> &mut f64 {
&mut self.constant[self.net_count * 2 + equation.index]
}
fn raw_current_term(&mut self, raw_equation: usize, connection: usize) -> &mut f64 {
&mut self.coefficient[(raw_equation, (self.net_count + connection) * 2)]
}
fn raw_current_derivative_term(&mut self, raw_equation: usize, connection: usize) -> &mut f64 {
&mut self.coefficient[(raw_equation, (self.net_count + connection) * 2 + 1)]
}
fn solve(&self) -> Result<Vec<f64>, RspiceError> {
match self
.coefficient
.clone()
.solveGauss(&self.constant, Some(1e-6f64))
{
Ok(v) => Ok(v),
Err(_) => Err(RspiceError::CouldNotSolve),
}
}
}
pub struct TransientVector {
vector: Vec<f64>,
net_count: usize,
}
impl TransientVector {
fn new(vector: Vec<f64>, net_count: usize) -> Self {
Self {
vector: vector,
net_count: net_count,
}
}
pub fn voltage(&self, net: NetRef) -> f64 {
self.vector[net.index * 2]
}
pub fn voltage_derivative(&self, net: NetRef) -> f64 {
self.vector[net.index * 2 + 1]
}
pub fn current(&self, connection: ConnectionRef) -> f64 {
self.vector[(self.net_count + connection.index) * 2]
}
pub fn current_derivative(&self, connection: ConnectionRef) -> f64 {
self.vector[(self.net_count + connection.index) * 2 + 1]
}
}
mod basic_component;
pub use basic_component::BasicComponent;
mod circuit;
pub use circuit::Circuit;
pub mod components;
mod transient_result;
pub use transient_result::TransientResult;