Warning! Will Robinson...

Wait the compiler executes the RLC1 program but there are 15 warnings. Let's not ignore them and try to improve our code.

Warning #1

warning: method `Z` should have a snake case name

  --> examples\rlc1.rs:16:8

   |

16 |     fn Z(&self) -> f64 {

   |        ^ help: convert the identifier to snake case (notice the capitalization): `

   |

   = note: `#[warn(non_snake_case)]` on by default

The compiler is complaining about the use of a capital letter (Z) as a variable name and suggests converting it to snake case. How about res_z?

The change must be made on two lines: (1) In the fn definition and (2) in the function call in main().

Clear the terminal (CTRL-SHFT-P Termina:Clear) and run the program. Now there are 14 warnings.

Next warning: the same warning occurs in the definition for Z in the Inductor and Capacitor structs. Let's change the names to ind_z and cap_z as we did for the Resistor struct.

Clear the terminal (CTRL-SHFT-P Termina:Clear) and run the program. Now there are 12 warnings.

Next warnings: Reviewing the 12 remaining warnings shows that they are all variable name case warnings. Change the variable names as follows:

Zr1 -> z_r1

ABCD1 -> abcd_r1

Zl1 -> z_l1

ABCD2 -> abcd_l1

Zc1 -> z_c1

ABCD3 -> abcd_c1

ABCD -> abcd_ckt

A -> a

B -> b

C -> c

D -> d

S -> s

Here is the updated rlc1.rs code:

// rlc1.rs - Calculate the S-parameters for an RLC circuit
// Method: 2-port cascade analysis using ABCD matrices

// Math libraries
use ndarray::arr2;
use num::complex::Complex;
use std::f64::consts::PI;

// Resistor component
#[derive(Debug)]
struct Resistor {
    pub value: f64,
}

impl Resistor {
    fn res_z(&self) -> f64 {
        let z = self.value;
        z
    }
}

// Inductor component
#[derive(Debug)]
struct Inductor {
    value: f64,
    frequency: f64,
}

impl Inductor {
    fn ind_z(&self) -> Complex<f64> {
        let z = Complex::new(0.0, 1.0 / (2.0 * PI * self.frequency * self.value));
        z
    }
}

// Capacitor component
#[derive(Debug)]
struct Capacitor {
    value: f64,
    frequency: f64,
}

impl Capacitor {
    fn cap_z(&self) -> Complex<f64> {
        let z = Complex::new(0.0, -1.0 * (2.0 * PI * self.frequency * self.value));
        z
    }
}

// Run the analysis
fn main() {
    let r1 = Resistor { value: 75.0 };
    let z_r1 = r1.res_z();
    let abcd_r1 = arr2(&[
        [Complex::new(1.0, 0.0), Complex::new(z_r1, 0.0)],
        [Complex::new(0.0, 0.0), Complex::new(1.0, 0.0)],
    ]);

    let l1 = Inductor {
        value: 5e-9,
        frequency: 2e9,
    };
    let z_l1 = l1.ind_z();
    let abcd_l1 = arr2(&[
        [Complex::new(1.0, 0.0), z_l1],
        [Complex::new(0.0, 0.0), Complex::new(1.0, 0.0)],
    ]);

    let c1 = Capacitor {
        value: 1e-12,
        frequency: 2e9,
    };
    let z_c1 = c1.cap_z();
    let abcd_c1 = arr2(&[
        [Complex::new(1.0, 0.0), z_c1],
        [Complex::new(0.0, 0.0), Complex::new(1.0, 0.0)],
    ]);

    // Display netlist
    println!("\nRLC Netlist:");
    println!("R1 = {:#?}", r1);
    println!("L1 = {:#?}", l1);
    println!("C1 = {:#?}\n", c1);

    // Multiply cascaded component ABCD matrices
    let mut abcd_ckt = abcd_r1.dot(&abcd_l1);
    abcd_ckt = abcd_ckt.dot(&abcd_c1);

    // println!("{:#?}", &ABCD);
    // println!("{}", &ABCD);

    // Convert ABCD to S
    // https://www.rfwireless-world.com/Terminology/abcd-matrix-vs-s-matrix.html

    // S-parameter matrix
    let mut s = arr2(&[
        [Complex::new(0.0, 0.0), Complex::new(0.0, 0.0)],
        [Complex::new(0.0, 0.0), Complex::new(0.0, 0.0)],
    ]);

    // Define A, B, C, D & denominator from the ABCD matrix
    let a: Complex<f64> = abcd_ckt[[0, 0]];
    let b: Complex<f64> = abcd_ckt[[0, 1]];
    let c: Complex<f64> = abcd_ckt[[1, 0]];
    let d: Complex<f64> = abcd_ckt[[1, 1]];

    let denom: Complex<f64> = &a + &b / 50.0 + &c * 50.0 + &c;

    // S-parmater equations from ABCD matrix
    s[[0, 0]] = (&a + &b / 50.0 - &c * 50.0 - &d) / &denom;
    s[[0, 1]] = 2.0 * (&a * &d - &b * &c) / &denom;
    s[[1, 0]] = 2.0 / &denom;
    s[[1, 1]] = (-&a + &b / 50.0 - &c * 50.0 + &d) / &denom;

    // Final S-parameter results
    println!("S-parameters:");
    println!("{}", &s);
}

Wooh! That was painful however the code now runs without warnings.


C:\Users\RICKC\Desktop\rust_projects\engr_tools>cargo run --example rlc1

   Compiling engr_tools v0.1.0 (C:\Users\RICKC\Desktop\rust_projects\engr_tools)

    Finished dev [unoptimized + debuginfo] target(s) in 1.12s

     Running `target\debug\examples\rlc1.exe`


RLC Netlist:

R1 = Resistor {

    value: 75.0,

}

L1 = Inductor {

    value: 5e-9,

    frequency: 2000000000.0,

}

C1 = Capacitor {

    value: 1e-12,

    frequency: 2000000000.0,

}

S-parameters:

[[0.6000000002871457+0.000010717195815763663i, 0.7999999994257085-0.000021434391631527323i],

 [0.7999999994257085-0.000021434391631527323i, 0.6000000002871457+0.000010717195815763663i]]

I feel like a better programmer for resolving these warnings. I know the traditional microwave equations are written with uppercase variables that is why I used uppercase in the first place. However, I still feel better about the code because the compiler is enforcing the Rust Style Guide. Note that some of the variable names are now more expressive:

ABCD1 -> abcd_r1

This is clearer that the ABCD matrix is associated with the resistor. Updated code is available on GitHub.


Comments

Popular posts from this blog

Microwave RLC circuit analysis

Project Setup and Toolchain