CalculationUtil.java 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460
  1. package com.jiayue.biz.util;
  2. import cn.hutool.core.convert.Convert;
  3. import com.jiayue.biz.domain.ProphaseAnemometryData;
  4. import com.jiayue.biz.domain.ProphaseWeatherData;
  5. import com.jiayue.biz.domain.WindTowerCalculationData;
  6. import com.jiayue.biz.eunms.WindDirectionEnum;
  7. import lombok.extern.slf4j.Slf4j;
  8. import org.apache.commons.lang3.time.DateUtils;
  9. import java.math.BigDecimal;
  10. import java.math.BigInteger;
  11. import java.math.RoundingMode;
  12. import java.text.SimpleDateFormat;
  13. import java.util.*;
  14. import java.util.stream.Collectors;
  15. @Slf4j
  16. public class CalculationUtil {
  17. /**
  18. * 根据设备属性风向获取数据
  19. *
  20. * @param filterList 过滤出的风数据
  21. * @param height 属性名(层高)
  22. * @return
  23. */
  24. public static List<Map<String, Object>> getForHeightAndWindDirectionEnum(List<Map<String, Object>> filterList, String height, WindDirectionEnum windDirectionEnum) {
  25. List<Map<String, Object>> collect = new ArrayList<>();
  26. if (windDirectionEnum.name().equals("N")) {
  27. // N的范围为 348.75<wd<360 + 0<wd<11.25
  28. filterList.stream().filter(w -> w.get("wd_ave" + height) != null && (getBigDecimal(w.get("wd_ave" + height)).compareTo(windDirectionEnum.getLower()) >= 0 && getBigDecimal(w.get("wd_ave" + height)).compareTo(new BigDecimal(360)) <= 0) || (getBigDecimal(w.get("wd_ave" + height)).compareTo(windDirectionEnum.getUpper()) < 0 && getBigDecimal(w.get("wd_ave" + height)).compareTo(new BigDecimal(0)) > 0)).collect(Collectors.toList());
  29. } else {
  30. collect = filterList.stream().filter(w -> w.get("wd_ave" + height) != null && getBigDecimal(w.get("wd_ave" + height)).compareTo(windDirectionEnum.getLower()) >= 0 && getBigDecimal(w.get("wd_ave" + height)).compareTo(windDirectionEnum.getUpper()) < 0).collect(Collectors.toList());
  31. }
  32. return collect;
  33. }
  34. /**
  35. * 根据设备属性风向获取数据 Todo 新数据库格式
  36. *
  37. * @param List 过滤出的风数据
  38. * @return
  39. */
  40. public static List<ProphaseAnemometryData> getForHeightAndWindDirectionEnum(List<ProphaseAnemometryData> List, WindDirectionEnum windEnum) {
  41. List<ProphaseAnemometryData> collect = new ArrayList<>();
  42. if (windEnum.name().equals("N")) {
  43. // N的范围为 348.75<wd<360 + 0<wd<11.25
  44. List.stream().filter(e -> e.getWdAve() != null).filter(w -> (getBigDecimal(w.getWdAve()).compareTo(windEnum.getLower()) >= 0 && getBigDecimal(w.getWdAve()).compareTo(new BigDecimal(360)) <= 0) || (getBigDecimal(w.getWdAve()).compareTo(windEnum.getUpper()) < 0 && getBigDecimal(w.getWdAve()).compareTo(new BigDecimal(0)) > 0)).collect(Collectors.toList());
  45. } else {
  46. collect = List.stream().filter(w -> w.getWdAve() != null && getBigDecimal(w.getWdAve()).compareTo(windEnum.getLower()) >= 0 && getBigDecimal(w.getWdAve()).compareTo(windEnum.getUpper()) < 0).collect(Collectors.toList());
  47. }
  48. return collect;
  49. }
  50. /**
  51. * 根据层高获取风速数据 todo 旧
  52. *
  53. * @param filterList 过滤出的风数据
  54. * @param fieldName 属性名(层高)
  55. * @return
  56. */
  57. public static List<BigDecimal> getWsForHeight(List<Map<String, Object>> filterList, String fieldName) {
  58. List<BigDecimal> wsList = new ArrayList<>();
  59. for (Map<String, Object> map : filterList) {
  60. String abnormal_type = "";
  61. //过滤异常值
  62. if (map.get("abnormal_type") != null) {
  63. abnormal_type = map.get("abnormal_type").toString();
  64. }
  65. if (map.get("ws_ave" + fieldName) != null && !map.get("ws_ave" + fieldName).equals("") && (!abnormal_type.contains("wsAve" + fieldName) || !abnormal_type.contains("ws_ave" + fieldName))) {
  66. if (Double.parseDouble(map.get("ws_ave" + fieldName).toString()) < 50) {
  67. wsList.add(getBigDecimal(map.get("ws_ave" + fieldName)));
  68. }
  69. }
  70. }
  71. return wsList;
  72. }
  73. /**
  74. * 根据层高获取空气密度
  75. *
  76. * @param filterList 过滤出的风数据
  77. * @return
  78. */
  79. public static List<BigDecimal> getAir(List<Map<String, Object>> filterList) {
  80. List<BigDecimal> wsList = new ArrayList<>();
  81. for (Map<String, Object> map : filterList) {
  82. String abnormal_type = "";
  83. //过滤异常值
  84. if (map.get("abnormal_type") != null) {
  85. abnormal_type = map.get("abnormal_type").toString();
  86. }
  87. if (map.get("air_density") != null && !map.get("air_density").equals("") && (!abnormal_type.contains("air_density"))) {
  88. if (Double.parseDouble(map.get("air_density").toString()) < 50) {
  89. wsList.add(getBigDecimal(map.get("air_density")));
  90. }
  91. }
  92. }
  93. return wsList;
  94. }
  95. /**
  96. * 根据层高获取最大风速数据
  97. *
  98. * @param filterList 过滤出的风数据
  99. * @param fieldName 属性名(层高)
  100. * @return
  101. */
  102. public static List<BigDecimal> getWsMaxForHeight(List<Map<String, Object>> filterList, String fieldName) {
  103. List<BigDecimal> wsMaxList = new ArrayList<>();
  104. for (Map<String, Object> map : filterList) {
  105. String abnormal_type = "";
  106. //过滤异常值
  107. if (map.get("abnormal_type") != null) {
  108. abnormal_type = map.get("abnormal_type").toString();
  109. }
  110. if (map.get("ws_max" + fieldName) != null && (!abnormal_type.contains("wsMax" + fieldName) || !abnormal_type.contains("ws_max" + fieldName))) {
  111. wsMaxList.add(getBigDecimal((map.get("ws_max" + fieldName))));
  112. }
  113. }
  114. return wsMaxList;
  115. }
  116. /**
  117. * 根据层高获取标准差数据
  118. *
  119. * @param filterList 过滤出的风数据
  120. * @param fieldName 属性名(层高)
  121. * @return
  122. */
  123. public static List<BigDecimal> getWsStaForHeight(List<Map<String, Object>> filterList, String fieldName) {
  124. List<BigDecimal> wsStaList = new ArrayList<>();
  125. for (Map<String, Object> map : filterList) {
  126. String abnormal_type = "";
  127. //过滤异常值
  128. if (map.get("abnormal_type") != null) {
  129. abnormal_type = map.get("abnormal_type").toString();
  130. }
  131. if (map.get("ws_sta" + fieldName) != null && (!abnormal_type.contains("wsSta" + fieldName) || !abnormal_type.contains("ws_sta" + fieldName))) {
  132. if (Double.parseDouble(map.get("ws_sta" + fieldName).toString()) < 50) {
  133. wsStaList.add(getBigDecimal((map.get("ws_sta" + fieldName))));
  134. }
  135. }
  136. }
  137. return wsStaList;
  138. }
  139. /**
  140. * 计算平均风速
  141. *
  142. * @param bigDecimalList 风速数据
  143. * @return
  144. */
  145. public static BigDecimal getAvgWind(List<BigDecimal> bigDecimalList) {
  146. return new BigDecimal(bigDecimalList.stream().collect(Collectors.averagingDouble(BigDecimal::doubleValue))).setScale(2,RoundingMode.HALF_UP);
  147. }
  148. /**
  149. * 计算风能密度(风功率玫瑰图) todo 旧
  150. *
  151. * @return 风能密度
  152. */
  153. public static BigDecimal windEnergyDensity(List<ProphaseAnemometryData> anemometryData, List<ProphaseWeatherData> weatherData) {
  154. BigDecimal density = new BigDecimal(-99);
  155. try {
  156. if (anemometryData.size() == weatherData.size() && anemometryData.size() != 0) {
  157. BigDecimal count = new BigDecimal(0);
  158. for (int i = 0; i < anemometryData.size(); i++) {
  159. if (weatherData.get(i).getAirDensity() != null && anemometryData.get(i).getWsAve() != null) {
  160. if (weatherData.get(i).getTs().getTime() == anemometryData.get(i).getTs().getTime()) {
  161. //计算风功率密度 空气密度*第i点的风速值的立方 求和/2 各个层高都有
  162. count = count.add(getWpdCalculate(getBigDecimal(weatherData.get(i).getAirDensity()), getBigDecimal(anemometryData.get(i).getWsAve())));
  163. } else {
  164. int finalI = i;
  165. List<ProphaseWeatherData> collect = weatherData.stream().filter(w -> w.getTs().getTime() == anemometryData.get(finalI).getTs().getTime()).collect(Collectors.toList());
  166. if (collect.size() > 0) {
  167. count = count.add(getWpdCalculate(getBigDecimal(collect.get(0).getAirDensity()), getBigDecimal(anemometryData.get(i).getWsAve())));
  168. }
  169. }
  170. }
  171. }
  172. density = count.divide((new BigDecimal(weatherData.size())), 2, RoundingMode.HALF_UP);
  173. }
  174. } catch (Exception e) {
  175. log.error("计算风风能密度时发生错误");
  176. } finally {
  177. return density;
  178. }
  179. }
  180. //计算风功率密度公式
  181. public static BigDecimal getWpdCalculate(BigDecimal wsAve, BigDecimal airAve) {
  182. return airAve.multiply(power(getBigDecimal(wsAve), 3)).multiply(BigDecimal.valueOf(0.5));
  183. }
  184. /**
  185. * @param x 参数
  186. * @param total 指数
  187. * @return x的total次方
  188. */
  189. public static BigDecimal power(BigDecimal x, Integer total) {
  190. BigDecimal power = x;
  191. for (int i = 1; i < total; i++) {
  192. power = power.multiply(x);
  193. }
  194. return power;
  195. }
  196. /**
  197. * 从 String 中提取数字
  198. *
  199. * @param string
  200. * @return
  201. */
  202. public static String getNumberFromString(String string) {
  203. String str = string;
  204. str = str.trim();
  205. StringBuffer str2 = new StringBuffer();
  206. if (str != null && !"".equals(str)) {
  207. for (int i = 0; i < str.length(); i++) {
  208. if (str.charAt(i) >= 48 && str.charAt(i) <= 57) {
  209. String s = String.valueOf(str.charAt(i));
  210. str2.append(s);
  211. }
  212. }
  213. }
  214. return str2.toString();
  215. }
  216. /**
  217. * 计算风切变指数
  218. *
  219. * @param v2 高度 Z2 的风速
  220. * @param v1 高度 Z1 的风速
  221. * @param z2 高度
  222. * @param z1 高度
  223. * @return 风切变指数
  224. */
  225. public static BigDecimal caWindShear(BigDecimal v2, BigDecimal v1, BigDecimal z2, BigDecimal z1) {
  226. v2 = v2.setScale(4, BigDecimal.ROUND_HALF_UP);
  227. z2 = z2.setScale(4, BigDecimal.ROUND_HALF_UP);
  228. BigDecimal result = new BigDecimal(-99);
  229. try {
  230. double v = v2.divide(v1, 2, BigDecimal.ROUND_HALF_UP).doubleValue();
  231. double v3 = 0;
  232. if (v != 0) {
  233. v3 = Math.log10(v);
  234. }
  235. double z = z2.divide(z1, 2, BigDecimal.ROUND_HALF_UP).doubleValue();
  236. double z3 = 0;
  237. if (z != 0) {
  238. z3 = Math.log10(z);
  239. }
  240. if (z3 != 0) {
  241. result = new BigDecimal(v3).divide(new BigDecimal(z3), 2, BigDecimal.ROUND_HALF_UP);
  242. }
  243. } catch (Exception e) {
  244. e.printStackTrace();
  245. } finally {
  246. return result;
  247. }
  248. }
  249. /**
  250. * 计算湍流强度
  251. *
  252. * @param wsSta 风速标准差
  253. * @param ws 风速
  254. * @return 湍流强度
  255. */
  256. public static BigDecimal caTurbulenceIntensity(BigDecimal wsSta, BigDecimal ws) {
  257. BigDecimal result = new BigDecimal(-99);
  258. try {
  259. if (ws.compareTo(new BigDecimal(0)) > 0) {
  260. result = wsSta.divide(ws, 2, BigDecimal.ROUND_HALF_UP);
  261. }
  262. } catch (Exception e) {
  263. e.printStackTrace();
  264. } finally {
  265. return result;
  266. }
  267. }
  268. /**
  269. * 封装逐小时数据集合
  270. *
  271. * @param awsList 数据
  272. * @return
  273. */
  274. public static List<BigDecimal> getData24(List<WindTowerCalculationData> awsList) {
  275. Long hour = 3600000l;
  276. Date systemDate = new Date();
  277. List<BigDecimal> results = new ArrayList<>();
  278. SimpleDateFormat simpleDateFormat = new SimpleDateFormat("HH");
  279. //获取昨日开始和结束时间
  280. Long startTime = DateMomentUtil.getDayStartTime(DateUtils.addDays(systemDate, -1).getTime());
  281. Long endTime = startTime + 86399000;
  282. for (Long time = startTime; time <= endTime; time += hour) {
  283. Long finalTime = time;
  284. String format = simpleDateFormat.format(finalTime);
  285. List<BigDecimal> collect = awsList.stream().filter(s -> simpleDateFormat.format(s.getTime())
  286. .equals(format) && s.getValue().compareTo(new BigDecimal(-99)) != 0)
  287. .map(WindTowerCalculationData::getValue).collect(Collectors.toList());
  288. BigDecimal avg = BigDecimal.ZERO;
  289. if (collect.size() > 0) {
  290. avg = collect.stream().reduce(BigDecimal.ZERO, BigDecimal::add).divide(BigDecimal.valueOf(collect.size()), 4, RoundingMode.HALF_UP);
  291. }
  292. results.add(avg);
  293. }
  294. return results;
  295. }
  296. /**
  297. * Object转BigDecimal类型
  298. *
  299. * @param value 要转的object类型
  300. * @return 转成的BigDecimal类型数据
  301. */
  302. public static BigDecimal getBigDecimal(Object value) {
  303. BigDecimal ret = null;
  304. if (value != null) {
  305. if (value instanceof BigDecimal) {
  306. ret = (BigDecimal) value;
  307. } else if (value instanceof String) {
  308. ret = new BigDecimal((String) value);
  309. } else if (value instanceof BigInteger) {
  310. ret = new BigDecimal((BigInteger) value);
  311. } else if (value instanceof Number) {
  312. ret = BigDecimal.valueOf(((Number) value).doubleValue());
  313. } else {
  314. throw new ClassCastException("不能将数据 [" + value + "] 从 " + value.getClass() + "类型转为BigDecimal类型.");
  315. }
  316. }
  317. return ret;
  318. }
  319. /**
  320. * 机型:WH6.25N-182
  321. *
  322. * @param ws 风速
  323. * @return 拟合功率 BigDecimal
  324. */
  325. public static BigDecimal getBattery(BigDecimal ws) {
  326. BigDecimal battery = new BigDecimal(0);
  327. if (ws.compareTo(BigDecimal.valueOf(3)) > 0 && ws.compareTo(BigDecimal.valueOf(12.5)) < 0) {
  328. //拟合功率 = (-9.066 * e^-5 * ws^8)+ (0.01055 * ws^7) - (0.5109 * ws^6) + (13.29 * ws^5) - (200.3 * ws^4) + (1755 * ws^3) - (8549 * ws^2) + (2.152 * e^4 * ws) - (2.153 * e^4)
  329. battery = (BigDecimal.valueOf(-9.006).multiply(BigDecimal.valueOf(Math.pow(10, -5)).multiply(CalculationUtil.power(ws, 8)))
  330. .add(BigDecimal.valueOf(0.01055).multiply(CalculationUtil.power(ws, 7)))
  331. .subtract(BigDecimal.valueOf(0.5109).multiply(CalculationUtil.power(ws, 6)))
  332. .add(BigDecimal.valueOf(13.29).multiply(CalculationUtil.power(ws, 5)))
  333. .subtract(BigDecimal.valueOf(200.3).multiply(CalculationUtil.power(ws, 4)))
  334. .add(BigDecimal.valueOf(1755).multiply(CalculationUtil.power(ws, 3)))
  335. .subtract(BigDecimal.valueOf(8549).multiply(CalculationUtil.power(ws, 2)))
  336. .add(BigDecimal.valueOf(2.152).multiply(BigDecimal.valueOf(Math.pow(10, 4)).multiply(ws)))
  337. .subtract(BigDecimal.valueOf(2.153).multiply(BigDecimal.valueOf(Math.pow(10, 4)))))
  338. .setScale(4, RoundingMode.HALF_UP);
  339. } else if (ws.compareTo(BigDecimal.valueOf(12.5)) >= 0) {
  340. battery = BigDecimal.valueOf(6250);
  341. }
  342. //单个风速功率
  343. return battery;
  344. }
  345. /**
  346. * 计算威布尔值
  347. *
  348. * @param e e
  349. * @param d 风速
  350. * @param K K
  351. * @param A A
  352. * @return weibull
  353. */
  354. public static BigDecimal getBigDecimal(double e, double d, double K, double A) {
  355. BigDecimal value = BigDecimal.ZERO;
  356. //e的-(U/K)次方的K次方
  357. if (A != 0.0 && K != 0.0) {
  358. // U/A
  359. BigDecimal UAK1 = BigDecimal.valueOf(d).divide(BigDecimal.valueOf(A), 4, RoundingMode.HALF_UP);
  360. double UAK2 = UAK1.doubleValue();
  361. //U/A 的k次方
  362. double UAK = Math.pow(UAK2, K);
  363. //e的负 UAK次方
  364. double EUAK = Math.pow(e, -UAK);
  365. //K/A
  366. BigDecimal KA = BigDecimal.valueOf(K).divide(BigDecimal.valueOf(A), 4, RoundingMode.HALF_UP);
  367. BigDecimal UA1 = BigDecimal.valueOf(d).divide(BigDecimal.valueOf(A), 4, RoundingMode.HALF_UP);
  368. double v = UA1.doubleValue();
  369. double pow = Math.pow(v, (K - 1));
  370. BigDecimal pow1 = BigDecimal.valueOf(pow).multiply(BigDecimal.valueOf(EUAK));
  371. value = pow1.multiply(KA).setScale(4, BigDecimal.ROUND_HALF_UP);
  372. }
  373. return value;
  374. }
  375. //计算十分钟综合风切变
  376. public static BigDecimal getWindShear(List<ProphaseAnemometryData> prophaseAnemometryData, String[] heights) {
  377. BigDecimal sumWShear = BigDecimal.ZERO;
  378. if(prophaseAnemometryData.size() > 0){
  379. String maxHeight = heights[0];
  380. List<ProphaseAnemometryData> heightCollect = prophaseAnemometryData.stream().filter(p -> p.getLayerHeight().equals(maxHeight)).collect(Collectors.toList());
  381. BigDecimal wsAveForMax = BigDecimal.valueOf(heightCollect.get(0).getWsAve());
  382. BigDecimal total = BigDecimal.ZERO;
  383. for (String minHeight : heights) {
  384. if (!getNumberFromString(minHeight).equals(getNumberFromString(maxHeight))) {
  385. List<ProphaseAnemometryData> sCollect = prophaseAnemometryData.stream().filter(p -> p.getLayerHeight().equals(minHeight)).collect(Collectors.toList());
  386. BigDecimal wsAveMin = BigDecimal.valueOf(sCollect.get(0).getWsAve());
  387. double z = new BigDecimal(getNumberFromString(maxHeight)).divide(new BigDecimal(getNumberFromString(minHeight)), 4, RoundingMode.HALF_UP).doubleValue();
  388. double z1 = Math.log10(z);
  389. BigDecimal shear = Convert.toBigDecimal(Math.log10(Convert.toDouble(wsAveForMax.divide(wsAveMin, 8, RoundingMode.HALF_UP))))
  390. .divide(BigDecimal.valueOf(z1), 8, RoundingMode.HALF_UP);
  391. sumWShear = sumWShear.add(shear);
  392. total = total.add(BigDecimal.ONE);
  393. }
  394. }
  395. if(total.compareTo(BigDecimal.ZERO) > 0){
  396. sumWShear = sumWShear.divide(total,2,RoundingMode.HALF_UP);
  397. }
  398. }
  399. return sumWShear;
  400. }
  401. }