Skip to content

Capacitor Discharge with Exponential Functions

Try it live on Compiler Explorer

Overview

This example demonstrates using mathematical functions with dimensional analysis by modeling an RC circuit's capacitor discharge. It showcases:

  • How exponential functions work with dimensionless quantities
  • Automatic SI prefix selection for readable output across wide value ranges
  • Dimensional analysis ensuring correct physics

Circuit Model

The example simulates an RC discharge circuit where a charged capacitor discharges through a resistor, following the exponential decay equation:

\[V(t) = V_0 \cdot e^{-\frac{t}{RC}}\]
V₀ R C
  • Parameters:
    • Capacitance: 0.47 μF
    • Initial voltage: 5.0 V
    • Resistance: 4.7 kΩ
    • Time constant: τ = RC = 2.209 ms
5 V 4 V 3 V 2 V 1 V 0 V 0 τ Time Voltage ≈1.84 V @ τ
  • Expected behavior:
    • At t = 0: V = 5.0 V (initial)
    • At t = τ: V ≈ 1.84 V (37% of initial)
    • At t = 5τ: V ≈ 0.034 V (< 1%)

Key Concepts

Dimensional Analysis in Exponential Functions

The library provides exp() that works with dimensionless quantities:

capacitor_time_curve.cpp
{
  using namespace mp_units;
  using namespace mp_units::si::unit_symbols;

  constexpr auto CC = isq::capacitance(0.47 * uF);
  constexpr auto V0 = isq::voltage(5.0 * V);
  constexpr auto RR = isq::resistance(4.7 * si::kilo<si::ohm>);

  std::cout.setf(std::ios_base::fixed, std::ios_base::floatfield);
  std::cout.precision(3);
  std::cout << "Capacitor time curve example for the following parameters:\n";
  std::cout << "Capacitance: " << CC << "\n";
  std::cout << "Initial Voltage: " << V0 << "\n";
  std::cout << "Resistance: " << RR << "\n";

  std::cout << "Time curve:\n";
  for (auto tt = 0 * ms; tt <= 50 * ms; ++tt) {
    const QuantityOf<isq::voltage> auto Vt = V0 * exp(-tt / (RR * CC));
    std::cout << "- at " << tt << " voltage is ";
    si::invoke_with_prefixed([](auto q) { std::cout << q; }, Vt, V);
    std::cout << "\n";
  }
}

How it works:

  1. RC time constant: RR * CC results in a time quantity (Ω·F = s)
  2. Dimensionless ratio: tt / (RR * CC) divides time by timedimensionless
  3. Exponential function: exp() accepts the dimensionless quantity directly
  4. Dimension restoration: Multiplying by V0 gives the result being a voltage quantity

The library automatically verifies dimensional correctness at compile time, preventing common physics errors.

Automatic SI Prefix Selection

Rather than manually selecting output units, the example uses invoke_with_prefixed():

capacitor_time_curve.cpp
    const QuantityOf<isq::voltage> auto Vt = V0 * exp(-tt / (RR * CC));
    std::cout << "- at " << tt << " voltage is ";
    si::invoke_with_prefixed([](auto q) { std::cout << q; }, Vt, V);

This function automatically:

  • Calculates the appropriate SI prefix (V, mV, μV, nV, pV, etc.)
  • Ensures values stay in readable range (typically [1.0, 1000) for engineering mode)
  • Handles the output formatting in a single call

The lambda receives the quantity scaled to the optimal prefix, ready for output.

Sample Output

Capacitor time curve example for the following parameters:
Capacitance: 0.470 µF
Initial Voltage: 5.000 V
Resistance: 4.700 kΩ
Time curve:
- at 0 ms voltage is 5.000 V
- at 1 ms voltage is 3.180 V
- at 2 ms voltage is 2.022 V
- at 3 ms voltage is 1.286 V
- at 4 ms voltage is 817.638 mV    ← Transition to millivolts
- at 5 ms voltage is 519.946 mV
...
- at 15 ms voltage is 5.623 mV
- at 18 ms voltage is 1.446 mV
- at 19 ms voltage is 919.446 µV   ← Transition to microvolts
- at 20 ms voltage is 584.688 µV
...
- at 30 ms voltage is 6.323 µV
- at 34 ms voltage is 1.034 µV
- at 35 ms voltage is 657.491 nV   ← Transition to nanovolts
...
- at 45 ms voltage is 7.110 nV
- at 49 ms voltage is 1.163 nV
- at 50 ms voltage is 739.358 pV   ← Transition to picovolts

The output demonstrates seamless transitions between SI prefixes (V → mV → μV → nV → pV) as the voltage decays over 9 orders of magnitude, keeping values in a readable range throughout.

Why This Matters

Compile-Time Dimensional Safety

The library ensures dimensional correctness at compile time:

// ✓ Correct: time/time is dimensionless
QuantityOf<dimensionless> auto dimensionless_arg = -tt / (RR * CC);

// ✗ Won't compile: can't take exp of a dimensional quantity
// auto wrong = exp(-tt);  // Error: exp requires dimensionless!

This prevents common physics/engineering errors where equations are dimensionally invalid.

Practical Applications

This exponential decay pattern applies across many domains:

  • Electrical: RC/RL circuits, signal decay, filter response
  • Thermal: Newton's law of cooling, heat dissipation
  • Mechanical: Damped oscillations, friction
  • Chemistry: First-order reactions, radioactive decay
  • Biology: Drug metabolism, population decay

Output Readability

Instead of choosing fixed units (forcing users to read 0.000005 V or 5000000 nV), automatic prefix selection maintains readability across 9+ orders of magnitude.