|
|
@@ -0,0 +1,786 @@
|
|
|
+package easydo.technology.util;
|
|
|
+
|
|
|
+import easydo.technology.model.WeatherData;
|
|
|
+
|
|
|
+import java.time.LocalDateTime;
|
|
|
+import java.util.*;
|
|
|
+import java.util.stream.Collectors;
|
|
|
+
|
|
|
+public class WeatherUtil {
|
|
|
+
|
|
|
+ // 天气状态定义
|
|
|
+ public enum WeatherState {
|
|
|
+ SUNNY, CLOUDY, RAINY, STORMY, FOGGY
|
|
|
+ }
|
|
|
+
|
|
|
+ // 季节定义
|
|
|
+ public enum Season {
|
|
|
+ WINTER, SPRING, SUMMER, AUTUMN
|
|
|
+ }
|
|
|
+
|
|
|
+ // 风向定义(16方位)
|
|
|
+ public enum WindDirection {
|
|
|
+ N, NNE, NE, ENE, E, ESE, SE, SSE,
|
|
|
+ S, SSW, SW, WSW, W, WNW, NW, NNW,
|
|
|
+ OTHER
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ // 模拟参数常量
|
|
|
+ private static final int TIME_INTERVAL_MINUTES = 3;
|
|
|
+
|
|
|
+ // 污染物类型
|
|
|
+ private enum PollutantType {
|
|
|
+ PM2_5, PM10, PM100, NOISE
|
|
|
+ }
|
|
|
+
|
|
|
+ // 马尔可夫链状态转移概率矩阵(按季节调整)
|
|
|
+ private static final Map<Season, double[][]> TRANSITION_MATRICES;
|
|
|
+
|
|
|
+ static {
|
|
|
+ Map<Season, double[][]> tempMap = new EnumMap<>(Season.class);
|
|
|
+ tempMap.put(Season.WINTER, new double[][]{
|
|
|
+ {0.70, 0.20, 0.08, 0.00, 0.02}, // SUNNY
|
|
|
+ {0.25, 0.55, 0.15, 0.00, 0.05}, // CLOUDY
|
|
|
+ {0.10, 0.30, 0.55, 0.00, 0.05}, // RAINY
|
|
|
+ {0.00, 0.00, 0.00, 0.00, 0.00}, // STORMY (冬季无雷暴)
|
|
|
+ {0.15, 0.25, 0.10, 0.00, 0.50} // FOGGY
|
|
|
+ });
|
|
|
+ tempMap.put(Season.SPRING, new double[][]{
|
|
|
+ {0.65, 0.25, 0.07, 0.01, 0.02},
|
|
|
+ {0.30, 0.50, 0.15, 0.03, 0.02},
|
|
|
+ {0.15, 0.35, 0.45, 0.03, 0.02},
|
|
|
+ {0.05, 0.15, 0.30, 0.45, 0.05},
|
|
|
+ {0.20, 0.30, 0.10, 0.00, 0.40}
|
|
|
+ });
|
|
|
+ tempMap.put(Season.SUMMER, new double[][]{
|
|
|
+ {0.60, 0.30, 0.05, 0.05, 0.00},
|
|
|
+ {0.35, 0.45, 0.10, 0.08, 0.02},
|
|
|
+ {0.20, 0.40, 0.30, 0.08, 0.02},
|
|
|
+ {0.10, 0.20, 0.20, 0.45, 0.05},
|
|
|
+ {0.25, 0.35, 0.05, 0.00, 0.35}
|
|
|
+ });
|
|
|
+ tempMap.put(Season.AUTUMN, new double[][]{
|
|
|
+ {0.55, 0.30, 0.10, 0.03, 0.02},
|
|
|
+ {0.25, 0.50, 0.20, 0.03, 0.02},
|
|
|
+ {0.10, 0.30, 0.55, 0.03, 0.02},
|
|
|
+ {0.05, 0.15, 0.30, 0.45, 0.05},
|
|
|
+ {0.15, 0.25, 0.10, 0.00, 0.50}
|
|
|
+ });
|
|
|
+ TRANSITION_MATRICES = Collections.unmodifiableMap(tempMap);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 基础温度范围(摄氏度,按季节和天气状态)
|
|
|
+ private static final Map<Season, Map<WeatherState, int[]>> BASE_TEMPERATURES;
|
|
|
+
|
|
|
+ static {
|
|
|
+ Map<Season, Map<WeatherState, int[]>> tempMap = new EnumMap<>(Season.class);
|
|
|
+
|
|
|
+ Map<WeatherState, int[]> winterTemps = new EnumMap<>(WeatherState.class);
|
|
|
+ winterTemps.put(WeatherState.SUNNY, new int[]{-5, 5});
|
|
|
+ winterTemps.put(WeatherState.CLOUDY, new int[]{-8, 2});
|
|
|
+ winterTemps.put(WeatherState.RAINY, new int[]{-3, 3});
|
|
|
+ winterTemps.put(WeatherState.STORMY, new int[]{-5, 0});
|
|
|
+ winterTemps.put(WeatherState.FOGGY, new int[]{-10, 0});
|
|
|
+ tempMap.put(Season.WINTER, Collections.unmodifiableMap(winterTemps));
|
|
|
+
|
|
|
+ Map<WeatherState, int[]> springTemps = new EnumMap<>(WeatherState.class);
|
|
|
+ springTemps.put(WeatherState.SUNNY, new int[]{8, 18});
|
|
|
+ springTemps.put(WeatherState.CLOUDY, new int[]{5, 15});
|
|
|
+ springTemps.put(WeatherState.RAINY, new int[]{6, 12});
|
|
|
+ springTemps.put(WeatherState.STORMY, new int[]{10, 16});
|
|
|
+ springTemps.put(WeatherState.FOGGY, new int[]{3, 10});
|
|
|
+ tempMap.put(Season.SPRING, Collections.unmodifiableMap(springTemps));
|
|
|
+
|
|
|
+ Map<WeatherState, int[]> summerTemps = new EnumMap<>(WeatherState.class);
|
|
|
+ summerTemps.put(WeatherState.SUNNY, new int[]{20, 32});
|
|
|
+ summerTemps.put(WeatherState.CLOUDY, new int[]{18, 28});
|
|
|
+ summerTemps.put(WeatherState.RAINY, new int[]{16, 24});
|
|
|
+ summerTemps.put(WeatherState.STORMY, new int[]{22, 28});
|
|
|
+ summerTemps.put(WeatherState.FOGGY, new int[]{15, 22});
|
|
|
+ tempMap.put(Season.SUMMER, Collections.unmodifiableMap(summerTemps));
|
|
|
+
|
|
|
+ Map<WeatherState, int[]> autumnTemps = new EnumMap<>(WeatherState.class);
|
|
|
+ autumnTemps.put(WeatherState.SUNNY, new int[]{15, 25});
|
|
|
+ autumnTemps.put(WeatherState.CLOUDY, new int[]{13, 22});
|
|
|
+ autumnTemps.put(WeatherState.RAINY, new int[]{10, 20});
|
|
|
+ autumnTemps.put(WeatherState.STORMY, new int[]{13, 24});
|
|
|
+ autumnTemps.put(WeatherState.FOGGY, new int[]{10, 18});
|
|
|
+ tempMap.put(Season.AUTUMN, Collections.unmodifiableMap(autumnTemps));
|
|
|
+
|
|
|
+ BASE_TEMPERATURES = Collections.unmodifiableMap(tempMap);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 基础湿度范围(百分比,按天气状态)
|
|
|
+ private static final Map<WeatherState, int[]> BASE_HUMIDITIES;
|
|
|
+
|
|
|
+ static {
|
|
|
+ Map<WeatherState, int[]> tempMap = new EnumMap<>(WeatherState.class);
|
|
|
+ tempMap.put(WeatherState.SUNNY, new int[]{30, 60});
|
|
|
+ tempMap.put(WeatherState.CLOUDY, new int[]{50, 80});
|
|
|
+ tempMap.put(WeatherState.RAINY, new int[]{75, 90});
|
|
|
+ tempMap.put(WeatherState.STORMY, new int[]{70, 88});
|
|
|
+ tempMap.put(WeatherState.FOGGY, new int[]{70, 85});
|
|
|
+ BASE_HUMIDITIES = Collections.unmodifiableMap(tempMap);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 新增:基础污染物范围(按天气状态和季节)
|
|
|
+ private static final Map<Season, Map<WeatherState, Map<PollutantType, int[]>>> BASE_POLLUTANTS;
|
|
|
+
|
|
|
+ static {
|
|
|
+ Map<Season, Map<WeatherState, Map<PollutantType, int[]>>> tempMap = new EnumMap<>(Season.class);
|
|
|
+
|
|
|
+ // 冬季污染物范围
|
|
|
+ Map<WeatherState, Map<PollutantType, int[]>> winterPollutants = new EnumMap<>(WeatherState.class);
|
|
|
+ winterPollutants.put(WeatherState.SUNNY, createPollutantMap(25, 75, 30, 80, 40, 90, 45, 65));
|
|
|
+ winterPollutants.put(WeatherState.CLOUDY, createPollutantMap(20, 60, 25, 70, 35, 90, 40, 60));
|
|
|
+ winterPollutants.put(WeatherState.RAINY, createPollutantMap(5, 20, 10, 30, 20, 50, 35, 55));
|
|
|
+ winterPollutants.put(WeatherState.STORMY, createPollutantMap(10, 30, 15, 40, 25, 60, 50, 70));
|
|
|
+ winterPollutants.put(WeatherState.FOGGY, createPollutantMap(70, 90, 80, 100, 90, 120, 40, 60));
|
|
|
+ tempMap.put(Season.WINTER, Collections.unmodifiableMap(winterPollutants));
|
|
|
+
|
|
|
+ // 春季污染物范围
|
|
|
+ Map<WeatherState, Map<PollutantType, int[]>> springPollutants = new EnumMap<>(WeatherState.class);
|
|
|
+ springPollutants.put(WeatherState.SUNNY, createPollutantMap(15, 40, 20, 50, 30, 70, 50, 70));
|
|
|
+ springPollutants.put(WeatherState.CLOUDY, createPollutantMap(20, 50, 25, 60, 35, 80, 45, 65));
|
|
|
+ springPollutants.put(WeatherState.RAINY, createPollutantMap(5, 25, 10, 35, 20, 60, 40, 60));
|
|
|
+ springPollutants.put(WeatherState.STORMY, createPollutantMap(10, 35, 15, 45, 25, 70, 55, 75));
|
|
|
+ springPollutants.put(WeatherState.FOGGY, createPollutantMap(40, 80, 60, 100, 80, 110, 45, 65));
|
|
|
+ tempMap.put(Season.SPRING, Collections.unmodifiableMap(springPollutants));
|
|
|
+
|
|
|
+ // 夏季污染物范围
|
|
|
+ Map<WeatherState, Map<PollutantType, int[]>> summerPollutants = new EnumMap<>(WeatherState.class);
|
|
|
+ summerPollutants.put(WeatherState.SUNNY, createPollutantMap(10, 30, 15, 40, 25, 60, 55, 75));
|
|
|
+ summerPollutants.put(WeatherState.CLOUDY, createPollutantMap(15, 35, 20, 45, 30, 70, 50, 70));
|
|
|
+ summerPollutants.put(WeatherState.RAINY, createPollutantMap(5, 20, 10, 30, 20, 50, 45, 65));
|
|
|
+ summerPollutants.put(WeatherState.STORMY, createPollutantMap(8, 25, 12, 35, 22, 55, 60, 80));
|
|
|
+ summerPollutants.put(WeatherState.FOGGY, createPollutantMap(30, 80, 50, 100, 70, 90, 50, 70));
|
|
|
+ tempMap.put(Season.SUMMER, Collections.unmodifiableMap(summerPollutants));
|
|
|
+
|
|
|
+ // 秋季污染物范围
|
|
|
+ Map<WeatherState, Map<PollutantType, int[]>> autumnPollutants = new EnumMap<>(WeatherState.class);
|
|
|
+ autumnPollutants.put(WeatherState.SUNNY, createPollutantMap(20, 50, 25, 60, 35, 80, 50, 70));
|
|
|
+ autumnPollutants.put(WeatherState.CLOUDY, createPollutantMap(25, 60, 30, 70, 40, 90, 45, 65));
|
|
|
+ autumnPollutants.put(WeatherState.RAINY, createPollutantMap(8, 30, 12, 40, 25, 70, 40, 60));
|
|
|
+ autumnPollutants.put(WeatherState.STORMY, createPollutantMap(12, 40, 18, 50, 30, 80, 55, 75));
|
|
|
+ autumnPollutants.put(WeatherState.FOGGY, createPollutantMap(60, 80, 80, 100, 80, 110, 45, 65));
|
|
|
+ tempMap.put(Season.AUTUMN, Collections.unmodifiableMap(autumnPollutants));
|
|
|
+
|
|
|
+ BASE_POLLUTANTS = Collections.unmodifiableMap(tempMap);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 新增:基础风速范围(米/秒,按季节和天气状态)
|
|
|
+ private static final Map<Season, Map<WeatherState, int[]>> BASE_WIND_SPEEDS;
|
|
|
+
|
|
|
+ static {
|
|
|
+ Map<Season, Map<WeatherState, int[]>> tempMap = new EnumMap<>(Season.class);
|
|
|
+
|
|
|
+ Map<WeatherState, int[]> winterSpeeds = new EnumMap<>(WeatherState.class);
|
|
|
+ winterSpeeds.put(WeatherState.SUNNY, new int[]{1, 5});
|
|
|
+ winterSpeeds.put(WeatherState.CLOUDY, new int[]{2, 8});
|
|
|
+ winterSpeeds.put(WeatherState.RAINY, new int[]{3, 10});
|
|
|
+ winterSpeeds.put(WeatherState.STORMY, new int[]{6, 10});
|
|
|
+// winterSpeeds.put(WeatherState.STORMY, new int[]{10, 20});
|
|
|
+ winterSpeeds.put(WeatherState.FOGGY, new int[]{0, 3});
|
|
|
+ tempMap.put(Season.WINTER, Collections.unmodifiableMap(winterSpeeds));
|
|
|
+
|
|
|
+ Map<WeatherState, int[]> springSpeeds = new EnumMap<>(WeatherState.class);
|
|
|
+ springSpeeds.put(WeatherState.SUNNY, new int[]{2, 6});
|
|
|
+ springSpeeds.put(WeatherState.CLOUDY, new int[]{3, 8});
|
|
|
+// springSpeeds.put(WeatherState.RAINY, new int[]{4, 12});
|
|
|
+ springSpeeds.put(WeatherState.RAINY, new int[]{4, 9});
|
|
|
+// springSpeeds.put(WeatherState.STORMY, new int[]{12, 25});
|
|
|
+ springSpeeds.put(WeatherState.STORMY, new int[]{6, 10});
|
|
|
+ springSpeeds.put(WeatherState.FOGGY, new int[]{1, 4});
|
|
|
+ tempMap.put(Season.SPRING, Collections.unmodifiableMap(springSpeeds));
|
|
|
+
|
|
|
+ Map<WeatherState, int[]> summerSpeeds = new EnumMap<>(WeatherState.class);
|
|
|
+ summerSpeeds.put(WeatherState.SUNNY, new int[]{1, 4});
|
|
|
+ summerSpeeds.put(WeatherState.CLOUDY, new int[]{2, 6});
|
|
|
+ summerSpeeds.put(WeatherState.RAINY, new int[]{3, 9});
|
|
|
+// summerSpeeds.put(WeatherState.STORMY, new int[]{15, 30});
|
|
|
+ summerSpeeds.put(WeatherState.STORMY, new int[]{6, 10});
|
|
|
+ summerSpeeds.put(WeatherState.FOGGY, new int[]{0, 2});
|
|
|
+ tempMap.put(Season.SUMMER, Collections.unmodifiableMap(summerSpeeds));
|
|
|
+
|
|
|
+ Map<WeatherState, int[]> autumnSpeeds = new EnumMap<>(WeatherState.class);
|
|
|
+ autumnSpeeds.put(WeatherState.SUNNY, new int[]{2, 7});
|
|
|
+// autumnSpeeds.put(WeatherState.CLOUDY, new int[]{3, 10});
|
|
|
+ autumnSpeeds.put(WeatherState.CLOUDY, new int[]{3, 7});
|
|
|
+// autumnSpeeds.put(WeatherState.RAINY, new int[]{4, 14});
|
|
|
+ autumnSpeeds.put(WeatherState.RAINY, new int[]{4, 9});
|
|
|
+// autumnSpeeds.put(WeatherState.STORMY, new int[]{10, 25});
|
|
|
+ autumnSpeeds.put(WeatherState.STORMY, new int[]{6, 10});
|
|
|
+ autumnSpeeds.put(WeatherState.FOGGY, new int[]{1, 5});
|
|
|
+ tempMap.put(Season.AUTUMN, Collections.unmodifiableMap(autumnSpeeds));
|
|
|
+
|
|
|
+ BASE_WIND_SPEEDS = Collections.unmodifiableMap(tempMap);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 新增:主导风向概率(按季节)
|
|
|
+ private static final Map<Season, Map<WindDirection, Double>> DOMINANT_WIND_DIRECTIONS;
|
|
|
+
|
|
|
+ static {
|
|
|
+ Map<Season, Map<WindDirection, Double>> tempMap = new EnumMap<>(Season.class);
|
|
|
+
|
|
|
+ // 冬季主导风向(北风、西北风)
|
|
|
+ Map<WindDirection, Double> winterDirs = new EnumMap<>(WindDirection.class);
|
|
|
+ winterDirs.put(WindDirection.N, 0.35);
|
|
|
+ winterDirs.put(WindDirection.NNW, 0.20);
|
|
|
+ winterDirs.put(WindDirection.NW, 0.15);
|
|
|
+ winterDirs.put(WindDirection.NNE, 0.10);
|
|
|
+ winterDirs.put(WindDirection.W, 0.05);
|
|
|
+ winterDirs.put(WindDirection.E, 0.05);
|
|
|
+ winterDirs.put(WindDirection.S, 0.05);
|
|
|
+ winterDirs.put(WindDirection.OTHER, 0.05);
|
|
|
+ tempMap.put(Season.WINTER, Collections.unmodifiableMap(winterDirs));
|
|
|
+
|
|
|
+ // 春季主导风向(东南风、南风)
|
|
|
+ Map<WindDirection, Double> springDirs = new EnumMap<>(WindDirection.class);
|
|
|
+ springDirs.put(WindDirection.SE, 0.30);
|
|
|
+ springDirs.put(WindDirection.S, 0.25);
|
|
|
+ springDirs.put(WindDirection.SSE, 0.15);
|
|
|
+ springDirs.put(WindDirection.ESE, 0.10);
|
|
|
+ springDirs.put(WindDirection.E, 0.05);
|
|
|
+ springDirs.put(WindDirection.N, 0.05);
|
|
|
+ springDirs.put(WindDirection.W, 0.05);
|
|
|
+ springDirs.put(WindDirection.OTHER, 0.05);
|
|
|
+ tempMap.put(Season.SPRING, Collections.unmodifiableMap(springDirs));
|
|
|
+
|
|
|
+ // 夏季主导风向(南风、西南风)
|
|
|
+ Map<WindDirection, Double> summerDirs = new EnumMap<>(WindDirection.class);
|
|
|
+ summerDirs.put(WindDirection.S, 0.30);
|
|
|
+ summerDirs.put(WindDirection.SSW, 0.20);
|
|
|
+ summerDirs.put(WindDirection.SW, 0.15);
|
|
|
+ summerDirs.put(WindDirection.SSE, 0.10);
|
|
|
+ summerDirs.put(WindDirection.W, 0.05);
|
|
|
+ summerDirs.put(WindDirection.N, 0.05);
|
|
|
+ summerDirs.put(WindDirection.E, 0.05);
|
|
|
+ summerDirs.put(WindDirection.OTHER, 0.10);
|
|
|
+ tempMap.put(Season.SUMMER, Collections.unmodifiableMap(summerDirs));
|
|
|
+
|
|
|
+ // 秋季主导风向(西北风、西风)
|
|
|
+ Map<WindDirection, Double> autumnDirs = new EnumMap<>(WindDirection.class);
|
|
|
+ autumnDirs.put(WindDirection.NW, 0.30);
|
|
|
+ autumnDirs.put(WindDirection.W, 0.25);
|
|
|
+ autumnDirs.put(WindDirection.WNW, 0.15);
|
|
|
+ autumnDirs.put(WindDirection.NNW, 0.10);
|
|
|
+ autumnDirs.put(WindDirection.N, 0.05);
|
|
|
+ autumnDirs.put(WindDirection.S, 0.05);
|
|
|
+ autumnDirs.put(WindDirection.E, 0.05);
|
|
|
+ autumnDirs.put(WindDirection.OTHER, 0.05);
|
|
|
+ tempMap.put(Season.AUTUMN, Collections.unmodifiableMap(autumnDirs));
|
|
|
+
|
|
|
+ DOMINANT_WIND_DIRECTIONS = Collections.unmodifiableMap(tempMap);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 辅助方法:创建污染物范围映射
|
|
|
+ private static Map<PollutantType, int[]> createPollutantMap(int pm25Min, int pm25Max,
|
|
|
+ int pm10Min, int pm10Max,
|
|
|
+ int pm100Min, int pm100Max,
|
|
|
+ int noiseMin, int noiseMax) {
|
|
|
+ Map<PollutantType, int[]> map = new EnumMap<>(PollutantType.class);
|
|
|
+ map.put(PollutantType.PM2_5, new int[]{pm25Min, pm25Max});
|
|
|
+ map.put(PollutantType.PM10, new int[]{pm10Min, pm10Max});
|
|
|
+ map.put(PollutantType.PM100, new int[]{pm100Min, pm100Max});
|
|
|
+ map.put(PollutantType.NOISE, new int[]{noiseMin, noiseMax});
|
|
|
+ return Collections.unmodifiableMap(map);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 辅助方法:获取随机风向(考虑季节主导风向)
|
|
|
+ private static WindDirection getRandomWindDirection(Season season, Random random) {
|
|
|
+ Map<WindDirection, Double> probs = DOMINANT_WIND_DIRECTIONS.get(season);
|
|
|
+ double rand = random.nextDouble();
|
|
|
+ double cumulative = 0.0;
|
|
|
+
|
|
|
+ for (Map.Entry<WindDirection, Double> entry : probs.entrySet()) {
|
|
|
+ cumulative += entry.getValue();
|
|
|
+ if (rand < cumulative) {
|
|
|
+ if (entry.getKey() == WindDirection.OTHER) {
|
|
|
+ while (true){
|
|
|
+ List<WindDirection> allDirs = Arrays.asList(WindDirection.values());
|
|
|
+ WindDirection direction = allDirs.get(random.nextInt(allDirs.size()));
|
|
|
+ if(!direction.equals(WindDirection.OTHER)){
|
|
|
+ return direction;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ return entry.getKey();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 默认返回北风
|
|
|
+ return WindDirection.N;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 辅助方法:获取风向角度(0-360度)
|
|
|
+ private static int getDirectionAngle(WindDirection direction) {
|
|
|
+ return direction.ordinal() * 22; // 每个方位22.5度,近似为22度
|
|
|
+ }
|
|
|
+
|
|
|
+ // 辅助方法:计算两个风向之间的角度差(考虑圆形)
|
|
|
+ private static int getAngleDifference(int angle1, int angle2) {
|
|
|
+ int diff = Math.abs(angle1 - angle2);
|
|
|
+ return Math.min(diff, 360 - diff);
|
|
|
+ }
|
|
|
+
|
|
|
+ public static List<WeatherData> simulateYearlyWeather(LocalDateTime currentTime, LocalDateTime endTime) {
|
|
|
+ List<WeatherData> yearlyData = new ArrayList<>();
|
|
|
+ Random random = new Random();
|
|
|
+
|
|
|
+// LocalDateTime currentTime = LocalDateTime.of(year, 1, 1, 0, 0);
|
|
|
+// LocalDateTime endTime = LocalDateTime.of(year + 1, 1, 1, 0, 0);
|
|
|
+
|
|
|
+ // 初始状态
|
|
|
+ WeatherState currentState = WeatherState.CLOUDY;
|
|
|
+ Season currentSeason = getSeason(currentTime);
|
|
|
+
|
|
|
+ // 使用平均值初始化
|
|
|
+ double currentTemp = getAverageTemperature(currentSeason, currentState);
|
|
|
+ double currentHumidity = getAverageHumidity(currentState);
|
|
|
+ double currentPM25 = getAveragePollutant(currentSeason, currentState, PollutantType.PM2_5);
|
|
|
+ double currentPM10 = getAveragePollutant(currentSeason, currentState, PollutantType.PM10);
|
|
|
+ double currentPM100 = getAveragePollutant(currentSeason, currentState, PollutantType.PM100);
|
|
|
+ double currentNoise = getAveragePollutant(currentSeason, currentState, PollutantType.NOISE);
|
|
|
+ double currentWindSpeed = getAverageWindSpeed(currentSeason, currentState);
|
|
|
+ WindDirection currentWindDir = getRandomWindDirection(currentSeason, random);
|
|
|
+
|
|
|
+ // 状态切换时的过渡参数
|
|
|
+ WeatherState targetState = currentState;
|
|
|
+ int transitionSteps = 0;
|
|
|
+ final int TOTAL_TRANSITION_STEPS = 12; // 过渡时长 = 12*3min = 36分钟
|
|
|
+
|
|
|
+ while (currentTime.isBefore(endTime)) {
|
|
|
+ // 每8小时检查状态变化
|
|
|
+ if (currentTime.getMinute() == 0 && currentTime.getHour() % 8 == 0) {
|
|
|
+ currentSeason = getSeason(currentTime);
|
|
|
+ WeatherState newState = getNextWeatherState(currentState, currentSeason, random);
|
|
|
+
|
|
|
+ if (!newState.equals(currentState)) {
|
|
|
+ targetState = newState;
|
|
|
+ transitionSteps = 0;
|
|
|
+// System.out.println("开始状态过渡: " + currentState + " → " + targetState + " at " + currentTime);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 计算过渡比例 (0.0=当前状态 → 1.0=目标状态)
|
|
|
+ double transitionRatio = transitionSteps < TOTAL_TRANSITION_STEPS ?
|
|
|
+ (double) transitionSteps / TOTAL_TRANSITION_STEPS : 1.0;
|
|
|
+
|
|
|
+ // 获取混合状态下的参数范围
|
|
|
+ int[] tempRange = getTransitionTemperatureRange(currentSeason, currentState, targetState, transitionRatio);
|
|
|
+ int[] humidityRange = getTransitionHumidityRange(currentState, targetState, transitionRatio);
|
|
|
+ Map<PollutantType, int[]> pollutantRanges = getTransitionPollutantRanges(
|
|
|
+ currentSeason, currentState, targetState, transitionRatio);
|
|
|
+ int[] windSpeedRange = getTransitionWindSpeedRange(currentSeason, currentState, targetState, transitionRatio);
|
|
|
+
|
|
|
+ // 获取目标风向(只在过渡开始时确定)
|
|
|
+ WindDirection targetWindDir = transitionSteps == 0 ?
|
|
|
+ getRandomWindDirection(currentSeason, random) : currentWindDir;
|
|
|
+
|
|
|
+ // 生成数据
|
|
|
+ double timeFactor = calculateTimeFactor(currentTime);
|
|
|
+ double seasonProgress = getSeasonProgress(currentTime);
|
|
|
+
|
|
|
+ currentTemp = generateSmoothTemperature(
|
|
|
+ tempRange, currentTime, timeFactor, seasonProgress,
|
|
|
+ random, currentTemp, transitionRatio);
|
|
|
+
|
|
|
+ currentHumidity = generateSmoothHumidity(
|
|
|
+ humidityRange, currentTime, timeFactor,
|
|
|
+ random, currentHumidity, transitionRatio);
|
|
|
+
|
|
|
+ // 生成污染物数据
|
|
|
+ currentPM25 = generateSmoothPollutant(
|
|
|
+ pollutantRanges.get(PollutantType.PM2_5),
|
|
|
+ random, currentPM25, transitionRatio, 1.5, 0.3);
|
|
|
+
|
|
|
+ currentPM10 = generateSmoothPollutant(
|
|
|
+ pollutantRanges.get(PollutantType.PM10),
|
|
|
+ random, currentPM10, transitionRatio, 2.0, 0.4);
|
|
|
+
|
|
|
+ currentPM100 = generateSmoothPollutant(
|
|
|
+ pollutantRanges.get(PollutantType.PM100),
|
|
|
+ random, currentPM100, transitionRatio, 3.0, 0.5);
|
|
|
+
|
|
|
+ // 生成噪音
|
|
|
+ currentNoise = generateSmoothNoise(
|
|
|
+ pollutantRanges.get(PollutantType.NOISE),
|
|
|
+ currentTime, random, currentNoise, transitionRatio);
|
|
|
+
|
|
|
+ // 生成风速
|
|
|
+ currentWindSpeed = generateSmoothWindSpeed(
|
|
|
+ windSpeedRange, random, currentWindSpeed, transitionRatio);
|
|
|
+
|
|
|
+ // 生成风向(平滑过渡)
|
|
|
+ currentWindDir = generateSmoothWindDirection(
|
|
|
+ currentWindDir, targetWindDir, transitionRatio, random);
|
|
|
+
|
|
|
+ // 添加到结果集
|
|
|
+ yearlyData.add(new WeatherData(
|
|
|
+ currentTime,
|
|
|
+ currentTemp,
|
|
|
+ currentHumidity,
|
|
|
+ transitionRatio < 1.0 ? currentState : targetState, // 显示当前有效状态
|
|
|
+ currentPM25,
|
|
|
+ currentPM10,
|
|
|
+ currentPM100,
|
|
|
+ currentNoise,
|
|
|
+ currentWindSpeed,
|
|
|
+ currentWindDir
|
|
|
+ ));
|
|
|
+
|
|
|
+ // 更新状态过渡进度
|
|
|
+ if (transitionSteps < TOTAL_TRANSITION_STEPS) {
|
|
|
+ transitionSteps++;
|
|
|
+ if (transitionSteps == TOTAL_TRANSITION_STEPS) {
|
|
|
+ currentState = targetState; // 过渡完成
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ currentTime = currentTime.plusMinutes(TIME_INTERVAL_MINUTES);
|
|
|
+ }
|
|
|
+
|
|
|
+ return yearlyData;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取过渡期间的温度范围
|
|
|
+ private static int[] getTransitionTemperatureRange(Season season,
|
|
|
+ WeatherState from,
|
|
|
+ WeatherState to,
|
|
|
+ double ratio) {
|
|
|
+ int[] fromRange = BASE_TEMPERATURES.get(season).get(from);
|
|
|
+ int[] toRange = BASE_TEMPERATURES.get(season).get(to);
|
|
|
+
|
|
|
+ return new int[]{
|
|
|
+ (int) Math.round(fromRange[0] * (1 - ratio) + toRange[0] * ratio),
|
|
|
+ (int) Math.round(fromRange[1] * (1 - ratio) + toRange[1] * ratio)
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取过渡期间的湿度范围
|
|
|
+ private static int[] getTransitionHumidityRange(WeatherState from,
|
|
|
+ WeatherState to,
|
|
|
+ double ratio) {
|
|
|
+ int[] fromRange = BASE_HUMIDITIES.get(from);
|
|
|
+ int[] toRange = BASE_HUMIDITIES.get(to);
|
|
|
+
|
|
|
+ return new int[]{
|
|
|
+ (int) Math.round(fromRange[0] * (1 - ratio) + toRange[0] * ratio),
|
|
|
+ (int) Math.round(fromRange[1] * (1 - ratio) + toRange[1] * ratio)
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ // 新增:获取过渡期间的污染物范围
|
|
|
+ private static Map<PollutantType, int[]> getTransitionPollutantRanges(Season season,
|
|
|
+ WeatherState from,
|
|
|
+ WeatherState to,
|
|
|
+ double ratio) {
|
|
|
+ Map<PollutantType, int[]> fromRanges = BASE_POLLUTANTS.get(season).get(from);
|
|
|
+ Map<PollutantType, int[]> toRanges = BASE_POLLUTANTS.get(season).get(to);
|
|
|
+
|
|
|
+ Map<PollutantType, int[]> result = new EnumMap<>(PollutantType.class);
|
|
|
+
|
|
|
+ for (PollutantType type : PollutantType.values()) {
|
|
|
+ int[] fromRange = fromRanges.get(type);
|
|
|
+ int[] toRange = toRanges.get(type);
|
|
|
+
|
|
|
+ int min = (int) Math.round(fromRange[0] * (1 - ratio) + toRange[0] * ratio);
|
|
|
+ int max = (int) Math.round(fromRange[1] * (1 - ratio) + toRange[1] * ratio);
|
|
|
+ result.put(type, new int[]{min, max});
|
|
|
+ }
|
|
|
+
|
|
|
+ return Collections.unmodifiableMap(result);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 新增:获取过渡期间的风速范围
|
|
|
+ private static int[] getTransitionWindSpeedRange(Season season,
|
|
|
+ WeatherState from,
|
|
|
+ WeatherState to,
|
|
|
+ double ratio) {
|
|
|
+ int[] fromRange = BASE_WIND_SPEEDS.get(season).get(from);
|
|
|
+ int[] toRange = BASE_WIND_SPEEDS.get(season).get(to);
|
|
|
+
|
|
|
+ return new int[]{
|
|
|
+ (int) Math.round(fromRange[0] * (1 - ratio) + toRange[0] * ratio),
|
|
|
+ (int) Math.round(fromRange[1] * (1 - ratio) + toRange[1] * ratio)
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ // 辅助方法:获取平均温度
|
|
|
+ private static double getAverageTemperature(Season season, WeatherState state) {
|
|
|
+ int[] range = BASE_TEMPERATURES.get(season).get(state);
|
|
|
+ return (range[0] + range[1]) / 2.0;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 辅助方法:获取平均湿度
|
|
|
+ private static double getAverageHumidity(WeatherState state) {
|
|
|
+ int[] range = BASE_HUMIDITIES.get(state);
|
|
|
+ return (range[0] + range[1]) / 2.0;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 辅助方法:获取平均污染物浓度
|
|
|
+ private static double getAveragePollutant(Season season, WeatherState state, PollutantType type) {
|
|
|
+ int[] range = BASE_POLLUTANTS.get(season).get(state).get(type);
|
|
|
+ return (range[0] + range[1]) / 2.0;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 辅助方法:获取平均风速
|
|
|
+ private static double getAverageWindSpeed(Season season, WeatherState state) {
|
|
|
+ int[] range = BASE_WIND_SPEEDS.get(season).get(state);
|
|
|
+ return (range[0] + range[1]) / 2.0;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 使用马尔可夫链获取下一个天气状态
|
|
|
+ private static WeatherState getNextWeatherState(WeatherState currentState, Season season, Random random) {
|
|
|
+ double[][] matrix = TRANSITION_MATRICES.get(season);
|
|
|
+ double rand = random.nextDouble();
|
|
|
+ double cumulativeProb = 0.0;
|
|
|
+
|
|
|
+ for (int i = 0; i < matrix[currentState.ordinal()].length; i++) {
|
|
|
+ cumulativeProb += matrix[currentState.ordinal()][i];
|
|
|
+ if (rand < cumulativeProb) {
|
|
|
+ return WeatherState.values()[i];
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return currentState;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 计算时间影响因子(昼夜节律)
|
|
|
+ private static double calculateTimeFactor(LocalDateTime time) {
|
|
|
+ double hour = time.getHour() + time.getMinute() / 60.0;
|
|
|
+ // 使用两个正弦波叠加模拟昼夜温度变化
|
|
|
+ return 0.6 * Math.sin((hour / 24) * 2 * Math.PI - Math.PI / 2) +
|
|
|
+ 0.4 * Math.sin((hour / 12) * 2 * Math.PI);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取季节进度(0.0到1.0)
|
|
|
+ private static double getSeasonProgress(LocalDateTime time) {
|
|
|
+ int dayOfYear = time.getDayOfYear();
|
|
|
+ if (dayOfYear < 80) return dayOfYear / 80.0; // 冬季
|
|
|
+ else if (dayOfYear < 172) return (dayOfYear - 80) / 92.0; // 春季
|
|
|
+ else if (dayOfYear < 264) return (dayOfYear - 172) / 92.0;// 夏季
|
|
|
+ else if (dayOfYear < 355) return (dayOfYear - 264) / 91.0;// 秋季
|
|
|
+ else return (dayOfYear - 355) / 10.0; // 冬季
|
|
|
+ }
|
|
|
+
|
|
|
+ // 平滑温度生成(过渡感知)
|
|
|
+ private static double generateSmoothTemperature(int[] range, LocalDateTime time,
|
|
|
+ double timeFactor, double seasonProgress,
|
|
|
+ Random random, double previousTemp,
|
|
|
+ double transitionRatio) {
|
|
|
+ // 基础温度计算(考虑过渡比例)
|
|
|
+ double baseTemp = range[0] + (range[1] - range[0]) * seasonProgress;
|
|
|
+
|
|
|
+ // 昼夜影响(过渡期间减弱)
|
|
|
+ double diurnalEffect = timeFactor * (range[1] - range[0]) *
|
|
|
+ (0.25 * (1 - transitionRatio) + 0.15 * transitionRatio);
|
|
|
+
|
|
|
+ // 随机波动(过渡期间减小)
|
|
|
+ double randomEffect = (random.nextDouble() - 0.5) *
|
|
|
+ (1.0 * (1 - transitionRatio) + 0.3 * transitionRatio);
|
|
|
+
|
|
|
+ // 计算目标温度
|
|
|
+ double targetTemp = baseTemp + diurnalEffect + randomEffect;
|
|
|
+
|
|
|
+ // 应用变化率限制(过渡期间更严格)
|
|
|
+ double maxDelta = 0.3 + 0.2 * (1 - transitionRatio); // 0.3~0.5℃
|
|
|
+ targetTemp = Math.max(previousTemp - maxDelta,
|
|
|
+ Math.min(previousTemp + maxDelta, targetTemp));
|
|
|
+
|
|
|
+ // 确保在合理范围内
|
|
|
+ return Math.max(range[0], Math.min(range[1], targetTemp));
|
|
|
+ }
|
|
|
+
|
|
|
+ // 平滑湿度生成(过渡感知)
|
|
|
+ private static double generateSmoothHumidity(int[] range, LocalDateTime time,
|
|
|
+ double timeFactor, Random random,
|
|
|
+ double previousHumidity,
|
|
|
+ double transitionRatio) {
|
|
|
+ // 基础湿度(考虑过渡比例)
|
|
|
+ double baseHumidity = range[0] + (range[1] - range[0]) * random.nextDouble();
|
|
|
+
|
|
|
+ // 昼夜影响(过渡期间减弱)
|
|
|
+ double diurnalEffect = timeFactor * 9 * (1 - 0.5 * transitionRatio);
|
|
|
+
|
|
|
+ // 随机波动(过渡期间减小)
|
|
|
+ double randomEffect = (random.nextDouble() - 0.5) * 6 * (1 - 0.7 * transitionRatio);
|
|
|
+
|
|
|
+ // 计算目标湿度
|
|
|
+ double targetHumidity = baseHumidity - diurnalEffect + randomEffect;
|
|
|
+
|
|
|
+ // 应用变化率限制(过渡期间更严格)
|
|
|
+ double maxDelta = 0.8 + 0.7 * (1 - transitionRatio); // 0.8~1.5%
|
|
|
+ targetHumidity = Math.max(previousHumidity - maxDelta,
|
|
|
+ Math.min(previousHumidity + maxDelta, targetHumidity));
|
|
|
+
|
|
|
+ // 确保在合理范围内
|
|
|
+ return Math.max(range[0], Math.min(range[1], targetHumidity));
|
|
|
+ }
|
|
|
+
|
|
|
+ // 新增:平滑污染物生成(通用方法)
|
|
|
+ private static double generateSmoothPollutant(int[] range, Random random,
|
|
|
+ double previousValue, double transitionRatio,
|
|
|
+ double baseDelta, double fluctuationFactor) {
|
|
|
+ // 基础值(考虑过渡比例)
|
|
|
+ double baseValue = range[0] + (range[1] - range[0]) * random.nextDouble();
|
|
|
+
|
|
|
+ // 随机波动(过渡期间减小)
|
|
|
+ double randomEffect = (random.nextDouble() - 0.5) * fluctuationFactor * range[1] *
|
|
|
+ (1 - 0.7 * transitionRatio);
|
|
|
+
|
|
|
+ // 计算目标值
|
|
|
+ double targetValue = baseValue + randomEffect;
|
|
|
+
|
|
|
+ // 应用变化率限制(过渡期间更严格)
|
|
|
+ double maxDelta = baseDelta + baseDelta * (1 - transitionRatio);
|
|
|
+ targetValue = Math.max(previousValue - maxDelta,
|
|
|
+ Math.min(previousValue + maxDelta, targetValue));
|
|
|
+
|
|
|
+ // 确保在合理范围内
|
|
|
+ return Math.max(range[0], Math.min(range[1], targetValue));
|
|
|
+ }
|
|
|
+
|
|
|
+ // 新增:平滑噪音生成(考虑昼夜节律)
|
|
|
+ private static double generateSmoothNoise(int[] range, LocalDateTime time,
|
|
|
+ Random random, double previousNoise,
|
|
|
+ double transitionRatio) {
|
|
|
+ // 基础噪音
|
|
|
+ double baseNoise = range[0] + (range[1] - range[0]) * random.nextDouble();
|
|
|
+
|
|
|
+ // 昼夜影响(白天高,夜晚低)
|
|
|
+ double hour = time.getHour() + time.getMinute() / 60.0;
|
|
|
+ double diurnalEffect = 0;
|
|
|
+ if (hour >= 6 && hour <= 22) { // 白天(6:00-22:00)
|
|
|
+ // 早晚高峰
|
|
|
+ if ((hour >= 7 && hour <= 9) || (hour >= 17 && hour <= 19)) {
|
|
|
+ diurnalEffect = 10 + 5 * Math.sin((hour - 8) * Math.PI / 6);
|
|
|
+ } else {
|
|
|
+ diurnalEffect = 5 * Math.sin((hour - 12) * Math.PI / 12);
|
|
|
+ }
|
|
|
+ } else { // 夜间
|
|
|
+ diurnalEffect = -15;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 随机波动
|
|
|
+ double randomEffect = (random.nextDouble() - 0.5) * 5;
|
|
|
+
|
|
|
+ // 计算目标噪音
|
|
|
+ double targetNoise = baseNoise + diurnalEffect + randomEffect;
|
|
|
+
|
|
|
+ // 应用变化率限制
|
|
|
+ double maxDelta = 2.0 + 1.5 * (1 - transitionRatio); // 2.0~3.5 dB
|
|
|
+ targetNoise = Math.max(previousNoise - maxDelta,
|
|
|
+ Math.min(previousNoise + maxDelta, targetNoise));
|
|
|
+
|
|
|
+ // 确保在合理范围内
|
|
|
+ return Math.max(range[0], Math.min(range[1], targetNoise));
|
|
|
+ }
|
|
|
+
|
|
|
+ // 新增:平滑风速生成
|
|
|
+ private static double generateSmoothWindSpeed(int[] range, Random random,
|
|
|
+ double previousSpeed,
|
|
|
+ double transitionRatio) {
|
|
|
+ // 基础风速(考虑过渡比例)
|
|
|
+ double baseSpeed = range[0] + (range[1] - range[0]) * random.nextDouble();
|
|
|
+
|
|
|
+ // 随机波动(过渡期间减小)
|
|
|
+ double randomEffect = (random.nextDouble() - 0.5) * 2.0 * (1 - 0.7 * transitionRatio);
|
|
|
+
|
|
|
+ // 计算目标风速
|
|
|
+ double targetSpeed = baseSpeed + randomEffect;
|
|
|
+
|
|
|
+ // 应用变化率限制(过渡期间更严格)
|
|
|
+ double maxDelta = 0.5 + 0.4 * (1 - transitionRatio); // 0.5~0.9 m/s
|
|
|
+ targetSpeed = Math.max(previousSpeed - maxDelta,
|
|
|
+ Math.min(previousSpeed + maxDelta, targetSpeed));
|
|
|
+
|
|
|
+ // 确保在合理范围内
|
|
|
+ return Math.max(range[0], Math.min(range[1], targetSpeed));
|
|
|
+ }
|
|
|
+
|
|
|
+ // 新增:平滑风向过渡
|
|
|
+ private static WindDirection generateSmoothWindDirection(WindDirection currentDir,
|
|
|
+ WindDirection targetDir,
|
|
|
+ double transitionRatio,
|
|
|
+ Random random) {
|
|
|
+ // 如果已经是目标风向,或者过渡完成
|
|
|
+ if (currentDir == targetDir || transitionRatio >= 1.0) {
|
|
|
+ return targetDir;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 有20%的概率在非过渡期间改变风向
|
|
|
+ if (transitionRatio == 0 && random.nextDouble() < 0.2) {
|
|
|
+ // 随机小幅变化(±1个方位)
|
|
|
+ int currentIndex = currentDir.ordinal();
|
|
|
+ int change = random.nextBoolean() ? 1 : -1;
|
|
|
+ int newIndex = (currentIndex + change + WindDirection.values().length) % WindDirection.values().length;
|
|
|
+ return WindDirection.values()[newIndex];
|
|
|
+ }
|
|
|
+
|
|
|
+ // 过渡期间:逐步转向目标风向
|
|
|
+ int currentAngle = getDirectionAngle(currentDir);
|
|
|
+ int targetAngle = getDirectionAngle(targetDir);
|
|
|
+
|
|
|
+ // 计算最短转向路径
|
|
|
+ int diff1 = (targetAngle - currentAngle + 360) % 360;
|
|
|
+ int diff2 = diff1 - 360;
|
|
|
+ int shortestDiff = Math.abs(diff1) < Math.abs(diff2) ? diff1 : diff2;
|
|
|
+
|
|
|
+ // 最大转向角度(每次最多22.5度)
|
|
|
+ int maxTurn = (int) (22 * transitionRatio);
|
|
|
+ int actualTurn = Math.min(Math.abs(shortestDiff), maxTurn);
|
|
|
+ if (shortestDiff < 0) actualTurn = -actualTurn;
|
|
|
+
|
|
|
+ // 计算新角度
|
|
|
+ int newAngle = (currentAngle + actualTurn + 360) % 360;
|
|
|
+
|
|
|
+ // 转换为最接近的风向
|
|
|
+ int index = (int) Math.round(newAngle / 22.5) % 16;
|
|
|
+ return WindDirection.values()[index];
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取当前季节
|
|
|
+ private static Season getSeason(LocalDateTime time) {
|
|
|
+ int month = time.getMonthValue();
|
|
|
+ if (month == 12 || month <= 2) return Season.WINTER;
|
|
|
+ if (month <= 5) return Season.SPRING;
|
|
|
+ if (month <= 8) return Season.SUMMER;
|
|
|
+ return Season.AUTUMN;
|
|
|
+ }
|
|
|
+
|
|
|
+// public static void main(String[] args) {
|
|
|
+// int year = 2024;
|
|
|
+// List<WeatherData> yearlyData = simulateYearlyWeather(year);
|
|
|
+//
|
|
|
+// // 打印前3天的数据(每小时间隔)
|
|
|
+// System.out.println("时间戳\t\t\t\t温度\t湿度\t天气状态\tPM2.5\tPM10\tPM100\t噪音\t风速和风向");
|
|
|
+// for (int i = 0; i < 480; i += 20) { // 每20个点 = 1小时 (3分钟间隔)
|
|
|
+// WeatherData data = yearlyData.get(i);
|
|
|
+// System.out.println(data);
|
|
|
+// }
|
|
|
+// System.out.println(yearlyData.size());
|
|
|
+
|
|
|
+ // 统计不同天气下的平均风速
|
|
|
+// Map<WeatherState, Double> avgWindSpeedByWeather = yearlyData.stream()
|
|
|
+// .collect(Collectors.groupingBy(WeatherData::getWeatherState,
|
|
|
+// Collectors.averagingDouble(WeatherData::getWindSpeed)));
|
|
|
+//
|
|
|
+// System.out.println("\n不同天气状态下的平均风速:");
|
|
|
+// avgWindSpeedByWeather.forEach((state, avg) ->
|
|
|
+// System.out.printf("%s: %.1f m/s%n", state, avg));
|
|
|
+
|
|
|
+ // 统计主导风向分布
|
|
|
+// Map<WindDirection, Long> windDirectionDistribution = yearlyData.stream()
|
|
|
+// .collect(Collectors.groupingBy(WeatherData::getWindDirection, Collectors.counting()));
|
|
|
+
|
|
|
+// System.out.println("\n风向分布:");
|
|
|
+// windDirectionDistribution.entrySet().stream()
|
|
|
+// .sorted(Map.Entry.comparingByValue(Comparator.reverseOrder()))
|
|
|
+// .forEach(entry ->
|
|
|
+// System.out.printf("%s: %.1f%%%n", entry.getKey(),
|
|
|
+// entry.getValue() * 100.0 / yearlyData.size()));
|
|
|
+// }
|
|
|
+}
|