доработки всякие

This commit is contained in:
2026-08-12 12:11:55 +03:00
parent 862781fa6a
commit 1db89fca79
9 changed files with 163 additions and 37 deletions

View File

@@ -89,7 +89,7 @@ bool dutyWithin(float measured, float expected, float tolerance) {
}
float effectiveTolerancePct(float configured) {
return configured > 0.0f && configured <= 1.0001f ? 1.25f : configured;
return configured;
}
uint8_t choosePwmResolution(uint32_t frequencyHz, uint32_t sourceClockHz,
@@ -166,14 +166,17 @@ bool chooseIntegerPwmConfig(uint32_t requestedHz, uint32_t sourceClockHz,
}
FailReason validateResolution(uint32_t frequencyHz, float dutyPct, float accuracyPct,
uint32_t captureHz, uint8_t pwmBits) {
if (!frequencyHz || !captureHz || !pwmBits) return FailReason::RESOLUTION;
uint32_t captureHz, uint8_t pwmBits,
uint16_t averagingPeriods) {
if (!frequencyHz || !captureHz || !pwmBits || !averagingPeriods)
return FailReason::RESOLUTION;
const float periodTicks = static_cast<float>(captureHz) / frequencyHz;
const float activeTicks = periodTicks * dutyPct / 100.0f;
const float inactiveTicks = periodTicks - activeTicks;
if (periodTicks < 4.0f || activeTicks < 2.0f || inactiveTicks < 2.0f) return FailReason::RESOLUTION;
const float timerPeriodError = 100.0f / periodTicks;
const float timerDutyError = 100.0f / periodTicks;
const float averagedTicks = periodTicks * averagingPeriods;
const float timerPeriodError = 100.0f / averagedTicks;
const float timerDutyError = 100.0f / averagedTicks;
// Measurement uses the duty actually programmed into LEDC. A coarse PWM
// step is not itself an error when the requested value (e.g. 50%) is exactly
// representable; only the selected value's actual quantization matters.
@@ -256,3 +259,60 @@ FailReason evaluatePeriodFast(const PulsePeriod &p, uint32_t tickHz,
}
return reason;
}
FailReason evaluatePeriodWindow(uint64_t periodSum, uint64_t activeSum,
uint32_t periodCount, uint32_t tickHz,
float expectedHz, float expectedDuty,
float tolerance,
uint32_t minPeriod, uint32_t maxPeriod,
uint8_t repeat,
StageStats &s) {
if (!periodSum || !periodCount || activeSum >= periodSum || !tickHz)
return FailReason::EXTRA_EDGE;
const float hz = static_cast<float>(
static_cast<double>(tickHz) * periodCount / periodSum);
const float duty = static_cast<float>(
100.0 * static_cast<double>(activeSum) / periodSum);
bool frequencyOk = periodWithin(hz, expectedHz, tolerance);
if (!frequencyOk && maxPeriod == minPeriod + 1U) {
// At a tolerance boundary, alternating adjacent RMT counts prove that the
// result is quantization-limited. Accept only when a one-tick correction
// toward the expected value returns the averaged frequency into tolerance.
// Consecutive periods telescope into one first-to-last edge interval, so
// the whole window has a one-tick endpoint uncertainty, not one tick per
// period.
uint64_t correctedPeriodSum = periodSum;
if (hz > expectedHz) ++correctedPeriodSum;
else if (periodSum > 1U) --correctedPeriodSum;
const float correctedHz = static_cast<float>(
static_cast<double>(tickHz) * periodCount / correctedPeriodSum);
frequencyOk = periodWithin(correctedHz, expectedHz, tolerance);
}
bool dutyOk = dutyWithin(duty, expectedDuty, tolerance);
if (!dutyOk) {
// Unlike full periods, active intervals do not telescope: every pulse is
// bounded by a different rising/falling edge pair. With slowly drifting
// asynchronous clocks an entire short window can therefore quantize to
// the same adjacent count (e.g. 41/80 for a true 50% duty). Apply one tick
// per active interval even when minActive == maxActive.
const bool dutyHigh = duty > expectedDuty;
const uint64_t correctedActive = dutyHigh
? (activeSum > periodCount ? activeSum - periodCount : 0U)
: activeSum + periodCount;
const float correctedDuty = static_cast<float>(
100.0 * static_cast<double>(correctedActive) / periodSum);
dutyOk = dutyWithin(correctedDuty, expectedDuty, tolerance);
}
FailReason reason = !frequencyOk ? FailReason::PERIOD_OUT :
(!dutyOk ? FailReason::DUTY_OUT : FailReason::NONE);
if (reason != FailReason::NONE && s.reason == FailReason::NONE) {
s.reason = reason;
s.firstBadPeriod = s.periods >= periodCount ? s.periods - periodCount + 1U : 1U;
s.firstBadRepeat = repeat;
s.badFrequency = hz;
s.badDuty = duty;
}
return reason;
}