Tronald / CoordinateSharp

A library designed to ease geographic coordinate format conversions, and determine sun/moon information in C#
Other
364 stars 59 forks source link

[proposed help wanted] Calculating beginning of a day (i.e. end of the sunrise) #47

Closed DerPeit closed 6 years ago

DerPeit commented 6 years ago

Is it possible to include calculation of the beginning of a day? I saw that you @Tronald forked the suncalc.net repository which includes this timestamp.

I ported the javascript code to C# code months ago but unfortunately now discovered that there are certain issues with this lib, i.e. the calculated timestamps sometimes don't reflect the day they belong to. I also tried to calculate it myself based on some of the references you also used to create this library before I stumbled upon your code.

In my opinion, CoordinateSharp is the only useful .NET library for those astronomical calculations. Everything else I found either yielded wrong results (as far as I can tell) or insufficient results. The only thing I cannot find is the beginning of the day (or the end of the sunrise) or do I miss something here?

Tronald commented 6 years ago

Thank you for reaching out!

I can certainly help, but just need some clarification on exactly what you need. Sunrise and sunset don’t really have a start or end time. It basically just occurs when the top of the solar disc hits the horizon (or technically a little below the horizon). SolarCalc is probably specificying the time between the lower part of the disc and the upper part of the disc hitting the horizon.

Is that what you are looking for and is it something you need? You really only need that for observation purposes (sunrise occurs when you don’t see the sun because the top is just touching the horizon). “Daylight” still starts at sunrise. I can certainly assist if needed though, it may just take me a few days to get an update out.

I converted most of my SunCalc algorithms for the reasons you specified, so it’s been a while since I’ve looked through them.

JTrotta commented 6 years ago

In my opinion he is looking for the three standard twilights. The astronomical, the nautical and the civil one. They occur when the sun declination is -18, -12 and -6 degrees respectively. The most common used to say 'beginning of day's should be -6, the civil one, and starts at -6 and ends at sunrise, so we have two datetime objects.

Tronald commented 6 years ago

Ah ok!

Have a look at AdditonalSolarTimes in the Celestial object or in the Coordinate.CelestialInfo property. Civil and Nautical Dusk/Dawn times can be found in there. There is currently no astronomical twilight value, but I can certainly add it in the future.

I will leave this open until @DerPeit confirms this is what he needs.

Thanks @JTrotta

DerPeit commented 6 years ago

Sorry for the late reply.

I indeed had a look at the AdditionalSolarTimes due to the lack of the astronomical twilight. This was easy to add, thus, I did not ask for it. 😄

Anyways, @JTrotta is not exactly correct with his assumption. Considering Germany, that's where I live, at a more or less regular day (i.e. not these days because we don't have night now, but just astronomical twilight). At such a usual day we start with night followed by astronomical dawn, nautical dawn and civil dawn. Then, the sunrise starts. I consider it to be the moment when one could see the first part of the sun to come up at the horizon. Now comes what is missing from my point of view: The moment where the sunrise ends. I think it should be the point in time where the sun is fully visible. From then on, I consider it to be day. After this, the sunset starts (i.e. the point in time where the sun is no longer fully visible), followed by civil dusk, nautical dusk, astronomical dusk and night. That's what suncalc.net gives you when you hit the "more detailled" link. Although, I must admit I am not sure if my explanations with the sun partly or fully being visible are correct. These are just my assumptions what I expect the values from suncalc.net to be.

Unfortunately, as I said, suncalc.net seems to do anything wrong and I tried to port different code already and even implemented it myself using the algorithm state at http://edwilliams.org/sunrise_sunset_algorithm.htm. Whatever I tried, it did not work, i.e. I got dozens of NaN results and so on. Thus, I cannot point you more towards any direction, because I don't yet get all the maths.

JTrotta commented 6 years ago

@DerPeit Mmhhh. It's not clear, to me, what you need or, better to say, why you need it. The Sunrise and Sunset are single events with one datetime, not a period with a start datetime and a end datetime. Twilights have a start datetime and a end datetime. Those datetimes correspond to the periods when the sun declination is in an interval of values: -18/-12, -12/-6 and -6/0. When the day begins? It depends: at delta = 0° (sunrise) for someones, at delta = -6° for others (traffic rules?), at delta =-12° for sailors, etc. The same is for sunset. Does not exists a datetime for sun 'fully visible', even because the sun diameter depends on multiple factors. But if you need it, you could calculate it empirically, adding to the value of declination at sunrise, the value of the angular diameter in degrees using a medium standard sun diameter, (~2000 arc-seconds or 0.50° degrees, if I remember). It does not exists, because it's not used in astronomy.

Tronald commented 6 years ago

Ok @DerPeit I think I understand a bit more. The Astro twilight is easy and should have been added to begin with (not sure why I left it out). I will add on the next release. As for the sunrise/sunset "begin/end", let's discuss.

Technical Definition for Sunrise and sunset (FROM USNO): For computational purposes, sunrise or sunset is defined to occur when the geometric zenith distance of center of the Sun is 90.8333 degrees. That is, the center of the Sun is geometrically 50 arcminutes below a horizontal plane. For an observer at sea level with a level, unobstructed horizon, under average atmospheric conditions, the upper limb of the Sun will then appear to be tangent to the horizon. The 50-arcminute geometric depression of the Sun's center used for the computations is obtained by adding the average apparent radius of the Sun (16 arcminutes) to the average amount of atmospheric refraction at the horizon (34 arcminutes).

As @JTrotta said, there is no "beginning or end" in astronomy, but I have seen what you discussed out there. If people need it I am not opposed to adding that value somewhere. I think the best way to handle this is to add the properties SunriseBottomDisc & SunsetBottomDisc to the AdditionalSolarTimes property. This way you can grab those times and compare them to the Sunrise or Sunset times as needed to get the TimeSpan as needed. The Bottom disc time SHOULD be about when the sun is just fully visible on the horizon.

Based on the above definition, I believe plugging in .833333 -.2998 into the GetTime() function (where you saw the AdditionalSolarTimes calculated) will solve your problem. So If I (or you) added the properties, the functions would would look like this.

            //Bottom Disc
            Jset = GetTime(-.2998 * rad, lw, phi, dec, n, M, L); 
            Jrise = Jnoon - (Jset - Jnoon);

            c.AdditionalSolarTimes.SunriseBottomDisc = DayMatch(JulianConversions.GetDate_FromJulian(Jrise),date);
            c.AdditionalSolarTimes.SunsetBottomDisc = DayMatch(JulianConversions.GetDate_FromJulian(Jset),date);

This is me speculating for now, I need to plug it in and test it though. Also, the times will not be perfect, as these formulas account only for average refraction, but if times have been sufficient thus far for you, it should be fine.

I just pushed an update last night, so I am going to hold off for a week to get this out, but I will throw a BETA version if this works on the website for you to download, or you can grab it from the 1.1.3.5 branch I am about to make once it's ready.

I will reply once I get the code working and posted. Let me know if if this doesn't fulfill your requirements though.

EDIT: Math was off (coffee hadn't kicked in yet).

Tronald commented 6 years ago

It ended up being a bit more involved, as I forgot I was in the middle of converting some of my sun calculations. The current release uses a mix of Meeus, Suncalc and Zacky Pickholtz algorithms. I'm in the process of converting to pure Meeus (more involved, but more accurate). I needed to finish removing the Pickholtz algorithms to get the BottomDisc times to work and not add more time to my benchmarks. Anyway, because of this the sun times may adjust a bit and you should see an accuracy increase with the additional times.

I threw a zip file with the BETA library HERE.

I still need to do a lot of testing, as the changes to the algorithm are significant. With that said the properties are now built in for you if you wish to start building your product with the BETA. The only changes from here would be toward internal calculations.

You can find the new properties in the AdditionalSolarTimes property.

If you use this, please alert me to any bugs/issues. I plan to get a stable version out next week.

DerPeit commented 6 years ago

Man, you are so fast with your updates, I cannot even catch up. :smile: Alright, first thank you so much for your effort. I am not an expert in this field and I got your point. I think I read in the source code of suncalc.net that they were doing exactly what you were writing: taking the sun's diameter into account. I am completely fine if you stick to the times the library currently supports, Don't worry. The reason why I ask is because to me all those single timestamps build up periods, like the astronomical dawn ends when the nautical dawn starts, the nautical dawn ends when the civil dawn starts and so on. Thus, the sunset ends when the civil dusk starts and, in contrast, the sunrise then (in terms of CoordinateSharp) ends when the sunset starts. Anyways, I think you got my point right and I appreciate that you're thinking about it! But there is also no need to rush!

I am currently working on "yet another home automation software" that runs on Windows 10 Iot Core, i.e. on Raspberry Pi. I am doing this because I don't like what can be found on the internet nowadays: Certain solutions are very expensive, others don't have a good UX. My approach is to build an SDK so advanced users can "configure" their home in code. My approach heavily relies on the Reactive Extensions, i.e. Observables, to avoid having sorts of triggers and conditions and instead create rules declaratively, like

Rule.Create(x => x.When(Livingroom.Lightswitch.IsPressed).Then(Livingroom.Lights.Toggle))

I know this is a bad example because it does not automate anything. The properties, like IsPressed are observables. And so is what I call the "solar calendar":

Rule.Create(x => x.When(SolarCalendar.Now.IsSunset).And(ObservableDateTime.Now.TimeOfDay).IsGreaterThan(17.OClock()).Then(Bathroom.Lights.TurnOn))

The interface for this solar calendar has certain boolean observable properties: IsNight, IsAstronomicalDawn, IsNauticalDawn, IsCivilDawn, IsSunrise, IsDaylight, IsSunset, IsCivilDusk, IsNauticalDusk and IsAstronomicalDusk.

It's going to be open source at some point, but it's still under heavy development and thus there is really no need to apply any change immediately. Frankly, I will have to fork CoordinateSharp and port it to .netstandard either way. That's the reason why I proposed the "help wanted" label: I would have been completely fine with just advice! Now I am overwhelmed with your plan to directly integrate it. 😄

Tronald commented 6 years ago

HAHA I try to add what people need fast, as I want the library to grow. The more people it helps the better!

Your project sounds really cool, keep me updated! Just for your awareness, the library should work in .NET standard as is with this last update. If you download via Nuget, you will get a compatibility warning, but you can ignore it as it should still work. Downloading the library directly won't throw the error. @dsherret solved that issue a couple days ago and may be able to warrant further advice if you run into any problems. If you need to fork it regardless, have fun!

Anyway, I'll let you know when the updates pushed.

Tronald commented 6 years ago

@DerPeit & @JTrotta sorry to keep bugging you. I plan to push an update Tuesday. This update fully ports the library to .NET Standard 2.0 and allows multi-runtime targeting for people that still wish to use .NET 4.0. Also, I found a couple minor bugs in the BETA, so you will want to replace it if you grabbed it.

Thank you for helping to make this library better.

DerPeit commented 6 years ago

That's very good news! Thank you.

It's a little bit off topic, but wouldn't it even possible to target .netstandard 1.4 or even less to support more platforms? When I cloned CoordinateSharp to initially test whether it was possible to port it, it compiled almost seamlessly. If I remember correctly, I only had to replace one call to TimeZone with a similar call to TimeZoneInfo, but that was basically it.

I didn't try anything below 1.4 though because all my libraries were targeting this version. Wait... I'll give it a shot. :smile: Ok, it also even compiles on 1.3. You need to reference System.Reflection.TypeExtensions, System.Runtime.Serialization.Formatters and System.Runtime.Serialization.Primitives though.

It's a great library and I am happy to help.

Tronald commented 6 years ago

Awesome thanks! I just tried as you suggested and it almost works. I am getting issues with the Trace.WriteLine() commands though. It looks like the command isn't supported in 1.3, 1.4 using System.Diagnostics.

Not sure how to proceed with this one. The commands aren't crucial, but convenient for developers so I don't want to get rid of them. Any suggestions on handling this?

Tronald commented 6 years ago

Hmmmm looks like it's just flat out not supported. I may just convert those lines to Debug.Print I don't really 100% need those outputs in release versions of the library, it was just convenient. At this point I think the cross compatibility with minimal dependencies is more important.

Edit: Ok Debug.Print isn't either. That's a bummer. I don't want to remove those sections. I can't believe something so basic wasn't included with early releases of those platforms.

DerPeit commented 6 years ago

Oh yes, excuse me! You are right, I commented them out, but you should be able to simply change them to Debug.WriteLine after referencing the System.Diagnostics.Debug NuGet even with .netstandard 1.3 if that's sufficient for you.

Tronald commented 6 years ago

Sweet it works!!! Glad we're able to get this working, should make the library more versatile!

Tronald commented 6 years ago

@DerPeit Update has been pushed. It's fully ported to Standard now so you shouldn't have any issues with either Nuget or direct download. The properties we discussed have been added.

DerPeit commented 6 years ago

I know I am a little late. :smile: However, I just wanted to chime in again and say thank you. I was suffering some hardware issues lately and thus was not able to integrate the updated library. Anyway, I did so now and everything is working like a charm also with .NET standard!