4

日の出から日没までの一日の長さと、日没から日の出までの夜の長さを概算しようとしています。私の現在の概算は大雑把ですが (昨日と明日が今日と同等の値を持っていると想定しています)、今のところ、昨日の日没、今日の日の出、今日の日没、明日の日の出を特定することに特に関心はありません (まだ)。私の目標は、1 泊 12 均等時間 (12 時間は相互に等しく、標準時間または昼間の時間とは異なります)、および 1 日 12 均等時間に基づく計算です。

私が懸念しているのは、私の iOS アプリでは、計算がかなりずれていることです。1 分は 5 ~ 6 (標準) 秒で過ぎていきます。ここからの他のコードで変更されていない時間を使用すると、時計は標準的なペースで動きますが、このコードを時計コードにフィードしようとすると、何かが範囲外になります。

近似として、私が取り組んできたコードは次のとおりです。

NSDate *now = [[NSDate alloc] init];
NSDate *factory = [[NSDate alloc] init];
NSDate *summerSolstice2013 = [factory initWithTimeIntervalSinceReferenceDate:_referenceSummerSolstice];
double distanceAlong = [now timeIntervalSinceDate:summerSolstice2013];
double angleAlong = M_PI * 2 * distanceAlong / (2 * (_referenceWinterSolstice - _referenceSummerSolstice));
double currentHeight = cos(angleAlong) * _latitudeAngle + _tiltAngle;
...
if (_secondsAreNatural)
{
    _secondsAreShadowed = FALSE;
    double dayDuration = 12 * 60 * 60 + 12 * 60 * 60 * sin(currentHeight);
    double midday = fmod(24 * 60 * 60 * _longitudeAngle / (2 * M_PI) + 12 * 60 * 60, 24 * 60 * 60);
    double sunrise = midday - dayDuration / 2;
    double sunset = midday + dayDuration / 2;
    double seconds = fmod([now timeIntervalSinceReferenceDate], 24 * 60 * 60);
    double proportionAlong = 0;
    if (seconds < sunrise)
    {
        _naturalSeconds = (seconds - sunset - 24 * 60 * 60) / (sunrise - sunset - 24 * 60 * 60);
    }
    else if (seconds > sunset)
    {
        _naturalSeconds = 12 * 60 * 60 * (seconds - sunset) / (sunrise + 24 * 60 * 60 - sunset) + 18 * 60 * 60;
    }
    else
    {
        _naturalSeconds = 12 * 60 * 60 * (seconds - sunrise) / (sunset - sunrise) + 6 * 60 * 60;
    }
}

このコードで特定できる問題はありますか?

ありがとう、

- 編集 -

私が上で書いたコードは、それを読んでいる人に提示されるルーズエンドという点でかなり要求が厳しいものでした。私は別のパスを取り、より単純な用語とより純粋な数学的モデルで書き直そうとしました。私が書き、コメントを追加しました:

NSDate *now = [[NSDate alloc] init];
NSDate *summerSolstice2013 = [[NSDate alloc] initWithTimeIntervalSinceReferenceDate:_referenceSummerSolstice];
double distanceAlong = [now timeIntervalSinceDate:summerSolstice2013];
    // How far along are we, in seconds, since the reference date?
double angleAlong = M_PI * 2 * distanceAlong / (2 * (_referenceWinterSolstice - _referenceSummerSolstice));
    // What's the angle if 2 &pi; radians corresponds to a whole year?
double currentHeight = cos(angleAlong) * _latitudeAngle + _tiltAngle;
    // _latitudeAngle is the angle represented by our latitude; _tiltAngle is the angle of the earth's tilt.
NSInteger day = 24 * 60 * 60;
    // 'day' could have been called secondsInADay, but it was mean to reduce the number of multiplicands represented in the code.
// If we are in the endless day or endless night around the poles, leave the user with standard clock hours.
if (currentHeight > M_PI / 2)
{
    _secondsAreShadowed = TRUE;
}
else if (currentHeight < - M_PI / 2)
{
     _secondsAreShadowed = TRUE;
}
// Otherwise, calculate the time this routine is meant to calculate. (This is the main intended use case.)
else if (_secondsAreNatural)
{
    _secondsAreShadowed = FALSE;

    // closestDay is intended to be the nearest midnight (or, in another hemisphere, midday), not exactly in hours offset from UTC, but in longitude offset from Greenwich.
    double closestDay;
    if (fmod(distanceAlong, day) < .5 * day)
    {
        closestDay = distanceAlong - fmod(distanceAlong, day);
    }
    else
    {
        closestDay = day + distanceAlong - fmod(distanceAlong, day);
    }
    // As we go through the calculations, for the most part we keep up information on the previous and next days, which will to some degree be consulted at the end.
    double previousDay = closestDay - day;
    double nextDay = closestDay + day;

    // For the three days, what proportion of the way along are they from the solstices?
    double closestDayAngleAlong = M_PI * 2 * closestDay / (2 * (_referenceWinterSolstice - _referenceSummerSolstice));
    double previousDayAngleAlong = M_PI * 2 * previousDay / (2 * (_referenceWinterSolstice - _referenceSummerSolstice));
    double nextDayAngleAlong = M_PI * 2 * nextDay / (2 * (_referenceSummerSolstice - _referenceSummerSolstice));

    // What angle are we placed by on the year's cycle, between _latitudeAngle + _tiltAngle and -latitudeAngle + _tiltAngle?
    double closestDayHeight = cos(closestDayAngleAlong) * _latitudeAngle + _tiltAngle;
    double previousDayHeight = cos(previousDayAngleAlong) * _latitudeAngle + _tiltAngle;
    double nextDayHeight = cos(nextDayAngleAlong) * _latitudeAngle + _tiltAngle;

    // Based on that, what are the daylight durations for the three twenty-four hour days?
    double closestDayDuration = day / 2 + (day / 2) * sin(closestDayHeight);
    double previousDayDuration = day / 2 + (day / 2) * sin(previousDayHeight);
    double nextDayDuration = day / 2 + (day / 2) * sin(nextDayHeight);

    // Here we use both morning and evening for the closest day, and the previous day's morning and the next day's evening.
    double closestDayMorning = closestDay + (day / 2) - (closestDayDuration / 2);
    double closestDayEvening = closestDay + (day / 2) + (closestDayDuration / 2);
    double previousDayEvening = previousDay + (day / 2) + (previousDayDuration / 2);
    double nextDayMorning = nextDay + (day / 2) + (nextDayDuration / 2);

    // We calculate the proportion along the day that we are between evening and morning (or morning and evening), along with the sooner endpoint of that interval.
    double proportion;
    double referenceTime;
    if (distanceAlong < closestDayMorning)
    {
        proportion = (distanceAlong - previousDayEvening) / (closestDayMorning - previousDayEvening);
        referenceTime = previousDay + day * 3 / 4;
    }
    else if (distanceAlong > closestDayEvening)
    {
        proportion = (distanceAlong - closestDayEvening) / (nextDayMorning - closestDayEvening);
        referenceTime = closestDay + day * 3 / 4;            
    }
    else
    {
        proportion = (distanceAlong - closestDayMorning) / (closestDayEvening - closestDayMorning);
        referenceTime = closestDay + day * 1 / 4;
    }

    // Lastly, we take both that endpoint and the proportion of it, and we get the number of seconds according to the daylight / nighttime calculation intended.
    _naturalSeconds = referenceTime + proportion * day / 2;

コードをより明確で理解しやすくしたいと思っていましたが、それを実行したと思いますが、以前の試みと同様の動作を示しています。標準時/分/秒の 0.8 ~ 1.2。

何かアドバイス?私の編集したコードは、何が意図されているか、何が間違っているかについてより明確になりましたか?

ありがとう、

4

1 に答える 1

1

あなたのコードは理解するのが難しいですが、いくつかのヒントを得ようとします:

  • 特定の日付の太陽の角度/方位角と日の出/日の入りを計算する既存のライブラリがあります。Google を参考にしてください。関連するリソースは次のとおりです: http://www.esrl.noaa.gov/gmd/grad/solcalc/
  • 日付と時刻の計算に double を使用しないでください。これは紛らわしく、エラーが発生します。日付を格納するためのデータ型を使用してください。
  • あなたのコードでは、時間があっという間に過ぎていると言います。最後の行の referenceTime と day は一定であるため (少なくとも半日は)、誤差は比例するはずです。そこには多くのケースが混在していると思います。補間は範囲の開始から終了まで行う必要があるため、次の場合

    比率 = (distanceAlong - 前日の夕方) / (closestDayMorning - 前日の夕方); referenceTime = 前の日 + 日 * 3 / 4;

割合は、(previousDay + day * 3 / 4) から (closestDay + day * 3 / 4) まで、または別の言い方をすれば、closestDay の夕暮れから夜明けまでである必要があります。しかし、この補間がどのように機能するかは完全に不明です。

さまざまなケース (昼用と夜用の 2 つだけでよいと思います) と対応する補間の図を描いてみてください。

しかし: 結局のところ、何を達成しようとしているのですか? 結果として得られる時間は、実際には緯度、経度、または時刻とは無関係です。ですから、時間を計るために、太陽がどこにあるかを知る必要はありません。

于 2013-10-27T18:09:30.790 に答える