Source code for thevenin.loadfns._ramps
from __future__ import annotations
import numpy as np
[docs]
class Ramp:
"""Linearly ramping load."""
__slots__ = ('_m', '_b',)
def __init__(self, m: float, b: float = 0.) -> None:
"""
A load profile that continuously ramps with slope m.
Parameters
----------
m : float
Slope [units/s].
b : float, optional
Y-intercept [units]. The default is 0.
"""
self._m = m
self._b = b
def __repr__(self) -> str: # pragma: no cover
return f"Ramp(m={self._m:.2e}, b={self._b:.2e})"
def __call__(self, t: float) -> float:
return self._m*t + self._b
[docs]
class Ramp2Constant:
"""Ramp to a constant load."""
__slots__ = ('_m', '_b', '_step', '_sharpness',)
def __init__(self, m: float, step: float, b: float = 0.,
sharpness: float = 100.) -> None:
"""
A load profile that ramps with slope m unil the constant step value
is reached, after which, the load is equal to the step constant. A
sigmoid is used to smooth the transition between the two piecewise
functions. Use a large 'sharpness' to reduce smoothing effects.
Parameters
----------
m : float
Slope [units/s].
step : float
Constant step value [units].
b : float, optional
Y-intercept [units]. The default is 0.
sharpness : float, optional
How sharp to make the transition between the ramp and step. Low
values will smooth the transition more. The default is 100.
Raises
------
ValueError
m = 0. and m = inf are invalid slopes.
ValueError
Cannot reach step with m > 0. and b >= step.
ValueError
Cannot reach step with m < 0. and b <= step.
ValueError
'sharpness' must be strictly positive.
"""
if m == 0. or abs(m) == np.inf:
raise ValueError("m = 0. and m = inf are invalid slopes.")
elif m > 0. and b >= step:
raise ValueError("Cannot reach step with m > 0. and b >= step.")
elif m < 0. and b <= step:
raise ValueError("Cannot reach step with m < 0. and b <= step.")
if sharpness <= 0:
raise ValueError("'sharpness' must be strictly positive.")
self._m = m
self._b = b
self._step = step
self._sharpness = np.sign(m)*sharpness
def __repr__(self) -> str: # pragma: no cover
data = {'m': self._m, 'b': self._b, 'step': self._step}
summary = ", ".join([f"{k}={v:.2e}" for k, v in data.items()])
return f"Ramp2Constant({summary})"
def __call__(self, t: float) -> float:
linear = self._m*t + self._b
z = self._sharpness*(linear - self._step)
sigmoid = 1. / (1. + np.exp(-np.clip(z, -700, None)))
return (1. - sigmoid)*linear + sigmoid*self._step