const AXIAL_RESISTANCE: f64 = 1e4; const CAPACITANCE: f64 = 1e-5; const LEAK_RESISTANCE: f64 = 1e6;
const CABLE_LENGTH: f64 = 500.0; const NUM_POINTS: usize = 600;
const DELTA_TIME: f64 = 1e-3;
const ACCURACY: f64 = 1e-3;
const POINT_DISTANCE: f64 = (CABLE_LENGTH) / (NUM_POINTS - 1) as f64; const R_AXIAL: f64 = AXIAL_RESISTANCE * POINT_DISTANCE; const C: f64 = CAPACITANCE * POINT_DISTANCE; const R_LEAK: f64 = LEAK_RESISTANCE / POINT_DISTANCE;
#[test]
fn leaky_cable() {
let mut point_locations = Vec::with_capacity(NUM_POINTS);
let mut m =
impulse_response::Model::new(DELTA_TIME, ACCURACY, DELTA_TIME / 10_000.0, f64::EPSILON);
for idx in 0..NUM_POINTS {
let fraction = idx as f64 / (NUM_POINTS - 1) as f64;
point_locations.push((fraction - 0.5) * CABLE_LENGTH);
m.touch(idx);
}
let center_point_location = point_locations[NUM_POINTS / 2];
for x in point_locations.iter_mut() {
*x -= center_point_location;
}
let derivative_function =
|voltage: &impulse_response::SparseVector,
derivative: &mut impulse_response::SparseVector| {
for (point, v) in voltage.iter() {
let mut total_current = v / R_LEAK;
let mut adjacent = Vec::with_capacity(2);
if *point > 0 {
adjacent.push(*point - 1)
}
if *point + 1 < NUM_POINTS {
adjacent.push(*point + 1)
}
for adj in adjacent {
match voltage.get(&adj) {
Some(adj_v) => {
total_current += (v - adj_v) / R_AXIAL;
}
None => {
let current = v / R_AXIAL;
total_current += current;
derivative.insert(adj, current / C);
}
}
}
derivative.insert(*point, -total_current / C);
}
};
let v_source = 3.3;
let length_constant = f64::sqrt(LEAK_RESISTANCE / AXIAL_RESISTANCE);
let time_constant = LEAK_RESISTANCE * CAPACITANCE;
let steady_state =
|point: usize| v_source * f64::exp(-point_locations[point].abs() / length_constant);
assert!(CABLE_LENGTH > 10.0 * length_constant);
assert!(POINT_DISTANCE < length_constant / 10.0);
assert!(DELTA_TIME < time_constant / 10.0);
let mut voltages = vec![0.0; NUM_POINTS];
voltages[NUM_POINTS / 2] = v_source;
let mut next_voltages = vec![0.0; NUM_POINTS];
let mut elapsed_time = 0.0;
while elapsed_time <= time_constant * 20.0 {
m.advance(&voltages, &mut next_voltages, derivative_function);
std::mem::swap(&mut voltages, &mut next_voltages);
voltages[NUM_POINTS / 2] = v_source;
elapsed_time += DELTA_TIME;
}
for point in 0..NUM_POINTS {
let exact = steady_state(point);
let apprx = voltages[point];
if apprx >= ACCURACY {
assert!(apprx <= exact * 1.01);
assert!(apprx >= exact * 0.99);
}
}
}