29 float apparentPower = 0.0f;
30 float powerFactor = NAN;
37 virtual void begin() { _enabled =
true; };
38 virtual void end() { _enabled =
false; };
39 virtual const char* type()
const {
return "virtual"; }
51 _dutyCycleLimit = _contrain(limit, 0, 1);
52 if (_dutyCycle > _dutyCycleLimit)
63 _dutyCycleMin = _contrain(min, 0, _dutyCycleMax);
74 _dutyCycleMax = _contrain(max, _dutyCycleMin, 1);
111 _powerLUTEnabled =
false;
115 if (semiPeriod > 0) {
117 _semiPeriod = semiPeriod;
120 if (_semiPeriod == 0) {
121 ESP_LOGE(
"Dimmer",
"enablePowerLUT: semiPeriod must be provided or must be already set when enabling power LUT");
123 assert(_semiPeriod > 0);
125 _powerLUTEnabled =
true;
150 bool isOnline()
const {
return _enabled && _online; }
159 _dutyCycleFire = 0.0f;
204 _dutyCycle = _contrain(dutyCycle, 0, _dutyCycleLimit);
208 if (_powerLUTEnabled) {
210 _dutyCycleFire = 0.0f;
211 }
else if (mapped == 1) {
212 _dutyCycleFire = 1.0f;
214 _dutyCycleFire = 1.0f -
static_cast<float>(_lookupFiringDelay(mapped, _semiPeriod)) /
static_cast<float>(_semiPeriod);
217 _dutyCycleFire = mapped;
235 float getDutyCycleMapped()
const {
return _dutyCycleMin + _dutyCycle * (_dutyCycleMax - _dutyCycleMin); }
255 bool calculateHarmonics(
float* array,
size_t n)
const {
256 if (array ==
nullptr || n == 0)
260 if (!
isOnline() || _dutyCycleFire <= 0.0f) {
261 for (
size_t i = 0; i < n; i++) {
267 if (_dutyCycleFire >= 1.0f) {
269 for (
size_t i = 1; i < n; i++) {
276 for (
size_t i = 0; i < n; i++) {
280 return _calculateHarmonics(array, n);
283 virtual bool calculateMetrics(
Metrics& metrics,
float gridVoltage,
float loadResistance)
const {
return false; }
285#ifdef MYCILA_JSON_SUPPORT
291 virtual void toJson(
const JsonObject& root)
const;
295 bool _enabled =
false;
296 bool _online =
false;
298 float _dutyCycle = 0.0f;
299 float _dutyCycleFire = 0.0f;
300 float _dutyCycleLimit = 1.0f;
301 float _dutyCycleMin = 0.0f;
302 float _dutyCycleMax = 1.0f;
304 bool _powerLUTEnabled =
false;
305 uint16_t _semiPeriod = 0;
307 virtual bool _apply() {
return _enabled; }
308 virtual bool _calculateHarmonics(
float* array,
size_t n)
const {
309 for (
size_t i = 0; i < n; i++) {
319 static uint16_t _lookupFiringDelay(
float dutyCycle, uint16_t semiPeriod);
321 static inline float _contrain(
float amt,
float low,
float high) {
322 return (amt < low) ? low : ((amt > high) ? high : amt);
325 static bool _calculatePhaseControlHarmonics(
float dutyCycleFire,
float* array,
size_t n) {
329 const float firingAngle = M_PI * (1.0f - dutyCycleFire);
333 const float sin_2a = sinf(2.0f * firingAngle);
334 const float i1_rms = sqrtf((2.0f / M_PI) * (M_PI - firingAngle + 0.5f * sin_2a));
336 if (i1_rms <= 0.001f)
342 const float scale_factor = (2.0f / M_PI) * 0.70710678f * 100.0f / i1_rms;
348 for (
size_t i = 1; i < n; i++) {
349 const float n_f =
static_cast<float>(2 * i + 1);
350 const float n_minus_1 = n_f - 1.0f;
351 const float n_plus_1 = n_f + 1.0f;
354 const float coeff = cosf(n_minus_1 * firingAngle) / n_minus_1 -
355 cosf(n_plus_1 * firingAngle) / n_plus_1;
358 array[i] = fabsf(coeff) * scale_factor;
364 static bool _calculatePhaseControlMetrics(
Metrics& metrics,
float dutyCycleFire,
float gridVoltage,
float loadResistance) {
365 if (loadResistance > 0 && gridVoltage > 0) {
366 if (dutyCycleFire > 0) {
367 const float nominalPower = gridVoltage * gridVoltage / loadResistance;
368 if (dutyCycleFire >= 1.0f) {
370 metrics.powerFactor = 1.0f;
372 metrics.power = nominalPower;
373 metrics.voltage = gridVoltage;
374 metrics.current = gridVoltage / loadResistance;
375 metrics.apparentPower = nominalPower;
379 metrics.powerFactor = std::sqrt(dutyCycleFire);
380 metrics.thdi = 100.0f * std::sqrt(1 / dutyCycleFire - 1);
381 metrics.power = dutyCycleFire * nominalPower;
382 metrics.voltage = metrics.powerFactor * gridVoltage;
383 metrics.current = metrics.voltage / loadResistance;
384 metrics.apparentPower = gridVoltage * metrics.current;
389 metrics.voltage = 0.0f;
390 metrics.current = 0.0f;
391 metrics.power = 0.0f;
392 metrics.apparentPower = 0.0f;
393 metrics.powerFactor = NAN;