Pulp 1.88.0
Cross-platform audio plugin framework
Loading...
Searching...
No Matches
junction.hpp
Go to the documentation of this file.
1#pragma once
2
61
62#include <algorithm>
63#include <cmath>
64
66
69inline constexpr double kThermalVoltage = 0.02585;
70
74inline constexpr double kMaxExponent = 80.0;
75
77inline double safe_exp(double x) {
78 return std::exp(std::clamp(x, -kMaxExponent, kMaxExponent));
79}
80
85inline double exprel(double x) {
86 if (std::abs(x) < 1e-6) return 1.0 + x * 0.5 + x * x * (1.0 / 6.0);
87 return std::expm1(std::clamp(x, -kMaxExponent, kMaxExponent)) / x;
88}
89
98 double saturation_current = 1e-14;
99
101 double ideality = 1.0;
102
105 double leg_a = 1.0;
106
109 double leg_b = 1.0;
110
112 double theta() const { return ideality * kThermalVoltage; }
113
116 double current(double v) const {
117 const double t = theta();
118 return saturation_current * (safe_exp(leg_a * v / t) - safe_exp(-leg_b * v / t));
119 }
120
123 double conductance(double v) const {
124 const double t = theta();
125 return saturation_current / t *
126 (leg_a * safe_exp(leg_a * v / t) + leg_b * safe_exp(-leg_b * v / t));
127 }
128
131 double antiderivative(double v) const {
132 const double t = theta();
133 return saturation_current * v * (exprel(leg_a * v / t) - exprel(-leg_b * v / t));
134 }
135
150 double conduction_estimate(double v_drive, double resistance) const {
151 const double leg = v_drive >= 0.0 ? leg_a : leg_b;
152 if (!(leg > 0.0)) return v_drive;
153 const double ratio = std::abs(v_drive) / (resistance * saturation_current);
154 if (!(ratio > 1.0)) return v_drive;
155 const double magnitude = (theta() / leg) * std::log(ratio);
156 return std::copysign(std::min(magnitude, std::abs(v_drive)), v_drive);
157 }
158
166 double knee_voltage(double target_current) const {
167 if (!(leg_a > 0.0)) return 0.0;
168 return (theta() / leg_a) * std::log(target_current / saturation_current + 1.0);
169 }
170
178 double adaa_current(double v, double previous, double epsilon) const {
179 const double delta = v - previous;
180 if (std::abs(delta) <= epsilon) return current(v);
181 return (antiderivative(v) - antiderivative(previous)) / delta;
182 }
183
203 double adaa_conductance(double v, double previous, double epsilon) const {
204 const double delta = v - previous;
205 // HALF the conductance, not the conductance. As `v → p` the quotient
206 // `(F1(v) − F1(p))/(v − p)` tends to `i(p)` but its SLOPE tends to
207 // `i'(p)/2` — the mean of `i` over a collapsing interval moves at half
208 // the rate of `i` itself. Returning the full conductance here overstates
209 // the Jacobian by exactly 2x near the fallback, which is where a solve
210 // spends most of its time on a slow-moving signal.
211 if (std::abs(delta) <= epsilon) return 0.5 * conductance(v);
212 const double integral = antiderivative(v) - antiderivative(previous);
213 return (current(v) * delta - integral) / (delta * delta);
214 }
215};
216
217} // namespace pulp::signal::junction
Definition junction.hpp:65
constexpr double kMaxExponent
Ceiling on an exponent argument, so a transient overshoot cannot produce inf.
Definition junction.hpp:74
constexpr double kThermalVoltage
Thermal voltage k·T/q at 300 K, in volts.
Definition junction.hpp:69
double exprel(double x)
(exp(x) − 1) / x, with the removable singularity at 0 handled.
Definition junction.hpp:85
double safe_exp(double x)
exp(x) with the argument clamped into the safe range.
Definition junction.hpp:77
@ ratio
base_frequency_hz * ratio.
Definition fm_operator_engine.hpp:20
@ e
Definition formant_filter_bank.hpp:20
One junction network: the exponential law over one or two antiparallel legs.
Definition junction.hpp:94
double conduction_estimate(double v_drive, double resistance) const
A closed-form estimate of where a clipped node voltage will land, for use as a solver's warm start.
Definition junction.hpp:150
double saturation_current
Is, the reverse saturation current.
Definition junction.hpp:98
double ideality
n, the ideality factor. Sets the knee's SOFTNESS: higher is softer.
Definition junction.hpp:101
double leg_b
Reciprocal series-diode count of the reverse leg.
Definition junction.hpp:109
double leg_a
Reciprocal series-diode count of the forward leg.
Definition junction.hpp:105
double adaa_current(double v, double previous, double epsilon) const
First-order antiderivative-antialiasing evaluation of the current between two consecutive junction vo...
Definition junction.hpp:178
double theta() const
θ = n·V_T, the exponential's scale in volts.
Definition junction.hpp:112
double knee_voltage(double target_current) const
The junction voltage at which the network conducts target_current on its forward leg — the conduction...
Definition junction.hpp:166
double conductance(double v) const
di/dv — the incremental conductance a Newton solve needs.
Definition junction.hpp:123
double adaa_conductance(double v, double previous, double epsilon) const
d/dv of adaa_current — the Jacobian a Newton solve needs when its residual is built on the ADAA quoti...
Definition junction.hpp:203
double antiderivative(double v) const
∫i(v)dv, in closed form — no numerical quadrature.
Definition junction.hpp:131
double current(double v) const
i(v).
Definition junction.hpp:116