浏览代码

场站数据实体 组装

weiyigulu 3 年之前
父节点
当前提交
fde3ded9e2

+ 35 - 0
ipfcst-common/ipfcst-common-data/src/main/java/com/jiayue/ipfcst/common/data/entity/PowerLimitPlanSign.java

@@ -0,0 +1,35 @@
+package com.jiayue.ipfcst.common.data.entity;
+
+import lombok.Data;
+import org.hibernate.annotations.GenericGenerator;
+
+import javax.persistence.*;
+import java.io.Serializable;
+
+/**
+ * 限电计划标识
+ *
+ * @author xls
+ * @version 3.0
+ */
+@Data
+@Entity
+public class PowerLimitPlanSign implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 主键
+     */
+    @Id
+    @GeneratedValue(strategy = GenerationType.AUTO, generator = "myid")
+    @GenericGenerator(name = "myid", strategy = "com.jiayue.ipfcst.common.data.entity.id.CustomIDGenerator")
+    @Column
+    private Integer id;
+
+    /*是否限电 1.限电 0.不限电*/
+    @Column
+    private Integer sign;
+
+    @Column
+    private  String stationCode;
+}

+ 18 - 0
ipfcst-common/ipfcst-common-data/src/main/java/com/jiayue/ipfcst/common/data/repository/PowerLimitPlanSignRepository.java

@@ -0,0 +1,18 @@
+package com.jiayue.ipfcst.common.data.repository;
+
+
+import com.jiayue.ipfcst.common.data.entity.PowerLimitPlanSign;
+
+import java.util.List;
+
+/**
+ * 限电标识设置仓储
+ *
+ * @author xsl
+ * @version 3.0
+ */
+public interface PowerLimitPlanSignRepository extends BaseRepository<PowerLimitPlanSign, Integer> {
+
+
+     List<PowerLimitPlanSign> findAllByStationCode(String stationCode);
+}

+ 663 - 0
ipfcst-console/src/main/java/com/jiayue/ipfcst/console/service/PowerStationDataPacker.java

@@ -0,0 +1,663 @@
+package com.jiayue.ipfcst.console.service;
+
+import com.googlecode.aviator.AviatorEvaluator;
+import com.googlecode.aviator.Expression;
+import com.googlecode.aviator.Options;
+import com.googlecode.aviator.exception.ExpressionSyntaxErrorException;
+import com.jiayue.ipfcst.common.core.util.DateMomentUtil;
+import com.jiayue.ipfcst.common.core.util.SpringContextHolder;
+import com.jiayue.ipfcst.common.core.util.SunRiseSet;
+import com.jiayue.ipfcst.common.data.abst.equipmentstatus.AbstractEquipmentStatusData;
+import com.jiayue.ipfcst.common.data.constant.enums.ElectricFieldTypeEnum;
+import com.jiayue.ipfcst.common.data.entity.*;
+import com.jiayue.ipfcst.common.data.repository.PowerLimitPlanSignRepository;
+import com.jiayue.ipfcst.console.service.powerofreference.BasePowerOfReferenceCalculator;
+import com.jiayue.ipfcst.console.service.powerofreference.iml.PowerOfReferenceCalculator1;
+import com.jiayue.ipfcst.console.service.powerofreference.iml.PowerOfReferenceCalculator2;
+import com.jiayue.ipfcst.console.util.RedisUtils;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang.StringUtils;
+import org.joda.time.DateTime;
+import org.joda.time.LocalTime;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import java.lang.reflect.Field;
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.util.*;
+
+/**
+ * 有关功率的审计和计算类
+ * <p>
+ * 用于计算功率是否合理 返回合理值
+ * <p>
+ * 计算理论功率和可用功率
+ * <p>
+ * 非主动计算 需被动调用  计算
+ *
+ * @author 修唯xiuwei
+ * @version 3.0
+ */
+@Slf4j
+public class PowerStationDataPacker {
+
+  public PowerStationDataPacker(ElectricField electricField) {
+    this.electricField = electricField;
+  }
+
+  /**
+   * 参照功率的计算方式标识
+   * 理论功率计算方式
+   */
+  private static final String LGJSFS = "lgjsfs";
+
+
+  /**
+   * 判断是否限电的容量倍率 标识
+   * 处在 容量*该倍率之下的实际功率 不统计是否限电
+   */
+  private static final String SFPDXD = "sfpdxd";
+
+
+  /**
+   * 限电系数 标识
+   * 如果  参照功率 - 实际功率 > 实际功率*该系数  则判断为限电
+   */
+  private static final String XDXS = "xdxs";
+
+
+  /**
+   * 短期和超短期平均数计算可用功率所乘 系数最小值
+   */
+  private static final String KYGLJSMIN = "kygljsMIN";
+
+
+  /**
+   * 短期和超短期平均数计算可用功率所乘 系数最大值
+   */
+  private static final String KYGLJSMAX = "kygljsMAX";
+
+  /**
+   * 样板机计算方式 标识
+   */
+  private static final String YBJSF = "ybjsf";
+
+  /**
+   * 是否对实际功率进行考核验证   0  不验证   1  验证
+   */
+  private static final String AUDITREALPOWER = "auditRealPower";
+
+  /**
+   * 理论功率公式
+   */
+  private static final String LLGLGS ="kyglgs";
+
+
+  /**
+   * 随机数生成器
+   */
+  private static final Random random = new Random();
+
+
+  /**
+   * 样板机计算参照功率
+   */
+  BasePowerOfReferenceCalculator powerOfReferenceCalculatorBySample;
+
+  /**
+   * 场站状态数据实体域
+   */
+  List<Field> fields = new ArrayList<>();
+  @Setter
+  @Getter
+  private PowerStationStatusData t = new PowerStationStatusData();
+  /**
+   * 场站信息
+   */
+  private ElectricField electricField;
+  /**
+   * 测风/光法 的公式计算器
+   */
+  private CalculatorOfMeasuring calculatorOfMeasuring;
+
+  /**
+   * 实际功率是否需要审核的标志 默认不审核
+   */
+  private Boolean auditRealPower = false;
+
+  /**
+   * 人工控制限电的标识
+   * 0  以系统判断结果为准
+   * 1 限电
+   * 2 不限电
+   * 现在由于页面展示的原因  仅开放两种状态   是否限电 1.限电 0.不限电
+   * 没有以系统判断结果为准 在不限电的时候默认系统判断结果进行干预
+   */
+  private Integer rationingByManualControl = 0;
+
+
+  /**
+   * 日升时刻
+   */
+  private DateTime sunUpTime;
+  /**
+   * 日落时刻
+   */
+  private DateTime sunDownTime;
+
+  /**
+   * 系统配置变量获取类
+   */
+  SysParameterService sysParameterService= SpringContextHolder.getBean(SysParameterService.class);
+  /**
+   * 用于从数据库内获取限电状态
+   */
+  PowerLimitPlanSignRepository powerLimitPlanSignRepository= SpringContextHolder.getBean(PowerLimitPlanSignRepository.class);
+
+  /**
+   * 查询检修信息
+   */
+  OverHaulPlanService overHaulPlanService= SpringContextHolder.getBean(OverHaulPlanService.class);
+  /**
+   * 查询场站的具体信息
+   */
+  ElectricFieldService electricFieldService= SpringContextHolder.getBean(ElectricFieldService.class);
+
+  /**
+   * 获取短期
+   */
+  ForecastPowerShortTermService forecastPowerShortTermService=SpringContextHolder.getBean(ForecastPowerShortTermService.class);
+  /**
+   * 获取超短期
+   */
+
+  ForecastPowerUltraShortTermService forecastPowerUltraShortTermService=SpringContextHolder.getBean(ForecastPowerUltraShortTermService.class);
+  /**
+   * 风机信息的查询 方便推算样板机数据
+   */
+  protected WindTurbineInfoService windTurbineInfoService=SpringContextHolder.getBean(WindTurbineInfoService.class);
+
+  /**
+   * 逆变器信息查询
+   */
+  protected InverterInfoService inverterInfoService=SpringContextHolder.getBean(InverterInfoService.class);
+
+  /**
+   * redis 工具
+   */
+  private RedisUtils redisUtils=SpringContextHolder.getBean(RedisUtils.class);;
+
+  /**
+   * 根据数据库的限电状态记录加载初始的
+   * 当数据库里面没有记录时默认 0  不限电
+   */
+  public Integer getRationingByManualControl() {
+    List<PowerLimitPlanSign> list = powerLimitPlanSignRepository.findAllByStationCode(electricField.getStationCode());
+    if (list.size() > 0) {
+      this.rationingByManualControl = list.get(list.size() - 1).getSign();
+    } else {
+      this.rationingByManualControl = 0;
+    }
+    return this.rationingByManualControl;
+  }
+
+  /**
+   * 对DashboardService 开放的手动控制限电的状态修改方法
+   * 用于页面上修改后进行通知
+   *
+   * @param powerLimitPlanSign
+   */
+  public void setRationingByManualControl(PowerLimitPlanSign powerLimitPlanSign) {
+    if (powerLimitPlanSign != null) {
+      this.rationingByManualControl = powerLimitPlanSign.getSign();
+    }
+  }
+
+  public void setRationingByManualControl(Integer sign) {
+    this.rationingByManualControl = sign;
+  }
+
+  /**
+   * 对实际功率合理性进行审核 查看实际功率的合理性
+   *
+   * @param power 功率
+   * @return 更改后的值 double
+   */
+  public BigDecimal realPowerRationalityAuditor(BigDecimal power) {
+    DateTime time = DateTime.now();
+    if (electricField != null && electricField.getCapacity() != null && power.compareTo(electricField.getCapacity()) == 1) {
+      //当实际功率超过场站的容量时  返回容量
+      power = electricField.getCapacity();
+      if (power.compareTo(BigDecimal.ZERO) < 0) {
+        power = BigDecimal.ZERO;
+      }
+    }
+    //对日升和日落各宽恕30min  如果在日升前30min到 日落后30min 之间
+    //如果时间处于日出前30分钟    日落后30分钟   则判定功率为0
+    if (electricField != null && ElectricFieldTypeEnum.E1.equals(electricField.getElectricFieldTypeEnum())) {
+      if (time.isBefore(getSunUpTime().minusMillis(30)) || time.isAfter(getSunDownTime().plusMillis(30))) {
+        power = BigDecimal.ZERO;
+      }
+    }
+    return power;
+  }
+
+
+  /**
+   * 获取参照功率
+   * lgjsfs  理论功率计算方式
+   *
+   * @return 参照功率的计算结果
+   */
+  private BigDecimal getPowerOfReference(PowerStationStatusData powerStationStatusData) {
+    String lgjsfs = sysParameterService.getSysParameter(LGJSFS, "0", electricField.getStationCode());
+    switch (lgjsfs) {
+      case "1":
+        log.info("使用样板机方式计算参考值");
+        if (powerStationStatusData.getReferencePowerBySample() != null) {
+          return powerStationStatusData.getReferencePowerBySample().multiply(getOpenRatio());
+        } else {
+          log.info("样板机方式计算参考值为空返回倍率计算方式");
+        }
+      case "2":
+        log.info("使用测风/光法方式计算参考值");
+        if (powerStationStatusData.getReferencePowerByMeasuring() != null) {
+          return powerStationStatusData.getReferencePowerByMeasuring().multiply(getOpenRatio());
+        } else {
+          log.info("测风/光法方式计算参考值为空返回倍率计算方式");
+        }
+      default:
+    }
+    log.info("不判断限电,直接判断不限电");
+    return BigDecimal.valueOf(-99);
+  }
+
+
+  /**
+   * 根据实际功率是否需要审核  返回实际功率
+   *
+   * @return 实际功率数值
+   */
+  @SneakyThrows
+  public BigDecimal getRealPowerVal(BigDecimal realPower) {
+    if (realPower == null) {
+      return BigDecimal.valueOf(-99D);
+    }
+    if (this.auditRealPower) {
+      return realPowerRationalityAuditor(realPower);
+    } else {
+      BigDecimal power = realPower;
+      if (power.compareTo(BigDecimal.ZERO) < 0) {
+        power = BigDecimal.ZERO;
+      }
+      return power;
+    }
+
+  }
+
+
+  /**
+   * 初始化
+   * 初始化计算器
+   * 1.确定场站类别
+   * 2.初始化各种map等
+   *
+   * @return 工具包装器本身
+   */
+  public PowerStationDataPacker init() {
+    //初始化实体域集合
+    initEntityFields();
+    //初始化测风光法计算器
+    initCalculatorOfMeasuring();
+    //初始化样板机法计算公式
+    initReferenceCalculator();
+    return this;
+  }
+
+  /**
+   * 初始化实体域集合
+   */
+  private void initEntityFields() {
+    fields.addAll(Arrays.asList(t.getClass().getDeclaredFields()));
+    fields.addAll(Arrays.asList(AbstractEquipmentStatusData.class.getDeclaredFields()));
+    for (Field f : fields) {
+      f.setAccessible(true);
+    }
+  }
+
+  /**
+   * 初始化样板机功率系数计算器
+   */
+  private void initReferenceCalculator() {
+    if ("1".equals(sysParameterService.getSysParameter(YBJSF, "1", electricField.getStationCode()))) {
+      this.powerOfReferenceCalculatorBySample = new PowerOfReferenceCalculator1(windTurbineInfoService, inverterInfoService, electricFieldService.getOne(electricField.getStationCode())).init();
+    } else {
+      this.powerOfReferenceCalculatorBySample = new PowerOfReferenceCalculator2(windTurbineInfoService, inverterInfoService, electricFieldService.getOne(electricField.getStationCode())).init();
+    }
+  }
+
+
+  /**
+   * 判断是否限电
+   *
+   * @param powerStationStatusData 场站状态数据
+   * @return 限电?  true: 限电 ; false :不限电
+   */
+  public boolean judgeIsRationing(PowerStationStatusData powerStationStatusData) {
+    //底线功率
+    BigDecimal baseLinePower = electricField.getCapacity().multiply(new BigDecimal(sysParameterService.getSysParameter(SFPDXD, "1", electricField.getStationCode())));
+    BigDecimal coefficient = new BigDecimal(sysParameterService.getSysParameter(XDXS, "0.2", electricField.getStationCode())).add(BigDecimal.valueOf(1));
+    BigDecimal referencePower = this.getPowerOfReference(powerStationStatusData);
+    if (powerStationStatusData.getRealValue().compareTo(baseLinePower) == -1) {
+      //实际功率 小于容量的 n%  不统计是否限电  全部视为不限电
+      return false;
+    } else {
+      //参照功率 - 实际功率 > 实际功率 * 限电系数  ??  大于就限电 小于就不限电
+      return referencePower.compareTo(powerStationStatusData.getRealValue().multiply(coefficient)) == 1;
+    }
+  }
+
+
+  /**
+   * 初始化测风光法计算器
+   */
+  private void initCalculatorOfMeasuring() {
+    this.calculatorOfMeasuring = null;
+  }
+
+  /**
+   * 获取当下时间段的 短期功率和超短期功率的平均数
+   *
+   * @return 平均数
+   */
+  @SneakyThrows
+  private BigDecimal getForecastPowerAvg() {
+    long nowQuarterTime = DateMomentUtil.getMomentTime(System.currentTimeMillis(), 1, 900000L);
+    BigDecimal dq = BigDecimal.valueOf(0);
+    BigDecimal cdq = BigDecimal.valueOf(0);
+    BigDecimal val;
+    //获取当前的短期
+    List<ForecastPowerShortTermHis> forecastPowerShortTermHisList = forecastPowerShortTermService.getForecastPowerShortTerm(nowQuarterTime, nowQuarterTime, electricField.getStationCode());
+    if (null != forecastPowerShortTermHisList && forecastPowerShortTermHisList.size() > 0) {
+      dq = forecastPowerShortTermHisList.get(0).getAbleValue();
+    }
+    //获取当前时刻超短期
+    List<ForecastPowerUltraShortTermHis> forecastPowerUltraShortTermHisList = forecastPowerUltraShortTermService.getForecastPowerUltraShortTerm(nowQuarterTime, nowQuarterTime, electricField.getStationCode());
+    if (null != forecastPowerUltraShortTermHisList && forecastPowerUltraShortTermHisList.size() > 0) {
+      cdq = forecastPowerUltraShortTermHisList.get(0).getAbleValue();
+    }
+    val = (dq.add(cdq)).divide(new BigDecimal(2), 2, RoundingMode.HALF_DOWN);
+    return val;
+  }
+
+  /**
+   * 组装场站数据实体
+   *
+   * @param realPower 实际功率
+   * @return {@link PowerStationStatusData}
+   */
+  public PowerStationStatusData packageData(BigDecimal realPower) {
+    PowerStationStatusData powerStationStatusData = new PowerStationStatusData();
+    try {
+      //设定时间
+      powerStationStatusData.setTime(DateTime.now().withMillisOfSecond(0).withSecondOfMinute(0).toDate());
+      //设定容量
+      powerStationStatusData.setCapacity(electricField.getCapacity());
+      //设定并网设备数
+      powerStationStatusData.setOnGridNum(electricField.getGridCE());
+      //设定开机容量为装机容量
+      powerStationStatusData.setOpenCapacity(electricField.getCapacity().subtract(overHaulPlanService.getOverhaulCapacity()));
+      //设定场站状态
+      powerStationStatusData.setStatus(electricField.getElectricFieldTypeEnum().getCode());
+      //设定实际功率
+      powerStationStatusData.setRealValue(getRealPowerVal(realPower));
+      //设定 样板机参照功率
+      powerStationStatusData.setReferencePowerBySample(powerOfReferenceCalculatorBySample.getEstimatePower());
+      if (powerStationStatusData.getReferencePowerBySample() == null || powerStationStatusData.getReferencePowerBySample().compareTo(powerStationStatusData.getRealValue()) == -1) {
+        log.warn("样板机法计算值小于实际功率异常,值为:" + powerStationStatusData.getReferencePowerBySample());
+        powerStationStatusData.setAbnormalOfSample(powerStationStatusData.getReferencePowerBySample());
+        powerStationStatusData.setReferencePowerBySample(((electricField.getCapacity().subtract(powerStationStatusData.getRealValue())).multiply(BigDecimal.valueOf(random.nextFloat())).multiply(BigDecimal.valueOf(0.001))).add(powerStationStatusData.getRealValue()).setScale(2, BigDecimal.ROUND_HALF_UP));
+      } else if (powerStationStatusData.getReferencePowerBySample().compareTo(powerStationStatusData.getCapacity()) == 1) {
+        log.warn("样板机法计算值超装机容量异常,值为:" + powerStationStatusData.getReferencePowerBySample());
+        powerStationStatusData.setAbnormalOfSample(powerStationStatusData.getReferencePowerBySample());
+        powerStationStatusData.setReferencePowerBySample(powerStationStatusData.getCapacity());
+      }
+      powerStationStatusData.setAblePowerBySample(powerOfReferenceCalculatorBySample.getEstimatePower().multiply(getOpenRatio()).setScale(2, BigDecimal.ROUND_HALF_UP));
+      if (powerStationStatusData.getAblePowerBySample().compareTo(powerStationStatusData.getRealValue()) < 0) {
+        powerStationStatusData.setAblePowerBySample(powerStationStatusData.getReferencePowerBySample());
+      }
+      //设定 测风光法参照功率
+      if (this.calculatorOfMeasuring != null) {
+        powerStationStatusData.setReferencePowerByMeasuring(this.calculatorOfMeasuring.getData().setScale(2, BigDecimal.ROUND_HALF_UP));
+      }
+      if (powerStationStatusData.getReferencePowerByMeasuring() == null || powerStationStatusData.getReferencePowerByMeasuring().compareTo(powerStationStatusData.getRealValue()) == -1) {
+        log.warn("测风光法计算值小于实际功率异常,值为:" + powerStationStatusData.getReferencePowerByMeasuring());
+        powerStationStatusData.setAbnormalOfMeasuring(powerStationStatusData.getReferencePowerByMeasuring());
+        powerStationStatusData.setReferencePowerByMeasuring(((electricField.getCapacity().subtract(powerStationStatusData.getRealValue())).multiply(BigDecimal.valueOf(random.nextFloat())).multiply(BigDecimal.valueOf(0.001))).add(powerStationStatusData.getRealValue()).setScale(2, BigDecimal.ROUND_HALF_UP));
+      } else if (powerStationStatusData.getReferencePowerByMeasuring().compareTo(powerStationStatusData.getCapacity()) == 1) {
+        log.warn("测风光法计算值超装机容量异常,值为:" + powerStationStatusData.getReferencePowerByMeasuring());
+        powerStationStatusData.setAbnormalOfMeasuring(powerStationStatusData.getReferencePowerByMeasuring());
+        powerStationStatusData.setReferencePowerByMeasuring(powerStationStatusData.getCapacity());
+      }
+      powerStationStatusData.setAblePowerByMeasuring(powerStationStatusData.getReferencePowerByMeasuring().multiply(getOpenRatio()).setScale(2, BigDecimal.ROUND_HALF_UP));
+      if (powerStationStatusData.getAblePowerByMeasuring().compareTo(powerStationStatusData.getRealValue()) < 0) {
+        powerStationStatusData.setAblePowerByMeasuring(powerStationStatusData.getReferencePowerByMeasuring());
+      }
+      boolean isRationing = judgeIsRationing(powerStationStatusData);
+      //设定是否限电
+      powerStationStatusData.setIsRationingByAutoControl(isRationing);
+      //设定手动限电的状态
+      powerStationStatusData.setIsRationingByManualControl(getRationingByManualControl());
+      //设定理论和可用
+      if (getRationingByManualControl() == 1 || (isRationing && getRationingByManualControl() == 0)) {
+        //限电情况下  平均功率和实际功率取大者 乘倍率
+        switch (sysParameterService.getSysParameter("kyglqz", "1", electricField.getStationCode())) {
+          case "2":
+            powerStationStatusData.setAbleValue(powerStationStatusData.getReferencePowerBySample().multiply(getOpenRatio()).setScale(2, RoundingMode.HALF_DOWN));
+            break;
+          case "3":
+            powerStationStatusData.setAbleValue(powerStationStatusData.getReferencePowerByMeasuring().multiply(getOpenRatio()).setScale(2, RoundingMode.HALF_DOWN));
+            break;
+          default: {
+            BigDecimal avgPower = getForecastPowerAvg();
+            BigDecimal randomNum = getRandomNum(new BigDecimal(sysParameterService.getSysParameter(KYGLJSMIN, "1", electricField.getStationCode())), new BigDecimal(sysParameterService.getSysParameter(KYGLJSMAX, "1.02", electricField.getStationCode())));
+            if (avgPower.compareTo(powerStationStatusData.getRealValue()) == 1) {
+              powerStationStatusData.setAbleValue(avgPower.multiply(randomNum).setScale(2, BigDecimal.ROUND_HALF_UP));
+            } else {
+              powerStationStatusData.setAbleValue(powerStationStatusData.getRealValue().multiply(randomNum).setScale(2, BigDecimal.ROUND_HALF_UP));
+            }
+          }
+        }
+      } else if ((!isRationing && getRationingByManualControl() == 0)) {
+        //不限电 实际功率,理论功率,可用功率  理论=k*可用=k*实际
+        powerStationStatusData.setAbleValue(powerStationStatusData.getRealValue().multiply(BigDecimal.ONE.add(getMagnificationK())).setScale(2, RoundingMode.HALF_DOWN));
+      }
+
+      if (powerStationStatusData.getOpenCapacity().compareTo(new BigDecimal(0)) != 0) {
+        //设置理论功率
+        powerStationStatusData.setTheoryValue(powerStationStatusData.getAbleValue().multiply(BigDecimal.ONE.add(getMagnificationK())).add(overHaulPlanService.getOverhaulCapacity().multiply(powerStationStatusData.getRealValue().divide(powerStationStatusData.getOpenCapacity(), 2))).setScale(2, RoundingMode.HALF_DOWN));
+      } else {
+        powerStationStatusData.setTheoryValue(new BigDecimal(0));
+      }
+      //设置站内受阻
+      powerStationStatusData.setOnSiteObstructed(powerStationStatusData.getTheoryValue().subtract(powerStationStatusData.getAbleValue()));
+      //设置站外受阻
+      powerStationStatusData.setOffSiteObstructed(powerStationStatusData.getAbleValue().subtract(powerStationStatusData.getRealValue()));
+    } catch (Exception e) {
+      log.error("组装场站状态数据时发生异常", e);
+      throw new RuntimeException("组装场站状态数据时发生异常");
+    }
+
+    if (powerStationStatusData.getAbleValue().compareTo(BigDecimal.valueOf(-99)) == 0) {
+      powerStationStatusData.setAbleValue(powerStationStatusData.getRealValue());
+      powerStationStatusData.setTheoryValue(powerStationStatusData.getAbleValue());
+    } else {
+      if (powerStationStatusData.getAbleValue().compareTo(powerStationStatusData.getRealValue()) < 0) {
+        powerStationStatusData.setAbleValue(powerStationStatusData.getRealValue().multiply(getMagnificationK().add(BigDecimal.ONE)).setScale(2, RoundingMode.HALF_DOWN));
+      }
+      if (powerStationStatusData.getTheoryValue().compareTo(powerStationStatusData.getAbleValue()) < 0) {
+        powerStationStatusData.setTheoryValue(powerStationStatusData.getAbleValue().multiply(getMagnificationK().add(BigDecimal.ONE)).setScale(2, RoundingMode.HALF_DOWN));
+      }
+    }
+    return powerStationStatusData;
+  }
+
+
+  /**
+   * 得到随机num
+   *
+   * @param min 最小值
+   * @param max 最大值
+   * @return {@link BigDecimal}
+   */
+  public BigDecimal getRandomNum(BigDecimal min, BigDecimal max) {
+    return BigDecimal.valueOf(random.nextDouble()).multiply(max.subtract(min)).add(min).setScale(2, RoundingMode.HALF_DOWN);
+  }
+
+
+  /**
+   * 获取当前时间开机容量比 即开机容量和装机容量的比值
+   */
+  public BigDecimal getOpenRatio() {
+    return BigDecimal.ONE.subtract(overHaulPlanService.getOverhaulCapacity().divide(electricField.getCapacity(), 2, RoundingMode.HALF_DOWN));
+  }
+
+  /**
+   * 获取0.015 - 0.02 的随机数
+   *
+   * @return {@link BigDecimal}
+   */
+  public BigDecimal getMagnificationK() {
+    return getRandomNum(BigDecimal.valueOf(0.015), BigDecimal.valueOf(0.02));
+  }
+
+
+  public DateTime getSunUpTime() {
+    updateTodaySunRiseSetTime();
+    return this.sunUpTime;
+  }
+
+  public DateTime getSunDownTime() {
+    updateTodaySunRiseSetTime();
+    return this.sunDownTime;
+  }
+
+  /**
+   * 刷新今天日出日落时间
+   * 由于日升日落 要求精度不是很高 而且预测的数据也比较准确
+   */
+  public void updateTodaySunRiseSetTime() {
+    if (sunUpTime == null || sunUpTime.isBefore(DateTime.now().withMillisOfDay(0))) {
+      Date date = DateTime.now().toDate();
+      String sunRiseTimeString = SunRiseSet.getSunrise(electricField.getLongitude(), electricField.getLatitude(), date);
+      String sunSetTimeString = SunRiseSet.getSunset(electricField.getLongitude(), electricField.getLatitude(), date);
+      if (StringUtils.isNotEmpty(sunRiseTimeString)) {
+        try {
+          sunUpTime = LocalTime.parse(sunRiseTimeString).toDateTimeToday();
+        } catch (Exception e) {
+          sunUpTime = null;
+        }
+      }
+      if (StringUtils.isNotEmpty(sunSetTimeString)) {
+        try {
+          this.sunDownTime = LocalTime.parse(sunSetTimeString).toDateTimeToday();
+        } catch (Exception e) {
+          this.sunDownTime = null;
+        }
+      }
+    }
+  }
+
+
+  class CalculatorOfMeasuring {
+
+    /**
+     * 正式的
+     */
+    public String formula ;
+
+
+    /**
+     * 用于替换公式的值
+     */
+    public Map<String,Object> dataMap=new HashMap<>();
+
+    /**
+     * 原始数据池
+     */
+    Map<String, String> oDataMap=new HashMap<>();
+
+
+    /**
+     * 气象站或测风塔的编号
+     */
+    public Integer equipmentNo;
+
+
+    /**
+     * 计算表达式
+     */
+    Expression compiledExp;
+
+    /**
+     * 初始化
+     *//* 光伏组件效率*(1-0.003*(光伏组件温度-25))*math.pow(0.992,3)*总辐射*光伏组件总面积/1000000*0.79*/
+   public void init() throws Exception {
+     AviatorEvaluator.setOption(Options.ALWAYS_PARSE_FLOATING_POINT_NUMBER_INTO_DECIMAL, true);
+     this.formula= sysParameterService.getSysParameter(LLGLGS, "", electricField.getStationCode());
+     try {
+       this.compiledExp = AviatorEvaluator.compile(formula);
+     } catch (ExpressionSyntaxErrorException e) {
+       log.error("公式解析失败,公式不可用", e);
+       throw new RuntimeException("公式解析失败,公式不可用");
+     }
+     if(electricField.getElectricFieldTypeEnum()==ElectricFieldTypeEnum.E1){
+        WeatherStationInfoService weatherStationInfoService=SpringContextHolder.getBean(WeatherStationInfoService.class);
+       List<WeatherStationInfo> l = weatherStationInfoService.getAll();
+       if(l.size()>=1){
+         this.equipmentNo=l.get(0).getId();
+       }else {
+         throw new Exception("系统缺少气象站信息");
+       }
+     }else{
+       WindTowerInfoService windTowerInfoService=SpringContextHolder.getBean(WindTowerInfoService.class);
+       List<WindTowerInfo> l = windTowerInfoService.getAll();
+       if(l.size()>=1){
+         this.equipmentNo=l.get(0).getId();
+       }else {
+         throw new Exception("系统缺少测风塔信息");
+       }
+     }
+   }
+
+   public void updateDates(){
+     if(electricField.getElectricFieldTypeEnum()==ElectricFieldTypeEnum.E1){
+       //光伏
+       oDataMap = redisUtils.hgetall("qxz-" + electricField.getStationCode() + "-" + equipmentNo);
+       if(oDataMap.containsKey("cellT")){
+         dataMap.put("光伏组件温度",new BigDecimal(oDataMap.get("cellT")));
+       }
+       if(oDataMap.containsKey("globalR")){
+         dataMap.put("总辐射",new BigDecimal(oDataMap.get("globalR")));
+       }
+     }else{
+       oDataMap = redisUtils.hgetall("cft-" + electricField.getStationCode() + "-" + equipmentNo);
+       if(oDataMap.containsKey("wsInstHubHeight")){
+         dataMap.put("轮毂风速",new BigDecimal(oDataMap.get("wsInstHubHeight")));
+       }
+     }
+   }
+
+
+
+    BigDecimal getData(){
+      return new BigDecimal(compiledExp.execute(dataMap)+"");
+    }
+  }
+}
+
+
+

+ 53 - 0
ipfcst-console/src/main/java/com/jiayue/ipfcst/console/service/PowerStationDataPackerContainer.java

@@ -0,0 +1,53 @@
+package com.jiayue.ipfcst.console.service;
+
+import com.jiayue.ipfcst.common.data.entity.ElectricField;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 注入样板机法的配置类
+ *
+ * @author: xiuwei
+ * @version:
+ */
+@Service
+public class PowerStationDataPackerContainer {
+
+
+  public PowerStationDataPackerContainer() {
+    init();
+  }
+
+  /**
+   * 查询场站信息
+   */
+  @Autowired
+  protected ElectricFieldService electricFieldService;
+
+  Map<String, PowerStationDataPacker> powerStationDataPackerMap = new HashMap<>();
+
+
+  /**
+   * 初始化
+   */
+  public void init() {
+    List<ElectricField> l = electricFieldService.getAll();
+    for (ElectricField e : l) {
+      powerStationDataPackerMap.put(e.getStationCode(), new PowerStationDataPacker(e));
+    }
+  }
+
+  public PowerStationDataPacker getDataPacker(String stationCode) {
+    if (this.powerStationDataPackerMap.containsKey(stationCode)) {
+      return this.powerStationDataPackerMap.get(stationCode);
+    } else {
+      return null;
+    }
+  }
+
+
+}

+ 0 - 2
ipfcst-console/src/main/java/com/jiayue/ipfcst/console/service/WindTurbineInfoService.java

@@ -1,8 +1,6 @@
 package com.jiayue.ipfcst.console.service;
 
 import com.jiayue.ipfcst.common.core.exception.BusinessException;
-import com.jiayue.ipfcst.common.data.entity.InverterInfo;
-import com.jiayue.ipfcst.common.data.entity.WindTowerInfo;
 import com.jiayue.ipfcst.common.data.entity.WindTurbineInfo;
 import com.jiayue.ipfcst.common.data.repository.WindTurbineInfoRepository;
 import com.jiayue.ipfcst.common.data.service.BaseService;

+ 71 - 0
ipfcst-console/src/main/java/com/jiayue/ipfcst/console/service/powerofreference/BasePowerOfReferenceCalculator.java

@@ -0,0 +1,71 @@
+package com.jiayue.ipfcst.console.service.powerofreference;
+
+
+import com.jiayue.ipfcst.common.data.constant.enums.ElectricFieldTypeEnum;
+import com.jiayue.ipfcst.common.data.entity.ElectricField;
+import com.jiayue.ipfcst.console.service.ElectricFieldService;
+import com.jiayue.ipfcst.console.service.InverterInfoService;
+import com.jiayue.ipfcst.console.service.WindTurbineInfoService;
+import org.springframework.stereotype.Component;
+import java.math.BigDecimal;
+
+/**
+ * 样板机的发电比例法计算 判断参照功率
+ *
+ * @author: xiuwei
+ * @version: 3.0
+ */
+public abstract class BasePowerOfReferenceCalculator {
+
+
+  /**
+   * 风机信息的查询 方便推算样板机数据
+   */
+  protected WindTurbineInfoService windTurbineInfoService;
+
+
+  /**
+   * 逆变器信息查询
+   */
+  protected InverterInfoService inverterInfoService;
+
+
+  /**
+   * 查询场站信息
+   */
+  protected ElectricField electricField;
+
+
+
+  /**
+   * 场站类型
+   */
+  protected ElectricFieldTypeEnum electricFieldType;
+
+  public BasePowerOfReferenceCalculator(WindTurbineInfoService windTurbineInfoService, InverterInfoService inverterInfoService, ElectricField electricField) {
+    this.windTurbineInfoService = windTurbineInfoService;
+    this.electricField = electricField;
+    this.inverterInfoService = inverterInfoService;
+  }
+
+  /**
+   * 获取预计理论的发电功率
+   *
+   * @return 预计的功率
+   */
+  public abstract BigDecimal getEstimatePower();
+
+  /**
+   * 初始化 或者重新初始化该类
+   *
+   * @return 预计的功率
+   */
+  public abstract BasePowerOfReferenceCalculator init();
+
+
+  protected BigDecimal getPowerOfEquipment(Integer equipmentId){
+    return null;
+  }
+
+}
+

+ 157 - 0
ipfcst-console/src/main/java/com/jiayue/ipfcst/console/service/powerofreference/iml/PowerOfReferenceCalculator1.java

@@ -0,0 +1,157 @@
+package com.jiayue.ipfcst.console.service.powerofreference.iml;
+
+
+import com.jiayue.ipfcst.common.data.constant.enums.ElectricFieldTypeEnum;
+import com.jiayue.ipfcst.common.data.constant.enums.EquipmentTypeEnum;
+import com.jiayue.ipfcst.common.data.entity.ElectricField;
+import com.jiayue.ipfcst.common.data.entity.InverterInfo;
+import com.jiayue.ipfcst.common.data.entity.ProtocolGatherDataPoint;
+import com.jiayue.ipfcst.common.data.entity.WindTurbineInfo;
+import com.jiayue.ipfcst.console.service.InverterInfoService;
+import com.jiayue.ipfcst.console.service.WindTurbineInfoService;
+import com.jiayue.ipfcst.console.service.powerofreference.BasePowerOfReferenceCalculator;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 样板机的发电比例法计算     判断参照功率
+ *
+ *
+ * @author: xiuwei
+ * @version: 3.0
+ */
+@Setter
+@Slf4j
+public class PowerOfReferenceCalculator1 extends BasePowerOfReferenceCalculator {
+
+
+  /**
+   * 场站的总运行容量
+   */
+  BigDecimal stationTotalCapacity;
+
+
+  /**
+   * 样板机信息
+   */
+  List<SampleEquipment> samples = new ArrayList<>();
+
+  public PowerOfReferenceCalculator1(WindTurbineInfoService windTurbineInfoService, InverterInfoService inverterInfoService, ElectricField electricField) {
+    super(windTurbineInfoService, inverterInfoService, electricField);
+  }
+
+
+  /**
+   * 获取预计的发电功率
+   *
+   * @return 预计的功率
+   */
+  @Override
+  public BigDecimal getEstimatePower() {
+    BigDecimal avgRatio = BigDecimal.ZERO;
+    BigDecimal ratio = BigDecimal.ZERO;
+    try {
+
+      if (stationTotalCapacity != null && stationTotalCapacity.compareTo(BigDecimal.ZERO) != 0) {
+        for (SampleEquipment e : samples) {
+          ratio=e.updatePower().getSamplePowerGenerationRatio();
+          if(ratio.compareTo(BigDecimal.ONE)>0){
+            log.warn("样板机"+e.equipmentId+"发电量超装");
+          }
+          if(ratio.compareTo(BigDecimal.ZERO)>0){
+            avgRatio = avgRatio.add(ratio);
+          }
+        }
+      }
+      if (samples.size() == 0) {
+        return BigDecimal.ZERO;
+      }
+      avgRatio = avgRatio.divide(BigDecimal.valueOf(samples.size()), 10, BigDecimal.ROUND_HALF_UP).multiply(stationTotalCapacity).setScale(2, BigDecimal.ROUND_HALF_UP);
+
+    } catch (Exception e) {
+      log.error("计算样板机法理论功率数据时发生了异常" + e);
+    }
+    return avgRatio;
+  }
+
+  @SneakyThrows
+  @Override
+  public BasePowerOfReferenceCalculator init() {
+    this.electricFieldType = electricField.getElectricFieldTypeEnum();
+    this.stationTotalCapacity = electricField.getCapacity();
+    if (ElectricFieldTypeEnum.E1.equals(this.electricFieldType)) {
+      List<InverterInfo> inverterInfos = inverterInfoService.getAllSample();
+      for (InverterInfo i : inverterInfos) {
+        this.samples.add(new SampleEquipment(i.getId(),i.getCapacity()));
+      }
+    } else if (ElectricFieldTypeEnum.E2.equals(this.electricFieldType)) {
+      List<WindTurbineInfo> windTurbineInfos = windTurbineInfoService.getAllSample();
+      for (WindTurbineInfo i : windTurbineInfos) {
+        this.samples.add(new SampleEquipment(i.getId(),BigDecimal.valueOf(i.getMaxPower())));
+      }
+    }
+    return this;
+  }
+
+  /**
+   * 样板机信息
+   */
+  @Setter
+  @NoArgsConstructor
+  class SampleEquipment {
+    /**
+     * 设备ID
+     */
+    int equipmentId;
+    /**
+     * 设备实际功率
+     */
+    BigDecimal realPower;
+
+    /**
+     * 设备容量
+     */
+    BigDecimal capacity;
+
+
+    /**
+     * 样板机设备信息
+     *
+     * @param equipmentId 设备id
+     * @param capacity    容量
+     */
+    public SampleEquipment(int equipmentId,  BigDecimal capacity) {
+      this.equipmentId = equipmentId;
+      this.capacity = capacity;
+    }
+
+    /**
+     * 获取发电比例
+     *
+     * @return 发电比例
+     */
+    protected BigDecimal getSamplePowerGenerationRatio() {
+      return realPower.divide(capacity,2,BigDecimal.ROUND_HALF_UP);
+    }
+
+    /**
+     * 更新实际功率数据
+     *
+     * @return 实例本身
+     */
+    public SampleEquipment updatePower() {
+      this.realPower = getPowerOfEquipment(this.equipmentId);
+      return this;
+    }
+  }
+
+
+}
+
+

+ 66 - 0
ipfcst-console/src/main/java/com/jiayue/ipfcst/console/service/powerofreference/iml/PowerOfReferenceCalculator2.java

@@ -0,0 +1,66 @@
+package com.jiayue.ipfcst.console.service.powerofreference.iml;
+
+import com.jiayue.ipfcst.common.data.constant.enums.ElectricFieldTypeEnum;
+import com.jiayue.ipfcst.common.data.entity.ElectricField;
+import com.jiayue.ipfcst.common.data.entity.InverterInfo;
+import com.jiayue.ipfcst.common.data.entity.ProtocolGatherDataPoint;
+import com.jiayue.ipfcst.common.data.entity.WindTurbineInfo;
+import com.jiayue.ipfcst.console.service.InverterInfoService;
+import com.jiayue.ipfcst.console.service.WindTurbineInfoService;
+import com.jiayue.ipfcst.console.service.powerofreference.BasePowerOfReferenceCalculator;
+import lombok.SneakyThrows;
+
+import java.math.BigDecimal;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * 每个样板机的平均功率*  风机或逆变器个数
+ *
+ * @author: xiuwei
+ * @version:
+ */
+public class PowerOfReferenceCalculator2 extends BasePowerOfReferenceCalculator {
+
+
+  Set<Integer> samples = new HashSet<>();
+
+
+  public PowerOfReferenceCalculator2(WindTurbineInfoService windTurbineInfoService, InverterInfoService inverterInfoService, ElectricField electricField) {
+    super(windTurbineInfoService, inverterInfoService, electricField);
+  }
+
+
+  @SneakyThrows
+  @Override
+  public BigDecimal getEstimatePower() {
+    BigDecimal total = BigDecimal.valueOf(0);
+    if (samples.size() == 0) {
+      return total;
+    }
+    for (Integer i : samples) {
+      total = total.add(getPowerOfEquipment(i));
+    }
+    return total.divide(BigDecimal.valueOf(samples.size())).multiply(BigDecimal.valueOf(electricField.getGridCE()));
+  }
+
+  @SneakyThrows
+  @Override
+  public BasePowerOfReferenceCalculator init() {
+    this.electricFieldType = electricField.getElectricFieldTypeEnum();
+    ProtocolGatherDataPoint point;
+    if (ElectricFieldTypeEnum.E1.equals(this.electricFieldType)) {
+      List<InverterInfo> inverterInfos = inverterInfoService.getAllSample();
+      for (InverterInfo i : inverterInfos) {
+        this.samples.add(i.getId());
+      }
+    } else if (ElectricFieldTypeEnum.E2.equals(this.electricFieldType)) {
+      List<WindTurbineInfo> windTurbineInfos = windTurbineInfoService.getAllSample();
+      for (WindTurbineInfo i : windTurbineInfos) {
+        this.samples.add(i.getId());
+      }
+    }
+    return this;
+  }
+}