-------------------------------------------------------------------------------
-- This is capacitor model.  It was written by Jim Lear at Cirrus Logic in 2010
-- and is released directly to the public domain without copyright restrictions.
-------------------------------------------------------------------------------

library work;
use work.thevenin_pkg.all;

entity capacitor is

  generic (
    V0 : real := 0.0;                   -- initial value
    Ts : real := 1.0e-6;                -- integrator sample period in seconds
    R  : real := 1.0e-3;                -- non-zero inline resistance required
    C  : real := 1.0);

  port (
    p, n : inout thevenin := (Vth => 0.0, Rth => real'right));

-- Note: non-ideal capacitor.  Non-zero inline resistance is required.
end capacitor;

library work;
use work.thevenin_pkg.all;
library ieee;
use ieee.math_real.all;

architecture one of capacitor is
  signal driven_p, driven_n : uthevenin := (rth => real'right, vth => 0.0);
  signal Vc : real := V0;
begin  -- one

  -- purpose: Integrates the current though the capacitor
  -- type   : combinational
  -- inputs : p, n
  -- outputs: Vc
  integrator: process
    variable external_p, external_n : uthevenin;
    variable i : real := 0.0;
    variable Vapplied, Rapplied : real := 0.0;
  begin  -- process integrator
    wait for Ts*1 sec;
    -- calculate instantaneous current
    external_p := external_drive(p, driven_p);
    external_n := external_drive(n, driven_n);
    Vapplied := external_p.vth-external_n.vth-Vc;
    Rapplied := external_p.Rth+external_n.Rth+R;
    Vc <= Vc+Vapplied*(1.0-exp(-Ts/Rapplied/C));
  end process integrator;

  -- purpose: drives the p output
  -- type   : combinational
  -- inputs : n
  -- outputs: p
  calc_p: process (n, Vc)
    variable external_n : uthevenin;
  begin  -- process calc_p
    external_n := external_drive(n, driven_n);
    driven_p.rth <= external_n.rth+R;
    driven_p.vth <= external_n.vth+Vc;
  end process calc_p;

  -- purpose: drives the n output
  -- type   : combinational
  -- inputs : p
  -- outputs: n
  calc_n: process (p, Vc)
    variable external_p : uthevenin;
  begin  -- process calc_p
    external_p := external_drive(p, driven_p);
    driven_n.rth <= external_p.rth+R;
    driven_n.vth <= external_p.vth-Vc;
  end process calc_n;

  p <= driven_p;
  n <= driven_n;

end one;
