-
-
Notifications
You must be signed in to change notification settings - Fork 213
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
find_discrete is more reliable than find_risings/settings #998
Comments
Let's start with this item first, because maybe the documentation could be clearer here. On 02-18 there is no moonrise, so whether you ask for the Moon rise or set, Skyfield instead can only give you the moment of culmination, where the Moon was as close to the horizon as possible — the same moment, whether you are asking about rise or set. Because rise and set only become distinct points when the horizon is intersected. So we would expect both return values to be exactly the same time and elevation. How can the documentation be improved so that users are not surprised at both the rise and the set routine returning the same "sorry, it didn't rise or set" value? Maybe you could clarify what return value you expected in this case. Thanks! |
Greetings, Brandon! Thanks for your prompt response. Scenario 1: almost moonrise The moon is "all day below the horizon". Its declination is increasing (approaching moonrise); stops before moonrise; then declination decreases again. The moment it stops and changes direction can be labelled "False". Scenario 2: almost moonset The moon is "all day above the horizon". Its declination is decreasing (approaching moonset); stops before moonset; then declination increases again. The moment it stops and changes direction can be labelled "False". The moon cannot be "all day above the horizon" and "all day below the horizon" so you can have only have scenario 1 or 2. Alternatively ... and this explanation is independent of the day boundary (let's see what happens within 24 hours beginning at midnight): the declination of an object can only stop under these conditions:
Maybe I have overlooked something, but I cannot see how both of the first two conditions can occur simultaneously (at least within a split second) at Regarding the last two conditions, one cannot say that either a moonrise or moonset was almost reached because "the story continues" towards either a moonrise or a moonset. Besides, it is only possible if "stops" has a bandwidth, i.e. if a declination delta less than a given value within a defined time gap counts as "declination stopped increasing or decreasing". In other words ... it will never happen. And permit me to compliment you on your excellent documentation in Skyfield ... I always have trouble writing documentation because I am never satisfied with it. |
Could you clarify what return value you are suggesting for the day 2023-02-18, instead of the two |
There is indeed a bug here. The In an attempt to be more efficient, the new functions use an equation to calculate expected hour angle of alt=horizon (and then looks for the time of that hour angle via Newton's method). See this equation from Fundamental Astronomy: Where h = hour angle, delta = declination, phi = latitude, and a = altitude: Unfortunately this equation is undefined for Here is a plot of the relevant days: Because the function used with Newton's Method is not continuous the solution does not converge properly. It gets partway there by pure luck due to one of the sample points being near the rise time. @brandon-rhodes Proposed solution would be to detect if search function (called |
@brandon-rhodes The return values I would expect on 2023-02-18 at latitude 70°N are:
to signify that the moon, being below the horizon, rose as high as it could but failed (hence Does that make sense? Please note that I am not interested in the 'False' values in the results from Having mentioned that, I find it awkward to skip the
It's obvious that a moonrise is always followed by a moonset, and a moonset is always followed by a moonrise - though not necessarily on the same day. So what I would really appreciate is .....
(Neither did I find Skyfield documentation on how to create a Time object with multiple times, by the way. All examples, as far as I am aware, create a Time object with a single time.) As this request is unrelated to this #998 issue, I could open a new issue if wanted. |
This can be accomplished like so with python semantics: risings = find_risings(observer, moon, t0, t1)
risings = [time for time, true_event in zip(*risings) if true_event]
>> [<Time tt=2459995.8982223687>, <Time tt=2459996.8716849447>, <Time tt=2459997.8519764347>] This will return a list of time objects for which the event was true. As far as accessing the times themselves, its a numpy array in a trench coat. So you can do most anything you can do with one of those. Here is a way to remove the false events with numpy semantics: time, true_event = find_risings(observer, moon, t0, t1)
risings = time[true_event == True]
>> <Time tt=[2459995.89822237 2459996.87168494 2459997.85197643]> This will return a single Time object containing the array of Time's |
This can be found here Date Arrays. Also mentioned here UTC and Your Timezone at the bottom regarding turning a list of datetimes into a date array. Date Arithmatic might also interest you. |
@EndlessDex Many thanks for your explanations above. I will find them very useful! While scanning for further discrepancies between I also came across a few test cases which I think belong to the category above that needs a bugfix. I would like to add them here for more comprehensive testing. (I hope more test cases are useful to you.)
TEST CASE 4: 28-Apr 2023 to 30-Apr 2023 at latitude 72° HMNAO data: On 28th April the moon is above horizon all day. So the next event must be a moonset (at 7:33) followed by a moonrise (at 7:38) on 29th April. TEST CASE 5: 3-Jul 2023 to 5-Jul 2023 at latitude 66° HMNAO data: On 3rd and 4th July the moon is below horizon all day. So the next event must be a moonrise (at 1:46) followed by a moonset (at 1:57) on 5th. July. TEST CASE 6: 27-Jul 2023 to 29-Jul 2023 at latitude 68° HMNAO data: On 28th and 29th July the moon is below horizon all day. So the previous event on 27th must be a moonset (at 19:25) preceded by a moonrise (at 18:51) on 27th July. |
TAKE TWO: Addressing Issues and Corrective Action The test cases above (4 to 6) are not in the same category as Test Case 3: here I detected discrepancies not with One point is that using The test cases above (4 to 6) are marginal cases where it is difficult to detect what the moon state is, and it only fails when given marginal cases at relatively high latitude. Okay, so the onus is on the end user (as ‘step one’) to detect these cases and provide assistance by avoiding a moonrise that follows a moonrise as well as a moonset that follows a moonset. Be aware that a pre-requisite is to filter out all “False” events first (as none of these are candidates for an actual documented moonrise or moonset). This can be done with good accuracy by making a note of the moon state at the time the search begins. This assumes that the moon state can be reliably assessed at the beginning search time, which is not always the case, however it is possibly an improvement rather than discounting it entirely. We can implement this idea in the Test Program provided to show any ‘True’ moonrise or moonset that was rejected on logical grounds, i.e. “a moonrise cannot follow a moonrise” and “a moonset cannot follow a moonset”. The same test cases as above are still not satisfactory as key events are not detected. (The issue is that BOTH incorrect events ARE detected by find_risings()/find_settings() AND that correct events ARE NOT detected.) TEST CASE 4: 28-Apr 2023 to 1-May 2023 at latitude 72° HMNAO data: On 28th April the moon is above horizon all day at latitude 72°N. On 29th the moon sets at 7:33 and rises 5 minutes later. So I am not concerned if we ignore these two events altogether. As you see, the single moonrise has been discarded. A day later there is a moonset at 5:18 and a moonrise at 11:22. Perfect agreement. On 1st May there is a moonset at 3:34 and a moonrise at 13:35. Almost perfect. There is NO ISSUE here - all looks well now. TEST CASE 5: 3-Jul 2023 to 6-Jul 2023 at latitude 66° HMNAO data: On 3rd, 4th and 5th July the moon is below horizon all day at latitude 66°N. The incorrect moonset has now been discarded so these days are correct. On 6th June there is a moonrise at 00:13, a moonset at 5:34 and a moonrise at 23:49. Excellent! Perfect agreement now. NO ISSUE here now. TEST CASE 6: 26-Jul 2023 to 29-Jul 2023 at latitude 68° HMNAO data: On 26th July at latitude 68°N there is a moonrise at 15:31 and a mooonset at 21:01. Perfect agreement. On 27th there is a moonrise at 18:51 and a moonset at 19:25 (34 minutes later). ONLY THE MOONRISE is detected. No event is detected on the following two days suggesting that moon is above the horizon all day. THIS IS INCORRECT (or to quote Brandon: "Well, Drat!"). HMNAO data shows that on 28th, 29th (and 30th) the moon is BELOW THE HORIZON all day. This discrepancy (lasting several days) is caused by the undetected moonset at 19:25 on 27th. July. I hope a bugfix will cure this mistake too. (It is easy for me to ignore events that must be incorrect; it is impossible for me discover events that are missing using I highly appreciate your time and effort when looking into this issue for me. The modified Test Program is included here (no points for elegant programming – it merely demonstrates the necessary logic):
|
@aendie Thanks for all the interesting data! Skyfield uses this USNO generator as a source of truth for comparison against. This table uses the Refraction + Apparent Radius method. For "normal" locations (ex W112 31, N36 57) Skyfield is accurate to within one minute for all events. Generating a table for (W0, N70) shows that both old and new methods are grossly wrong (as you have noted). PS. Take a look at the other Data Services of the USNO there's a lot of cool stuff! A couple requests for you:
I am working on resolutions to this and already have a resolution to the same false event being reported for both rise and set. I know you have stated you don't really care about the false events but it is a feature to support regardless. Side note: I will be using Skyfield's built-in horizon calculation for all testing. (-34' - r_moon/d) I am looking for both algorithmic (better math) and computational (more CPU time) solutions for the "Bin 1" cases. The latter is easier and I already have a working partial solution but it is significantly more expensive. One of the stated goals of the new method is to be more efficient than find_discrete paired with find_rising_and_settings. Depending on if I can find a better algorithm or not, there may need to be a "fast" segment and a "slow" segment of these functions. Where the "fast" method is used for low latitudes but above a certain point "slow" does some more expensive calculations in the name of accuracy. I hope we can all agreed that providing WRONG results is worst thing we can do and that it is worth extra time-cost to avoid that. |
Good afternoon, @aendie and @EndlessDex! With the holiday weekend upon us, it looks like I have some spare hours for this Skyfield issue. Through the last week, when I’ve had spare time, I have been digging into the behavior of the search routine for this interesting 2023-02-19 70°N case — but haven’t yet sat down to write further comments because of the sheer number of topics that require replies at this point. So instead of trying to write up a knock-down drag-out comment that addresses them all, I’ll try writing a series of comments through this afternoon that will hopefully get me caught up. For this first reply, I’ll focus on a few points that I think I can answer quickly:
The other points you both have raised in your comments will require more investigation and/or longer answers, so I’ll pause here and click ‘Comment’, so that these answers can go ahead and become part of the thread while I start work on some others. |
@brandon-rhodes Thanks for the updates :) Definitely appreciate that there is a lot of discourse to parse through. I think the key point for me is that the hour angle equation breaks down for certain times/locations. This leads to the newtons method not converging correctly because it's trying to develop a slope for a non-linear function. Please reference my comment here for plots and equations. I hope we can get something better than falling back on |
@EndlessDex Thanks for your very prompt response. Initial comparison between the official HMNAO Nautical Almanac and the US Navy – Astronomical Applications Department Moonrise/Moonset table data. The website is interesting and useful. I note that the results provide UT (Universal Time = UT1) just as in the Nautical Almanac. Quickly scanning the dates and times below, they agree very well with differences that occasionally just cross into the next or previous minute. The Nautical Almanac for 2023 was published in 2022 (earlier obviously). The web site might be based on more recent data. NA = official HMNAO Nautical Almanac 2023 All discrepancies in 2023 at latitude 70°N: So the data agrees very well and is probably off by only a few seconds (of time). |
Two quick notes:
Happily, the data source should not be an issue for Moon rise and set, since we have known the Moon's orbit in such exquisite detail for a couple of decades. To double-check, I just ran a full year of 2023 Moon rises and sets from 70° north using ephemerides DE406 (1997), DE421 (2008), and DE440 (2020). All gave exactly the same output. So, for contemporary Moon positions, feel free to use data sources that are 25+ years old, if that's faster or more convenient for you; it shouldn't make a difference.
Note that the USNO does not see the Moon set at 7:33 or rise 5 minutes later; instead, it outputs |
@aendie — Having read back through all of your Test Cases, am I correct that you are happy with the output of I'm actually surprised that you're getting good results from it, because If you want to catch the Moon even when it's only up for one minute, maybe try something like |
@EndlessDex — could you share the table? I would have expected the old method to agree completely with the USNO, and if it doesn't, then that's a separate issue that will need to be fixed. Working code to generate the table would also be helpful. Thanks! |
@brandon-rhodes I agree with your comments. |
By "not perfect", I think you mean that it sometimes differs by 1 minute from a USNO moonrise or moonset? Or is there a case where it does worse than that — in which case I would definitely want to get |
@brandon-rhodes It's well over a year since I was working with the Nautical Almanac tables. I would have to look into that again. I should be able to give you feedback on this but it'll take some time still as I am right in the middle of updating this software that hasn't received an update since April 2023. I am making it compatible with both Also .... I was side-tracked by looking into the results that the US Navy - AAD web site gives. I experimented by entering Longitudes that are not 0°E. I can reproduce that results as long as the Time Zone remains at Zero/Zulu. I cannot determine if they use the local elevation (like |
@EndlessDex Also in answer to your request #1: I checked all moonrise/moonset data for 2023 at latitude 68°N.... Comparison between the official HMNAO Nautical Almanac and the US Navy – Astronomical Applications Department Moonrise/Moonset table data. NA = official HMNAO Nautical Almanac 2023 All discrepancies in 2023 at latitude 68°N: The data agrees very well and is probably off by only a few seconds (of time). |
Happy first day of September! I’ve generated a few diagrams to help us think through how the search routine works. If you want to see the (work-in-progress) code that produced the diagrams, the script is here: To keep things simple, I’m going to stick with the Moon as the primary target, and (70°N,0°E) as the location of the observer. (That will let me say simple things like ‘south horizon’, instead of complicated things like ‘the opposite horizon from the hemisphere the observer is in’!) So let’s dive in. The search routine’s normal approach is:
This works stunningly well for the fixed stars. Let’s imagine five stars that range in declination from -20.8° to -21.0°. If we ask for when, say, the -20.85° star rises:
Here’s a diagram of that process, that leaves out Point 0 (which is way over in some other part of the sky) but shows that the final three iterations all land at exactly the point where the star rises. If the moment of rising can be found immediately using geometry, why go through with the expense of generating Point 2 and Point 3? The reason is that the rising routine might have been given a moving target, like a planet, instead of a fixed star. In that case the declination will change slightly between the arbitrary So Iteration 2 takes the new declination value, and uses it to compute an even better geometric prediction. Repeating that again in Iteration 3 produces excellent results for all the cases that I had tested so far. But let’s now consider a special case. But what if the geometry simply doesn’t predict a moment of rising? What about a star whose declination is so negative that it never rises for our observer at 70°N? In this case there’s unfortunately no solution to the geometric equation that would provide an intercept between the star’s circle of declination and the horizon. So the search routine does something different in step 2: it falls back to instead computing the moment of transit. Why fall back to the moment of transit?
In the case of our fictional star, whose declination does not, in fact, change over the hours, the search routine immediately finds the moment of transit at Point 1, and Points 2 and 3 simply dwell on the same point: But for the Moon, there’s trouble! The Moon moves more rapidly against the background of stars than any of the planets, and thus poses the biggest challenge for the rising and setting routines. And its rising on 2023-02-19 from 70°N is a severe enough event that our search routine, alas, gets stuck! And it gets stuck in a fairly stable way. Here I’ve expanded the number of search iterations so they go all the way to Iteration 9: What story is this diagram telling us?
Three quick points: First, wow, these angles are very small! But they seem to matter. Even though the Moon only rises 0.1° above the horizon, it stays above the horizon for a full 37 minutes! That wasn’t my intuition when I first approached the problem — that such a low rising angle and altitude could produce such a long event. I had assumed that I could ignore tiny-angle cases because they would put a target above the horizon for only a few dozen seconds. But that’s not the case, and we can’t be ignoring events that last 37 minutes, so I agree that this needs to be fixed. Second, @aendie is particularly unhappy that risings were being missed. It turns out that this is an artifact: it’s the mere result of my happening to choose an odd number of iterations for the search routine loop! Because I stopped after an odd number iterations, I wound up always returning a Third, my vague idea that every possible edge case would somehow just magically resolve itself if I did a few more iterations is clearly false. This case shows that the search routine can become stuck in a very stable behavior from which more iterations will never rescue it. So some final maneuver is clearly needed here to break out of this cycle — at the very least, one final step that would take the results of the previous two iterations, and jump intelligently between them to reach the horizon. I’ve made one experiment in that direction already, but I’m not happy with the results, so I’ll play with some more ideas and see what I can come up with. Finally — With all of the above as background, I think I can sweep through the rest of the unanswered comments from @EndlessDex and try to provide some kind of response:
I’m not sure this quite describes the problem. First, as noted above, in no case does the search routine try to compute a slope. Second, even if it did compute a slope, the whole point of Newton’s Method is to explore non-linear functions. If a function is linear, can’t we simply compute its zero-crossing directly, using its slope? My understanding is that Newton’s Method is always used with non-linear functions. In which case, that by itself can’t be the problem here. I would describe the problem as: the search routine at each step treats the declination as a constant, instead of trying to model it as a moving target with its own rate of motion. But feel free to follow up with a clarification; maybe you’re getting at something interesting here that I’m not quite catching yet.
I’m not sure luck is involved? I’m not quite sure what you’re claiming, so please show your work and correct me here if I’m wrong, but as the diagrams above show, when the Moon’s declination is too low for it to rise, the search routine’s behavior is robust and doesn’t depend on the particular initial sample point. In all cases, if the declination is too negative for a moonrise at 70°N, the search routine immediately decides to rotate the sky all the way to the moment of transit to see whether the Moon is above the horizon at transit or not. In which case the search routine’s behavior will enter the stable two-region attractor, I think? And so the result won’t ever depend on luck?
My guess is that we shouldn’t pick a single location. I have, alas, had unfortunate experiences before, where the very tweaks that happen to make a routine work perfectly at one location (like 70°N) promptly wind up breaking the routine for other latitudes — or even for all other latitudes! This is a specific case of a more general rule with software, where fixing a bug for one specific case often breaks the software for all other cases. If we want a robust rise-set solution, we should probably generate USNO moonrise and moonset tables for every latitude, and tweak the search routine until it gives good results for all of them. It would be slow to run so many checks as part of the normal test suite, so maybe the thorough rise-set check could live inside a separate little script that we could run by hand whenever the search routine is being tweaked? Then we can take each specific edge case that’s uncovered, and promote those to full membership in the normal test suite.
Fleshing out your idea a little bit, it sounds like your proposal is to:
Is that a fair description of the approach you’re thinking of? Thanks, by the way, for being willing to do such a deep dive on this issue as a first-time contributor! I’ll be interested to hear how your experiments go, and I’ll let you know how mine turn out. |
I was referencing the output of the Though for the |
@brandon-rhodes Using Most agreed with the HMNAO Nautical Almanac, however I have highlighted those that didn't ("NA:" below) in the list below. So I found some cases where 2023-04-14 Lat 66°N 2023-07-05 Lat 66°N 2023-07-27 Lat 68°N 2023-07-30 Lat 62°N 2023-10-18 Lat 64°N 2023-10-19 Lat 62°N 2023-12-14 Lat 62°N 2023-12-26 Lat 62°N P.S. All times in the Nautical Almanac tables I create are rounded to minutes if I print HH:MM or rounded to seconds if I print HH:MM:SS |
Yes, you are correct about my imprecise language above. When referring to "non-continuous" or "non-linear" I was intending to reference the piecewise-like nature of the desired hour angle function where the value is 0 for certain inputs that trigger the clamping while it is a smooth, continuous function for other inputs. I believe the proper mathematical phrasing should been "The desired hour angle function is not a SMOOTH function."
Yes, you are not technically using Newton's method mathematically (except sortof for the first point). It is however similar/equivalent. Your method iteratively approaches a more accurate solution using error and rate of change. Your method IS using a
Two sides of the same coin I think. The routine treats declination as constant and because the desired hour angle function is non-smooth the model does not converge as the changing declination pushes us from one region to another of the desired hour angle function. We bounce back and forth over the point/cusp of the desired hour angle function. Which causes the guess not increase in accuracy with each iteration. But your description does lead more directly to a possible solution. Pre-correcting the step size based on predicted change in declination. My description only leads to the analytical geometry problem of smoothing out the discontinuity from the transformation functions.
This mention of luck came from a misunderstanding on my part about the transit time fallback and how this will always be "best case". I did not know at the time that this was guaranteed.
I was of course not suggesting to only ever test one location. That would be stupid. However, for the purpose of developing problem analyses and solution proposals, it makes sense to focus on a single error case initially. Once a problem is somewhat understood then you can start exploring how it behaves under different circumstances.
Each location takes 1-2 seconds for each table so definitely agreed. I think this already partially exists?
Basically yes. If the
You're very welcome! My work deals heavily with programming for satellite propagation and I have used skyfield as an easy server-side TLE propagator for a long time. I was browsing your issues page for my own bug and came across something I could answer. Since then I have been on a bit of a kick haha. Not as familiar with astronomical propagation as I am orbital propagation but it's all very interesting to me. Hope to become a long term contributor actually. Please let me know how I can better help out 😄 (PS take a look at my PR. I really want to be able to use python 3.12 haha) |
Ah, thank you for pointing out the specific script! Looking back at it, its reporting and logic were a bit fragile, so I've improved them so that missing events, whether on the Skyfield or USNO side, no longer cause it to halt. Instead, it always finishes, having checked every event reported by either library. Also, it was using time zone of UTC-7, which I think is the source of all the errors you were seeing, since the new table uses UTC instead. Here's an updated copy of the script, where I started with your own version of the script before making any improvements: The script now shows only 1-minute or 2-minute differences of opinion for 2023 moon risings at 70°N using
Which I'm not entirely happy with — I want everything to be within 1 minute of the USNO, or, ideally, a perfect match — but it's at least not the gross errors you feared And when using
So I'm glad to find that |
Try rounding skyfield's output to the nearest minute. It's what the tests do. How to round skyfield timesimport skyfield.api as sf
def round_to_nearest_minute(sf_time):
THIRTY_SECONDS = 1.0 / 24.0 / 60.0 / 2.0
sf_time += THIRTY_SECONDS
calendar_tuple = sf_time.utc
sf_time = sf_time.ts.utc(
calendar_tuple.year,
calendar_tuple.month,
calendar_tuple.day,
calendar_tuple.hour,
calendar_tuple.minute,
)
return sf_time
ts = sf.load.timescale()
t = ts.utc(2023, 1, 19, 12, 3, range(0, 60, 15))
print("original", t.utc_iso())
print("rounded ", round_to_nearest_minute(t).utc_iso())
# original ['2023-01-19T12:03:00Z', '2023-01-19T12:03:15Z', '2023-01-19T12:03:30Z', '2023-01-19T12:03:45Z']
# rounded ['2023-01-19T12:03:00Z', '2023-01-19T12:03:00Z', '2023-01-19T12:04:00Z', '2023-01-19T12:04:00Z'] |
(@EndlessDex — Whoops — I just pushed another update to the script, because I had commented out the thirty-second offset to perform rounding, but forgot to uncomment it before committing. I've now updated my previous comment with the result.) |
@EndlessDex — Oh, I think I have a guess as to why |
Yes that was a stupid gaff. I found it yesterday and hadn't pushed it yet. Merged your stuff into mine. You missed one timezone value btw on line 236. Ooo interesting bit about the apparent radius calc. Would you want to update |
I'm not sure what you mean here. My Test Program included in this ISSUE calculates the horizon value to pass on to |
@brandon-rhodes This works in all cases I've tested but I hate it :( Feel like there should be a mathematical/algorithmic solution but I haven't found one yet. Took a break from that to whip this up. Regarding the code itself def _find
...
...
# TODO: How many iterations do we need? And can we cut down on that
# number if we use velocity intelligently? For now, we experiment
# using the ./design/test_sunrise_moonrise.py script in the
# repository, that checks both the old Skyfiled routines and this
# new one against the USNO. It suggests that 3 iterations is enough
# for the Moon, the fastest-moving Solar System object, to match.
last_desired_ha = None
fallback_mask = np.full_like(t, False)
for i in 0, 1, 2:
_fastify(t)
ha, dec, distance = observer.at(t).observe(target).apparent().hadec()
desired_ha = f(latitude, dec, h(distance))
if last_desired_ha is not None:
# One is zero and one is non zero, ie we are at the edgecase so add to list to redo
fallback_mask = np.logical_or(fallback_mask, np.logical_xor(last_desired_ha, desired_ha))
last_desired_ha = desired_ha
ha_adjustment = desired_ha - ha.radians
ha_adjustment = (ha_adjustment + pi) % tau - pi
timebump = ha_adjustment / ha_per_day
t = ts.tt_jd(t.whole, t.tt_fraction + timebump)
# find_discrete cannot take time arrays :(
fallback_times = np.empty_like(fallback_mask)
for i, f in enumerate(fallback_mask):
if f:
fallback_t = t[i]
else:
fallback_times[i] = None
continue
def is_body_up_at(t_search):
_fastify(t_search)
alt, _, dist = observer.at(t_search).observe(target).apparent().altaz()
return alt.radians > h(dist)
is_body_up_at.step_days = 1 / 1440.0
event, _ = find_discrete(fallback_t - (10 / 1440), fallback_t + (10 / 1440), is_body_up_at)
fallback_times[i] = event[0]
# Combine t and fallback_times |
Initial thoughts from my side (of the 'puddle')... Stars remain almost constant in the celestial sphere, which can be represented as a dot on a graph of Declination (degrees) versus Sidereal Hour Angle (degrees). This I created long ago: Well, what does the Moon do, say in February 2023? It moves thus: I labelled each point with the date (at 00h). The red line is the ecliptic. It more-or-less follows the ecliptic. The Moon's orbital plane is inclined about 5.1° with respect to the ecliptic plane (as seen above). Each calendar month is similar - only the starting position (first day of the month) moves around. The direction of movement is always decreasing SHA (right-to-left). So the Moon's SHA tells us immediately if its Declination is increasing, decreasing or nearly flat at SHA 90° and 270°. I'm no further than this. It took me 2 days fighting with matplotlib.pyplot.annotate to generate labels with more-or-less equal length arrows :-( But a picture is always great ... methinks. UPDATE: The matplotlib.pyplot.annotate problem is solved: |
I completely agree that pictures are great. It's so useful to see what's going on in the math, and to double-check that it looks like I expect. And, yes, annotations are awkward in matplotlib. In fact, my annotations looked so bad in my earlier comment — — that I've gone back and edited it to include better annotations, so they don't overlap and are much easier to read! In other news, I had some time this week to draw some more graphs involving the problem, and I have some ideas about how progress might be made. I'll update as soon as I have a bit of working code. |
Did you know that there's a second version of the quadratic equation, where the square root is on the bottom? I had no idea! https://people.csail.mit.edu/bkph/articles/Quadratics.pdf I ran into exactly the problem described in the second link — of getting nonsense floating-point results from the quadratic equation — when I tried modeling the Moon's rising in the above diagrams as a parabola, and so I had to learn about and switch to this alternative quadratic formula. But the result is very encouraging. Given the Moon's altitude and the altitude's rate of change at Point 2 and Point 3, and approximating the change in altitude versus time with a parabola, we can produce the black dot as our guess for the moment of Moonrise: Here's my current tangle of code, for the curious: There should only be two steps necessary for me to get this added to the rising and setting routines.
But it looks, in any case, like there will be a reliable way to jump — without needing to do an expensive binary search — to the actual time of rising, using just what we know already about the Moon's position and motion at Point 2 and Point 3. |
If you are interested in development of another quadratic solution algorithm, follow the hyperlink noted below.
The overall theme of the algorithm addresses numeric issues relative to the standard/conventional quadratic solution formula. Like the hyper-linked paper in your email below. This paper is also from the MIT brain trust (circa 1992, by R.D.Middlebrook - his career focus was electrical engineering).
I like how the Middlebrook addresses the standard/conventional quadratic solution defects.
https://web.mit.edu/6.969/www/readings/quadratic-formula.pdf
I've had several opportunities to use the development approach.Though in these times, numerical precision muscle is used to overcome the issue of both big and small number relations. One example may be useful when determining near parabolic solutions (time-of-flight, etc.)...
********************************************************
On Tuesday, October 15, 2024 at 05:07:08 AM CDT, Brandon Rhodes ***@***.***> wrote: Did you know that there's a second version of the quadratic equation, where the square root is on the bottom?
$$x=\frac{-b+\sqrt{b^2-4ac}}{2a}=-\frac{2c}{b+\sqrt{b^2-4ac}}.$$
I had no idea!
https://math.stackexchange.com/questions/4000135/quadratic-formula-fails-numerically-at-small-a-coefficients
https://people.csail.mit.edu/bkph/articles/Quadratics.pdf
I ran into exactly the problem described in the second link — of getting nonsense floating-point results from the quadratic equation — when I tried modeling the Moon's rising in the above diagrams as a parabola, and so I had to learn about and switch to this alternative quadratic formula.
But the result is very encouraging. Given the Moon's altitude and the altitude's rate of change at Point 2 and Point 3, and approximating the change in altitude versus time with a parabola, we can produce the black dot as our guess for the moment of Moonrise:
image.png (view on web)
Here's my current tangle of code, for the curious:
https://github.com/skyfielders/python-skyfield/blob/91930a900d5f121724f4cbfd0897f2ec06284a45/design/illustrate_moonrise_edge_case.py
There should only be two steps necessary for me to get this added to the rising and setting routines.
- First, I need to decide when to deploy it in the rising/setting routine. Always as a final step after Point 2 and Point 3 have been generated? Should it be followed by a final round of declination-targeting, or would that be more likely to hurt than to help? Should I do it even earlier, with Point 1 and Point 2? And what should I do if the solution seems to lie outside of the two final points I generate — would it be speculative/dangerous to guess a time outside of the ones I've tested?
- Second, which three numbers should I use? I know altitude and rate-of-change-in-altitude at (in the above case) Point 2 and Point 3, which is 4 total values. But that would over-determine a parabola, which only has three unknowns. In the sample code above you can see that I use the two altitudes, plus the rate at one of the points. But I could instead use two rates and one point? I'm not sure how to choose between them yet.
But it looks, in any case, like there will be a reliable way to jump — without needing to do an expensive binary search — to the actual time of rising, using just what we know already about the Moon's position and motion at Point 2 and Point 3.
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.Message ID: ***@***.***>
|
I am running initial tests having converted my Nautical Almanac software to use
find_risings()
andfind_settings()
when Skyfield VERSION is 1.48 or higher. Lower versions still usefind_discrete()
. As both are implemented I began comparing them and I came across a discrepancy that I wish to describe in detail here.To gain confidence in my 'quick and dirty' test program, I quote three test cases: the first two show correct results. I am aware that almanacs print time in UT (=UT1) and my test program simply prints UTC time, which is irrelevant here. Furthermore times in almanacs are rounded to minutes so a 24-hour search begins at 30 seconds before midnight. My test program begins at midnight (again irrelevant here).
TEST CASE 1: 31-May 2023 to 2-June 2023 at latitude 68°
I expect to see these results (my almanac data using
find_discrete()
) for Wed Thu Fri:The test Program prints results from
find_risings()
andfind_settings()
as 'moonrise' and 'moonset' and results from find_discrete() as 'moonevent' where '0' represents a moonset and '1' a moonrise:The data looks good!
TEST CASE 2: 31-May 2023 to 2-June 2023 at latitude 72°
Again, the new routines match the data with the legacy
find_discrete()
logic. Looks good!TEST CASE 3: 18-Feb 2023 to 20-Feb 2023 at latitude 70°
Here I expected to see this:
but instead saw this:
Note that my old almanac code searches day-by-day forward for the next moonrise or moonset event to determine the current moon state. "All day above horizon" (a white rectangle) is printed because the next event detected is a moonset at 12:05 on Sunday. So what went wrong here? The Test Program shows this:
The "moonrise" at 11:35 on 19-Feb is 'False'. There is no moonrise on 19-Feb. I look into the official HMNAO Nautical Almanac and see a moonrise at 11:28 on Feb 19th. Exactly what
find_discrete()
prints (when rounded). Why didfind_risings()
miss it? I use a calculatedhorizon
value but if you omit the last parameter "-horizon" fromfind_risings()
, it makes no difference.But the horizon value does have an impact on the results. Some reverse-engineering showed that increasing the value of "horizon" by 0.048 degrees not only fixes the problem but gives a result very close to 11:28, i.e. this works:
moonrise, yR = almanac.find_risings(observer, moon, t0, t1, -horizon-0.048)
Is
find_risings()
using an incorrect horizon value?Another thing that looks suspicious: on Feb 18th: both "False" events have the same time
'2023-02-18 10:34:20Z'
.I understand "False" events to mean that the moon vertical motion changes, even though this is below the horizon, i.e. not an actual moonrise or moonset. But I cannot believe that the moon changes direction twice within a split second.
I cannot dig deeper ....... I hope someone can look into this and either explain or fix the problem.
Here is my Test Program (note I use de421.bsp as my ephemeris):
Sincere thanks to whoever looks into this case. I hope I provided a useful test case here.
The text was updated successfully, but these errors were encountered: