This commit is contained in:
wr
2024-12-26 11:30:48 +08:00
parent 270b89ef2a
commit 514f31a50a
8 changed files with 621 additions and 10 deletions

View File

@@ -1,8 +1,6 @@
package com.njcn.gather.detection.pojo.param;
import com.alibaba.fastjson.annotation.JSONField;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.swagger.annotations.ApiOperation;
import lombok.Data;
import lombok.NoArgsConstructor;

View File

@@ -3,6 +3,7 @@ package com.njcn.gather.detection.pojo.po;
import com.alibaba.fastjson.annotation.JSONField;
import lombok.Data;
import java.util.List;
import java.util.Map;
@@ -55,5 +56,31 @@ public class SourceCompareDev {
@JSONField(ordinal = 6)
private Map<String, Double> DevData;
@Data
public static class Info {
/**
* 装置名称
*/
@JSONField(ordinal = 1)
private String devName;
/**
* 装置ip
*/
@JSONField(ordinal = 2)
private String ip;
/**
* 描述
*/
@JSONField(ordinal = 3)
private String desc;
/**
* 装置下所有通道信息
*/
@JSONField(ordinal = 4)
List<SourceCompareDev> devNumlist;
}
}

View File

@@ -0,0 +1,550 @@
package com.njcn.gather.detection.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import com.njcn.gather.detection.pojo.po.DevData;
import com.njcn.gather.device.err.pojo.param.PqErrSysParam;
import com.njcn.gather.device.err.pojo.po.PqErrSysDtls;
import com.njcn.gather.device.err.service.IPqErrSysDtlsService;
import com.njcn.gather.device.script.pojo.po.SourceIssue;
import com.njcn.gather.system.dictionary.pojo.enums.DictDataEnum;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;
/**
* @author wr
* @description
* @date 2024/12/20 13:52
*/
@Service
@RequiredArgsConstructor
public class DetectionServiceImpl {
public final IPqErrSysDtlsService pqErrSysDtlsService;
public final String TYPE_A = "A";
public final String TYPE_B = "B";
public final String TYPE_C = "C";
public final String TYPE_T = "T";
public final String U = "U";
public final String I = "I";
public final String F = "F";
/**
* 开始处理指标类型
* 一共20组数据开始处理格式
*/
public void text(List<DevData> dev, SourceIssue issue, DictDataEnum dataRule) {
Map<String, List<DevData>> devDataMap = dev.stream().collect(Collectors.groupingBy(DevData::getId));
devDataMap.forEach(((key, value) -> {
DetectionIndexProcessing(value, dataRule, issue);
}));
}
/**
* 取值的方法
* 1.根据源参数下发,获得所检测项目的误差体系
* 2.根据数据处理原则先将原始20组数据进行处理是任意还是部分
* 3.根据误差体系筛选出,在范围内的数据,然后根据最大误差值是不是在合理范围内
*
* @param dev 原始数据
* @param sourceIssue 源下发的参数
* @return
*/
public Boolean DetectionIndexProcessing(List<DevData> dev, DictDataEnum dataRule, SourceIssue sourceIssue) {
PqErrSysParam.DetectionParam param = new PqErrSysParam.DetectionParam();
List<PqErrSysDtls> pqErrSysDtls = pqErrSysDtlsService.listPqErrSysDtlsByPqErrSysIdAndTypes(param);
//判断取值是否在误差范围内
return isQualified(dev, pqErrSysDtls, U, sourceIssue, dataRule);
//获得对应的误差体系
// switch (errSysEnum) {
// case VOL:
// return isQualified(dev, pqErrSysDtls, U, sourceIssue, dataRule);
// case Freq:
// return isQualified(dev, pqErrSysDtls, I, sourceIssue, dataRule);
// case MSQI_U:
// break;
// case MSQI_I:
// break;
// case Flicker:
// break;
// case Harm_V:
// isHarmQualified(dev, pqErrSysDtls, U, sourceIssue, dataRule);
// break;
// case Harm_I:
// isHarmQualified(dev, pqErrSysDtls, I, sourceIssue, dataRule);
// break;
// case Harm_P:
// break;
// case InHarm_V:
// isHarmQualified(dev, pqErrSysDtls, U, sourceIssue, dataRule);
// break;
// case InHarm_I:
// isHarmQualified(dev, pqErrSysDtls, I, sourceIssue, dataRule);
// break;
// case CUR:
// return isQualified(dev, pqErrSysDtls, F, sourceIssue, dataRule);
// case Dip:
// break;
//
// }
// return null;
}
/**
* 处理非谐波类型取值
*
* @param dev
* @param dataRule
*/
public Map<String, List<Double>> devListMap(List<DevData> dev, DictDataEnum dataRule) {
//设置
Map<String, List<Double>> map = new HashMap<>(3);
List<Double> a = new ArrayList<>();
List<Double> b = new ArrayList<>();
List<Double> c = new ArrayList<>();
List<Double> t = new ArrayList<>();
List<DevData.SqlDataDTO> sqlDataDTOS = dev.stream().flatMap(x -> x.getSqlData().stream()).collect(Collectors.toList());
if (CollUtil.isNotEmpty(sqlDataDTOS)) {
List<DevData.SqlDataDTO.ListDTO> list = sqlDataDTOS.stream().map(DevData.SqlDataDTO::getList).collect(Collectors.toList());
a = list.stream()
.filter(x -> ObjectUtil.isNotNull(x.getA()))
.map(DevData.SqlDataDTO.ListDTO::getA)
.sorted(Comparator.comparing(Double::doubleValue).reversed())
.collect(Collectors.toList());
b = list.stream()
.filter(x -> ObjectUtil.isNotNull(x.getA()))
.map(DevData.SqlDataDTO.ListDTO::getB)
.sorted(Comparator.comparing(Double::doubleValue).reversed())
.collect(Collectors.toList());
c = list.stream()
.filter(x -> ObjectUtil.isNotNull(x.getC()))
.map(DevData.SqlDataDTO.ListDTO::getC)
.sorted(Comparator.comparing(Double::doubleValue).reversed())
.collect(Collectors.toList());
t = list.stream().filter(x -> ObjectUtil.isNotNull(x.getT()))
.map(DevData.SqlDataDTO.ListDTO::getT)
.sorted(Comparator.comparing(Double::doubleValue).reversed())
.collect(Collectors.toList());
}
switch (dataRule) {
case SECTION_VALUE:
a = getDoubles(a, 1, 19);
b = getDoubles(b, 1, 19);
c = getDoubles(c, 1, 19);
t = getDoubles(t, 1, 19);
break;
case CP95_VALUE:
a = getDoubles(a, 1, 2);
b = getDoubles(b, 1, 2);
c = getDoubles(c, 1, 2);
t = getDoubles(t, 1, 2);
break;
case AVG_VALUE:
a = getAvgDoubles(a);
b = getAvgDoubles(b);
c = getAvgDoubles(c);
t = getAvgDoubles(t);
break;
}
map.put(TYPE_A, a);
map.put(TYPE_B, b);
map.put(TYPE_C, c);
if (CollUtil.isNotEmpty(t)) {
map.put(TYPE_T, t);
}
return map;
}
/**
* 判断值是否在误差范围内,有则进行判断否则则不进行计算(非谐波类型)
*
* @param dev 处理过后的数据
* @param pqErrSysDtls 误差体系
* @param type (电压还是电流)
* @param sourceIssue 源下发所对应的参数
* @param dataRule 数据处理原则
* @return
*/
public Boolean isQualified(List<DevData> dev, List<PqErrSysDtls> pqErrSysDtls, String type, SourceIssue sourceIssue, DictDataEnum dataRule) {
Map<String, List<Double>> map = devListMap(dev, dataRule);
Double fData = 1.0;
if (U.equals(type)) {
fData = sourceIssue.getFUn();
}
if (I.equals(type)) {
fData = sourceIssue.getFIn();
}
if (F.equals(type)) {
fData = sourceIssue.getFFreq();
}
if (map.containsKey(TYPE_T)) {
return rangeComparisonList(map.get(TYPE_T), pqErrSysDtls, fData, 1.0, dataRule);
} else {
//取出源所对应的相别信息
List<SourceIssue.ChannelListDTO> channelTypeAList = sourceIssue.getChannelList().stream()
.filter(x -> (type + "a").equals(x.getChannelType()))
.collect(Collectors.toList());
Boolean a = rangeComparisonList(map.get(TYPE_A), pqErrSysDtls, fData, channelTypeAList.get(0).getFAmp(), dataRule);
List<SourceIssue.ChannelListDTO> channelTypeBList = sourceIssue.getChannelList().stream()
.filter(x -> (type + "b").equals(x.getChannelType()))
.collect(Collectors.toList());
Boolean b = rangeComparisonList(map.get(TYPE_B), pqErrSysDtls, fData, channelTypeBList.get(0).getFAmp(), dataRule);
List<SourceIssue.ChannelListDTO> channelTypeCList = sourceIssue.getChannelList().stream()
.filter(x -> (type + "c").equals(x.getChannelType()))
.collect(Collectors.toList());
Boolean c = rangeComparisonList(map.get(TYPE_C), pqErrSysDtls, fData, channelTypeCList.get(0).getFAmp(), dataRule);
if (ObjectUtil.isAllNotEmpty(a, b, c)) {
return a && b && c;
}
if (ObjectUtil.isAllEmpty(a, b, c)) {
return null;
}
}
return null;
}
/**
* 判断值是否在误差范围内,有则进行判断否则则不进行计算(谐波类型)
*
* @param dev 处理过后的数据
* @param pqErrSysDtls 误差体系
* @param type (电压还是电流)
* @param sourceIssue 源下发所对应的参数
* @param dataRule 数据处理原则
* @return
*/
public Boolean isHarmQualified(List<DevData> dev, List<PqErrSysDtls> pqErrSysDtls, String type, SourceIssue sourceIssue, DictDataEnum dataRule) {
Map<String, Map<Integer, List<Double>>> devMap = devHarmListMap(dev, sourceIssue, dataRule);
Double fData = 1.0;
if (U.equals(type)) {
fData = sourceIssue.getFUn();
}
if (I.equals(type)) {
fData = sourceIssue.getFIn();
}
Map<Integer, Boolean> integerBooleanMapA = harmRangeComparison(pqErrSysDtls, type, TYPE_A, sourceIssue, dataRule, devMap.get(TYPE_A), fData);
Map<Integer, Boolean> integerBooleanMapB = harmRangeComparison(pqErrSysDtls, type, TYPE_B, sourceIssue, dataRule, devMap.get(TYPE_B), fData);
Map<Integer, Boolean> integerBooleanMapC = harmRangeComparison(pqErrSysDtls, type, TYPE_C, sourceIssue, dataRule, devMap.get(TYPE_C), fData);
List<Boolean> list = new ArrayList<>();
list.addAll(integerBooleanMapA.values());
list.addAll(integerBooleanMapB.values());
list.addAll(integerBooleanMapC.values());
if (CollUtil.isNotEmpty(list)) {
List<Boolean> integerList = list.stream().filter(x -> ObjectUtil.isNotNull(x)).collect(Collectors.toList());
if (integerList.size() == list.size()) {
List<Boolean> booleans = integerList.stream().distinct().collect(Collectors.toList());
if (booleans.size() > 1) {
return false;
} else {
return booleans.get(0);
}
}
}
return null;
}
/**
* @param pqErrSysDtls 误差体系
* @param type U,I
* @param phase A,B,C
* @param sourceIssue 源下发的值(谐波)
* @param dataRule 数据处理原则
* @param devMap
* @param fData
* @return
*/
public Map<Integer, Boolean> harmRangeComparison(List<PqErrSysDtls> pqErrSysDtls, String type, String phase, SourceIssue sourceIssue, DictDataEnum dataRule, Map<Integer, List<Double>> devMap, Double fData) {
Map<Integer, Boolean> map = new LinkedHashMap<>();
//根据谐波几次相值/额定值
Map<Integer, Double> issueHarmMap = sourceIssue.getChannelList().stream()
.filter(x -> (type + phase.toLowerCase()).equals(x.getChannelType()))
.flatMap(x -> x.getHarmList().stream())
.collect(Collectors.toMap(SourceIssue.ChannelListDTO.HarmModel::getHarm, x -> x.getFApm()));
Map<Integer, PqErrSysDtls> errSysDtlMap = new LinkedHashMap<>();
issueHarmMap.forEach((key, value) -> {
//获得误差体系
List<PqErrSysDtls> errSysDtls = pqErrSysDtls.stream().filter(x -> rangeComparison(x.getStartValue(),
x.getStartFlag(),
x.getEndValue(),
x.getEndFlag(),
divide(value - fData, fData).doubleValue())).collect(Collectors.toList());
if (CollUtil.isNotEmpty(errSysDtls)) {
errSysDtlMap.put(key, errSysDtls.get(0));
} else {
errSysDtlMap.put(key, null);
}
});
devMap.forEach((harm, harmDataList) -> {
Boolean harmBigNum = getHarmNum(dataRule, harmDataList, errSysDtlMap.get(harm), issueHarmMap.get(harm), fData);
if (ObjectUtil.isNotNull(harmBigNum)) {
map.put(harm, harmBigNum);
}
});
return map;
}
public Boolean getHarmNum(DictDataEnum dataRule, List<Double> harmDataList, PqErrSysDtls errSysDtl, Double channelData, Double fData) {
if (ObjectUtil.isNotNull(errSysDtl)) {
if (0 == errSysDtl.getErrorValueType()) {
errSysDtl.setMaxErrorValue(multiply(errSysDtl.getMaxErrorValue(), fData, 0));
}
List<Double> qualifiedList = harmDataList.stream()
.filter(x -> NumberUtil.isIn(devSubtractChannelData(x, channelData, errSysDtl.getErrorValueType()),
BigDecimal.valueOf(-errSysDtl.getMaxErrorValue()),
BigDecimal.valueOf(errSysDtl.getMaxErrorValue()))).collect(Collectors.toList());
switch (dataRule) {
case AT_WILL_VALUE:
case CP95_VALUE:
case AVG_VALUE:
if (qualifiedList.size() > 0) {
return true;
}
break;
case SECTION_VALUE:
case Own_value:
if (qualifiedList.size() == harmDataList.size()) {
return true;
}
break;
}
return false;
}
return null;
}
public Map<String, Map<Integer, List<Double>>> devHarmListMap(List<DevData> dev, SourceIssue sourceIssue, DictDataEnum dataRule) {
List<Integer> harmNum = sourceIssue.getChannelList().stream()
.flatMap(x -> x.getHarmList().stream().map(f -> f.getHarm()))
.sorted().distinct().collect(Collectors.toList());
Map<String, Map<Integer, List<Double>>> map = new HashMap<>(3);
for (DevData devData : dev) {
DevData.SqlDataHarmDTO fund = devData.getSqlDataHarm().stream().filter(x -> 1 == x.getNum()).collect(Collectors.toList()).stream().findFirst().get();
DevData.SqlDataHarmDTO harm = devData.getSqlDataHarm().stream().filter(x -> 49 == x.getNum()).collect(Collectors.toList()).stream().findFirst().get();
if(ObjectUtil.isNotNull(fund)){
harmPut(TYPE_A, map, harmNum, harm, fund.getList().getA().get(0));
harmPut(TYPE_B, map, harmNum, harm, fund.getList().getA().get(0));
harmPut(TYPE_C, map, harmNum, harm, fund.getList().getA().get(0));
}else{
harmPut(TYPE_A, map, harmNum, harm, "1.0");
harmPut(TYPE_B, map, harmNum, harm, "1.0");
harmPut(TYPE_C, map, harmNum, harm, "1.0");
}
}
map.forEach((typeKey, typeValue) -> {
typeValue.forEach((key, value) -> {
value.sort(Comparator.comparing(Double::doubleValue).reversed());
switch (dataRule) {
case SECTION_VALUE:
value.subList(19, value.size()).clear(); // 保留前19个元素
value.remove(0); // 移除第一个元素
break;
case CP95_VALUE:
value.subList(1, value.size()).clear(); // 保留第一个元素
break;
case AVG_VALUE:
double average = value.stream().mapToDouble(Double::doubleValue).average().orElse(0.0);
value.clear(); // 清空列表
value.add(average); // 添加平均值
break;
}
});
});
return map;
}
/**
* 处理数据是否合格
*
* @param listT 原始的数据
* @param pqErrSysDtls 误差体系
* @param data 源下发的额定信息(额定电压,额定电流)
* @param channelData 源下发的通道信息的值包括 {Ua, Ub, Uc, Ux, Ia, Ib, Ic, Ix ,NULL}
* @param dataRule 数据处理原则
* @returnd
*/
public Boolean rangeComparisonList(List<Double> listT, List<PqErrSysDtls> pqErrSysDtls, Double data, Double channelData, DictDataEnum dataRule) {
//先根据源所下发的数据,是否在误差体系范围内在则可以进行误差体系判断
//获得误差体系
List<PqErrSysDtls> errSysDtls = pqErrSysDtls.stream().filter(x -> rangeComparison(multiply(x.getStartValue(), data, x.getConditionType()),
x.getStartFlag(),
multiply(x.getEndValue(), data, x.getConditionType()),
x.getEndFlag(),
channelData)).collect(Collectors.toList());
if (CollUtil.isNotEmpty(errSysDtls)) {
PqErrSysDtls errSysDtl = errSysDtls.get(0);
if (0 == errSysDtl.getErrorValueType()) {
errSysDtl.setMaxErrorValue(multiply(errSysDtl.getMaxErrorValue(), data, 0));
}
List<Double> qualifiedList = listT.stream().filter(x -> NumberUtil.isIn(devSubtractChannelData(x, channelData, errSysDtl.getErrorValueType()),
BigDecimal.valueOf(-errSysDtl.getMaxErrorValue()),
BigDecimal.valueOf(errSysDtl.getMaxErrorValue()))).collect(Collectors.toList());
switch (dataRule) {
case AT_WILL_VALUE:
case CP95_VALUE:
case AVG_VALUE:
if (qualifiedList.size() > 0) {
return true;
}
break;
case SECTION_VALUE:
case Own_value:
if (qualifiedList.size() == listT.size()) {
return true;
}
break;
}
}
return null;
}
/**
* 先判断在范围的数据,在进行误差体系的判断
*
* @param startValue 开始值
* @param startFlag 是否包含
* @param endValue 结束值
* @param endFlag 是否包含
* @param devData 装置上送值
* @return
*/
public Boolean rangeComparison(Double startValue, Integer startFlag, Double endValue, Integer endFlag, Double devData) {
Boolean minBool = null;
Boolean maxBool = null;
if (ObjectUtil.isNotNull(startValue)) {
if (1 == startFlag) {
minBool = NumberUtil.isGreaterOrEqual(BigDecimal.valueOf(devData), BigDecimal.valueOf(startValue));
} else {
minBool = NumberUtil.isGreater(BigDecimal.valueOf(devData), BigDecimal.valueOf(startValue));
}
}
if (ObjectUtil.isNotNull(endValue)) {
if (1 == endFlag) {
maxBool = NumberUtil.isLessOrEqual(BigDecimal.valueOf(devData), BigDecimal.valueOf(endValue));
} else {
maxBool = NumberUtil.isLess(BigDecimal.valueOf(devData), BigDecimal.valueOf(endValue));
}
}
if (ObjectUtil.isNotNull(minBool) && ObjectUtil.isNotNull(maxBool)) {
return minBool && maxBool;
} else {
if (ObjectUtil.isNotNull(minBool)) {
return minBool;
}
if (ObjectUtil.isNotNull(maxBool)) {
return maxBool;
}
}
return true;
}
/**
* 技术数据误差值(装置返回的值 - 源通道下发的值)
*
* @param devData
* @param channelData
* @param errorValueType
* @return
*/
public BigDecimal devSubtractChannelData(Double devData, Double channelData, Integer errorValueType) {
switch (errorValueType) {
case 2:
return BigDecimal.valueOf(devData - channelData)
.divide(BigDecimal.valueOf(devData), 7, RoundingMode.HALF_UP);
case 3:
return BigDecimal.valueOf(devData - channelData)
.divide(BigDecimal.valueOf(channelData), 7, RoundingMode.HALF_UP);
}
return BigDecimal.valueOf(devData - channelData);
}
public BigDecimal divide(Double devData, Double channelData) {
return BigDecimal.valueOf(devData)
.divide(BigDecimal.valueOf(channelData), 7, RoundingMode.HALF_UP);
}
public Double multiply(Double devData, Double channelData, Integer type) {
if (0 == type) {
return BigDecimal.valueOf(devData).multiply(BigDecimal.valueOf(channelData))
.setScale(7, RoundingMode.HALF_UP).doubleValue();
} else {
return BigDecimal.valueOf(devData).doubleValue();
}
}
public Double multiply(String devData, String channelData) {
return BigDecimal.valueOf(Double.valueOf(devData)).multiply(BigDecimal.valueOf(Double.valueOf(channelData)))
.setScale(7, RoundingMode.HALF_UP).doubleValue();
}
/**
* 处理谐波原始数据
*
* @param type A,b,c
* @param map 初始化集合
* @param harmNum 多少次谐波集合
* @param harm 基波信息
* @param fund 2-50次谐波信息
*/
public void harmPut(String type, Map<String, Map<Integer, List<Double>>> map, List<Integer> harmNum, DevData.SqlDataHarmDTO harm, String fund) {
if (map.containsKey(type)) {
Map<Integer, List<Double>> integerListMap = map.get(type);
for (Integer i : harmNum) {
if (integerListMap.containsKey(i)) {
if (type.equals("A")) {
integerListMap.get(i).add(multiply(harm.getList().getA().get(i - 2), fund));
}
if (type.equals("B")) {
integerListMap.get(i).add(multiply(harm.getList().getB().get(i - 2), fund));
}
if (type.equals("C")) {
integerListMap.get(i).add(multiply(harm.getList().getC().get(i - 2), fund));
}
}
}
} else {
Map<Integer, List<Double>> integerListMap = new LinkedHashMap<>(5);
for (Integer i : harmNum) {
List<Double> integerList = new ArrayList<>();
if (type.equals("A")) {
integerList.add(multiply(harm.getList().getA().get(i - 2), fund));
}
if (type.equals("B")) {
integerList.add(multiply(harm.getList().getB().get(i - 2), fund));
}
if (type.equals("C")) {
integerList.add(multiply(harm.getList().getC().get(i - 2), fund));
}
integerListMap.put(i, integerList);
}
map.put(type, integerListMap);
}
}
public static List<Double> getAvgDoubles(List<Double> t) {
if (CollUtil.isNotEmpty(t)) {
t = Arrays.asList(t.stream().mapToDouble(Double::doubleValue).average().orElse(0.0));
}
return t;
}
public static List<Double> getDoubles(List<Double> t, Integer start, Integer end) {
if (CollUtil.isNotEmpty(t)) {
t = t.subList(start, end);
}
return t;
}
}