6

新しい行に 10 秒ごとの風向 (他の気象値の中でも) を含むテーブルがあります。方向は、0 ~ 360 度の単位で保存されます。


目的

この平均の意味は何ですか?データベースは、10 秒ごとに 1 行の情報を格納します。パフォーマンスの問題については、5 日より古いデータを 1 時間あたり 1 行 (平均) に集約したいと考えています。

温度を使用すると、達成するのは簡単です。 avg(temp) は、温度が大幅に異なる値の間でジャンプしないため、トリックを行います。

卓越風では、この「平均」を取得するのははるかに困難です。


度単位の平均風向の計算は、集計関数 avg() を使用するほど単純ではありません。例:

dir1 = 10; dir2 = 350;
avg() = (10+350)/2 = 180;

これは正確ではありません。0 または 360 である必要があります。

だから、私の頭の後ろにある大学の三角法のクラスで、それをラジアンに変換し、x と y 成分を計算すれば、平均方向を再計算できるだろうと考えました。

$w['w'] はデータベースに保存されている方向です。

while($w = $stmt->fetch()){
    $x += cos(deg2rad($w['w']));
    $y += sin(deg2rad($w['w']));     
}

$angle = atan2($y, $x);
$angle = 360 + round(rad2deg($angle));

この式は正しいですか?

この式が正しい場合。理想的には、完全な機能を MySQL に提供したいと考えています。私はそれからこれを作りました。()がたくさん出てきますが…

(360 + degrees(atan2(sum(sin(radians(W))), sum(cos(radians(W))))))) AS angle
4

4 に答える 4

3

最初の提案の問題は、常に 360 を追加することですが、実際には、atan2 が負の結果を返す場合にのみ 360 を追加する必要があります。これは IF ステートメントでソートできますが、オリジナルよりもさらにかさばります。

IF( degrees (atan2( sum(sin(radians(WindDirection))) , sum(cos(radians(WindDirection))) ) )<0,
360+degrees ( atan2( sum(sin(radians(WindDirection))), sum(cos(radians(WindDirection))) )),
degrees(atan2(sum(sin(radians(WindDirection))), sum(cos(radians(MastDirection))) )) ) AS angle 

2 番目のソリューションは集計関数ではないため、時間平均には使用できません。

私が管理した最良のソリューションは、実際にはストアド関数を使用します。これは、次のようにデータベースに対する権限を持っている場合に作成できます。

CREATE FUNCTION Vavg (sumsindir FLOAT,sumcosdir FLOAT) 
RETURNS FLOAT DETERMINISTIC 
RETURN IF( DEGREES(ATAN2(sumsindir,sumcosdir))<0,360+DEGREES(ATAN2(sumsindir,sumcosdir)) , DEGREES(ATAN2(sumsindir,sumcosdir)))

その後、クエリ内で関数を呼び出して平均を計算できます。

SELECT VavgTest( sum(sin(radians(WindDirection))),sum(cos(radians(WindDirection))) ) AS vectorAverage FROM table GROUP BY HOUR(MyTimestamp),DAYOFYEAR(MyTimestamp),YEAR(MyTimestamp)
ORDER BY MyTimestamp;

平均手順がどの平均化期間でも機能することを強調するために、group by を含めました。

実際の最良の答えは、ユーザー定義関数を使用することだと思いますが、C または C++ で行う必要があり、これらの言語のバックグラウンドがないため、それを管理できませんでした。

于 2014-11-21T12:30:22.597 に答える
2

円に方向を描くと、この場合の「平均」は、円の短いセグメント (緑色のセグメント) の中間にあることがわかります。長いセグメントの中間点は、他のセグメントの中間点の正反対側にあります。

サークルイラスト

簡単な(A+B)/2計算で、長いセグメントまたは短いセグメントの中間点が得られます。それが長いセグメントの場合、短いセグメントはS1 = (S2+180) % 360whereS2が長いセグメント (および%is the modulo operator ) で見つかります。

あとは、いつ長いセグメントを取得し、いつ短いセグメントを取得するかを決定するだけですABS(B-A) > 180

これらすべてをまとめると、計算は次のようになります。

( (A+B)/2 + IF( ABS(B-A) > 180, 180, 0 ) ) % 360

これはおそらく三角関数よりもはるかに高速です。

コメントで述べたように、2 つの方向が互いに正反対 (0° と 180° など) の場合、「平均」は円のどちらかの側 (90° または 270°) にある可能性があります。どちらを選択するかを決める必要があります。この場合、上記の式は 90° を選択します。代わりに 270° が必要な場合は、比較を から>に変更し>=ます。

于 2012-05-31T13:12:03.217 に答える
0

SQL Server 2008 の複数の値について、毎日の平均風向を度単位で計算するためのこのソリューションがあります。##Day は、時系列値の 1 日です。

SELECT @DayMean =
CASE WHEN ABS(@DayMax - @DayMin) > 180 THEN --this line could be wrong, might need to compare consecutive values
  CASE WHEN AVG(CASE WHEN (Value > 180) THEN Value-360 ELSE Value END) < 0 
    THEN 
      360+AVG(CASE WHEN (Value > 180) THEN Value-360 ELSE Value END)
    ELSE
      AVG(CASE WHEN (Value > 180) THEN Value-360 ELSE Value END)
  END
ELSE
  AVG(Value)
END
FROM ##Day

このページの最後から 2 番目の投稿http://www.control.com/thread/1026210133から着想を得て、Excel で計算しました。

この行は間違っている可能性がありますが、Excel での計算では、最後の値からゼロを引いたものを含め、連続する数値の差を見つける必要がありました。そして最大はExcelにあります)。

CASE WHEN ABS(@DayMax - @DayMin) > 180 THEN

代わりに、「いずれかの値が 180 を超える場合」または「連続するポイント間の最大「距離」が 180 を超える場合」にする必要があります。後者の場合の解決策は、おそらく計算をかなり遅くするでしょう。

できるところを批判して修正してください:)

于 2013-10-15T04:55:39.733 に答える