velxio/test/test_circuit/test/diodes.test.js

118 lines
4.6 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { describe, it, expect } from 'vitest';
import { Circuit, Resistor, VoltageSource, Diode, LED, BJT_NPN } from '../src/index.js';
describe('Shockley diode — basic', () => {
it('forward-biased diode in series with R drops ~0.6-0.7V', () => {
const c = new Circuit();
c.addComponent(new VoltageSource('V1', 'vcc', 'gnd', 5));
c.addComponent(new Resistor('R1', 'vcc', 'a', 1000));
c.addComponent(new Diode('D1', 'a', 'gnd')); // default Is=1e-14
c.solveDC();
const Vd = c.nodeVoltage('a');
expect(Vd).toBeGreaterThan(0.55);
expect(Vd).toBeLessThan(0.75);
// Current ≈ (5 0.65)/1000 ≈ 4.35 mA
const I = (5 - Vd) / 1000;
expect(I).toBeGreaterThan(0.004);
expect(I).toBeLessThan(0.005);
});
it('reverse-biased diode blocks current', () => {
const c = new Circuit();
c.addComponent(new VoltageSource('V1', 'vcc', 'gnd', 5));
c.addComponent(new Resistor('R1', 'gnd', 'a', 1000));
c.addComponent(new Diode('D1', 'a', 'vcc')); // anode to 'a' (~0V), cathode to +5V
c.solveDC();
// With the diode reverse biased, no current; 'a' pulled to gnd through R1.
expect(Math.abs(c.nodeVoltage('a'))).toBeLessThan(0.01);
});
});
describe('LED — forward voltage by color', () => {
it('red LED with 220Ω resistor @ 5V → Vf ≈ 2.0V, I ≈ 13.6mA', () => {
const c = new Circuit();
c.addComponent(new VoltageSource('V1', 'vcc', 'gnd', 5));
c.addComponent(new Resistor('R1', 'vcc', 'a', 220));
const led = new LED('LED1', 'a', 'gnd', 'red');
c.addComponent(led);
c.solveDC();
const Vf = c.nodeVoltage('a');
expect(Vf).toBeGreaterThan(1.8);
expect(Vf).toBeLessThan(2.3);
const I = led.currentThrough(c.state);
expect(I).toBeGreaterThan(0.010);
expect(I).toBeLessThan(0.016);
// Brightness proxy: ratio of I to rated 20 mA
const b = led.brightness(c.state);
expect(b).toBeGreaterThan(0.5);
expect(b).toBeLessThanOrEqual(1.0);
});
it('blue LED Vf higher than red', () => {
const mkCircuit = (color) => {
const c = new Circuit();
c.addComponent(new VoltageSource('V1', 'vcc', 'gnd', 5));
c.addComponent(new Resistor('R1', 'vcc', 'a', 220));
c.addComponent(new LED('LED1', 'a', 'gnd', color));
c.solveDC();
return c.nodeVoltage('a');
};
const Vred = mkCircuit('red');
const Vblue = mkCircuit('blue');
expect(Vblue).toBeGreaterThan(Vred);
expect(Vblue).toBeGreaterThan(2.8);
expect(Vblue).toBeLessThan(3.6);
});
it('LED brightness increases with supply voltage', () => {
const readBrightness = (V) => {
const c = new Circuit();
c.addComponent(new VoltageSource('V1', 'vcc', 'gnd', V));
c.addComponent(new Resistor('R1', 'vcc', 'a', 220));
const led = new LED('LED1', 'a', 'gnd', 'red');
c.addComponent(led);
c.solveDC();
return led.brightness(c.state);
};
const b1 = readBrightness(2.0); // below knee
const b2 = readBrightness(3.0);
const b3 = readBrightness(5.0);
expect(b1).toBeLessThan(b2);
expect(b2).toBeLessThan(b3);
expect(b1).toBeLessThan(0.1); // almost off
expect(b3).toBeGreaterThan(0.5); // bright
});
});
describe('BJT NPN — switch mode', () => {
it('NPN saturates with base drive, V_CE < 0.3V', () => {
// V_cc → R_c → collector. Base fed via R_b from +5V. Emitter to gnd.
const c = new Circuit();
c.addComponent(new VoltageSource('V1', 'vcc', 'gnd', 5));
c.addComponent(new VoltageSource('Vb', 'bsrc', 'gnd', 5));
c.addComponent(new Resistor('Rc', 'vcc', 'coll', 1000));
c.addComponent(new Resistor('Rb', 'bsrc', 'base', 10000));
c.addComponent(new BJT_NPN('Q1', 'coll', 'base', 'gnd'));
c.solveDC({ maxIter: 200, tol: 1e-6 });
const Vce = c.nodeVoltage('coll');
const Vbe = c.nodeVoltage('base');
expect(Vbe).toBeGreaterThan(0.5);
expect(Vbe).toBeLessThan(0.85);
// Should be saturated — near 0.10.3 V on real BJT, but simplified Ebers-Moll
// doesn't model saturation aggressively, so we accept up to 0.8 V.
expect(Vce).toBeLessThan(0.8);
// Must be much less than V_cc
expect(Vce).toBeLessThan(c.nodeVoltage('vcc') - 3);
});
it('NPN with no base drive is off, V_CE ≈ V_cc', () => {
const c = new Circuit();
c.addComponent(new VoltageSource('V1', 'vcc', 'gnd', 5));
c.addComponent(new Resistor('Rc', 'vcc', 'coll', 1000));
c.addComponent(new Resistor('Rb', 'gnd', 'base', 10000)); // base pulled to gnd
c.addComponent(new BJT_NPN('Q1', 'coll', 'base', 'gnd'));
c.solveDC({ maxIter: 200, tol: 1e-6 });
expect(c.nodeVoltage('coll')).toBeGreaterThan(4.9);
});
});