basnijholt / adaptive-lighting

Adaptive Lighting custom component for Home Assistant
https://basnijholt.github.io/adaptive-lighting/
Apache License 2.0
1.92k stars 138 forks source link

Explaining the formula that underpins the brightness and color temperature changes #633

Open backcountrymountains opened 1 year ago

backcountrymountains commented 1 year ago

Not an error but I would like to have documentation about the logic and formulas used to determine the brightness and color temperature. I'm not that smart and it took me a while to figure out what was going on with:

        """Calculate the position of the sun in %."""
        now = dt_util.utcnow()

        target_time = now + timedelta(seconds=transition)
        target_ts = target_time.timestamp()
        today = self.relevant_events(target_time)
        (_, prev_ts), (next_event, next_ts) = today
        h, x = (  # pylint: disable=invalid-name
            (prev_ts, next_ts)
            if next_event in (SUN_EVENT_SUNSET, SUN_EVENT_SUNRISE)
            else (next_ts, prev_ts)
        )
        k = 1 if next_event in (SUN_EVENT_SUNSET, SUN_EVENT_NOON) else -1
        percentage = (0 - k) * ((target_ts - h) / (h - x)) ** 2 + k
        return percentage

Can we add some comments to that or do a little explanation somewhere in the README?

Draft: The formula and logic for calculating the brightness is a set of parabolas that approximate $-\cos\left(\frac{\pi}{12}x\right)$, which is a cosine curve with a period of 24.

The values oscillate between -1 at midnight, to 0 at sunrise, to 1 at noon, to 0 at sunset and back to -1 at midnight.

There are 4 time events that control the value of the function: sunrise, solar noon, sunset, and solar midnight.

The logic looks at the next event after target_ts, which is a few seconds after the time now.

k = -1 between sunset and sunrise (sun below horizon) k = 1 between sunrise and sunset (sun above horizon)

target_ts is the current time + the transition time of the light, so it's the time now + a few seconds, or ~now.

h alternates between being the event previous to ~now and the next event after ~now. x also alternates, taking on the alternate value of h, e.g. if h is the previous event, x is the next event.

(h - x) is the time span between consecutive events, e.g. between midnight and sunrise.

(target_ts - h) is the time between ~now, and an event, h (sunrise, noon, sunset, midnight).

The following table shows the values

next event=> sunrise noon sunset midnight
$h – x$ = relevant time span midnight to sunrise sunrise to noon noon to sunset sunset to midnight
k -1 1 1 -1
h midnight noon noon midnight
x sunrise sunrise sunset sunset
$$\lvert target\_ts - h \rvert$$ increasing towards sunrise decreasing towards noon increasing towards sunset decreasing towards midnight
$$\left( target \_ ts - h\over h - x \right)^2$$ increasing to 1 at sunrise decreasing to 0 at noon increasing to 1 at sunset decreasing to 0 at midnight
$$- k\left( target \_ ts - h\over h - x \right)^2 + k$$ increasing from -1 to 0 at sunrise increasing from 0 to 1 at noon decreasing from 1 to 0 at sunset decreasing from 0 to -1 at sunset
graph shape $$x^2$$ $$-x^2$$ $$-x^2$$ $$x^2$$

I made a graph using 0 for midnight, 0600 for sunrise, 1200 for noon, and 1800 for sunset: desmos graph

Does anyone have a source for this logic and formula? Who came up with this?

Anyway, I think it's nice to know how it works in human words since I'm not good at interpreting the computer words.

basnijholt commented 1 year ago

This is awesome! We should certainly add this to the README 😄