Browse Source

agc曲线偏差分析

宁檬 2 years ago
parent
commit
193fc7f91a

+ 9 - 1
power-fitting/pom.xml

@@ -34,7 +34,15 @@
             <version>3.1.1</version>
         </dependency>
 
-<!--        <dependency>-->
+        <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-jpa -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-data-jpa</artifactId>
+            <version>2.7.4</version>
+        </dependency>
+
+
+        <!--        <dependency>-->
 <!--            <groupId>com.oracle</groupId>-->
 <!--            <artifactId>ojdbc6</artifactId>-->
 <!--            <version>11.2.0.3</version>-->

+ 32 - 0
power-fitting/src/main/java/com/gyee/power/fitting/common/feign/FeignsBuilder.java

@@ -0,0 +1,32 @@
+package com.gyee.power.fitting.common.feign;
+
+import feign.Feign;
+import feign.Request;
+import feign.Retryer;
+import feign.jackson.JacksonDecoder;
+import feign.jackson.JacksonEncoder;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * @author xysn
+ */
+@Configuration
+public class FeignsBuilder {
+    /**
+     * 数据适配器url
+     */
+    @Value("${gyee.adapter-url:http://192.168.101.8:8011}")
+    private String adapterUrl;
+
+    @Bean
+    public IDataAdapter dataAdapter() {
+        return Feign.builder()
+                .encoder(new JacksonEncoder())
+                .decoder(new JacksonDecoder())
+                .options(new Request.Options(1000, 100000))
+                .retryer(new Retryer.Default(5000, 5000, 3))
+                .target(IDataAdapter.class, adapterUrl);
+    }
+}

+ 26 - 0
power-fitting/src/main/java/com/gyee/power/fitting/common/feign/IDataAdapter.java

@@ -0,0 +1,26 @@
+package com.gyee.power.fitting.common.feign;
+
+import com.gyee.power.fitting.model.agc.PointData;
+import feign.Param;
+import feign.RequestLine;
+
+import java.util.List;
+
+/**
+ * DataAdapter数据请求
+ */
+public interface IDataAdapter {
+    /**
+     * 获取等间隔历史数据
+     *
+     * @param tagName  测点名称
+     * @param startTs  开始时间
+     * @param endTs    结束时间
+     * @param interval 数据间隔
+     * @return 历史数据
+     */
+    @RequestLine("GET /ts/history/snap?tagName={tagName}&startTs={startTs}&endTs={endTs}&interval={interval}")
+    List<PointData> getSnapValuesByKey(@Param(value = "tagName") String tagName, @Param(value = "startTs") long startTs,
+                                       @Param(value = "endTs") long endTs, @Param(value = "interval") int interval);
+}
+

+ 48 - 0
power-fitting/src/main/java/com/gyee/power/fitting/controller/analyse/AgcDeviateController.java

@@ -0,0 +1,48 @@
+package com.gyee.power.fitting.controller.analyse;
+
+import com.gyee.power.fitting.model.agc.AgcDeviateTag;
+import com.gyee.power.fitting.service.custom.curve.AgcDeviateService;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+/**
+ * 获取各个场站AGC偏差分析数据
+ */
+@RestController
+@RequestMapping("/agc")
+public class AgcDeviateController {
+    @Resource
+    private AgcDeviateService agcDeviateService;
+
+    /**
+     * 获取偏差信息
+     *
+     * @param startTs  开始时间
+     * @param endTs    结束时间
+     * @param id       场站id
+     * @param interval 时间间隔
+     * @return
+     */
+    @GetMapping("/deviate")
+    public List<AgcDeviateTag> getData(@RequestParam(value = "startTs") long startTs,
+                                       @RequestParam(value = "endTs") long endTs,
+                                       @RequestParam(value = "id") String id,
+                                       @RequestParam(value = "interval", defaultValue = "60", required = false) int interval) {
+        return agcDeviateService.getAgcDeviateTags(id, startTs, endTs, interval);
+    }
+
+    /**
+     * 获取配置
+     *
+     * @return
+     */
+    @GetMapping("/config")
+    public Object getAgcConifg() {
+        return agcDeviateService.getConfig();
+    }
+}

+ 13 - 0
power-fitting/src/main/java/com/gyee/power/fitting/mapper/AgcDeviateMapper.java

@@ -0,0 +1,13 @@
+package com.gyee.power.fitting.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.gyee.power.fitting.model.Equipmentmodel;
+import com.gyee.power.fitting.model.AgcDeviateModel;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.List;
+
+
+@Mapper
+public interface AgcDeviateMapper extends BaseMapper<AgcDeviateModel> {
+}

+ 92 - 0
power-fitting/src/main/java/com/gyee/power/fitting/model/AgcDeviateModel.java

@@ -0,0 +1,92 @@
+package com.gyee.power.fitting.model;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+
+import javax.persistence.Column;
+import javax.persistence.Id;
+
+@TableName("controlsettings")
+public class AgcDeviateModel extends Model<AgcDeviateModel> {
+    /**
+     * 唯一ID
+     */
+    @Id
+    @Column(name = "ID")
+    private String id;
+    /**
+     * key
+     */
+    @Column(name = "KEY")
+    private String key;
+    /**
+     * 时间戳
+     */
+    @Column(name = "TIMESTAMP")
+    private Long timestamp;
+    /**
+     * 说明,描述
+     */
+    @Column(name = "DESCRIPTION")
+    private String description;
+    /**
+     * 值
+     */
+    @Column(name = "VALUE")
+    private String value;
+
+    /**
+     * 是否是备份
+     */
+    @Column(name = "BACKUP")
+    private boolean backup;
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public String getKey() {
+        return key;
+    }
+
+    public void setKey(String key) {
+        this.key = key;
+    }
+
+    public Long getTimestamp() {
+        return timestamp;
+    }
+
+    public void setTimestamp(Long timestamp) {
+        this.timestamp = timestamp;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    public String getValue() {
+        return value;
+    }
+
+    public void setValue(String value) {
+        this.value = value;
+    }
+
+    public boolean getBackup() {
+        return backup;
+    }
+
+    public void setBackup(boolean backup) {
+        this.backup = backup;
+    }
+
+}

+ 48 - 0
power-fitting/src/main/java/com/gyee/power/fitting/model/agc/AgcDeviateConfig.java

@@ -0,0 +1,48 @@
+package com.gyee.power.fitting.model.agc;
+
+public class AgcDeviateConfig {
+
+    private String id;
+    /**
+     * 装机容量
+     */
+    private float installedCapacity;
+    /**
+     * 场站名称
+     */
+    private String title;
+
+    private AiPoints[] aiPoints;
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public float getInstalledCapacity() {
+        return installedCapacity;
+    }
+
+    public void setInstalledCapacity(float installedCapacity) {
+        this.installedCapacity = installedCapacity;
+    }
+
+    public String getTitle() {
+        return title;
+    }
+
+    public void setTitle(String title) {
+        this.title = title;
+    }
+
+    public AiPoints[] getAiPoints() {
+        return aiPoints;
+    }
+
+    public void setAiPoints(AiPoints[] aiPoints) {
+        this.aiPoints = aiPoints;
+    }
+}

+ 33 - 0
power-fitting/src/main/java/com/gyee/power/fitting/model/agc/AgcDeviateTag.java

@@ -0,0 +1,33 @@
+package com.gyee.power.fitting.model.agc;
+
+import java.util.List;
+
+/**
+ * agc曲线偏差数据
+ */
+public class AgcDeviateTag {
+    /**
+     * 数据点名称
+     */
+    private String name;
+    /**
+     * 数据值列表
+     */
+    private List<PointData> values;
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public List<PointData> getValues() {
+        return values;
+    }
+
+    public void setValues(List<PointData> values) {
+        this.values = values;
+    }
+}

+ 56 - 0
power-fitting/src/main/java/com/gyee/power/fitting/model/agc/AiPoints.java

@@ -0,0 +1,56 @@
+package com.gyee.power.fitting.model.agc;
+
+/**
+ * 从数据库的value里面取到需要的值
+ */
+public class AiPoints {
+
+    private String name;
+    /**
+     * 标签点
+     */
+    private String tag;
+    /**
+     * 倍率
+     */
+    private float multiplier;
+    /**
+     * 单位
+     */
+    private String unit;
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        if (name == null) {
+            return;
+        }
+        this.name = name.replaceAll(":","");
+    }
+
+    public String getTag() {
+        return tag;
+    }
+
+    public void setTag(String tag) {
+        this.tag = tag;
+    }
+
+    public float getMultiplier() {
+        return multiplier;
+    }
+
+    public void setMultiplier(float multiplier) {
+        this.multiplier = multiplier;
+    }
+
+    public String getUnit() {
+        return unit;
+    }
+
+    public void setUnit(String unit) {
+        this.unit = unit;
+    }
+}

+ 35 - 0
power-fitting/src/main/java/com/gyee/power/fitting/model/agc/PointData.java

@@ -0,0 +1,35 @@
+package com.gyee.power.fitting.model.agc;
+
+/**
+ * 测点数据
+ */
+public class PointData {
+    /**
+     * 时间戳
+     */
+    private long ts;
+    /**
+     * 数据
+     */
+    private double doubleValue;
+
+    public long getTs() {
+        return ts;
+    }
+
+    public void setTs(long ts) {
+        this.ts = ts;
+    }
+
+    public double getValue() {
+        return doubleValue;
+    }
+
+    public double getDoubleValue() {
+        return doubleValue;
+    }
+
+    public void setDoubleValue(double doubleValue) {
+        this.doubleValue = doubleValue;
+    }
+}

+ 191 - 0
power-fitting/src/main/java/com/gyee/power/fitting/service/custom/curve/AgcDeviateService.java

@@ -0,0 +1,191 @@
+package com.gyee.power.fitting.service.custom.curve;
+
+import com.alibaba.fastjson.JSON;
+import com.gyee.power.fitting.common.feign.IDataAdapter;
+import com.gyee.power.fitting.model.agc.AgcDeviateConfig;
+import com.gyee.power.fitting.model.agc.AgcDeviateTag;
+import com.gyee.power.fitting.model.agc.AiPoints;
+import com.gyee.power.fitting.mapper.AgcDeviateMapper;
+import com.gyee.power.fitting.model.AgcDeviateModel;
+import com.gyee.power.fitting.model.agc.PointData;
+import org.springframework.core.annotation.Order;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * 读取数据库配置文件
+ */
+@Order(0)
+@Component
+public class AgcDeviateService {
+    private final AgcDeviateMapper agcDeviateMapper;
+    /**
+     * AGC信息缓存
+     */
+    private Map<String, AgcDeviateConfig> agcDeviateConfigMap;
+
+    @Resource
+    private IDataAdapter iDataAdapter;
+
+
+    public AgcDeviateService(AgcDeviateMapper agcDeviateMapper) {
+        this.agcDeviateMapper = agcDeviateMapper;
+        agcDeviateConfigMap = new HashMap<>();
+        AgcDeviateModel adm = agcDeviateMapper.selectById("agc_info_net");
+
+        AgcDeviateConfig[] adcs = JSON.parseObject(adm.getValue(), AgcDeviateConfig[].class);
+        for (AgcDeviateConfig adc : adcs) {
+            agcDeviateConfigMap.put(adc.getId(), adc);
+        }
+    }
+
+    /**
+     * 获取agc曲线偏差分析需要的数据
+     *
+     * @param id       场站ID
+     * @param startTs  开始时间戳
+     * @param endTs    结束时间戳
+     * @param interval 数据时间间隔
+     * @return 分析数据
+     */
+    public List<AgcDeviateTag> getAgcDeviateTags(String id, long startTs, long endTs, int interval) {
+        List<AgcDeviateTag> ladt = new ArrayList<>();
+        List<AiPoints> laps = getAiPoints(id);
+        if (laps == null) {
+            return ladt;
+        }
+        for (AiPoints ap : laps) {
+            AgcDeviateTag adt = new AgcDeviateTag();
+            adt.setName(ap.getName());
+            List<PointData> lpd = getPointData(ap, startTs, endTs, interval);
+            adt.setValues(lpd);
+            ladt.add(adt);
+        }
+        // 上限下限
+        List<AgcDeviateTag> upperLowerLimits = getUpperLowerLimits(ladt, id);
+        ladt.addAll(upperLowerLimits);
+        return ladt;
+    }
+
+    private List<PointData> getPointData(AiPoints ap, long startTs, long endTs, int interval) {
+        List<PointData> lpds = null;
+        if (ap.getTag().contains(",")) {
+            lpds = getMultiple(ap, startTs, endTs, interval);
+        } else {
+            lpds = iDataAdapter.getSnapValuesByKey(ap.getTag(), startTs, endTs, interval);
+        }
+        if (ap.getMultiplier() != 1) {
+            for (PointData pd : lpds) {
+                pd.setDoubleValue(pd.getDoubleValue() * ap.getMultiplier());
+            }
+        }
+        return lpds;
+    }
+
+    /**
+     * 获取多个标签点数值
+     */
+    private List<PointData> getMultiple(AiPoints ap, long startTs, long endTs, int interval) {
+        String[] tags = ap.getTag().split(",");
+        boolean isFirst = true;
+        List<PointData> lpd = new ArrayList<>();
+        for (String tag : tags) {
+            if (tag.equals("")) {
+                continue;
+            }
+            List<PointData> vals = iDataAdapter.getSnapValuesByKey(tag, startTs, endTs, interval);
+            for (int i = 0; i < vals.size(); ++i) {
+                if (isFirst) {
+                    lpd.addAll(vals);
+                    isFirst = false;
+                    break;
+                } else {
+                    PointData pd = lpd.get(i);
+                    pd.setDoubleValue(vals.get(i).getDoubleValue() + pd.getDoubleValue());
+                }
+            }
+        }
+        return lpd;
+    }
+
+    /**
+     * 获取上限下限
+     */
+    private List<AgcDeviateTag> getUpperLowerLimits(List<AgcDeviateTag> ladt, String id) {
+        // 装机容量
+        double capacity = getCapacity(id);
+        // 偏差
+        double deviation = capacity * 0.03;
+        // 有功设定
+        Optional<AgcDeviateTag> agcLimit = ladt.stream().filter(ad -> ad.getName().equals("有功设定限值")).findFirst();
+
+        List<AgcDeviateTag> la = new ArrayList<>();
+        if (!agcLimit.isPresent()) {
+            return la;
+        }
+        AgcDeviateTag adtUper = new AgcDeviateTag();
+        adtUper.setName("偏差上限");
+        adtUper.setValues(new ArrayList<>());
+        AgcDeviateTag adtLimt = new AgcDeviateTag();
+        adtLimt.setName("偏差下限");
+        adtLimt.setValues(new ArrayList<>());
+
+        for (PointData pd : agcLimit.get().getValues()) {
+            long ts = pd.getTs();
+            PointData pdUper = new PointData();
+            pdUper.setTs(ts);
+            pdUper.setDoubleValue(pd.getDoubleValue() + deviation);
+            PointData pdLimt = new PointData();
+            pdLimt.setTs(ts);
+            pdLimt.setDoubleValue(pd.getDoubleValue() - deviation);
+            adtUper.getValues().add(pdUper);
+            adtLimt.getValues().add(pdLimt);
+        }
+        la.add(adtUper);
+        la.add(adtLimt);
+        return la;
+    }
+
+
+    /**
+     * 根据ID获取agc配置信息
+     *
+     * @param id 场站ID
+     * @return 配置信息
+     */
+    private List<AiPoints> getAiPoints(String id) {
+        if (!agcDeviateConfigMap.containsKey(id)) {
+            return null;
+        }
+        AiPoints[] aiPoints = agcDeviateConfigMap.get(id).getAiPoints();
+        return Arrays.stream(aiPoints).filter(ap -> ap.getName().contains("功") && !ap.getName().contains("预测")).collect(Collectors.toList());
+    }
+
+    private double getCapacity(String id) {
+        if (!agcDeviateConfigMap.containsKey(id)) {
+            return 0;
+        }
+        return agcDeviateConfigMap.get(id).getInstalledCapacity();
+    }
+
+    /**
+     * 获取配置
+     *
+     * @return
+     */
+    public Object getConfig() {
+        return agcDeviateConfigMap;
+    }
+}
+
+
+
+
+
+
+
+
+

+ 1 - 1
power-fitting/src/main/resources/application.yaml

@@ -1,6 +1,6 @@
 gyee:
   # 实时适配器的url
-  adapter-url: http://10.155.32.4:8011
+  adapter-url: http://192.168.101.8:8011
   # 数据准备保存路径(原始数据)
   file-path-prepare: data\prepare\
   # 数据处理保存路径(处理后的数据)