21

I'm a hobbyist programmer, and not much of a mathematician. I'm trying to model something like the seasonal change in day length. There are two other questions here that are very similar to mine, and I posted a bounty for one of them, but the answers are over my head, and I don't think I can adapt them to what I'm doing. I was thinking more something like a sine-ish function, and hoping for some easier math. Perhaps if I show my specific case, the answers can be narrowed and simplified.

What I've been able to come up with is a function getSunHeight(x, cycleDuration, dayToNightRatio). (It's not for Earth; I'm experimenting with different values in a simulation, so a 24-hour cycle isn't a given.)

In mathematical terms, getSunHeight is calculated as follows.

Let $d_{\text{cycle}}$ denote the duration of a full cycle and $r_\text{day-to-night}$ denote the ratio of day to night.

Let $$d_\text{daylight} = d_\text{cycle} \times r_\text{day-to-night}$$ and $$d_\text{darkness}= d_\text{cycle} - d_\text{daylight}$$ Then the sun height is $$y(x)=\left\{ \begin{array}{lcl} \sin\left(\frac{\pi x}{d_\text{daylight}}\right) & : & 0\le x\le d_\text{daylight}\\ \sin\left(\frac{\pi\left(x-d_\text{cycle}\right)}{d_\text{darkness}}\right) & : & d_\text{daylight} < x \le d_\text{cycle} \end{array} \right.$$

So $y=\operatorname{getSunHeight}(x, 10, 0.2)$ gives me a graph like this:

enter image description here

Is there some way to get rid of the hard angle at $x=d_\text{daylight}$ (i.e. daylightDuration)? It's not a problem if the shape of the curve changes slightly; in fact it might be better, more realistic.

Also, I'm not trying for a general case where I specify the latitude. I'm looking for something that assumes I'm at a fixed latitude. Further, although I'm trying to model a change in the period, I'm not particularly attached to that approach. It was suggested that I try to vary the height of the sun and keep the period the same. After lots of experimentation on Desmos, I'm still at a loss.

I've been experimenting with averaging the slopes at that discontinuity, and using that average somewhere in the equation, but I haven't been able to make any headway.

News: With inspiration from the comments, I've finally realized that I need to think about the entire winter/summer cycle, not just one day/night cycle. I think I almost have it solved:

Let $d_{\text{annualCycle}}$ denote the duration of a full summer/winter cycle, expressed in full day/night cycles

Let $d_{\text{diurnalCycle}}$ denote the duration of a full day/night cycle

Let $d_{\text{daylight}}$ denote the duration of daylight for one day/night cycle

Let $d_{\text{darkness}}$ denote the duration of darkness for one day/night cycle

Let $r_{\text{day-to-night}}$ denote $d_{\text{daylight}}:d_{\text{diurnalCycle}}$ at the first solstice! At the second solstice, the ratio is 1 - $r_{\text{day-to-night}}$, and at the equinoxes, the day/night ratio is 1:1 (d'oh!)

Finally, rather than thinking of the sun's height, with all that angle stuff, I'll think of the function as a kind of temperature reading. So with a function

y = getTemperature(x, $d_{\text{diurnalCycle}}$, $d_{\text{annualCycle}}$, $r_{\text{day-to-night}}$)

I've come up with this:

Let yearFullDuration = $d_{\text{annualCycle}} \ x \ d_{\text{diurnalCycle}}$

Let $r_{\text{night-to-day}} = 1 - r_{\text{day-to-night}}$

Let $c=\left(r_{\text{night-to-day}}-r_{\text{day-to-night}}\right)\sin\left(\frac{2\pi r_{\text{night-to-day}}}{d_{\text{diurnalCycle}} r_{\text{day-to-night}}}\right)+r_{\text{night-to-day}}$

$y = \sin\left(\frac{2\pi xd_{\text{diurnalCycle}}}{\text{yearFullDuration}}\right) + \sin\left(\frac{1.3 cxr_{\text{night-to-day}}}{\text{yearFullDuration}}\right)$

It gives me a graph like the following. As you can see, the zeros don't land quite where they're supposed to. I put in a fudge factor of 1.3, which is incredibly unsatisfying, but I haven't yet figured out how to the crossings right.

Latest progress 2020.07.25

More News:

Again, with much inspiration and help from the comments, I've figured out the easier case of just adding the seasonal sine to the diurnal sine. The thing that was eluding me--the reason for the fudge factor of 1.3--was the need to square one of the ratios in the seasonal sine:

Let $d_{\text{diurnal}}$ denote the duration of one day/night cycle

Let $d_{\text{annual}}$ denote the number of full diurnal cycles in one summer/winter cycle

Let $d_{\text{full-year}}=d_{\text{annual}}*d_{\text{diurnal}}$

Let $r_{s}$ denote the ratio of daylight duration to $d_{diurnal}$ at the summer (first) solstice

Let $f_{a}=\sin\left(\frac{2xr_{s}^{2}}{d_{\text{full-year}}}\right)$ -- the annual curve

Let $f_{d}=\sin\left(\frac{2\pi xd_{\text{diurnal}}}{d_{\text{full-year}}}\right)$ -- the diurnal curve

And finally

$y=\frac{1}2\sin\left(f_{a}+f_{d}\right)$

The graph comes out looking like one might expect if one were more math-oriented. I'm still very curious to see whether there's a way to smoothly vary the daylight/darkness ratio as the seasons progress (my original idea, extended over the course of a year rather than just one day). I've been all over that one and not made any progress.

sai-kartik
  • 2,090
  • 9
    Side note: join the dark side and become a Mathematician! We have c̶o̶o̶k̶i̶e̶s̶ okay we don't have cookies, the Computer Scientists stole those - but we have ${\pi}$! – Riemann'sPointyNose Jul 23 '20 at 19:56
  • 3
    I used the python package https://pypi.org/project/ephem/ when I wanted to plot the solar noon versus my solar cell max production. Maybe it can help you as well. EDIT: Specifically to your question, maybe try a single $\sin$, with an offset to determine the night $y=\sin(2\pi{T\over 24})+ \text{offset}$ where the offset is a function of the daylight duration. – user619894 Jul 23 '20 at 16:52
  • @user619894 Thanks, I looked into ephem when you mentioned it the other day. I'm working with Swift, which is no problem, because someone has ported it already. But it looked pretty complicated. I guess I might go with that, thanks. Still, it would be interesting to see if there's anything like this that can work. Cheers – SaganRitual Jul 25 '20 at 04:10
  • 3
    https://blog.plover.com/calendar/Greek-clock.html – MJD Jul 25 '20 at 04:32
  • 1
    What do you mean by "height" of the sun? In particular, the max angle of the sun is going to change with the season, so perhaps all you have to do is just shift the sine function up or down like @user619894 said? If we let $T$ be the exact day/time of year, i.e. a real number between 0 and 365, then we could write a function like: $$\sin(2\pi T) + \sin(2\pi T/365) $$ (We could throw in some constants to account for latitude and daylight savings issues and others. The idea computes daylight from scratch rather than taking it as input. Let me know if this kind of solution might work for you?) – Sherwin Lott Jul 25 '20 at 23:32
  • 1
    @SherwinLott I think that's exactly the kind of solution I need. I've edited my question to show my progress. It almost works, but not quite. I'm still working on it, open to any ideas you have, cheers – SaganRitual Jul 26 '20 at 01:21
  • 1
    Would the following satisfy your original requirement$$\sin\left(\frac{\pi \left((1+r_\text{day-to-night}) x+(1-r_\text{day-to-night}) d_\text{cycle}\right)x}{d_\text{cycle}^2}\right)\ ?$$ The function$$\frac{\pi \left((1+r_\text{day-to-night}) x+(1-r_\text{day-to-night}) d_\text{cycle}\right)x}{d_\text{cycle}^2}$$appearing as the argument of the $\sin$ is smooth, strictly increasing, and has values $\ \pi\ $ and $\ 2\pi\ $ at $\ x=d_\text{daylight}\ $ and $\ x= d_\text{cycle}\ $, respectively. – lonza leggiera Jul 26 '20 at 01:47
  • @lonzaleggiera It totally satisfies my original question, although of course now I realize my original question was not the right question. Any thoughts on the expanded version? – SaganRitual Jul 26 '20 at 02:27
  • If a year comprises $n$ days of equal length $d > 0,$ then time $t$ belongs to day $i = \left\lfloor{t/d}\right\rfloor \in {0, 1, \ldots, n-1},$ for $t \in [0, nd).$ The daytime fraction of diurnal cycle $i$ could be $a = \tfrac12 + \left(a_\text{max} - \tfrac12\right)\sin(2\pi{i}/n),$ where $a_\text{max}$ is the Summer solstice value. Night-to-day ratio is $c = (1 - a)/a.$ If $f_c$ is one of the two functions I defined in a previous answer, $\sin(2\pi f_c(t/d-i))$ is continuously differentiable on $[0, nd),$ and seems to oscillate in a realistic way; but is this the kind of thing you want? – Calum Gilhooley Jul 26 '20 at 12:15
  • Indeed, time $t$ needn't be restricted to $[0, nd).$ It can have any real value, and the diurnal cycle number $i$ can then be any integer. Although the numbers $a$ and $c$ depend discontinuously on $t$, the function defined in terms of $f_c$ is continuously differentiable, because $f_c$ was constructed to have derivative $1$ at $0$ and $1,$ with precisely this kind of application in mind. (I hope that's right! I've only just seen this new question, having been busy recently writing a long and detailed appendix to my answer to the previous question.) – Calum Gilhooley Jul 26 '20 at 12:33
  • My main question is: do you want the graph of the temperature function to look like the second graph above - i.e., with a higher-frequency wiggle superimposed upon a lower-frequency wiggle - or do you want it to look like a chain of copies of the first graph above (getSunHeight), each copy having its own night-to-day ratio, which varies throughout the year? My function does the latter (without any "hard angles"). A low-frequency wiggle could be superimposed on it, by simply adding a suitable sine term; but I'm not clear if this was wanted, or if it was only an undesirable "fudge factor". – Calum Gilhooley Jul 26 '20 at 14:24
  • The effect of the seasons is much smaller than the rotation of the earth in terms of whether it is light out. Try something like: $$y = \sin\left(\frac{2\pi xd_{diurnalCycle}}{yearFullDuration}\right) + k\sin\left(\frac{cxr_{night-to-day}}{yearFullDuration}\right)$$ Where maybe $k = 23.5/90$ the tilt of the earth, which is slightly crude but might be enough for your application. There's a whole literature on getting this exactly right, see: The Sunrise Equation and Sun Declination. – Sherwin Lott Jul 26 '20 at 15:48
  • @CalumGilhooley My original thought was to vary the day/night ratio, while the amplitude of the curve would stay the same. I experimented with your functions, but I think I'm doing something wrong. From a practical standpoint, the second graph is probably close enough for my purposes, but I'd really like to have a graph with sensible values in it (values actually related to my parameters as opposed to out-of-thin-air values like 1.3 in the graph above). I'd gladly welcome your further input. – SaganRitual Jul 26 '20 at 18:11
  • So you are not looking for an accurate answer that models the real universe, but a reasonable answer that can be used, say, in a computer game? – timur Jul 26 '20 at 18:29
  • @timur Yes, that's exactly it. I want to be able to specify a couple of durations and ratios and get my "temperature" to fluctuate with the "days" and "seasons". I have something that is already kind of reasonable, but now I'm fixated on being able to derive the equations from my parameters, rather than hard-coding values like 1.3 in 2nd graph above – SaganRitual Jul 26 '20 at 18:37
  • 1
    In reality, the highest temperature lags behind the longest days. You don't want to take that into account? – timur Jul 26 '20 at 18:47
  • In other words, a more natural variable would be EnergyPerDay that depends on the duration of the day and height of the sun, and the temperature would be the sum of all EnergyPerDay(i). – timur Jul 26 '20 at 18:49
  • Is this roughly the kind of temperature variation you want, for a simplified planet whose years are 8 days long, and whose summer solstice days are twice as long as the nights? – Calum Gilhooley Jul 26 '20 at 19:27
  • 1
    I think all you really need to do is scale down the second sine function and you're done. (Again, perhaps by the tilt of the earth $23.5/90$.) – Sherwin Lott Jul 26 '20 at 21:16
  • @CalumGilhooley Something like that, yes, although I was originally thinking of curves that are rounder. Is there not really a good way to make the period change smoothly? – SaganRitual Jul 26 '20 at 22:39
  • It looks ugly in Wolfram Alpha, too! $\ \ddot\frown\ $ – Calum Gilhooley Jul 26 '20 at 23:00
  • The cubic spline looks much better! $\ \ddot\smile\ $ – Calum Gilhooley Jul 26 '20 at 23:18
  • @CalumGilhooley Wow! That's exactly the kind of curve I'm hoping for -- could it be adapted to a whole summer/winter cycle to make the light/dark durations change? Without making the math any harder to read? Haha, cheers – SaganRitual Jul 26 '20 at 23:45
  • Earth's orbit is an ellipse with eccentricity 0.0167. At the time of year when it's closer to the sun, it travels faster than when it is farther from the sun. If a day is a solar day, the earth has to rotate through more than 360 degrees in one day because its axial rotation is in the same direction as is orbit. By how much more is greater when the Earth is traveling faster. I believe the difference from shortest solar day to longest solar day is almost a minute. My point is that a really accurate accounting can't be a simple combination of sine waves because the period varies over the year. – 2'5 9'2 Jul 27 '20 at 00:15
  • 1
    To compare with the previous graph, computed using Hermite interpolation, here is the graph of annual temperature variation for the same planet with an $8$-day year and a maximum night-to-day ratio of $2$ to $1,$ computed using a cubic spline function. It is amusing and instructive to make an animation out of the two images - it looks for all the world as if the cubic spline function is correcting the silly mistakes made by the Hermite interpolation function! – Calum Gilhooley Jul 28 '20 at 14:54
  • @CalumGilhooley Looks great to me, thanks so much. If you'd like to post a formal answer, I'll ask Mr Gruber, the very helpful gentleman who posted the bounty, what our next steps are – SaganRitual Jul 28 '20 at 16:34
  • @CalumGilhooley: Well, I stepped away from this question for a few days, for external reasons and to grind through the question it raised in my mind that I thought might be able to answer it. I've got some results that I think are very nice, but I don't want to swoop in last minute when the +500 is all but yours. Would you be interested in a friendly competition? I'm going to post my partial result (a Desmos graph) as an answer below anyways, to see if SaganRitual is interested, and figure out how much of a write up to do based on that, but everyone ....(cont.) – JonathanZ Jul 28 '20 at 23:21
  • ... (cont.) involved in this question seems like more than decent people, and I'm sure we can work everything out okay. I'm curious to see what approach you used, and for me, I used this as a starting point to learn how to use Jupyter, Sympy, and Desmos better, and maybe it's worth me posting my work regardless. – JonathanZ Jul 28 '20 at 23:23
  • @JonathanZsupportsMonicaC Please feel free to go ahead! I was going to ignore the bounty, and just answer the original question by applying functions I had defined in a previous answer. (That answer was the really hard work!) Then I found myself idly wondering about the conditions that seem to be required for the bounty. I doodled a few diagrams, and was about to give up when I thought of idealisations that made it tractable after all. If it works out, I'll post it, but I care more about answering the original question, and it wouldn't seem inappropriate for the bounty to go to another answer. – Calum Gilhooley Jul 29 '20 at 00:07
  • @CalumGilhooley: Thank for the reply. I also used the this question as a springboard to follow my own curiosity, but it looped back to a possible answer so I figured it might be worth posting. It'll take me a while to write up (I miss chalk boards - so much easier than writing LaTeX!) but we'll see how it goes. – JonathanZ Jul 29 '20 at 00:15
  • "As you can see, the zeros don't land quite where they're supposed to." No, I don't see this at all. Where do you think they are landing, and where are they supposed to land? – David K Aug 01 '20 at 00:16
  • It's unclear what you are looking for. First, there is no such thing as a function that's going to give you day/night or temperature variation for an entire planet. You'll get one thing going on at the equator, another thing entirely at the poles, and something more complicated in between. For example, if you look at the daily temperature variation for Worcester, MA, USA in 2019, in the entire month of July it barely if ever got below 15 degrees C, but there were plenty of days in January when it stayed below freezing. (There were also some warm days.) – David K Aug 01 '20 at 01:30
  • Actual temperatures can vary a lot more wildly than your sine functions, and they're very hard to predict. If temperature is actually what you want, "fudging" the functions may be the best you can do. And if it's for a fictional planet it will all be guesswork. On the other hand, you have at least one answer that appears to give a reasonably good estimate of the angle of the sun above the horizon at any time during any day of the year for a planet with arbitrary year, day, and axial tilt. It does not account for elliptical orbits but that's a relatively minor effect. – David K Aug 01 '20 at 01:42

3 Answers3

12

The requirement is for a function $h \colon \mathbb{R} \to \mathbb{R}$ satisfying the following conditions. The argument of the function represents time, for the purpose of modelling life on an imaginary planet in a computer game. Each interval $[i, i + 1),$ where $i$ is an integer, represents one day, i.e., one rotation of the planet about its North-South axis. All days have exactly the same length. A year consists of exactly $n$ days, where $n$ is an integer. Because the planet's rotational axis is not perpendicular to the plane of its solar orbit, the length of the period of daylight varies throughout the year. The value of the function $h$ is to represent an idealised concept of temperature, which increases smoothly to a maximum value in the middle of the day (i.e., the period of daylight), then decreases smoothly to a minimum value in the middle of the night, before increasing smoothly again towards the dawn of the next day. That is, the behaviour of $h$ on each interval $[i, i + 1],$ where $i$ is an integer, is like that of a sine function on $[0, 2\pi],$ except that the positive values occur on an interval $(i, i + a),$ and the negative values occur on the interval $(i + a, i + 1),$ where the number $a \in (0, 1)$ is the fraction of the rotational period in which there is daylight (at a given point on the planet's surface, on a given day of the year), and $a$ is not a constant, but has a different value for each value of $i.$ Physical realism is not required, either for the variation in temperature during the day and night, or for the annual variation in the length of the period of daylight, but the value of $a$ should increase from $\frac12$ at the planet's "Spring equinox", to a maximum value $a_\text{max},$ say, at the "Summer solstice", then decrease again to $\frac12$ at the "Autumn equinox", then further to a minimum of $1 - a_\text{max}$ at the "Winter solstice", then increase to $\frac12$ again at the next year's "Spring equinox". The function $h$ must have a continuous derivative.

An older question, Continuous function for day/night with night being c times longer than day, which like this one has some latitude (no pun intended!) of interpretation, asks for a function $f_c \colon [0, 1) \to [0, 1),$ with $\left[0, \frac1{c + 1}\right)$ representing "day" and $\left[\frac1{c + 1}, 1\right)$ representing "night", and $f_c\left(\frac1{c + 1}\right) = \frac12,$ as if $f_c$ represents some physical quantity that changes by equal amounts in the day and night, even though night is $c$ times longer than day, $c$ being an arbitrary strictly positive parameter. I gave two solutions. The first was a polynomial function, obtained using Hermite interpolation. (The necessary general formulae were contained in an older answer of mine, but I gave a self-contained proof of its validity in an appendix to the more recent answer.) Being analytic, this function satisfied even the most rigid interpretation of the requirements of the question, but it also suffered from another form of rigidity, which not only limited the range of values of $c,$ but even for moderate values of $c$ made it uniformly inferior to the second solution, using cubic spline interpolation. The latter was not analytic, but it was continuously differentiable, and it was valid for all values of $c.$

The night-to-day ratio is $c = (1 - a)/a.$ If $f_c$ is either of the functions above [I've hit the length limit, so I can't repeat the definitions!], then the function $$ h \colon \mathbb{R} \to \mathbb{R}, \ t \mapsto \sin(2\pi f_{c(\left\lfloor t\right\rfloor)}(t - \left\lfloor t\right\rfloor)) $$ for some suitable function $$ c \colon \mathbb{Z} \to \mathbb{R}_{>0}, $$ of period $n,$ is continuously differentiable, and satisfies the requirements of the present question. Here is some Python code that implements those functions:

# ~\Work\Comp\Python\3\Lib\maths\diurnal.py
#
# Sun 26 Jul 2020  (created)
# Sat  1 Aug 2020  (updated)
"""
Day/night cycle: https://math.stackexchange.com/q/3766767.

See also previous question: https://math.stackexchange.com/q/3339606.

Has been run using Python 3.8.1 [MSC v.1916 64 bit (AMD64)] on win32. """

all = ['planet', 'hermite', 'spline']

from math import asin, atan, cos, fabs, inf, pi, sin, sqrt import matplotlib.pyplot as plt import numpy as np

class planet(object): # Sun 26 Jul 2020 (created) # Sat 1 Aug 2020 (updated) """ A simplified but not unrealistic model of a quite Earth-like exoplanet. """

def __init__(self, n=8, alg='spline', mod='physical', tilt=5/13, cmax=2):
    # Sun 26 Jul 2020  (created)
    # Sat  1 Aug 2020  (updated)
    &quot;&quot;&quot;
    Create planet, given days/year and axial tilt or max night/day ratio.

    The axial tilt is specified by its sine.
    &quot;&quot;&quot;
    self.n = n
    self.alg = alg
    self.mod = mod
    if mod == 'physical':
        self.tsin = tilt
        expr = self.tsin**2
        self.tcos = sqrt(1 - expr)
        self.tcot = self.tcos/self.tsin
        self.amax = 1/2 + atan(expr/sqrt(1 - 2*expr))/pi
    elif mod == 'empirical':
        self.cmax = cmax
        self.amax = cmax/(cmax + 1)
    else:
        raise ValueError
    self.f = []
    for i in range(n):
        if self.mod == 'physical':
           ai = self.day_frac(i/n)
        elif self.mod == 'empirical':
           ai = 1/2 + (self.amax - 1/2)*sin(2*pi*i/n)
        ci = (1 - ai)/ai
        if alg == 'spline':
            fi = spline(ci)
        elif alg == 'hermite':
            fi = hermite(ci)
        else:
            raise ValueError
        self.f.append(fi)

def day_frac(self, x, tolerance=.000001):
    # Fri 31 Jul 2020  (created)
    # Sat  1 Aug 2020  (updated)
    &quot;&quot;&quot;
    Compute daylight fraction of cycle as a function of time of year.

    Assumes the planet was created with the parameter mod='physical'.
    &quot;&quot;&quot;
    sin2pix = sin(2*pi*x)
    if fabs(sin2pix) &lt; tolerance:  # near an equinox
        return 1/2
    else:
        expr = self.tcot - sqrt(self.tcot**2 - sin2pix**2)
        cos2pix = cos(2*pi*x)
        t_X = expr/(1 + cos2pix)
        t_Y = expr/(1 - cos2pix)
        half_XY = (1 - t_X*t_Y)/(sqrt(1 + t_X**2)*sqrt(1 + t_Y**2))
        a = asin(half_XY/self.tcos)/pi
        if sin2pix &gt; 0:  # k &lt; x &lt; k + 1/2 for some integer k
            return 1 - a
        else:            # k - 1/2 &lt; x &lt; k for some integer k
            return a

def plot(self, xsz=12.0, ysz=3.0, N=50):
    # Sun 26 Jul 2020  (created)
    # Sun 26 Jul 2020  (updated)
    &quot;&quot;&quot;
    Plot the annual graph of temperature for this planet.
    &quot;&quot;&quot;
    plt.figure(figsize=(xsz, ysz))
    args = np.linspace(0, 1, N, endpoint=False)
    xvals = np.empty(self.n*N)
    yvals = np.empty(self.n*N)
    for i in range(self.n):
        fi = self.f[i]
        xvals[i*N : (i + 1)*N] = i + args
        yvals[i*N : (i + 1)*N] = [sin(2*pi*fi.val(x)) for x in args]
    plt.plot(xvals, yvals)
    return plt.show()

def compare(self, xsz=8.0, ysz=6.0, N=600):
    # Fri 31 Jul 2020  (created)
    # Sat  1 Aug 2020  (updated)
    &quot;&quot;&quot;
    Plot the daylight fraction as a function of the time of year.
    &quot;&quot;&quot;
    plt.figure(figsize=(xsz, ysz))
    plt.title(r'Annual variation of day length on tropic of Cancer, ' +
        r'axial tilt <span class="math-container">$= {:.1f}^\circ$</span>'.format(asin(self.tsin)*180/pi))
    plt.xlabel('Time from Spring equinox')
    plt.ylabel('Daylight fraction of cycle')
    xvals = np.linspace(0, 1, N)
    yvals = [self.day_frac(x) for x in xvals]
    plt.plot(xvals, yvals, label='Physical model')
    yvals = [1/2 + (self.amax - 1/2)*sin(2*pi*x) for x in xvals]
    plt.plot(xvals, yvals, label='Sine function')
    plt.legend()
    return plt.show()

class hermite(object): # Sun 26 Jul 2020 (created) # Sun 26 Jul 2020 (updated) """ Hermite interpolation function. """

def __init__(self, c=1):
    # Sun 26 Jul 2020  (created)
    # Sun 26 Jul 2020  (updated)
    &quot;&quot;&quot;
    Create Hermite interpolation function with parameter c.
    &quot;&quot;&quot;
    self.c = c
    self.a = 1/(c + 1)
    self.p = 1/2 - self.a
    self.b = inf if self.p == 0 else 1/2 + 1/(20*self.p)
    self.d = 5*self.a*self.b/2  # == inf if c == 1
    self.q = self.a*(1 - self.a)
    self.coef = 4*self.p**2/self.q**3

def val(self, x):
    # Sun 26 Jul 2020  (created)
    # Sun 26 Jul 2020  (updated)
    &quot;&quot;&quot;
    Compute Hermite interpolation function at point x.
    &quot;&quot;&quot;
    if self.c == 1:
        return x
    else:
        return x + self.coef*(x*(1 - x))**2*(self.d - x)

def deriv(self, x):
    # Sun 26 Jul 2020  (created)
    # Tue 28 Jul 2020  (updated)
    &quot;&quot;&quot;
    Compute derivative of Hermite interpolation function at point x.
    &quot;&quot;&quot;
    if self.c == 1:
        return 1
    else:
        return 1 + 5*self.coef*x*(1 - x)*(x - self.a)*(x - self.b)

def plot(self, xsz=12.0, ysz=7.5, N=50):
    # Sun 26 Jul 2020  (created)
    # Sun 26 Jul 2020  (updated)
    &quot;&quot;&quot;
    Plot Hermite interpolation function.
    &quot;&quot;&quot;
    plt.figure(figsize=(xsz, ysz))
    xvals = np.linspace(0, 1, N, endpoint=False)
    yvals = np.array([self.val(x) for x in xvals])
    plt.plot(xvals, yvals)
    return plt.show()

class spline(object): # Tue 28 Jul 2020 (created) # Tue 28 Jul 2020 (updated) """ Cubic spline interpolation function """ def init(self, c=1): # Tue 28 Jul 2020 (created) # Tue 28 Jul 2020 (updated) """ Create cubic spline interpolation function with parameter c. """ self.c = c self.a = 1/(c + 1) self.p = 1/2 - self.a self.coef0 = self.p/self.a3 self.coef1 = self.p/(1 - self.a)3

def val(self, x):
    # Tue 28 Jul 2020  (created)
    # Tue 28 Jul 2020  (updated)
    &quot;&quot;&quot;
    Compute cubic spline interpolation function at point x.
    &quot;&quot;&quot;
    if self.c == 1:
        return x
    elif x &lt;= self.a:
        return x + self.coef0*x**2*(3*self.a - 2*x)
    else:
        return x + self.coef1*(1 - x)**2*(1 - 3*self.a + 2*x)

def deriv(self, x):
    # Tue 28 Jul 2020  (created)
    # Tue 28 Jul 2020  (updated)
    &quot;&quot;&quot;
    Compute derivative of cubic spline interpolation function at point x.
    &quot;&quot;&quot;
    if self.c == 1:
        return 1
    elif x &lt;= self.a:
        return 1 + 6*self.coef0*x*(self.a - x)
    else:
        return 1 + 6*self.coef1*(1 - x)*(x - self.a)

def plot(self, xsz=12.0, ysz=7.5, N=50, start=0, stop=1):
    # Sun 26 Jul 2020  (created, for class 'hermite')
    # Sun 26 Jul 2020  (updated)
    # Tue 28 Jul 2020  (copied - too lazy to create abstract base class!)
    # Tue 28 Jul 2020  (improved - haven't bothered to improve 'hermite')
    &quot;&quot;&quot;
    Plot cubic spline interpolation function.
    &quot;&quot;&quot;
    plt.figure(figsize=(xsz, ysz))
    xvals = np.linspace(start, stop, N, endpoint=False)  # A bit naughty!
    yvals = np.array([self.val(x) for x in xvals])
    plt.plot(xvals, yvals)
    return plt.show()

def main(): # Sun 26 Jul 2020 (created) # Sat 1 Aug 2020 (updated) """ Function to exercise the module. """ planet(alg='hermite', mod='empirical', cmax=3/2).plot() planet(alg='spline', mod='empirical', cmax=5/2).plot() dat = planet(tilt=3/5) dat.plot() dat.compare()

if name == 'main': main()

end diurnal.py

Here is a graph of annual temperature variation for a planet with an $8$-day year and a maximum night-to-day ratio of $2$ to $1,$ obtained using Hermite interpolation:

Hermite interpolation

and here is a graph for the same planet using cubic spline interpolation:

cubic spline interpolation

It is amusing and instructive to make an animation out of the two images - it looks for all the world as if the cubic spline function is correcting the silly mistakes made by the Hermite interpolation function!

Now to inject at least a little bit of physical realism.

Turning the clock of science back a couple of thousand years, let us consider a perfectly spherical planet orbiting a distant star in a perfect circle at a constant speed. For the sake of simplicity, without sacrificing too much realism, let the planet's axial tilt, the angle between its polar axis and the normal to the ecliptic (orbital plane), be $$ \sin^{-1}\left(\frac5{13}\right) \bumpeq 22.6^\circ. $$ Consider a denizen of the planet who, fortunately for us (if not for him, her, or it!), lives on a circle of latitude that intersects the ecliptic. (There is no reason for this. It just makes the equations more tractable. It's a fictional planet, so we're free to idealise, so long as we do not abandon physical realism altogether. Since starting to write this answer, I have learned from Wikipedia that this circle of latitude is what could be called the planet's "tropic of Cancer".)

Take that point of intersection, $M,$ as $[1, 0, 0]$ in a system of spherical polar coordinates [there are several such systems; it will soon be clear which one I'm using] $[r, \theta, \phi]$ for the planet, whose radius is taken as the unit of length, and whose rotation is ignored, i.e., one should think of the planet as rotating within an invisible spherical shell, upon which is the "fixed" point $M.$ (One can even think of the star as orbiting the planet, i.e., orbiting the "fixed" shell; it makes no difference.) The angle between the polar axis, $SN,$ and the ecliptic is $$ \alpha = \cos^{-1}\left(\frac5{13}\right) \bumpeq 67.4^\circ, $$ so the North pole is $$ N = [1, 0, \alpha], $$ and another point on our friend's circle of latitude (as we shall check later) is $$ Q = [1, \pi, \pi - 2\alpha] \bumpeq [1, 180^\circ, 45.2^\circ]. $$

Projection on plane of polar axis normal to the ecliptic.

In Cartesian coordinates, the North pole $N$ is $$ \mathbf{n} = (\cos\alpha, 0, \sin\alpha), $$ and the point $M$ is $$ \mathbf{m} = (1, 0, 0). $$ A general point on the planet's surface with Cartesian coordinates $$ \mathbf{p} = (x, y, z) = (\cos\phi\cos\theta, \, \cos\phi\sin\theta, \, \sin\phi) $$ lies on the same circle of latitude as $M$ iff $$ \mathbf{p}\cdot\mathbf{n} = \mathbf{m}\cdot\mathbf{n}, $$ i.e., iff \begin{equation} \label{3766767:eq:1}\tag{$1$} \boxed{\cos\phi\cos\theta\cos\alpha + \sin\phi\sin\alpha = \cos\alpha.} \end{equation} We easily check that $Q$ lies on the circle: $$ \cos(\pi - 2\alpha)\cos\pi\cos\alpha + \sin(\pi - 2\alpha)\sin\alpha = \cos2\alpha\cos\alpha + \sin2\alpha\sin\alpha = \cos\alpha. $$

With our convenient choice of $\alpha,$ \eqref{3766767:eq:1} becomes \begin{equation} \label{3766767:eq:2}\tag{$2$} 5\cos\phi\cos\theta + 12\sin\phi = 5. \end{equation} As the planet orbits the faraway star, the terminator between light and darkness is (because the star is, for this purpose, considered to be effectively at infinity) a great circle, consisting of two great semicircles [I don't know if that's a term], each of whose equations in spherical polar coordinates is of the form $\theta =$ constant, the "constant" value changing with constant angular velocity. Our first need is to solve \eqref{3766767:eq:2} for $\phi$ in terms of $\theta$ (to determine the moments of dusk and dawn, so to speak). We already know that $\phi = 0$ when $\theta = 0$ (at point $M$), and $\phi = \pi - 2\alpha$ when $\theta = \pi$ (at point $Q$).

We'll have to be careful about the ranges of values of spherical polar coordinates $[\theta, \phi].$ (I haven't been explicit so far.) That said, I don't think we need to fuss too much about the values of $\theta$; just take everything modulo $2\pi,$ giving an informal preference to the interval $(-\pi, \pi]$ when a definite real value is required. However, we must insist that $-\frac\pi2 < \phi < \frac\pi2.$ (This excludes the point $M$ and its antipodal point, neither of which has a definite value of the azimuthal angle $\theta.$) Because our circle of latitude (the "tropic of Cancer") lies entirely above the ecliptic, we should always find that $0 \leqslant \phi < \frac\pi2.$

The radius of the circle of latitude (in space, ignoring the sphere on which it lies) is $\sin\alpha.$ It lies in a plane whose inclination to the ecliptic is $\tfrac\pi2 - \alpha.$ Looking down on the ecliptic from far above the point $P = (0, 0, 1)$ (itself above the planet's centre $O = (0, 0, 0),$ lying on the ecliptic), we therefore see the circle of latitude as an ellipse with semi-major axis $\sin\alpha$ and semi-minor axis $\sin^2\alpha$:

view from above the ecliptic

The solution of \eqref{3766767:eq:2} (see solution of \eqref{3766767:eq:1} below) is: $$ \phi = 2\tan^{-1}\left( \frac{12 - \sqrt{144 - 25\sin^2\theta}}{5 + 5\cos\theta}\right) \quad (0 \leqslant \theta < \pi). $$ The limit of this expression as $\theta \to \pi{-}$ is (not obviously!) $$ 2\tan^{-1}\left(\frac5{12}\right) = \pi - 2\tan^{-1}\left(\frac{12}5\right) = \pi - 2\alpha, $$ which is as it should be.

Here is a graph from Wolfram Alpha, showing latitude, $\phi,$ as a function of longitude, $\theta,$ on the planet's "tropic of Cancer":

Latitude as a function of longitude on the planet's "tropic of Cancer"

The centre, $C,$ of the circle of latitude has Cartesian coordinates $$ \mathbf{c} = (\cos^2\alpha, 0, \cos\alpha\sin\alpha) = \left(\frac{25}{169}, 0, \frac{60}{169}\right). $$ Two unit vectors orthogonal to each other and to $\mathbf{n} = (\cos\alpha, 0, \sin\alpha)$ are $$ \mathbf{u} = (0, 1, 0), \quad \mathbf{v} = \left(-\sin\alpha, 0, \cos\alpha\right) = \left(-\frac{12}{13}, 0, \frac5{13}\right). $$ The point $C$ and the unit vectors $(\mathbf{u}, \mathbf{v}, \mathbf{n})$ therefore determine a right-handed Cartesian coordinate system, in which a point with the "usual" Cartesian coordinates $\mathbf{p} = (x, y, z)$ has the "new" coordinates $$ \left\langle u, v, w\right\rangle = \left\langle (\mathbf{p} - \mathbf{c})\cdot\mathbf{u}, \, (\mathbf{p} - \mathbf{c})\cdot\mathbf{v}, \, (\mathbf{p} - \mathbf{c})\cdot\mathbf{n} \right\rangle. $$ The circle of latitude is centred on the "new" origin $C,$ its radius is $\sin\alpha,$ and it lies in the plane $w = 0.$ For example, the point $M$ on the circle has the usual Cartesian coordinates $\mathbf{m} = (1, 0, 0),$ therefore its "new" coordinates are \begin{multline*} \mathbf{m'} = \left\langle 0, \, (1 - \cos^2\alpha)(-\sin\alpha) + (-\cos\alpha\sin\alpha)(\cos\alpha), \right. \\ \left. (1 - \cos^2\alpha)(\cos\alpha) + (-\cos\alpha\sin\alpha)(\sin\alpha) \right\rangle = \left\langle 0, \, -\sin\alpha, \, 0 \right\rangle, \end{multline*} as one would expect. Similarly, the point $Q$ on the circle has the usual Cartesian coordinates $\mathbf{q} = (\cos2\alpha, 0, \sin2\alpha),$ therefore its "new" coordinates are \begin{multline*} \mathbf{q'} = \left\langle 0, \, (\cos2\alpha - \cos^2\alpha)(-\sin\alpha) + (\sin2\alpha - \cos\alpha\sin\alpha)(\cos\alpha), \right. \\ \left. (\cos2\alpha - \cos^2\alpha)(\cos\alpha) + (\sin2\alpha - \cos\alpha\sin\alpha)(\sin\alpha) \right\rangle = \left\langle 0, \, \sin\alpha, \, 0 \right\rangle, \end{multline*} which is also as expected.

An unexpectedly crucial role (not expected by me, anyway) is played by the point $R$ where $MQ$ meets $OP.$ This point wasn't even marked in the previous version of the diagram of the plane $OSNMCQRP.$ It is now easily seen from that diagram that $$ \|CR\| = \cos\alpha\cot\alpha = \frac{\cos^2\alpha}{\sin\alpha}. $$ This gives another way to derive the coordinates of the points $K$ and $L$ in the $\left\langle u, v, w \right\rangle$ system.

We have a circle on a sphere. It is smaller than a great circle, so that it has a well-defined "inside", i.e., the smaller of the two connected components of its complement in the sphere. We have a point $P$ inside the circle. (To ensure this, we require $\alpha > \frac\pi4.$) A plane through $O$ and $P$ necessarily intersects the circle in two points, $X$ and $Y,$ subdividing the circle into two arcs.

With appropriate assumptions about orientation (I'm not going to bother being explicit, and it would probably only be confusing to go into detail), $X$ is the point of occurrence of dusk, and $Y$ is the point of occurrence of dawn, on the imaginary planet's "tropic of Cancer". The length of the day at that latitude (equal to the planet's axial tilt), at this time of the year, is proportional to the length of the clockwise arc of the circle of latitude going from $X$ to $Y.$

Day and night are of equal length if and only if the plane of the terminator, $OPXY,$ coincides with the plane $OSNMCQP,$ shown in the first figure above. This is when either $X = M$ and $Y = Q$ (the "Spring equinox" of the planet) or $X = Q$ and $Y = M$ (the "Autumn equinox" of the planet). These are the cases $\theta \equiv 0 \pmod{2\pi},$ and $\theta \equiv \pi \pmod{2\pi},$ respectively.

Let the plane through the polar (rotational) axis $SON$ normal to the plane $OSNMCQP$ intersect the circle of latitude at points $K$ and $L.$ (Again, I'm assuming that it would be more confusing than helpful to try to be explicit about orientation, and I trust that the diagram suffices.) The day is longest (this is the planet's "Summer solstice") when $X = K$ and $Y = L,$ i.e., $\theta \equiv \frac\pi2 \pmod{2\pi}.$ The day is shortest (the "Winter solstice") when $X = L$ and $Y = K,$ i.e., $\theta \equiv -\frac\pi2 \pmod{2\pi}.$

In the $\left\langle u, v, w\right\rangle$ coordinate system, the coordinates of $K$ and $L$ respectively are (I omit the details of the calculation): \begin{align*} \mathbf{k'} = \left\langle \frac{\sqrt{-\cos2\alpha}}{\sin\alpha}, \, \frac{\cos^2\alpha}{\sin\alpha}, \, 0\right\rangle & = \left\langle \frac{\sqrt{119}}{12}, \, \frac{25}{156}, \, 0\right\rangle, \\ \mathbf{l'} = \left\langle -\frac{\sqrt{-\cos2\alpha}}{\sin\alpha}, \, \frac{\cos^2\alpha}{\sin\alpha}, \, 0\right\rangle & = \left\langle -\frac{\sqrt{119}}{12}, \, \frac{25}{156}, \, 0\right\rangle. \end{align*} The length of the clockwise arc $LK,$ divided by the circumference $2\pi\sin\alpha,$ is $$ a_\text{max} = \frac12 + \frac1\pi\tan^{-1}\left( \frac{\cos^2\alpha}{\sqrt{-\cos2\alpha}}\right) = \frac12 + \frac1\pi\tan^{-1}\left( \frac{25}{13\sqrt{119}}\right) \bumpeq 0.5555436, $$ for the imaginary planet.

I wanted to check this result before going on to the more complicated case of general $X$ and $Y.$ It ought to be at least approximately valid for the Earth, even though the Earth's shape is significantly non-spherical. The Earth's axial tilt at present is $\tau \bumpeq 23.43662^\circ.$ Taking $\alpha = \frac\pi2 - \tau,$ we get $$ a_\text{max} = \frac12 + \frac1\pi\tan^{-1}\left( \frac{\sin^2\tau}{\sqrt{1 - 2\sin^2\tau}}\right) \bumpeq 0.5601746, $$ which works out at about 13 hours and 27 minutes. With (to me, at least) surprising exactness, this figure is confirmed here:

Length of longest day on the tropic of Cancer.

I neglected to prove the blindingly "obvious" fact that the solstices occur just when $$ \theta \equiv \pm\frac\pi2\pmod{2\pi}. $$ Perhaps this is truly obvious. Nevertheless, it took me a while to think of a proof: the lengths of the two arcs $XY$ are monotonic functions of the length of the chord $XY,$ or alternatively its distance from the centre $C,$ and, given that $XY$ passes through the fixed point $R$ where $OP$ meets $MQ,$ the length of the chord is minimised, and its distance from $C$ is maximised, when $XY \perp MQ.$

The circle of latitude.

It is now really obvious that we do not need to calculate the coordinates of $X$ and $Y$ in the $\left\langle u, v, w \right\rangle$ system, and it is enough just to calculate the length $\|XY\|,$ which we can easily do in the old $(x, y, z)$ system.

Recall \eqref{3766767:eq:1}: $$ \cos\phi\cos\theta\cos\alpha + \sin\phi\sin\alpha = \cos\alpha. $$ We may as well solve this in general terms, assuming only $$ \frac\pi4 < \alpha \leqslant \frac\pi2. $$ We know that $\phi$ satisfies the condition $$ 0 \leqslant \phi < \frac\pi2. $$ Writing $$ t = \tan\frac\phi2, $$ we therefore have $0 \leqslant t < 1.$ The equation becomes \begin{gather*} (\cos\theta\cos\alpha)\frac{1 - t^2}{1 + t^2} + (\sin\alpha)\frac{2t}{1 + t^2} = \cos\alpha, \\ \text{i.e.,} \quad (\cos\alpha)(1 + \cos\theta)t^2 - 2(\sin\alpha)t + (\cos\alpha)(1 - \cos\theta) = 0. \end{gather*} When $\theta \equiv 0 \pmod{2\pi},$ the two solutions of the quadratic equation are $0$ and $\tan\alpha > 1,$ so $t = 0.$ When $\theta \equiv \pi \pmod{2\pi},$ the equation is linear, with the unique solution $t = \cot\alpha.$ Assume now that $\theta \not\equiv 0 \pmod{2\pi}$ and $\theta \not\equiv \pi \pmod{2\pi}.$ The solutions of the quadratic equation are: $$ t = \frac{\tan\alpha \pm \sqrt{\tan^2\alpha - \sin^2\theta}} {1 + \cos\theta}. $$ Both solutions are strictly positive. The larger of the two is at least: $$ \frac{1 + \sqrt{1 - \sin^2\theta}}{1 + \cos\theta} = \frac{1 + |\cos\theta|}{1 + \cos\theta} \geqslant 1 > \tan\frac\phi2, $$ therefore the only valid solution is $$ \boxed{t_X = \frac{\tan\alpha - \sqrt{\tan^2\alpha - \sin^2\theta}} {1 + \cos\theta},} $$ where the subscript $X$ is used to distinguish this value from the solution of the same equation with $\theta + \pi \pmod{2\pi}$ in place of $\theta$, viz.: $$ \boxed{t_Y = \frac{\tan\alpha - \sqrt{\tan^2\alpha - \sin^2\theta}} {1 - \cos\theta}.} $$ The Cartesian coordinates $(x, y, z)$ of the points $X$ and $Y$ are: \begin{align*} \mathbf{x} & = \left( \frac{1 - t_X^2}{1 + t_X^2}\cos\theta, \, \frac{1 - t_X^2}{1 + t_X^2}\sin\theta, \, \frac{2t_X}{1 + t_X^2} \right) \!, \\ \mathbf{y} & = \left( \frac{1 - t_Y^2}{1 + t_Y^2}\cos\theta, \, \frac{1 - t_Y^2}{1 + t_Y^2}\sin\theta, \, \frac{2t_Y}{1 + t_Y^2} \right) \!. \end{align*} After some heroic simplification, which I won't reproduce here, we get: $$ \boxed{\|XY\| = \|\mathbf{x} - \mathbf{y}\| = \frac{2(1 - t_Xt_Y)}{\sqrt{1 + t_X^2}\sqrt{1 + t_Y^2}}.} $$

The relative simplicity of this result suggests that there is a simpler and more enlightening derivation than the one I found. [There is indeed - see comment below.] We check that it is valid in the two familiar special cases, i.e., the equinoxes and solstices (even though the latter were excluded during the above derivation). When $\theta = 0,$ we have $t_X = 0$ and $t_Y = \cot\alpha,$ therefore $1 + t_Y^2 = 1/\sin^2\alpha,$ therefore $\|XY\| = 2\sin\alpha = \|MQ\|,$ as expected. When $\theta = \frac\pi2,$ we have $\phi_X = \phi_Y,$ so we can drop the subscripts. Directly from \eqref{3766767:eq:1}, we have $\sin\phi = \cot\alpha,$ whence: $$ \|XY\| = 2\frac{1 - t^2}{1 + t^2} = 2\cos\phi = 2\sqrt{1 - \cot^2\alpha} = 2\frac{\sqrt{-\cos2\alpha}}{\sin\alpha} = \|KL\|, $$ which is also as expected.

The length of the clockwise arc $XY,$ expressed as a fraction of the length of the circumference of the circle, is: $$ \boxed{a = \begin{cases} 1 - \frac1\pi\sin^{-1}\frac{\|XY\|}{2\sin\alpha} & (0 \leqslant \theta \leqslant \pi), \\ \frac1\pi\sin^{-1}\frac{\|XY\|}{2\sin\alpha} & (\pi \leqslant \theta \leqslant 2\pi). \end{cases}} $$ This function is implemented in the Python code above. Here is a log of the commands used to generate the graphs below:

>>> from math import pi, sin
>>> tilt = sin(23.43662*pi/180)
>>> tilt
0.39773438277624595
>>> from maths import diurnal
>>> earth = diurnal.planet(tilt=tilt)
>>> earth.amax
0.5601746469862512
>>> 60*(24*earth.amax - 13)
26.651491660201714
>>> earth.compare()
>>> zargon = diurnal.planet(tilt=3/5)
>>> zargon.amax
0.6901603684878477
>>> zargon.compare()

This graph is for the Earth's tropic of Cancer:

axial tilt = 23.43662 degrees

This graph is for the "tropic of Cancer" of an imaginary planet whose axial tilt is $\sin^{-1}\frac35 \bumpeq 36.9^\circ$:

sine of tilt = 3/5

  • 1
    This looks very cool, but I promised myself that I won't dig in to your results until I make a more decent write-up of my mine. Looking forward to it. – JonathanZ Jul 29 '20 at 15:07
  • BTW, I left AlexanderGruber a note in the Pearl Dive chat room, saying I was ready to have my answer "judged". I could keep adding stuff forever, but the bounty expires today (with a 24 hour grace period after that), and your answer looks to be at a good stage too, so I thought I'd notify him. Hope that's okay with you. – JonathanZ Aug 01 '20 at 16:41
  • Congratulations! You're going to hit 10k rep at this rate. – JonathanZ Aug 01 '20 at 17:17
  • 1
    @JonathanZsupportsMonicaC It would be interesting to see if your answer can be used to suggest a more physically realistic replacement (it doesn't have to be completely realistic, of course) for the function $[0, 1] \to [-1, 1],$ $u \mapsto \sin(2\pi u),$ which I used as a merely convenient function to represent temperature change through the day and night. I put all my effort into the easier problem of studying the variation of $a$ (or $c$) throughout the year, and even that turned out to be more than hard enough! – Calum Gilhooley Aug 01 '20 at 18:35
  • Ghilhooley: Well, I'm going to post my "length of day" results, upload my Jupyter notebook, take a well-earned walk, and then dig in to your post. I'm curious to see if there are quantities we independently invented. I'll keep that point in mind. – JonathanZ Aug 01 '20 at 18:43
  • As to temperature, I've been thinking that the amount of heat per unit area that the Sun applies is directly proportional to the $\cos$ of the angle the Sun's ray strike the Earth's surface. If that's roughly sinusoidal then one would use the Heat Equation, which gives an attenuated and phase shifted sine wave as the temperature on the Earth's surface, where the attenuation and phase shift depend on the relative heat capacities of air and earth. That's probably another question. Maybe I should post it and direct my bounty there? – JonathanZ Aug 01 '20 at 18:49
  • Now that I stop to think about it, it is embarrassingly obvious that the expression for $|XY|$ has a simpler form than the one I derived so laboriously, and it can be found by drawing a diagram in the plane of the terminator, which shows immediately that $$ |XY| = 2\sin\frac{\pi - \phi_X - \phi_Y}2 = 2\cos\frac{\phi_X + \phi_Y}2. $$ The formula in terms of $t_X$ and $t_Y$ is probably still as good a way of computing $|XY|$ as any, however. – Calum Gilhooley Aug 02 '20 at 06:48
  • @Callum Gilhooley: I finally got to read your answer. It's clear that you are much more comfortable with geometry than I, who writes co-ordinates and turns things into algebra at the very first opportunity. It looks like we both ended up with the same basic set of assumptions, and I also observed what your last two graphs show, where the parts between the solstices get flatter as the axial tilt increases. I haven't been able to harmonize the other parts of our answers, but I see you've added a Community Wiki response where you are. Curious to see where that leads. – JonathanZ Aug 04 '20 at 00:36
  • Thanks so much for all of this work! Given all these possibilities,I've decided to put them all into my simulation so I can experiment with the differences. My intention has been to make a video for you guys to show the different effects on my simulation, but (1) my computer crashed, needing a new battery (I hope that's all it is), and (2) this is hard stuff! I hope to get my computer back today, and with any luck I'll be able to show you guys my appreciation, even if it's just with a nerdy token. Thanks again, this is way beyond what I had hoped for, cheers – SaganRitual Aug 07 '20 at 23:37
  • 1
    Thanks, @SaganRitual, (and sorry 'bout your computer). This was a great question, and I've thought about relating the motion of the Earth to the changes in day length for a while -- your question gave me the excuse sit down and hammer it out. And apropos of your "this is hard stuff" comment, I've now got a (Jupyter) notebook full of Python code. If you're enjoying coding stuff up yourself, good, but if you have a specific function that you want for your simulation, I could probably generate the Python function super easy. Just let me know what it is if you'd like. – JonathanZ Aug 08 '20 at 00:51
  • I see that this answer has just been upvoted again. There is an important update, and a link to another question, all of which I typed up in detail more than a year ago (with a neat diagram that makes everything much clearer); but I was suffering from overwork (and the emotional aftermath of some stressful events in Maths.SE earlier that year), and I couldn't face coming back and posting this new work. I'll try to get round to it soon, I promise. – Calum Gilhooley Oct 24 '21 at 07:47
9

All the questions asked in this post -- how long the day is , how high does the sun get, how hot is it -- can all be answered if we pick a point on the surface of the Earth (or the fictional planet we are designing), figure out what direction in space is directly "up" and in what direction the Sun lies. So we'll start off by figuring out the formulas for the motion(s) of the planet.

Parameters

The question asks about the Earth, but points towards wanting to use the results for other planets, real or imaginary. So we'll start off leaving many values as parameters, derive our equations, and then assign values at the end. Also, since I'm going to include a few Desmos graphs in this post, I'll include the name used when exporting to Desmos. (The standard variables for some of these parameters are Greek characters, but Desmos handles single character Latin alphabet names more easily.)

  • Axial tilt: $\epsilon$, in radians. Earth value = 0.4091 rad, Desmos: $p$ = 23.44 degrees

  • Latitude: $\phi$, in radians, Desmos: $L$, in degrees

  • Hours in day: $H$, Earth value = 24.0 - This is merely to set the scale in some graphs. Note that this is for a sidereal day, which will probably lead to some confusion later on, but it makes the initial formulation easier.

  • Days in year $Y$, Earth value = 365.25

Simplifications

We'll also make the following simplifying assumptions, which aren't true but should only cause second-order errors:

  • The Earth's orbit is circular, and the Earth travels it at a constant speed.

  • The Earth's axis of rotation is fixed, and the rate of rotation is constant.

  • We will treat the Earth as a sphere of zero radius.

Note that this last item doesn't mean we think of it as a point, as we want to have a different normal vector (or "local up direction") at each point on the surface. It's just that the radius is very small compared to all the other sizes involved so it's ignorable.

If you prefer you can imagine a sphere with its field of unit normal vectors and then let the radius shrink to zero while maintaining the normal vector field -- what you have left is a point, but a very spiky point. Note that this assumption is equivalent to assuming that the Sun is infinitely far away, or that all the light rays from the Sun are parallel.

Co-ordinate System, Initial Position, and Angles of Motion $\alpha$ and $\beta$

To define our co-ordinate system, pick a point at the desired latitude (I picture it as lying in the Northern Hemisphere), and consider midnight on day of the Winter solstice. The Earth's axis of rotation will be tilted as far away from the Sun as possible, and our point is rotated as far away from the Sun as possible. This is our initial position. We will use two angles to parameterize the Earth's motion:

  • Rotation about its axis, denoted by $\alpha$, where $\alpha$: $0 \rightarrow 2\pi$ corresponds to one day's rotation, and

  • Orbit around the Sun, denoted by $\beta$, where $\beta$: $0 \rightarrow 2\pi$ corresponds to one years voyage around the Sun.

These will be tied to our time variable eventually, but we'll leave them as-is for now.

Our coordinate system is as follows:

  • $x$-axis = direction from the (center of the) Sun to the (center of the) Earth at the initial position
  • $z$-axis = "solar system up", i.e. normal to the plane of the Earth's orbit on the same side as the Earth's North Pole
  • $y$ axis = as required for $[x, y, z]$ to be a right-handed triple; also Earth's initial motion from its initial position is in the positive $y$ direction, not the negative.

As to the center of the coordinate system, we won't actually need it, but you can put it at the center of the Earth if you wish.

So, $\alpha$ and $\beta$ fully determine the position of the Earth and the position of our chosen point and direction of "Up" at that point. To compute "Up" we imagine starting with the Earth in an un-tilted orientation (i.e. the rotational axis is directly along the $z$-axis), so "Up" is the surface normal vector for latitude $\phi$

$$N(\phi) = \left[\begin{matrix}\cos{\left(\phi \right)}\\0\\\sin{\left(\phi \right)}\end{matrix}\right]$$

Now we need to rotate the Earth $\alpha$ radians counter-clockwise, which is given by the matrix

$$M_{rot}(\alpha) = \left[\begin{matrix}\cos{\left(\alpha \right)} & \sin{\left(\alpha \right)} & 0\\- \sin{\left(\alpha \right)} & \cos{\left(\alpha \right)} & 0\\0 & 0 & 1\end{matrix}\right]$$

Next we apply the axial tilt rotation:

$$M_{tilt}(\epsilon)=\left[\begin{matrix}\cos{\left(\epsilon \right)} & 0 & \sin{\left(\epsilon \right)}\\0 & 1 & 0\\- \sin{\left(\epsilon \right)} & 0 & \cos{\left(\epsilon \right)}\end{matrix}\right]$$

To deal with the Earth's rotation around the Sun, instead of moving the Earth we will just change the direction the Sun lies in relation to the Earth:

$$r_{sun}(\beta)= \left[\begin{matrix}- \cos{\left(\beta \right)}\\- \sin{\left(\beta \right)}\\0\end{matrix}\right]$$

Bringing it all together, the "Up" direction at latitude $\phi$ at "time" $\alpha$ is

$$ N(\alpha,\phi) = M_{tilt}(\epsilon)\cdot M_{rot}(\alpha) \cdot N(\phi) = \left[\begin{matrix}\sin{\left(\epsilon \right)} \sin{\left(\phi \right)} + \cos{\left(\alpha \right)} \cos{\left(\epsilon \right)} \cos{\left(\phi \right)}\\- \sin{\left(\alpha \right)} \cos{\left(\phi \right)}\\- \sin{\left(\epsilon \right)} \cos{\left(\alpha \right)} \cos{\left(\phi \right)} + \sin{\left(\phi \right)} \cos{\left(\epsilon \right)}\end{matrix}\right] $$

and if we denote the the angle it makes with the Sun by $\theta_{SA}$, (SA = solar angle), then

$$\begin{align} \cos(\theta_{SA}) & = \langle r_{sun}(\beta), N(\alpha,\phi) \rangle \\ & = \sin{\left(\alpha \right)} \sin{\left(\beta \right)} \cos{\left(\phi \right)} - \sin{\left(\epsilon \right)} \sin{\left(\phi \right)} \cos{\left(\beta \right)} - \cos{\left(\alpha \right)} \cos{\left(\beta \right)} \cos{\left(\epsilon \right)} \cos{\left(\phi \right)}\\ \end{align}$$

This is our key formula and the basis for all the rest of our formulas. Though I find the angle of the Sun above the horizon to be more meaningful, so that's what the graphs will show. In degrees, this is just $90 - 180*\theta_{SA}/\pi$.

Adding time to the equation

To watch the Sun move in the sky all we have to do is make $\alpha$ and $\beta$ (linear) functions of time, i.e. recalling that $H$ is the number of hours per day, and $Y$ is the number of days in a year, then

$$\begin{align}\alpha & = 2\pi t/H\\ \beta &= 2\pi t/ HY\end{align}$$

where $t$ is in hours. This Desmos graph will let you play with various parameters. (Recall that $L$ is degrees latitude and $p$ is degrees axial tilt. The $x$ axis is in units of hours.)

One Day At A Time and the Sidereal Cheat

My preferred way to visualize the length of day is to graph the angle of the Sun above the horizon over the course of 24 hours, and use sliders to control the day of the year and the latitude of our point on the Earth

The first thing to try is to let $\beta$ be determined by the day of the year (call it '$d$', running from $0$ to $365$, with $0$ being the winter solstice), and let $\alpha$, running from $0$ to $2\pi$, be determined by the hour of the day. (We will ignore the small variation that $\beta$ makes as it changes over the course of a day.) This yields the formula

$$- \frac{180 \operatorname{acos}{\left(- \left(\sin{\left(\epsilon \right)} \sin{\left(\phi \right)} + \cos{\left(\epsilon \right)} \cos{\left(\phi \right)} \cos{\left(\frac{\pi t}{12} \right)}\right) \cos{\left(\beta \right)} + \sin{\left(\beta \right)} \sin{\left(\frac{\pi t}{12} \right)} \cos{\left(\phi \right)} \right)}}{\pi} + 90$$

and this interactive graph.

If you play with it you can see the motion of the Sun change over the year and with latitude, but you may also notice that something's wrong, because midnight doesn't stay at midnight. In fact, by day 180 high noon is happening at $t = 0$, which is supposed to be midnight. This is because there is a difference between a sidereal day , where rotation is measured against the distant stars, and a solar day, where rotation is measured against the Sun. (Wikipedia article).

Stated briefly, suppose we start at midnight and let the Earth make one full rotation (as measured by our $\alpha$ increasing by $2\pi$). During this time the Earth has orbited the Sun a bit, so our point isn't quite exactly opposite the Sun, i.e. it's not quite yet midnight.

In fact, it takes roughly another 4 minutes before we hit the next midnight, i.e. a sidereal day is 4 minutes shorter than a solar day. This difference throws a bit of bomb into the middle of our whole simulation. When humans were inventing the "hour", all they knew was the period between two midnights (or more likely the period between two noons), and so the hour we usually use is the "solar hour". But our $\alpha$ was based on the sidereal day, so all the places where we used hours to measure $\alpha$ we really should have been saying "sidereal hours". However, this makes no qualitative difference in our results, and would only require a small relabeling of our $x$-axis. And, as the difference is only 1 part in 365 ($\lt 0.3\%$) it's not worth doing.

But, to deal with the problem of midnight skittering all over the day we can do another cheat, On a give day, (as determined by $\beta$), we compensate our daily rotation so that when $\alpha = 0$ we are at solar midnight, instead of sidereal midnight. This means that instead of

$$\begin{align}\cos(\theta_{SA}) & = \langle r_{sun}(\beta), M_{tilt}(\epsilon)\cdot M_{rot}(\alpha) \cdot N(\phi) \rangle\\ & = - \left(\sin{\left(\epsilon \right)} \sin{\left(\phi \right)} + \cos{\left(\epsilon \right)} \cos{\left(\phi \right)} \cos{\left(\frac{\pi t}{12} \right)}\right) \cos{\left(\beta \right)} + \sin{\left(\beta \right)} \sin{\left(\frac{\pi t}{12} \right)} \cos{\left(\phi \right)} \end{align}$$

we will define

$$\begin{align}\cos(\theta_{SA\_sid}) & = \langle r_{sun}(\beta), M_{tilt}(\epsilon)\cdot M_{rot}(\alpha - \beta) \cdot N(\phi) \rangle \\ & = - \left(\sin{\left(\epsilon \right)} \sin{\left(\phi \right)} + \cos{\left(\epsilon \right)} \cos{\left(\phi \right)} \cos{\left(\beta - \frac{\pi t}{12} \right)}\right) \cos{\left(\beta \right)} - \sin{\left(\beta \right)} \sin{\left(\beta - \frac{\pi t}{12} \right)} \cos{\left(\phi \right)}\end{align} $$ The interactive graphic for this formula behaves much better, and I found it very fun to explore by playing around with the sliders. See if you can spot the midnight sun effect, the equinoxes, and the way that the Sun can get directly overhead if you're on the Tropic of Cancer.

Length of Daylight

Let's try to use our model to generate curves showing the length of day over the course of a year. We will base it off the formula for $\cos( \theta_{SA})$, where we will let $\beta$ set the day of the year.

$$ \cos( \theta_{SA}) = \sin{\left(\alpha \right)} \sin{\left(\beta \right)} \cos{\left(\phi \right)} - \sin{\left(\epsilon \right)} \sin{\left(\phi \right)} \cos{\left(\beta \right)} - \cos{\left(\alpha \right)} \cos{\left(\beta \right)} \cos{\left(\epsilon \right)} \cos{\left(\phi \right)}$$

and sunrise and sunset happen when $\cos( \theta_{SA}) = 0$.

If we consider this as an equation in $\alpha$ we can see that it has the form

$$A \sin(\alpha) + B \cos(\alpha) + C = 0$$

where $$\begin{align} A & = \cos(\phi) \sin(\beta) \\ B & = -\cos(\epsilon) \cos(\phi) \cos(\beta) \\ C & = -\sin(\epsilon) \sin(\phi) \cos(\beta)\\ \end{align} $$

This equation is solved by re-writing $A \sin(\alpha) + B \cos(\alpha)$ as $D \cos( \alpha + \alpha_0)$, for appropriate values of $D$ and $\alpha_0$, which gives us

$$ \alpha_{sunrise} = 2 \operatorname{atan}{\left(\frac{A - \sqrt{A^{2} + B^{2} - C^{2}}}{B - C} \right)}$$

and

$$ \alpha_{sunset} = 2 \operatorname{atan}{\left(\frac{A + \sqrt{A^{2} + B^{2} - C^{2}}}{B - C} \right)}$$

(plugging in the values for $A$, $B$, and $C$ make the equation too cumbersome to fit on the page).

So, rescaling $\alpha$ to a 24-hour day (so we can compare our results against the Earth), we get the following graph, where $L$ is latitude, $p$ is axial tilt, $Y$ is number of days in the year, and the $x$ axis is day of the year.

If you "click and hold" on a point on the graph, Desmos will show the co-ordinates. When you first open the graph the sliders are set for Earth and the latitude for Boston, and the $y$-value of the highest point (15.11 hours) agrees very nicely with the value given by timeanddate.com (15:17) .

You might notice that the graph is made up of two pieces, and that's because of our old friend sidereal drift coming in to play again. At some point in the year (around the equinox it seems) the "sidereal sunrise" drifts to coming before "solar midnight", and our equation gets confused and gives us the negative of the number of hours of darkness. (If you increase the range of $y$ on the graph you can see those ghost values hanging around below the $x$-axis.) To make a nicer graph we plot the corrected version of the formula on the same graph -- it's easier than implementing a case-by-case formula in Desmos.

I was thinking that we would be able to produce a graph similar to one that the O.P. included with their question, i.e. this one. I wasn't able to find any values of the parameters that resembled it, and I'm wondering if that's because we've missed something here or if that graph isn't a good model of reality.

Conclusion

The one thing that has struck me about these results is that even though some of the formulas got hairy the generated graphs were pretty boring - they mostly look like a simple sine wave that moves up and down and changes amplitude as we vary latitude and axial tilt. The most "interesting" behavior was at the Tropic of Cancer, where the Sun passing directly overhead put a sharp corner in our graphs. Otherwise, basically just tweaked sine curves.

I'm left wondering if the O.P. could take these results and produce simple formulas that reproduce this observed behavior.

[If anyone wants the code I wrote for this answer, I've uploaded the raw text of the Jupyter notebook here.]

JonathanZ
  • 10,615
  • 1
    If I'd known it's allowed for mathematicians to have this much fun, I might have taken a different career path. I'm going to nerd out and compare the three (or however many) formulas on hand. Thanks so much – SaganRitual Jul 29 '20 at 03:25
  • I'm working on implementing this in Swift; if you have a moment, could you help me with the units? It's not clear to me which parts of the equation are using radians (if any), and where the $\frac{5\pi}{60}$ comes from. Is that a constant you selected deliberately, or something the Python script came up with? – SaganRitual Jul 30 '20 at 01:06
  • @SaganRitual: Hmm not sure I see a $\frac{5\pi}{60}$. Are you working off the equation pasted in my answer, or the formula in the Desmos page? In my program (and the pasted formula) angles are in radian, and then I rescaled them to degrees for Desmos, 'cause that's what Desmos wants. – JonathanZ Jul 30 '20 at 02:30
  • Also, I'm planning to post a much more complete write up by tomorrow PM. Maybe that will clear up some questions? – JonathanZ Jul 30 '20 at 02:33
  • Drat, I thought I was talking like the cool math kids. I was referring to the 0.0833333333333333$\pi \ t$ in a couple of places. I'll sit tight and wait for your illuminations, cheers – SaganRitual Jul 31 '20 at 01:25
  • D'oh, why didn't I see it? That's a $2\pi/24$, which is just basically setting the scale of the x-axis to "hour in the day", where 24 hours = $2\pi$ radians of rotation. – JonathanZ Jul 31 '20 at 03:46
  • 1
    @SaganRitual: Your question about the 0.083333 motivated me to figure out how to get proper fractions working in Sympy, so no need to feel bad about asking. I also tried to be better about noting units in this answer. And since I feel like I've now more-ore-less completed this part, feel free to start hitting me with questions! – JonathanZ Aug 01 '20 at 01:46
  • Oh, and something I realized about units -- Desmos expects radians, making my above remark wrong, but it's me who prefers to think about angular parameters in degrees. So in moving my formulas over to Desmos I rescaled angles (including those controlled by sliders) to be in degrees. Sorry for the confusion. It's just that 45 deg means something to my mind that 0.785 rad doesn't. – JonathanZ Aug 01 '20 at 01:50
  • 1
    Final comment for today: @SaganRitual, most of my work on this is contained in a Jupyter notebook that uses Sympy, Python's symbolic math package. I'd be more than happy to send you a copy of it, but I'm not really sure how to do so through math.se. I'm going to ask on meta if there's a way. – JonathanZ Aug 01 '20 at 01:52
  • Wow, and wow. I'm blown away by all the math, and by how helpful you guys have all been. Please refer to my final comment on Calum's answer, it's for you and everyone else who traveled with me on this interesting journey. You guys are a credit to the SE family – SaganRitual Aug 07 '20 at 23:40
2

Here, to make it easier to harmonise our conclusions, I'll use the standard notation $\varepsilon$ for the axial tilt of the Earth, or that of an imaginary planet. From Axial tilt - Wikipedia:

Earth's orbital plane is known as the ecliptic plane, and Earth's tilt is known to astronomers as the obliquity of the ecliptic, being the angle between the ecliptic and the celestial equator on the celestial sphere. It is denoted by the Greek letter $\varepsilon.$

Earth's axial tilt (obliquity) is currently about 23.4 degrees.

From Earth's orbit - Wikipedia:

From a vantage point above the north pole of either the Sun or Earth, Earth would appear to revolve in a counterclockwise direction around the Sun. From the same vantage point, both the Earth and the Sun would appear to rotate also in a counterclockwise direction about their respective axes.

The angle $\theta$ used in my answer and the angle $\beta$ used in JonathanZ's answer, if I have read it correctly, are shown together here. The diagram takes the position of the Sun, and the Earth's equinoxes and solstices, as fixed, and the Earth's solar orbit as circular. The same diagram will also be used for fictional planets.

Idealised circular orbit of a planet about a star.

That is, $$ \theta \equiv \beta - \frac\pi2 \pmod{2\pi}. $$

There is a confusing variety of similar-looking but incompatible spherical coordinate systems. Many use the Greek letter $\varphi$ to denote either the polar angle (colatitude, inclination angle) or its complement, the elevation angle. Nobody uses the alternative form of the same Greek letter, $\phi,$ so of course that's what I foolishly chose to use! The choice was especially unfortunate because $\phi$ is the standard notation for latitude, as correctly used in JonathanZ's answer. My simplifying assumption made the problem invisible, but now a saner choice must be made.

No choice is without its problems, but for now, at least, I shall use $\psi$ in place of $\phi$ as it was used in my answer. If it is necessary to refer to longitude, I shall use the letter $\lambda.$ Thus, $[1, \theta, \psi]$ and $[1, \lambda, \phi]$ are coordinates in two different spherical systems for the surface of the planet. (Ideally, I should not use $\theta$ in this way, but it will usually have the value defined above, only sometimes being used for $\theta + \pi \pmod{2\pi}.$ I don't think the confusion is serious enough to warrant another change of notation.) When more that one point is involved, I shall continue with the practice of using subscripts to distinguish the coordinate values of one from another.

The "simplifying assumption" just referred to is that we were only interested in the experiences of people, or alien beings, on the "tropic of Cancer" of their respective planets, i.e., the circle of latitude defined by $\phi = \varepsilon.$ That was because I imagined that the equations for the general case would get messy. Even with the simplifying assumption, my equations did get messy. I understood later that this was because I had missed something obvious. If $X$ and $Y$ are points on the respective "great semicircles" defined by $\theta$ and $\theta + \pi \pmod{2\pi},$ then it is (or should have been) clear that the distance $\|XY\|$ is given by $$ \|XY\| = 2\sin\frac{\pi - \psi_X - \psi_Y}2 = 2\cos\frac{\psi_X + \psi_Y}2. $$

Distance between two points on the terminator.

It should now be possible to treat the general case in my notation as well as in JonathanZ's notation, and thereby reconcile the two answers.

[More than one Community Wiki post might be needed, because this one is already quite long.]

I'm particularly interested in checking the realism of the results for the Earth, at several latitudes, and at several times of year - do our simplifications lead to any serious errors?

Projection on plane of polar axis normal to the ecliptic.

For simplicity, I will continue to assume that we are in the Northern hemisphere, i.e., $\phi \geqslant 0.$ (Symmetry can be used to get results for the Southern hemisphere; or else we can just drop the restriction, if it turns out not to simplify anything after all.) In order for $P$ and $R$ to be inside the circle of latitude ($P$ on the surface of the planet, $R$ inside it), we require $$ \phi + \varepsilon < \frac\pi2. $$ In spite of the appearance of the figure, it is not required that $\phi > \epsilon.$ The case $\phi = \varepsilon$ is the one already considered in my answer, i.e., the tropic of Cancer. The case $\phi = 0$ is the Equator. The line through $P$ perpendicular to $SN$ is the projection of the Arctic Circle, the upper bound of latitudes for which there is always an alternation of day and night, i.e., the circle of latitude $\frac\pi2 - \varepsilon.$

The radius of the circle of latitude is $$ \|CU\| = \|CV\| = \cos\phi, $$ and the important point $R$ is given by $$ \|CR\| = \sin\phi\tan\varepsilon. $$ (In the case already considered, $\phi = \varepsilon = \frac\pi2 - \alpha,$ whence $\|CR\| = \cos\alpha\cot\alpha.$)

Denoting by $a(\varepsilon, \phi, \theta)$ the fraction of the circle of latitude $\phi$ that is in daylight at the time of year given by the angle $\theta,$ we have: \begin{equation} \label{3766767:eq:3}\tag{$3$} a(\varepsilon, \phi, \theta + \pi) = a(\varepsilon, -\phi, \theta) = 1 - a(\varepsilon, \phi, \theta) \quad \left(\varepsilon \geqslant 0, \ |\phi| < \frac\pi2 - \varepsilon\right) \end{equation} where addition of angles is modulo $2\pi.$ It is therefore enough to give a formula for the case $\phi \geqslant 0,$ $\pi \leqslant \theta \leqslant 2\pi.$ The result turns out to be quite simple and neat: \begin{gather} \label{3766767:eq:4}\tag{$4$} a(\varepsilon, \phi, \theta) = \frac1\pi\sin^{-1}\sqrt{\frac {1 - \sec^2\phi\sin^2\varepsilon\sin^2\theta} {1 - \sin^2\varepsilon\sin^2\theta}} \\ \notag \left(\varepsilon \geqslant 0, \ \phi \geqslant 0, \ \phi + \varepsilon < \frac\pi2, \ \pi \leqslant \theta \leqslant 2\pi\right). \end{gather} At Northern latitudes, i.e., when $\phi \geqslant 0,$ the values of $a$ at the solstices are: \begin{gather} \label{3766767:eq:5}\tag{$5$} a_\text{max}(\varepsilon, \phi) = a\left(\varepsilon, \phi, \frac{\pi}2\right) = \frac12 + \frac{\sin^{-1}(\tan\varepsilon\tan\phi)}\pi, \\ \notag a_\text{min}(\varepsilon, \phi) = a\left(\varepsilon, \phi, \frac{3\pi}2\right) = \frac12 - \frac{\sin^{-1}(\tan\varepsilon\tan\phi)}\pi. \end{gather} I don't yet know a neat way to derive equation \eqref{3766767:eq:4}, although presumably it can be done by constructing a few cunningly-chosen right-angled triangles. For the moment, I'll give two derivations, both of which are unfortunately quite messy.

First method

In Cartesian coordinates, the North pole $N$ is $$ \mathbf{n} = (\sin\varepsilon, 0, \cos\varepsilon), $$ and the centre, $C,$ of the circle of latitude $\phi$ is $$ \mathbf{c} = (\sin\phi)\mathbf{n} = (\sin\varepsilon\sin\phi, 0, \cos\varepsilon\sin\phi). $$ A point $J$ on the planet's surface whose Cartesian coordinates are $\mathbf{j} = (x, y, z)$ lies on the circle of latitude $\phi$ iff $\mathbf{j}\cdot\mathbf{n} = \mathbf{c}\cdot\mathbf{n},$ i.e., iff $$ x\sin\varepsilon + z\cos\varepsilon = \sin\phi. $$ If $\mathbf{j} = (0, 0, \pm1),$ then $$ |\mathbf{j}\cdot\mathbf{n}| = \cos\varepsilon = \sin\left(\frac\pi2 - \varepsilon\right) > |\sin\phi|, $$ so $J$ does not lie on the plane, and we may ignore those points. If $\mathbf{j} \ne (0, 0, \pm1),$ then $J$ has well-defined spherical polar coordinates $[1, \theta, \psi],$ where $$ (x, y, z) = (\cos\psi\cos\theta, \, \cos\psi\sin\theta, \, \sin\psi), \quad |\psi| < \frac\pi2. $$ In terms of these coordinates, the equation of the plane is \begin{equation} \label{3766767:eq:6}\tag{$6$} \sin\varepsilon\cos\psi\cos\theta + \cos\varepsilon\sin\psi = \sin\phi. \end{equation}

Claim: For all $\varepsilon \geqslant 0,$ all $\phi \in \left(-\frac\pi2 + \varepsilon, \frac\pi2 - \varepsilon\right),$ and all real $\theta,$ equation \eqref{3766767:eq:6} has at least one solution for $\psi \in \left(-\frac\pi2, \frac\pi2\right).$ This follows from the Intermediate Value Theorem, because the left hand side of \eqref{3766767:eq:6} is nearly equal to $\pm\cos\varepsilon$ when $\psi$ is nearly equal to $\pm\frac\pi2$ respectively, and we have just observed, when considering the points $(0, 0, \pm1),$ that $\cos\varepsilon > |\sin\phi|.$ $\ \square$

The value of the coordinate $\psi$ is uniquely determined by the value of $$ t = \tan\frac\psi2 \quad (|t| < 1). $$ In terms of this parameter $t,$ equation \eqref{3766767:eq:6} becomes $$ (\sin\varepsilon\cos\theta)\frac{1 - t^2}{1 + t^2} + (\cos\varepsilon)\frac{2t}{1 + t^2} = \sin\phi, $$ i.e., \begin{equation} \label{3766767:eq:7}\tag{$7$} (\sin\phi + \sin\varepsilon\cos\theta)t^2 - 2(\cos\varepsilon)t + (\sin\phi - \sin\varepsilon\cos\theta) = 0. \end{equation} Consider also the same equation in which $\theta$ is replaced by $\theta + \pi \pmod{2\pi},$ i.e., \begin{equation} \label{3766767:eq:7p}\tag{$7^*$} (\sin\phi - \sin\varepsilon\cos\theta)t^2 - 2(\cos\varepsilon)t + (\sin\phi + \sin\varepsilon\cos\theta) = 0. \end{equation}

Bearing in mind once again the inequality $\cos\varepsilon > |\sin\phi|,$ together with the requirement $|t| < 1,$ we find: (i) if $\sin\varepsilon\cos\theta = \sin\phi,$ then the only admissible solution of \eqref{3766767:eq:7} is $t_X = 0,$ and the only admissible solution of \eqref{3766767:eq:7p} is $t_Y = \sin\phi/\cos\varepsilon$; (ii) if $\sin\varepsilon\cos\theta = -\sin\phi,$ then the only admissible solution of \eqref{3766767:eq:7} is $t_X = \sin\phi/\cos\varepsilon,$ and the only admissible solution of \eqref{3766767:eq:7p} is $t_Y = 0.$ In either of these exceptional cases (i) and (ii), therefore, we have: \begin{equation} \label{3766767:eq:8}\tag{$8$} t_X + t_Y = \frac{\sin\phi}{\cos\varepsilon}; \quad t_Xt_Y = 0. \end{equation}

Suppose now that $\sin\varepsilon\cos\theta \ne \pm\sin\phi.$ Then neither \eqref{3766767:eq:7} nor \eqref{3766767:eq:7p} has zero as a root, and the roots of one equation are the reciprocals of the roots of the other. Because of the requirement $|t| < 1,$ it follows that \eqref{3766767:eq:7} has only one admissible solution $t = t_X,$ and \eqref{3766767:eq:7p} has only one admissible solution $t = t_Y,$ where: \begin{align*} t_X & = \frac{\cos\varepsilon - \sqrt{\cos^2\varepsilon - (\sin^2\phi - \sin^2\varepsilon\cos^2\theta)}} {\sin\phi + \sin\varepsilon\cos\theta}, \\ t_Y & = \frac{\cos\varepsilon - \sqrt{\cos^2\varepsilon - (\sin^2\phi - \sin^2\varepsilon\cos^2\theta)}} {\sin\phi - \sin\varepsilon\cos\theta}. \end{align*} To simplify these formulae, we write $$ A = \sqrt{\cos^2\varepsilon - (\sin^2\phi - \sin^2\varepsilon\cos^2\theta)} = \sqrt{\cos^2\phi - \sin^2\varepsilon\sin^2\theta}. $$ This is well-defined (as indeed it was bound to be), because: $$ \cos^2\phi = \sin^2\left(\frac\pi2 - |\phi|\right) > \sin^2\varepsilon \geqslant \sin^2\varepsilon\sin^2\theta. $$ Recalling the reciprocal relationship between \eqref{3766767:eq:7} and \eqref{3766767:eq:7p}, we obtain: \begin{align*} t_X & = \frac{\cos\varepsilon - A}{\sin\phi + \sin\varepsilon\cos\theta} = \frac{\sin\phi - \sin\varepsilon\cos\theta}{\cos\varepsilon + A}, \\ t_Y & = \frac{\cos\varepsilon - A}{\sin\phi - \sin\varepsilon\cos\theta} = \frac{\sin\phi + \sin\varepsilon\cos\theta}{\cos\varepsilon + A}. \end{align*} This gives: \begin{equation} \label{3766767:eq:9}\tag{$9$} t_X + t_Y = \frac{2\sin\phi}{\cos\varepsilon + A}, \quad t_Xt_Y = \frac{\cos\varepsilon - A}{\cos\varepsilon + A}. \end{equation} In the special cases (i) and (ii) defined by $\sin\varepsilon\cos\theta = \pm\sin\phi,$ we have $A = \cos\varepsilon,$ therefore \eqref{3766767:eq:8} is a special case of \eqref{3766767:eq:9}, therefore \eqref{3766767:eq:9} holds in all cases.

Just as before, with only a change of notation: $$ a = \begin{cases} 1 - \dfrac1\pi\sin^{-1}\dfrac{\|XY\|}{2\cos\phi} & (0 \leqslant \theta \leqslant \pi), \\[1.5ex] \dfrac1\pi\sin^{-1}\dfrac{\|XY\|}{2\cos\phi} & (\pi \leqslant \theta \leqslant 2\pi), \end{cases} $$ and $$ \frac{\|XY\|}2 = \cos\frac{\psi_X + \psi_Y}2 = \frac{1 - t_Xt_Y}{\sqrt{1 + t_X^2}\sqrt{1 + t_Y^2}}. $$ From \eqref{3766767:eq:9}, \begin{gather*} (1 + t_X^2)(1 + t_Y^2) = 1 + (t_X + t_Y)^2 - 2t_Xt_Y + t_X^2t_Y^2 \\ = \frac{(\cos\varepsilon + A)^2 + 4\sin^2\phi - 2(\cos^2\varepsilon - A^2) + (\cos\varepsilon - A)^2} {(\cos\varepsilon + A)^2} \\ = \frac{4A^2 + 4\sin^2\phi}{(\cos\varepsilon + A)^2}, \\ \therefore\ \frac{(t_X + t_Y)^2}{(1 + t_X^2)(1 + t_Y^2)} = \frac{\sin^2\phi}{A^2 + \sin^2\phi}, \\ \therefore\ \frac{(1 - t_Xt_Y)^2}{(1 + t_X^2)(1 + t_Y^2)} = 1 - \frac{(t_X + t_Y)^2}{(1 + t_X^2)(1 + t_Y^2)} = \frac{A^2}{A^2 + \sin^2\phi} = \frac{\cos^2\phi - \sin^2\varepsilon\sin^2\theta} {1 - \sin^2\varepsilon\sin^2\theta}, \\ \therefore\ \frac{1 - t_Xt_Y}{\sqrt{1 + t_X^2}\sqrt{1 + t_Y^2}\cos\phi} = \sqrt{\frac{1 - \sec^2\phi\sin^2\varepsilon\sin^2\theta} {1 - \sin^2\varepsilon\sin^2\theta}}. \end{gather*} This completes the first proof of \eqref{3766767:eq:4}. $\ \square$

Second method

The projection of the circle of latitude $\phi$ onto the $(x, y)$ plane is an ellipse with semi-major axis $\cos\phi,$ semi-minor axis $\cos\varepsilon\cos\phi,$ and centre $(\sin\varepsilon\sin\phi, 0),$ so its equation is $$ \left(\frac{x - \sin\varepsilon\sin\phi}{\cos\varepsilon}\right)^2 + y^2 = \cos^2\phi. $$ The points $X, Y$ project onto the points of intersection $X', Y'$ of the ellipse with the straight line $\{t(\cos\theta, \sin\theta) : t \in \mathbb{R}\}.$ The length of the chord $X'Y'$ is equal to the absolute difference of the roots of the resulting quadratic equation for $t$: $$ \left(\frac{t\cos\theta - \sin\varepsilon\sin\phi}{\cos\varepsilon} \right)^2 + t^2\sin^2\theta = \cos^2\phi. $$ We rewrite this equation successively as \begin{gather*} (\cos^2\theta + \cos^2\varepsilon\sin^2\theta)t^2 - 2(\sin\varepsilon\sin\phi\cos\theta)t + (\sin^2\varepsilon\sin^2\phi - \cos^2\varepsilon\cos^2\phi) = 0, \\ (1 - \sin^2\varepsilon\sin^2\theta)t^2 - 2(\sin\varepsilon\sin\phi\cos\theta)t - (1 - \sin^2\varepsilon - \sin^2\phi) = 0, \end{gather*} which gives $$ \frac{\|X'Y'\|}2 = \frac {\sqrt{\sin^2\varepsilon\sin^2\phi\cos^2\theta + (1 - \sin^2\varepsilon\sin^2\theta) (1 - \sin^2\varepsilon - \sin^2\phi)}} {1 - \sin^2\varepsilon\sin^2\theta} $$ From the figure below, $$ \|XY\| = \|X'Y'\|\sec\eta = \|X'Y'\|\sqrt{1 + \tan^2\varepsilon\cos^2\theta} = \frac{\|X'Y'\|\sqrt{1 - \sin^2\varepsilon\sin^2\theta}} {\cos\varepsilon}. $$

Slope of line from slope of plane.

Substituting into the expression for $a$ in terms of $\|XY\|,$ and simplifying (a lot!), we end up with \eqref{3766767:eq:4}. $\ \square$

# ~\Work\Comp\Python\3\Lib\maths\latitude.py
#
# Wed 12 Aug 2020  (created)
# Fri 14 Aug 2020  (updated)
"""
Day/night cycle: https://math.stackexchange.com/q/3766767.

See also previous question: https://math.stackexchange.com/q/3339606.

Has been run using Python 3.8.1 [MSC v.1916 64 bit (AMD64)] on win32. """

all = ['circle']

from math import asin, fabs, pi, radians, sin, sqrt import matplotlib.pyplot as plt import numpy as np

class circle(object): # Wed 12 Aug 2020 (created) # Fri 14 Aug 2020 (updated) """ A circle of latitude on a spherical planet. """

def __init__(self, lati=4/5, tilt=5/13):
    # Wed 12 Aug 2020  (created)
    # Thu 13 Aug 2020  (updated)
    &quot;&quot;&quot;
    Create circle, given sines of latitude and axial tilt.
    &quot;&quot;&quot;
    self.lsin = lati
    self.tsin = tilt
    self.lcossq = 1 - self.lsin**2
    self.tsinsq = self.tsin**2
    self.amax = self.day_frac(1/4)

def day_frac(self, x, tolerance=.000001):
    # Wed 12 Aug 2020  (created)
    # Thu 13 Aug 2020  (updated)
    &quot;&quot;&quot;
    Compute daylight fraction of cycle as a function of time of year.
    &quot;&quot;&quot;
    sin2pix = sin(2*pi*x)
    if fabs(sin2pix) &lt; tolerance:  # near an equinox
        return 1/2
    else:
        sin2pixsq = sin2pix**2
        expr = self.tsinsq*sin2pixsq
        a = asin(sqrt((1 - expr/self.lcossq)/(1 - expr)))/pi
        if sin2pix &gt; 0:  # k &lt; x &lt; k + 1/2 for some integer k
            return 1 - a
        else:            # k - 1/2 &lt; x &lt; k for some integer k
            return a

def compare(self, xsz=8.0, ysz=6.0, N=600):
    # Wed 12 Aug 2020  (created)
    # Fri 14 Aug 2020  (updated)
    &quot;&quot;&quot;
    Plot the daylight fraction as a function of the time of year.
    &quot;&quot;&quot;
    plt.figure(figsize=(xsz, ysz))
    plt.title(r'Annual variation of day length at latitude ' +
        r'<span class="math-container">${:.2f}^\circ$</span> when axial tilt is <span class="math-container">${:.2f}^\circ$</span>'.format(
        asin(self.lsin)*180/pi, asin(self.tsin)*180/pi))
    plt.xlabel('Time from Spring equinox')
    plt.ylabel('Daylight fraction of cycle')
    xvals = np.linspace(0, 1, N)
    yvals = [1/2 + (self.amax - 1/2)*sin(2*pi*x) for x in xvals]
    plt.plot(xvals, yvals, label='Sine function', c='k', ls=':', lw=.75)
    yvals = [self.day_frac(x) for x in xvals]
    plt.plot(xvals, yvals, label='Physical model')
    plt.legend()
    return plt.show()

def main(): # Wed 12 Aug 2020 (created) # Fri 14 Aug 2020 (updated) """ Function to exercise the module. """ obliquity = sin(radians(23.43661)) greenwich = sin(radians(51.47793)) circle(lati=greenwich, tilt=obliquity).compare()

if name == 'main': main()

end latitude.py

Near Greenwich:

Greenwich

On another imaginary planet:

Axial tilt = 50 degrees, latitude = 39 degrees.

[I haven't finished floundering about yet, but I'll try not to make this answer much longer! If anyone manages to find a neat proof of \eqref{3766767:eq:4}, it could be added here; otherwise, this answer has completed the job of updating my answer to use the same notation as JonathanZ's answer, and to treat the case of general latitudes; so it is probably best frozen (except for the correction of any errors).

I may also ask in Astronomy SE for a reference to \eqref{3766767:eq:4}, which probably exists in an old source, even if not in a modern text. After that, if it remains a puzzle, I'll post a separate question about it in Maths.SE.

In another CW answer, I want to add in a correction for the Earth's movement in its solar orbit during its daily rotation. That should make it straightforward to compare these calculations with those in JonathanZ's answer. Then it would be interesting to add terms to correct for the apparent size of the Sun's disc and (empirically) diffraction in the Earth's atmosphere. Although I, for one, have no interest in trying to model the Earth's non-spherical shape, or its non-circular solar orbit, it would be interesting to get a numerical idea of the accuracy that can be obtained without considering those or other factors.]

  • The above figure was drawn with $\phi=\sin^{-1}\frac45\bumpeq53.13^\circ.$ I notice that according to 53rd parallel north - Wikipedia: "At this latitude the sun is visible for 16 hours, 56 minutes during the summer solstice and 7 hours, 34 minutes during the winter solstice." My simplified model (I haven't checked JonathanZ's answer yet) will give a symmetrical result, which must therefore be in error, perhaps by about 15 minutes at this latitude. (I won't use Wikipedia as a final reference, but it's unlikely to be grossly wrong about this.) – Calum Gilhooley Aug 03 '20 at 21:41
  • If you want some more real-world data to compare models against, I found timeanddate.com really good (scroll down for the complete tables.) One thing to remember is that our calculations give local sun times, and almost everyone else is going to give times for some time zone - so we can only compare time differences, not absolute times. – JonathanZ Aug 04 '20 at 00:39
  • @JonathanZsupportsMonicaC Have you any thoughts about what could be causing an error as large as 15 minutes? I know your answer allows for the rotation of the Earth, while mine doesn't, but I don't think that that factor alone could explain an error of more than about 3 minutes a day. I must be making some basic error, either about that or about something else. Anyway, I'll plough on (when I've had some more sleep!) with converting my arguments into the more sensible notation you used. Perhaps light will dawn. (Pun intended this time.) Congratulations on your bounty, by the way. – Calum Gilhooley Aug 04 '20 at 05:52
  • 1
    Thanks. And while I haven't calculated the numbers yet, the degree values specified for one of the forms of twilight descirbed here seem like they could easily account for the difference. – JonathanZ Aug 04 '20 at 06:13
  • Thanks you guys! Please see my final comments on the other questions. You guys are just awesome, I guess that's all there is to say, thanks so much! – SaganRitual Aug 07 '20 at 23:41
  • Unfortunate clash of notation: in the last geometrical figure, the length $a$ has nothing to do with the daylight fraction $a$ of the circle of latitude $\phi.$ I'll correct this if there is an occasion to edit the answer again. – Calum Gilhooley Aug 16 '20 at 17:13