package com.njcn.event.file.component;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.StrUtil;
import com.njcn.common.pojo.exception.BusinessException;
import com.njcn.common.utils.wave.BitConverter;
import com.njcn.event.file.pojo.dto.*;
import com.njcn.event.file.pojo.enums.WaveFileResponseEnum;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.awt.*;
import java.io.*;
import java.nio.file.Files;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.List;

/**
 * @author hongawen
 * @version 1.0.0
 * @date 2023年03月03日 10:01
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class WaveFileComponent {


    /******************************************
     * 调用读取comtrate文件方法
     * param strFilePath 波形.cfg文件路径
     * param iType == 0  高级算法的要求，采样率只能是32-128
     *       iType == 1  普通展示，采样率按照cfg里面最小的（大于32）
     *       iType == 2  App抽点要求，采样率抽点成32
     *       iType == 3  高级算法原始波形（大于32）
     ******************************************/
    public WaveDataDTO getComtrade(InputStream cfgStream, InputStream datStream, int iType) {
        WaveDataDTO waveDataDTO = new WaveDataDTO();
        // 首先判断文件路径是否为空
        // 读取cfg文件
        ComtradeCfgDTO comtradeCfgDTO = getComtradeCfg(cfgStream);
        // 为空或者未找到结束符号
        if (comtradeCfgDTO == null || !"BINARY".equalsIgnoreCase(comtradeCfgDTO.getStrBinType())) {
            throw new BusinessException(WaveFileResponseEnum.CFG_DATA_ERROR);
        }

        /*****根据通道号计算相别**  add by yexb -----Start****
         * 1、判断是否是3的倍数，是3的倍数则是3相
         * 2、假如不是3的倍数 ，是1的倍数则是单相
         ********************************************************/
        if (comtradeCfgDTO.getNAnalogNum() % 3 == 0) {
            comtradeCfgDTO.setNPhasic(3);
        } else {
            comtradeCfgDTO.setNPhasic(1);
        }

        // 给相别数量赋值
        waveDataDTO.setIPhasic(comtradeCfgDTO.getNPhasic());

        // 组装解析抬头
        getWaveTitle(waveDataDTO, comtradeCfgDTO);

        // 解析.dat文件
        List<List<Float>> listWaveData = getComtradeDat(comtradeCfgDTO, datStream, iType);

        waveDataDTO.setComtradeCfgDTO(comtradeCfgDTO);

        waveDataDTO.setListWaveData(listWaveData);

        //add by hongawen,将暂态触发起始时间记录下来
        waveDataDTO.setTime(DateUtil.format(comtradeCfgDTO.getTimeTrige(), DatePattern.NORM_DATETIME_MS_PATTERN));
        /*****根据通道号计算相别**  add by yexb -----end****/

        return waveDataDTO;
    }

    public WaveDataDTO getComtradeNoAddPoints(InputStream cfgStream, InputStream datStream, int iType) {
        WaveDataDTO waveDataDTO = new WaveDataDTO();
        // 首先判断文件路径是否为空
        // 读取cfg文件
        ComtradeCfgDTO comtradeCfgDTO = getComtradeCfgNoAddPoints(cfgStream);
        // 为空或者未找到结束符号
        if (comtradeCfgDTO == null || !"BINARY".equalsIgnoreCase(comtradeCfgDTO.getStrBinType())) {
            throw new BusinessException(WaveFileResponseEnum.CFG_DATA_ERROR);
        }

        /*****根据通道号计算相别**  add by yexb -----Start****
         * 1、判断是否是3的倍数，是3的倍数则是3相
         * 2、假如不是3的倍数 ，是1的倍数则是单相
         ********************************************************/
        if (comtradeCfgDTO.getNAnalogNum() % 3 == 0) {
            comtradeCfgDTO.setNPhasic(3);
        } else {
            comtradeCfgDTO.setNPhasic(1);
        }

        // 给相别数量赋值
        waveDataDTO.setIPhasic(comtradeCfgDTO.getNPhasic());

        // 组装解析抬头
        getWaveTitle(waveDataDTO, comtradeCfgDTO);

        // 解析.dat文件
        List<List<Float>> listWaveData = getComtradeDatNoAddPoints(comtradeCfgDTO, datStream, iType);

        waveDataDTO.setComtradeCfgDTO(comtradeCfgDTO);

        waveDataDTO.setListWaveData(listWaveData);

        //add by hongawen,将暂态触发起始时间记录下来
        waveDataDTO.setTime(DateUtil.format(comtradeCfgDTO.getTimeTrige(), DatePattern.NORM_DATETIME_MS_PATTERN));
        /*****根据通道号计算相别**  add by yexb -----end****/

        return waveDataDTO;
    }

    /*********************************
     * 根据波形数据算出rms值数据
     * param waveDataDTO 瞬时波形（包含了CFG配置文件）
     *  List<List<Float>>  返回RMS波形
     **********************************/
    @SuppressWarnings("unused")
    public WaveDataDTO getValidData(WaveDataDTO waveDataDTO) {
        //CFG 配置文件
        ComtradeCfgDTO comtradeCfgDTO = waveDataDTO.getComtradeCfgDTO();
        //瞬时波形值
        List<List<Float>> lstWave = waveDataDTO.getListWaveData();
        //返回rms的值
        List<List<Float>> listRms = new ArrayList<>();
        /*float fs = nOneWaveNum;
        int nWaveNum = (int) nAllWaveNum;*/

        // 全波有效值  (int)fs / 2;//半波有效值
        int halfTs = comtradeCfgDTO.getFinalSampleRate().intValue();
        // 计算有效值算法
        /*********************************
         * modify by yexibao 2020-10-29
         * 增加多波形算法  ---------start
         ********************************/
        double iWave;
        // 相别
        int nPhasic;
        //存放RMS值的最小值
        List<List<Float>> listRmsMin = new ArrayList<>();
        if (lstWave.size() > 0) {
            nPhasic = comtradeCfgDTO.getNPhasic();
            //ComtradeCfg.nAnalogNum为值的个数(-1的原因是一个存的是时间)
            iWave = Math.floor((lstWave.get(0).size() - 1) / (double) nPhasic);
            List<Float> tmpListRms;
            List<Float> tmpListRmsMin;
            //增加RMS的最小值
            double fMinTime = 0.0, fMinValue = 0.0;
            //每一项一项计算
            for (int j = 0; j < iWave; j++) {
                // 实例化
                tmpListRmsMin = new ArrayList<>();
                double fSumA = 0.0, fSumB = 0.0, fSumC = 0.0;
                double fValidA, fValidB, fValidC;
                //循环原始数据
                for (int i = 0; i < lstWave.size(); i++) {
                    // 当第一次循环的时候实例化，其余的获取已有的List//获取每一项的值
                    List<Float> tmpListValue = lstWave.get(i);
                    if (j == 0) {
                        tmpListRms = new ArrayList<>();
                        //获取时间
                        tmpListRms.add(tmpListValue.get(0));
                        listRms.add(tmpListRms);
                    } else {
                        tmpListRms = listRms.get(i);
                    }

                    //包含了时间、电压（A、B、C）三相、电流（A、B、C）三相
                    if (tmpListValue.size() >= 2) {
                        //电压有效值算法,根据相别进行处理
                        switch (comtradeCfgDTO.getNPhasic()) {
                            case 1:
                                fSumA += Math.pow(tmpListValue.get(1 + nPhasic * j), 2);
                                // 计算有效值
                                if (i >= halfTs) {
                                    //获取前推周波的值
                                    List<Float> forwardListValue = lstWave.get(i - halfTs);
                                    fSumA -= Math.pow(forwardListValue.get(1 + nPhasic * j), 2);
                                }
                                fValidA = Math.sqrt(fSumA / halfTs);
                                tmpListRms.add((float) (Math.round(fValidA * 100)) / 100);
                                listRms.set(i, tmpListRms);
                                // 最小值判断
                                if (i >= halfTs) {
                                    if (i == halfTs) {
                                        fMinValue = fValidA;
                                        fMinTime = tmpListValue.get(0);
                                    } else {
                                        if (fValidA < fMinValue) {
                                            fMinValue = fValidA;
                                            fMinTime = tmpListValue.get(0);
                                        }
                                    }
                                }
                                break;
                            case 2:
                                fSumA += Math.pow(tmpListValue.get(1 + nPhasic * j), 2);
                                fSumB += Math.pow(tmpListValue.get(2 + nPhasic * j), 2);
                                // 计算有效值
                                if (i >= halfTs) {
                                    //获取前推周波的值
                                    List<Float> forwardListValue = lstWave.get(i - halfTs);
                                    fSumA -= Math.pow(forwardListValue.get(1 + nPhasic * j), 2);
                                    fSumB -= Math.pow(forwardListValue.get(2 + nPhasic * j), 2);
                                }
                                fValidA = Math.sqrt(fSumA / halfTs);
                                fValidB = Math.sqrt(fSumB / halfTs);

                                tmpListRms.add((float) (Math.round(fValidA * 100)) / 100);
                                tmpListRms.add((float) (Math.round(fValidB * 100)) / 100);
                                listRms.set(i, tmpListRms);

                                // 最小值判断
                                if (i >= halfTs) {
                                    if (i == halfTs) {
                                        fMinValue = fValidA;
                                        fMinTime = tmpListValue.get(0);
                                    } else {
                                        if (fValidA < fMinValue) {
                                            fMinValue = fValidA;
                                            fMinTime = tmpListValue.get(0);
                                        }
                                        if (fValidB < fMinValue) {
                                            fMinValue = fValidB;
                                            fMinTime = tmpListValue.get(0);
                                        }
                                    }
                                }
                                break;
                            case 3:
                                fSumA += Math.pow(tmpListValue.get(1 + nPhasic * j), 2);
                                fSumB += Math.pow(tmpListValue.get(2 + nPhasic * j), 2);
                                fSumC += Math.pow(tmpListValue.get(3 + nPhasic * j), 2);
                                // 计算有效值
                                if (i >= halfTs) {
                                    //获取前推周波的值
                                    List<Float> forwardListValue = lstWave.get(i - halfTs);
                                    fSumA -= Math.pow(forwardListValue.get(1 + nPhasic * j), 2);
                                    fSumB -= Math.pow(forwardListValue.get(2 + nPhasic * j), 2);
                                    fSumC -= Math.pow(forwardListValue.get(3 + nPhasic * j), 2);
                                }
                                fValidA = Math.sqrt(fSumA / halfTs);
                                fValidB = Math.sqrt(fSumB / halfTs);
                                fValidC = Math.sqrt(fSumC / halfTs);

                                tmpListRms.add((float) (Math.round(fValidA * 100)) / 100);
                                tmpListRms.add((float) (Math.round(fValidB * 100)) / 100);
                                tmpListRms.add((float) (Math.round(fValidC * 100)) / 100);
                                listRms.set(i, tmpListRms);

                                // 最小值判断
                                if (i >= halfTs) {
                                    if (i == halfTs) {
                                        fMinValue = fValidA;
                                        fMinTime = tmpListValue.get(0);
                                    } else {
                                        if (fValidA < fMinValue) {
                                            fMinValue = fValidA;
                                            fMinTime = tmpListValue.get(0);
                                        }
                                        if (fValidB < fMinValue) {
                                            fMinValue = fValidB;
                                            fMinTime = tmpListValue.get(0);
                                        }
                                        if (fValidC < fMinValue) {
                                            fMinValue = fValidC;
                                            fMinTime = tmpListValue.get(0);
                                        }
                                    }
                                }
                                break;
                            default:
                                break;
                        }
                    }
                }
                //增加最小值时间，最小值//获取时间
                tmpListRmsMin.add((float) fMinTime);
                //获取时间
                tmpListRmsMin.add((float) (Math.round(fMinValue * 100)) / 100);
                listRmsMin.add(tmpListRmsMin);
            }

            //过滤前一个周波
            //HalfTs表示一个周波
            try {
                for (int i = 0; i < halfTs; i++) {
                    //电压有效值算法 //没相具体的值
                    List<Float> tmpNewListRms = new ArrayList<>();
                    for (int j = 0; j < iWave; j++) {
                        if (j == 0) {
                            //获取时间
                            tmpNewListRms.add(listRms.get(i).get(0));
                        }
                        switch (nPhasic) {
                            case 1:
                                tmpNewListRms.add(listRms.get(i + halfTs).get(1 + nPhasic * j));
                                break;
                            case 2:
                                tmpNewListRms.add(listRms.get(i + halfTs).get(1 + nPhasic * j));
                                tmpNewListRms.add(listRms.get(i + halfTs).get(2 + nPhasic * j));
                                break;
                            case 3:
                                tmpNewListRms.add(listRms.get(i + halfTs).get(1 + nPhasic * j));
                                tmpNewListRms.add(listRms.get(i + halfTs).get(2 + nPhasic * j));
                                tmpNewListRms.add(listRms.get(i + halfTs).get(3 + nPhasic * j));
                                break;
                            default:
                                break;
                        }
                    }
                    //重新赋值
                    listRms.set(i, tmpNewListRms);
                }
            } catch (Exception e) {
                throw new BusinessException(WaveFileResponseEnum.RMS_DATA_ERROR);
            }
        }
        waveDataDTO.setListRmsData(listRms);
        //RMS最小值
        waveDataDTO.setListRmsMinData(listRmsMin);

        return waveDataDTO;
    }

    /*****************************
     *获取暂降特征值，包含离线
     * param waveDataDTO 波形返回参数
     * param blType 计算方式 true：浮动门槛  false：固定门槛
     *****************************/
    public List<EigenvalueDTO> getEigenvalue(WaveDataDTO waveDataDTO, boolean blType) {
        //CFG 配置文件
        ComtradeCfgDTO comtradeCfgDTO = waveDataDTO.getComtradeCfgDTO();
        // 瞬时波形值
        List<List<Float>> lstWave = waveDataDTO.getListWaveData();
        //获取最终采样率
        int finalSampleRate = comtradeCfgDTO.getFinalSampleRate();
        // 返回值
        List<EigenvalueDTO> lstEigenvalueDTO = new ArrayList<>();

        // 必须包含了瞬时波形
        if (lstWave.size() > 0) {
            MutationDTO mutationDTO = getMutationValue(lstWave, finalSampleRate);
            //获取突变量和RMS值
            if (mutationDTO.getListRms_Offline().size() > 0 && mutationDTO.getListTBL_Offline().size() > 0) {
                lstEigenvalueDTO = getEventValue(lstWave, mutationDTO, comtradeCfgDTO, blType);
            }
        } else {
            lstEigenvalueDTO = null;
        }
        return lstEigenvalueDTO;
    }

    /***
     * 获取波形文件流，存在则返回inputStream，不存在则返回null
     * 为null时，这抛出波形文件不存在异常
     * @author hongawen
     * @date 2023/3/3 14:03
     */
    public InputStream getFileInputStreamByFilePath(String filePath) {
        File file = new File(filePath);
        if (file.isFile() && file.exists()) {
            InputStream inputStream;
            try {
                inputStream = Files.newInputStream(file.toPath());
                if (inputStream.available() < 1) {
                    throw new BusinessException(WaveFileResponseEnum.WAVE_DATA_INVALID);
                }
                return inputStream;
            } catch (IOException e) {
                throw new BusinessException(WaveFileResponseEnum.WAVE_DATA_INVALID);
            }
        } else {
            throw new BusinessException(WaveFileResponseEnum.ANALYSE_WAVE_NOT_FOUND);
        }
    }

    /*********************************
     * 读取cfg方法
     * param strFilePath 文件路径
     * return  返回bool为是否解析出错
     **********************************/
    private ComtradeCfgDTO getComtradeCfg(InputStream cfgStream) {
        ComtradeCfgDTO comtradeCfgDTO = new ComtradeCfgDTO();
        try (InputStreamReader read = new InputStreamReader(cfgStream, CharsetUtil.CHARSET_GBK); BufferedReader bufferedReader = new BufferedReader(read);) {
            // 第一行不关心仅仅是一些描述类的信息
            String strFileLine = bufferedReader.readLine();

            // 第二行需要关心第二个(模拟量的个数)和第三个参数(开关量的个数)
            strFileLine = bufferedReader.readLine();
            // 按“,”进行分割
            String[] strTempArray = strFileLine.split(StrUtil.COMMA);
            // 总个数
            comtradeCfgDTO.setNChannelNum(Integer.parseInt(strTempArray[0]));
            // 模拟量的个数
            comtradeCfgDTO.setNAnalogNum(Integer.parseInt(strTempArray[1].substring(0, strTempArray[1].length() - 1)));
            // 开关量的个数
            comtradeCfgDTO.setNDigitalNum(Integer.parseInt(strTempArray[2].substring(0, strTempArray[2].length() - 1)));

            // 从第三行开始的ComtradeCfg.nChannelNum行是模拟量通道和数字量通道
            List<AnalogDTO> lstAnalogDTO = new ArrayList<>();
            comtradeCfgDTO.setLstAnalogDTO(lstAnalogDTO);
            for (int i = 0; i < comtradeCfgDTO.getNChannelNum(); i++) {
                AnalogDTO analogDTO = new AnalogDTO();
                lstAnalogDTO.add(analogDTO);
                strFileLine = bufferedReader.readLine();
                strTempArray = strFileLine.split(StrUtil.COMMA);
                //通道序号
                analogDTO.setNIndex(Integer.parseInt(strTempArray[0]));
                // 通道名称
                analogDTO.setSzChannleName(strTempArray[1]);
                // 相位名称
                analogDTO.setSzPhasicName(strTempArray[2]);
                // 监视的通道名称
                analogDTO.setSzMonitoredChannleName(strTempArray[3]);
                // 通道的单位
                analogDTO.setSzUnitName(strTempArray[4]);
                // 通道的系数
                analogDTO.setFCoefficent(Float.parseFloat(strTempArray[5]));
                // 通道的偏移量
                analogDTO.setFOffset(Float.parseFloat(strTempArray[6]));
                // 起始采样时间的偏移量
                analogDTO.setFTimeOffset(Float.parseFloat(strTempArray[7]));
                // 采样值的最小值
                analogDTO.setNMin(Integer.parseInt(strTempArray[8]));
                // 采样值的最大值
                analogDTO.setNMax(Integer.parseInt(strTempArray[9]));
                // 一次变比
                analogDTO.setFPrimary(Float.parseFloat(strTempArray[10]));
                // 二次变比
                analogDTO.setFSecondary(Float.parseFloat(strTempArray[11]));
                // 一次值还是二次值标志
                analogDTO.setSzValueType(strTempArray[12]);
            }

            //WW 2019-11-14 // 采样频率
            String freqLine = bufferedReader.readLine();
            int nFreq;
            try {
                // 先尝试解析为double再四舍五入为整数，以兼容"50.00"这样的格式
                nFreq = (int) Math.round(Double.parseDouble(freqLine));
            } catch (NumberFormatException e) {
                // 如果失败则使用原来的整数解析方式
                nFreq = Integer.parseInt(freqLine);
            }

            // 获取采样段数
            strFileLine = bufferedReader.readLine();
            int nRates = Integer.parseInt(strFileLine);
            comtradeCfgDTO.setNRates(nRates);
            // 获得每段的采样率 //采样率
            List<RateDTO> lstRate = new ArrayList<>();
            int nOffset = 0;
            for (int i = 0; i < nRates; i++) {
                strFileLine = bufferedReader.readLine();
                strTempArray = strFileLine.split(StrUtil.COMMA);
                RateDTO rateDTO = new RateDTO();
                // 单周波采样点数 //WW 2019-11-14
                double doubleValue = Double.parseDouble(strTempArray[0]); // 解析为 double
                int result = (int) (doubleValue / nFreq); // 强制转换为 int
                rateDTO.setNOneSample(result);
                // 总点数 //这里的strTemp是一个偏移量
                rateDTO.setNSampleNum((Integer.parseInt(strTempArray[1]) - nOffset));
                nOffset += rateDTO.getNSampleNum();
                lstRate.add(rateDTO);
            }
            comtradeCfgDTO.setLstRate(lstRate);
            // 增加读取波形起始时间个结束时间
            String timeFormat = "dd/MM/yyyy,HH:mm:ss.SSS";
            // 波形起始时间
            strFileLine = bufferedReader.readLine();
            strFileLine = strFileLine.substring(0, strFileLine.length() - 3);
            comtradeCfgDTO.setTimeStart(DateUtil.parse(strFileLine, timeFormat));

            // 暂态触发时间
            strFileLine = bufferedReader.readLine();
            strFileLine = strFileLine.substring(0, strFileLine.length() - 3);
            comtradeCfgDTO.setTimeTrige(DateUtil.parse(strFileLine, timeFormat));

            // 获取触发时间的时间 + 毫秒
            Calendar calendar = DateUtil.calendar(comtradeCfgDTO.getTimeTrige());
            comtradeCfgDTO.setFirstMs(calendar.get(Calendar.MILLISECOND));
            comtradeCfgDTO.setFirstTime(calendar.getTime());


            long a = comtradeCfgDTO.getTimeStart().getTime();
            long b = comtradeCfgDTO.getTimeTrige().getTime();

            int c = (int) (b - a);
            if (c >= 90 && c <= 110) {
                comtradeCfgDTO.setNPush(100);
            } else if (c >= 190 && c <= 210) {
                comtradeCfgDTO.setNPush(200);
            }
            // 赋值编码格式（二进制）
            comtradeCfgDTO.setStrBinType(bufferedReader.readLine().toUpperCase());
        } catch (Exception e) {
            // 解析.cfg文件出错
            comtradeCfgDTO = null;
        }
        return comtradeCfgDTO;
    }

    private ComtradeCfgDTO getComtradeCfgNoAddPoints(InputStream cfgStream) {
        ComtradeCfgDTO comtradeCfgDTO = new ComtradeCfgDTO();
        try (InputStreamReader read = new InputStreamReader(cfgStream, CharsetUtil.CHARSET_GBK); BufferedReader bufferedReader = new BufferedReader(read);) {
            // 第一行不关心仅仅是一些描述类的信息
            String strFileLine = bufferedReader.readLine();

            // 第二行需要关心第二个(模拟量的个数)和第三个参数(开关量的个数)
            strFileLine = bufferedReader.readLine();
            // 按“,”进行分割
            String[] strTempArray = strFileLine.split(StrUtil.COMMA);
            // 总个数
            comtradeCfgDTO.setNChannelNum(Integer.parseInt(strTempArray[0]));
            // 模拟量的个数
            comtradeCfgDTO.setNAnalogNum(Integer.parseInt(strTempArray[1].substring(0, strTempArray[1].length() - 1)));
            // 开关量的个数
            comtradeCfgDTO.setNDigitalNum(Integer.parseInt(strTempArray[2].substring(0, strTempArray[2].length() - 1)));

            // 从第三行开始的ComtradeCfg.nChannelNum行是模拟量通道和数字量通道
            List<AnalogDTO> lstAnalogDTO = new ArrayList<>();
            comtradeCfgDTO.setLstAnalogDTO(lstAnalogDTO);
            for (int i = 0; i < comtradeCfgDTO.getNChannelNum(); i++) {
                AnalogDTO analogDTO = new AnalogDTO();
                lstAnalogDTO.add(analogDTO);
                strFileLine = bufferedReader.readLine();
                strTempArray = strFileLine.split(StrUtil.COMMA);
                //通道序号
                analogDTO.setNIndex(Integer.parseInt(strTempArray[0]));
                // 通道名称
                analogDTO.setSzChannleName(strTempArray[1]);
                // 相位名称
                analogDTO.setSzPhasicName(strTempArray[2]);
                // 监视的通道名称
                analogDTO.setSzMonitoredChannleName(strTempArray[3]);
                // 通道的单位
                analogDTO.setSzUnitName(strTempArray[4]);
                // 通道的系数
                analogDTO.setFCoefficent(Float.parseFloat(strTempArray[5]));
                // 通道的偏移量
                analogDTO.setFOffset(Float.parseFloat(strTempArray[6]));
                // 起始采样时间的偏移量
                analogDTO.setFTimeOffset(Float.parseFloat(strTempArray[7]));
                // 采样值的最小值
                analogDTO.setNMin(Integer.parseInt(strTempArray[8]));
                // 采样值的最大值
                analogDTO.setNMax(Integer.parseInt(strTempArray[9]));
                // 一次变比
                analogDTO.setFPrimary(Float.parseFloat(strTempArray[10]));
                // 二次变比
                analogDTO.setFSecondary(Float.parseFloat(strTempArray[11]));
                // 一次值还是二次值标志
                analogDTO.setSzValueType(strTempArray[12]);
            }

            //WW 2019-11-14 // 采样频率
            String freqLine = bufferedReader.readLine();
            int nFreq;
            try {
                // 先尝试解析为double再四舍五入为整数，以兼容"50.00"这样的格式
                nFreq = (int) Math.round(Double.parseDouble(freqLine));
            } catch (NumberFormatException e) {
                // 如果失败则使用原来的整数解析方式
                nFreq = Integer.parseInt(freqLine);
            }

            // 获取采样段数
            strFileLine = bufferedReader.readLine();
            int nRates = Integer.parseInt(strFileLine);
            comtradeCfgDTO.setNRates(nRates);
            // 获得每段的采样率 //采样率
            List<RateDTO> lstRate = new ArrayList<>();
            int nOffset = 0;
            for (int i = 0; i < nRates; i++) {
                strFileLine = bufferedReader.readLine();
                strTempArray = strFileLine.split(StrUtil.COMMA);
                RateDTO rateDTO = new RateDTO();
                // 单周波采样点数 //WW 2019-11-14
                double doubleValue = Double.parseDouble(strTempArray[0]); // 解析为 double
                int result = (int) (doubleValue / nFreq); // 强制转换为 int
                rateDTO.setNOneSample(result);
                // 总点数 //这里的strTemp是一个偏移量
                rateDTO.setNSampleNum((Integer.parseInt(strTempArray[1]) - nOffset));
                nOffset = rateDTO.getNSampleNum();
                lstRate.add(rateDTO);
            }
            comtradeCfgDTO.setLstRate(lstRate);
            // 增加读取波形起始时间个结束时间
            String timeFormat = "dd/MM/yyyy,HH:mm:ss.SSS";
            // 波形起始时间
            strFileLine = bufferedReader.readLine();
            strFileLine = strFileLine.substring(0, strFileLine.length() - 3);
            comtradeCfgDTO.setTimeStart(DateUtil.parse(strFileLine, timeFormat));

            // 暂态触发时间
            strFileLine = bufferedReader.readLine();
            strFileLine = strFileLine.substring(0, strFileLine.length() - 3);
            comtradeCfgDTO.setTimeTrige(DateUtil.parse(strFileLine, timeFormat));

            // 获取触发时间的时间 + 毫秒
            Calendar calendar = DateUtil.calendar(comtradeCfgDTO.getTimeTrige());
            comtradeCfgDTO.setFirstMs(calendar.get(Calendar.MILLISECOND));
            comtradeCfgDTO.setFirstTime(calendar.getTime());


            long a = comtradeCfgDTO.getTimeStart().getTime();
            long b = comtradeCfgDTO.getTimeTrige().getTime();

            int c = (int) (b - a);
            if (c >= 90 && c <= 110) {
                comtradeCfgDTO.setNPush(100);
            } else if (c >= 190 && c <= 210) {
                comtradeCfgDTO.setNPush(200);
            }
            // 赋值编码格式（二进制）
            comtradeCfgDTO.setStrBinType(bufferedReader.readLine().toUpperCase());
        } catch (Exception e) {
            // 解析.cfg文件出错
            comtradeCfgDTO = null;
        }
        return comtradeCfgDTO;
    }

    /*********************************
     * 读取dat方法
     * param strFilePath  .dat访问路径
     * param strFilePath  .dat访问路径
     * param iType  访问波形类型
     *  List<List<Float>>  返回波形瞬时值
     **********************************/
    private List<List<Float>> getComtradeDat(ComtradeCfgDTO comtradeCfgDTO, InputStream datStream, int iType) {
        //返回数据，如果仅仅做展示后期考虑换String类型，降低内存开销
        List<List<Float>> listWaveData = new ArrayList<>();
        //初始化xValue的值
        float xValueAll = 0;
        //判断是否首次登陆
        boolean blxValue = false;
        byte[] datArray;
        try {
            datArray = IoUtil.readBytes(datStream);
            if (ArrayUtil.isEmpty(datArray)) {
                throw new BusinessException(WaveFileResponseEnum.DAT_DATA_ERROR);
            }
            // 计算每个单独的数据块的大小 4个字节的序号 4个字节的时间 2个字节的值
            // 示例中的排布是 4个字节的序号 4个字节的时间 UA(2字节) UB(2字节) UC(2字节) IA(2字节) IB(2字节) IC(2字节)
            int nDigSize = (comtradeCfgDTO.getNDigitalNum() % 16) > 0 ? (comtradeCfgDTO.getNDigitalNum() / 16 + 1) * 2 : comtradeCfgDTO.getNDigitalNum() / 16 * 2;
            int nBlockSize = 2 * Integer.SIZE / 8 + comtradeCfgDTO.getNAnalogNum() * 2 + nDigSize;
            // 总长度除以每个块的大小
            int nBlockNum = (int)Math.floor(datArray.length / nBlockSize);

            // 获取采样率
            int finalSampleRate = getFinalWaveSample(comtradeCfgDTO.getLstRate(), iType);
            if (finalSampleRate != -1) {
                //设置最终采样率
                comtradeCfgDTO.setFinalSampleRate(finalSampleRate);
                // 计算转换后的采样率
                int nnInd = 0;
                // 抽点后总共多少点数据
                int nWaveNum;
                //抽点后新的的采样率
                List<RateDTO> newLstRate = new ArrayList<>();
                for (int iRate = 0; iRate < comtradeCfgDTO.getNRates(); iRate++) {
                    // 计算本段录波总共有多少波形
                    nWaveNum = comtradeCfgDTO.getLstRate().get(iRate).getNSampleNum() / comtradeCfgDTO.getLstRate().get(iRate).getNOneSample();
                    //设置总波形大小
                    comtradeCfgDTO.setNAllWaveNum(comtradeCfgDTO.getNAllWaveNum() + nWaveNum);
                    // 将最低采样率替换到本段录波内
                    RateDTO tmpRateDTO = new RateDTO();
                    // C# 原实现中 bool 默认是 false，16~31 点/周波段也应按普通抽点处理
                    tmpRateDTO.bRMSFlag = false;
                    // 有效值标志,如果是有效值，那么就需要反向补点，而不是抽点
                    if (comtradeCfgDTO.getLstRate().get(iRate).getNOneSample() >= 32) {
                        //YXB 2025-08-27
                        tmpRateDTO.bRMSFlag = false;
                    }
                    //如果采样是全波有效值或者半波有效值，需要去补足周波点数 YXB 2025-08-27
                    else if (comtradeCfgDTO.getLstRate().get(iRate).getNOneSample() <= 2) {
                        //YXB 2025-08-27
                        tmpRateDTO.bRMSFlag = true;
                    }
                    newLstRate.add(tmpRateDTO);
                    //iFlag =3 一定不进行抽点算法
                    if (iType != 3) {
                        //true 抽点算法（当前采样率跟统一采样率不一样则是抽点，否则是未抽点）
                        if (!Objects.equals(comtradeCfgDTO.getLstRate().get(iRate).getNOneSample(), comtradeCfgDTO.getFinalSampleRate())) {
                            newLstRate.get(nnInd).setNOneSample(comtradeCfgDTO.getFinalSampleRate());
                            // 计算本段录波按照最低采样点应该有多少录波
                            newLstRate.get(nnInd).setNSampleNum(comtradeCfgDTO.getFinalSampleRate() * nWaveNum);
                        } else {
                            newLstRate.get(nnInd).setNOneSample(comtradeCfgDTO.getLstRate().get(iRate).getNOneSample());
                            // 计算本段录波按照最低采样点应该有多少录波
                            newLstRate.get(nnInd).setNSampleNum(comtradeCfgDTO.getLstRate().get(iRate).getNOneSample() * nWaveNum);
                        }
                    } else {
                        newLstRate.get(nnInd).setNOneSample(comtradeCfgDTO.getLstRate().get(iRate).getNOneSample());
                        // 计算本段录波按照最低采样点应该有多少录波
                        newLstRate.get(nnInd).setNSampleNum(comtradeCfgDTO.getLstRate().get(iRate).getNOneSample() * nWaveNum);
                    }

                    nnInd++;
                }
                // 偏移量,采样间隔
                long nOffSet = 0, nWaveSpan;
                //两个点之间的时间差
                float fValue, dfValue;
                // 计算不同块的采样率
                int nIndex = 0;
                // .CFG中采样率
                RateDTO tmpRateDTO;
                // nBlockNum 总循环次数
                for (int i = 0; i < nBlockNum; i++) {
                    tmpRateDTO = comtradeCfgDTO.getLstRate().get(nIndex);
                    // 判断是否进入下一段
                    if (i == tmpRateDTO.getNSampleNum() + nOffSet) {
                        nOffSet += tmpRateDTO.getNSampleNum();
                        nIndex++;
                        if (nIndex == nnInd) {
                            break;
                        }
                    }
                    tmpRateDTO = comtradeCfgDTO.getLstRate().get(nIndex);
                    dfValue = (float) 20 / tmpRateDTO.getNOneSample();
                    // C# 原实现中 RMS 段与普通抽点是两条独立控制流，不能挂在同一个取模条件下
                    if (Boolean.TRUE.equals(newLstRate.get(nIndex).bRMSFlag)) {
                        //计算本段补点采样间隔
                        nWaveSpan = newLstRate.get(nIndex).getNOneSample() / tmpRateDTO.getNOneSample();
                        // 计算有多少个周波
                        long allWaveTemp = newLstRate.get(nIndex).getNSampleNum() / newLstRate.get(nIndex).getNOneSample();
                        // 本段需要补多少点
                        long allempSample = newLstRate.get(nIndex).getNOneSample();
                        int segmentEndIndex = (int) (nOffSet + tmpRateDTO.getNSampleNum() - 1);
                        for (int iWaveTemp = 0; iWaveTemp < allWaveTemp; iWaveTemp++) {
                            for (int mTempSample = 0; mTempSample < allempSample; mTempSample++) {
                                // 2 点/周波时，半周波位置需要切换到该周波的第二个原始采样点
                                if (mTempSample / nWaveSpan == 1 && mTempSample % nWaveSpan == 0) {
                                    i++;
                                }
                                //存储局部数据集合，包含了时间，A，B，C三相
                                List<Float> tmpWaveData = new ArrayList<>();
                                for (int j = 0; j < comtradeCfgDTO.getNAnalogNum(); j++) {
                                    if (comtradeCfgDTO.getLstAnalogDTO().get(j).getSzPhasicName().equalsIgnoreCase("N")) {
                                        break;
                                    }
                                    float fCoef = comtradeCfgDTO.getLstAnalogDTO().get(j).getFCoefficent();
                                    fValue = BitConverter.byte2ToUnsignedShort(datArray, i * nBlockSize + 2 * 4 + j * 2) * fCoef;
                                    //WW 2019-11-14
                                    /*************************
                                     * 1、接口返回的默认是二次值
                                     * 2、P是一次值 S是二次值
                                     * 3、S(二次值）情况下：
                                     *     ①、单位为"V"时候则直接等于；
                                     *     ②、单位为"kV"时候需要乘以1000
                                     * 4、P(一次值）情况下：
                                     *     ①、单位为"V"时候则直接等于；
                                     *     ②、单位为"kV"时候需要乘以1000
                                     *************************/
                                    //P是一次值 S是二次值
                                    if (comtradeCfgDTO.getLstAnalogDTO().get(j).getSzValueType().equalsIgnoreCase("S")) {
                                        //判断单位是V还是kV
                                        if (comtradeCfgDTO.getLstAnalogDTO().get(j).getSzUnitName().equalsIgnoreCase("KV")) {
                                            fValue = fValue * 1000.0f;
                                        } else {
                                            fValue = fValue;
                                        }
                                    }
                                    //P是一次值 S是二次值
                                    else if (comtradeCfgDTO.getLstAnalogDTO().get(j).getSzValueType().equalsIgnoreCase("P")) {
                                        //判断单位是V还是kV
                                        if (comtradeCfgDTO.getLstAnalogDTO().get(j).getSzUnitName().equalsIgnoreCase("V")) {
                                            //根据cfg内的变比，将一次值转换成二次值
                                            if (comtradeCfgDTO.getLstAnalogDTO().get(j).getFPrimary() != 0.0f) {
                                                fValue = fValue * comtradeCfgDTO.getLstAnalogDTO().get(j).getFSecondary() / comtradeCfgDTO.getLstAnalogDTO().get(j).getFPrimary();
                                            } else {
                                                fValue = fValue;
                                            }
                                        }
                                        //判断单位是V还是kV
                                        else if (comtradeCfgDTO.getLstAnalogDTO().get(j).getSzUnitName().equalsIgnoreCase("KV")) {
                                            //根据cfg内的变比，将一次值转换成二次值
                                            if (comtradeCfgDTO.getLstAnalogDTO().get(j).getFPrimary() != 0.0f) {
                                                fValue = fValue * 1000.0f * comtradeCfgDTO.getLstAnalogDTO().get(j).getFSecondary() / comtradeCfgDTO.getLstAnalogDTO().get(j).getFPrimary();
                                            } else {
                                                fValue = fValue;
                                            }
                                        } else //还有可能是  电流，单位是A
                                        {
                                            //根据cfg内的变比，将一次值转换成二次值
                                            if (comtradeCfgDTO.getLstAnalogDTO().get(j).getFPrimary() != 0.0f) {
                                                fValue = fValue * comtradeCfgDTO.getLstAnalogDTO().get(j).getFSecondary() / comtradeCfgDTO.getLstAnalogDTO().get(j).getFPrimary();
                                            } else {
                                                fValue = fValue;
                                            }
                                        }
                                    }

                                    //xValue前移量，假如是第一次时候则需要前移
                                    if (!blxValue && j == 0) {
                                        xValueAll = (float) (i * 20) / tmpRateDTO.getNOneSample() - comtradeCfgDTO.getNPush();
                                        blxValue = true;
                                        //只增加一个xValue的值 //增加时间值
                                        tmpWaveData.add((float) (Math.round(xValueAll * 100)) / 100);
                                    } else if (j == 0) {
                                        xValueAll += (float) dfValue / nWaveSpan;
                                        //只增加一个xValue的值 //增加时间值
                                        tmpWaveData.add((float) (Math.round(xValueAll * 100)) / 100);
                                    }

                                    //不同通道yValue的值都需要增加，最终成ABC三相 //每个通道的值
                                    tmpWaveData.add((float) (Math.round(fValue * 100)) / 100);
                                }
                                //把每个单独的值赋予到整体里面去
                                listWaveData.add(tmpWaveData);
                            }
                            // 本周波处理完成后，推进到下一周波的原始采样点
                            if (iWaveTemp < (allWaveTemp - 1)) {
                                i++;
                            }
                        }
                        // 某些文件的段点数并不是原始每周波点数的整倍数。
                        // RMS 段处理完成后，强制把原始游标对齐到当前段末尾，
                        // 这样外层 for 的下一次自增才能稳定落到下一段起点，避免重复进入同一 RMS 段。
                        i = segmentEndIndex;
                        continue;
                    }

                    // 计算本段抽点采样间隔
                    nWaveSpan = tmpRateDTO.getNOneSample() / newLstRate.get(nIndex).getNOneSample();
                    // 判断是否到了需要抽的采样点
                    if (i % nWaveSpan == 0) {
                        // 计算每个通道的值
                        //存储局部数据集合，包含了时间，A，B，C三相
                        List<Float> tmpWaveData = new ArrayList<>();
                        for (int j = 0; j < comtradeCfgDTO.getNAnalogNum(); j++) {
                            //数据只有电压ABC三相数据，不展示U0、I0等数据 YXB2020-10-09 去除相别为N相的数据
                            if (comtradeCfgDTO.getLstAnalogDTO().get(j).getSzPhasicName().equalsIgnoreCase("N")) {
                                break;
                            }

                            float fCoef = comtradeCfgDTO.getLstAnalogDTO().get(j).getFCoefficent();
                            fValue = BitConverter.byte2ToUnsignedShort(datArray, i * nBlockSize + 2 * 4 + j * 2) * fCoef;

                            //WW 2019-11-14
                            /**************************
                             * 1、接口返回的默认是二次值
                             * 2、P是一次值 S是二次值
                             * 3、S(二次值）情况下：
                             *     ①、单位为"V"时候则直接等于；
                             *     ②、单位为"kV"时候需要乘以1000
                             * 4、P(一次值）情况下：
                             *     ①、单位为"V"时候则直接等于；
                             *     ②、单位为"kV"时候需要乘以1000
                             **************************/
                            //P是一次值 S是二次值
                            if (comtradeCfgDTO.getLstAnalogDTO().get(j).getSzValueType().equalsIgnoreCase("S")) {
                                //判断单位是V还是kV
                                if (comtradeCfgDTO.getLstAnalogDTO().get(j).getSzUnitName().equalsIgnoreCase("KV")) {
                                    fValue = fValue * 1000.0f;
                                } else {
                                    fValue = fValue;
                                }
                            }
                            //P是一次值 S是二次值
                            else if (comtradeCfgDTO.getLstAnalogDTO().get(j).getSzValueType().equalsIgnoreCase("P")) {
                                //判断单位是V还是kV
                                if (comtradeCfgDTO.getLstAnalogDTO().get(j).getSzUnitName().equalsIgnoreCase("V")) {
                                    //根据cfg内的变比，将一次值转换成二次值
                                    if (comtradeCfgDTO.getLstAnalogDTO().get(j).getFPrimary() != 0.0f) {
                                        fValue = fValue * comtradeCfgDTO.getLstAnalogDTO().get(j).getFSecondary() / comtradeCfgDTO.getLstAnalogDTO().get(j).getFPrimary();
                                    } else {
                                        fValue = fValue;
                                    }
                                }
                                //判断单位是V还是kV
                                else if (comtradeCfgDTO.getLstAnalogDTO().get(j).getSzUnitName().equalsIgnoreCase("KV")) {
                                    //根据cfg内的变比，将一次值转换成二次值
                                    if (comtradeCfgDTO.getLstAnalogDTO().get(j).getFPrimary() != 0.0f) {
                                        fValue = fValue * 1000.0f * comtradeCfgDTO.getLstAnalogDTO().get(j).getFSecondary() / comtradeCfgDTO.getLstAnalogDTO().get(j).getFPrimary();
                                    } else {
                                        fValue = fValue;
                                    }
                                } else //还有可能是  电流，单位是A
                                {
                                    //根据cfg内的变比，将一次值转换成二次值
                                    if (comtradeCfgDTO.getLstAnalogDTO().get(j).getFPrimary() != 0.0f) {
                                        fValue = fValue * comtradeCfgDTO.getLstAnalogDTO().get(j).getFSecondary() / comtradeCfgDTO.getLstAnalogDTO().get(j).getFPrimary();
                                    } else {
                                        fValue = fValue;
                                    }
                                }
                            }
                            //xValue前移量，假如是第一次时候则需要前移
                            if (!blxValue && j == 0) {
                                xValueAll = (float) (i * 20) / tmpRateDTO.getNOneSample() - comtradeCfgDTO.getNPush();
                                blxValue = true;
                                //只增加一个xValue的值 //增加时间值
                                tmpWaveData.add((float) (Math.round(xValueAll * 100)) / 100);
                            } else if (j == 0) {
                                xValueAll += (float) nWaveSpan * dfValue;
                                //只增加一个xValue的值 //增加时间值
                                tmpWaveData.add((float) (Math.round(xValueAll * 100)) / 100);
                            }

                            //不同通道yValue的值都需要增加，最终成ABC三相 //每个通道的值
                            tmpWaveData.add((float) (Math.round(fValue * 100)) / 100);
                        }
                        //把每个单独的值赋予到整体里面去
                        listWaveData.add(tmpWaveData);
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new BusinessException(WaveFileResponseEnum.DAT_DATA_ERROR);
        }

        return listWaveData;
    }

    private List<List<Float>> getComtradeDatNoAddPoints(ComtradeCfgDTO comtradeCfgDTO, InputStream datStream, int iType) {
        //返回数据，如果仅仅做展示后期考虑换String类型，降低内存开销
        List<List<Float>> listWaveData = new ArrayList<>();
        //初始化xValue的值
        float xValueAll = 0;
        //判断是否首次登陆
        boolean blxValue = false;
        byte[] datArray;
        try {
            datArray = IoUtil.readBytes(datStream);
            if (ArrayUtil.isEmpty(datArray)) {
                throw new BusinessException(WaveFileResponseEnum.DAT_DATA_ERROR);
            }
            // 计算每个单独的数据块的大小 4个字节的序号 4个字节的时间 2个字节的值
            // 示例中的排布是 4个字节的序号 4个字节的时间 UA(2字节) UB(2字节) UC(2字节) IA(2字节) IB(2字节) IC(2字节)
            int nDigSize = (comtradeCfgDTO.getNDigitalNum() % 16) > 0 ? (comtradeCfgDTO.getNDigitalNum() / 16 + 1) * 2 : comtradeCfgDTO.getNDigitalNum() / 16 * 2;
            int nBlockSize = 2 * Integer.SIZE / 8 + comtradeCfgDTO.getNAnalogNum() * 2 + nDigSize;
            // 总长度除以每个块的大小
            int nBlockNum = (int)Math.floor(datArray.length / nBlockSize);

            // 获取采样率
            int finalSampleRate = getFinalWaveSample(comtradeCfgDTO.getLstRate(), iType);
            if (finalSampleRate != -1) {
                //设置最终采样率
                comtradeCfgDTO.setFinalSampleRate(finalSampleRate);
                // 计算转换后的采样率
                int nnInd = 0;
                // 抽点后总共多少点数据
                int nWaveNum;
                //抽点后新的的采样率
                List<RateDTO> newLstRate = new ArrayList<>();
                for (int iRate = 0; iRate < comtradeCfgDTO.getNRates(); iRate++) {
                    if (comtradeCfgDTO.getLstRate().get(iRate).getNOneSample() >= 32) {
                    // 计算本段录波总共有多少波形
                    nWaveNum = comtradeCfgDTO.getLstRate().get(iRate).getNSampleNum() / comtradeCfgDTO.getLstRate().get(iRate).getNOneSample();
                    //设置总波形大小
                    comtradeCfgDTO.setNAllWaveNum(comtradeCfgDTO.getNAllWaveNum() + nWaveNum);
                    // 将最低采样率替换到本段录波内
                    RateDTO tmpRateDTO = new RateDTO();
                    // 有效值标志,如果是有效值，那么就需要反向补点，而不是抽点
//                    if (comtradeCfgDTO.getLstRate().get(iRate).getNOneSample() >= 32) {
//                        //YXB 2025-08-27
//                        tmpRateDTO.bRMSFlag = false;
//                    }
//                    //如果采样是全波有效值或者半波有效值，需要去补足周波点数 YXB 2025-08-27
//                    else if (comtradeCfgDTO.getLstRate().get(iRate).getNOneSample() <= 2) {
//                        //YXB 2025-08-27
//                        tmpRateDTO.bRMSFlag = true;
//                    }
                    newLstRate.add(tmpRateDTO);
                    //iFlag =3 一定不进行抽点算法
                    if (iType != 3) {
                        //true 抽点算法（当前采样率跟统一采样率不一样则是抽点，否则是未抽点）
                        if (!Objects.equals(comtradeCfgDTO.getLstRate().get(iRate).getNOneSample(), comtradeCfgDTO.getFinalSampleRate())) {
                            newLstRate.get(nnInd).setNOneSample(comtradeCfgDTO.getFinalSampleRate());
                            // 计算本段录波按照最低采样点应该有多少录波
                            newLstRate.get(nnInd).setNSampleNum(comtradeCfgDTO.getFinalSampleRate() * nWaveNum);
                        } else {
                            newLstRate.get(nnInd).setNOneSample(comtradeCfgDTO.getLstRate().get(iRate).getNOneSample());
                            // 计算本段录波按照最低采样点应该有多少录波
                            newLstRate.get(nnInd).setNSampleNum(comtradeCfgDTO.getLstRate().get(iRate).getNOneSample() * nWaveNum);
                        }
                    } else {
                        newLstRate.get(nnInd).setNOneSample(comtradeCfgDTO.getLstRate().get(iRate).getNOneSample());
                        // 计算本段录波按照最低采样点应该有多少录波
                        newLstRate.get(nnInd).setNSampleNum(comtradeCfgDTO.getLstRate().get(iRate).getNOneSample() * nWaveNum);
                    }

                    // 正常的配置中采样率
                    comtradeCfgDTO.getLstRate().get(nnInd).setNOneSample(comtradeCfgDTO.getLstRate().get(iRate).getNOneSample());
                    comtradeCfgDTO.getLstRate().get(nnInd).setNSampleNum(comtradeCfgDTO.getLstRate().get(iRate).getNSampleNum());

                    nnInd++;
                    }
                }
                // 偏移量,采样间隔
                long nOffSet = 0, nWaveSpan;
                //两个点之间的时间差
                float fValue, dfValue;
                // 计算不同块的采样率
                int nIndex = 0;
                // 将最低采样率替换到本段录波内
                // .CFG中采样率
                RateDTO tmpRateDTO;
                // nBlockNum 总循环次数
                for (int i = 0; i < nBlockNum; i++) {
                    tmpRateDTO = comtradeCfgDTO.getLstRate().get(nIndex);
                    // 判断是否进入下一段
                    if (i == tmpRateDTO.getNSampleNum() + nOffSet) {
                        nOffSet += tmpRateDTO.getNSampleNum();
                        nIndex++;
                        if (nIndex == nnInd) {
                            break;
                        }
                    }
                    nWaveSpan = tmpRateDTO.getNOneSample() / newLstRate.get(nIndex).getNOneSample();
//                    tmpRateDTO = comtradeCfgDTO.getLstRate().get(nIndex);
//                    //YXB 2025-08-27 如果是有效值，那么需要去补点，而不是抽点
//                    if (newLstRate.get(nIndex).bRMSFlag == true) {
//                        //计算本段补点采样间隔
//                        nWaveSpan = newLstRate.get(nIndex).getNOneSample() / tmpRateDTO.getNOneSample();
//                    } else {
//                        // 计算本段抽点采样间隔
//                        nWaveSpan = tmpRateDTO.getNOneSample() / newLstRate.get(nIndex).getNOneSample();
//                    }

                    dfValue = (float) 20 / tmpRateDTO.getNOneSample();
                    // 判断是否到了需要抽的采样点
                    if (i % nWaveSpan == 0) {
                        // 计算每个通道的值
                        //存储局部数据集合，包含了时间，A，B，C三相
                        List<Float> tmpWaveData = new ArrayList<>();
                        for (int j = 0; j < comtradeCfgDTO.getNAnalogNum(); j++) {
                            //数据只有电压ABC三相数据，不展示U0、I0等数据 YXB2020-10-09 去除相别为N相的数据
                            if (comtradeCfgDTO.getLstAnalogDTO().get(j).getSzPhasicName().equalsIgnoreCase("N")) {
                                break;
                            }

                            float fCoef = comtradeCfgDTO.getLstAnalogDTO().get(j).getFCoefficent();
                            fValue = BitConverter.byte2ToUnsignedShort(datArray, i * nBlockSize + 2 * 4 + j * 2) * fCoef;

                            //WW 2019-11-14
                            /**************************
                             * 1、接口返回的默认是二次值
                             * 2、P是一次值 S是二次值
                             * 3、S(二次值）情况下：
                             *     ①、单位为"V"时候则直接等于；
                             *     ②、单位为"kV"时候需要乘以1000
                             * 4、P(一次值）情况下：
                             *     ①、单位为"V"时候则直接等于；
                             *     ②、单位为"kV"时候需要乘以1000
                             **************************/
                            //P是一次值 S是二次值
                            if (comtradeCfgDTO.getLstAnalogDTO().get(j).getSzValueType().equalsIgnoreCase("S")) {
                                //判断单位是V还是kV
                                if (comtradeCfgDTO.getLstAnalogDTO().get(j).getSzUnitName().equalsIgnoreCase("KV")) {
                                    fValue = fValue * 1000.0f;
                                } else {
                                    fValue = fValue;
                                }
                            }
                            //P是一次值 S是二次值
                            else if (comtradeCfgDTO.getLstAnalogDTO().get(j).getSzValueType().equalsIgnoreCase("P")) {
                                //判断单位是V还是kV
                                if (comtradeCfgDTO.getLstAnalogDTO().get(j).getSzUnitName().equalsIgnoreCase("V")) {
                                    //根据cfg内的变比，将一次值转换成二次值
                                    if (comtradeCfgDTO.getLstAnalogDTO().get(j).getFPrimary() != 0.0f) {
                                        fValue = fValue * comtradeCfgDTO.getLstAnalogDTO().get(j).getFSecondary() / comtradeCfgDTO.getLstAnalogDTO().get(j).getFPrimary();
                                    } else {
                                        fValue = fValue;
                                    }
                                }
                                //判断单位是V还是kV
                                else if (comtradeCfgDTO.getLstAnalogDTO().get(j).getSzUnitName().equalsIgnoreCase("KV")) {
                                    //根据cfg内的变比，将一次值转换成二次值
                                    if (comtradeCfgDTO.getLstAnalogDTO().get(j).getFPrimary() != 0.0f) {
                                        fValue = fValue * 1000.0f * comtradeCfgDTO.getLstAnalogDTO().get(j).getFSecondary() / comtradeCfgDTO.getLstAnalogDTO().get(j).getFPrimary();
                                    } else {
                                        fValue = fValue;
                                    }
                                } else //还有可能是  电流，单位是A
                                {
                                    //根据cfg内的变比，将一次值转换成二次值
                                    if (comtradeCfgDTO.getLstAnalogDTO().get(j).getFPrimary() != 0.0f) {
                                        fValue = fValue *comtradeCfgDTO.getLstAnalogDTO().get(j).getFSecondary() / comtradeCfgDTO.getLstAnalogDTO().get(j).getFPrimary();
                                    } else {
                                        fValue = fValue;
                                    }
                                }
                            }
                            //xValue前移量，假如是第一次时候则需要前移
                            if (!blxValue && j == 0) {
                                xValueAll = (float) (i * 20) / tmpRateDTO.getNOneSample() - comtradeCfgDTO.getNPush();
                                blxValue = true;
                                //只增加一个xValue的值 //增加时间值
                                tmpWaveData.add((float) (Math.round(xValueAll * 100)) / 100);
                            } else if (j == 0) {
                                xValueAll += (float) nWaveSpan * dfValue;
                                //只增加一个xValue的值 //增加时间值
                                tmpWaveData.add((float) (Math.round(xValueAll * 100)) / 100);
                            }

                            //不同通道yValue的值都需要增加，最终成ABC三相 //每个通道的值
                            tmpWaveData.add((float) (Math.round(fValue * 100)) / 100);
                        }
                        //把每个单独的值赋予到整体里面去
                        listWaveData.add(tmpWaveData);

                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new BusinessException(WaveFileResponseEnum.DAT_DATA_ERROR);
        }

        return listWaveData;
    }


    /*********************************
     * 获取最小(最终)采样率方法
     * @param lstRate  cfg中关于采样率参数
     * @return 返回最小采样率
     **********************************/
    private int getFinalWaveSample(List<RateDTO> lstRate, int iType) {
        // 最终返回采样率
        int nFinalOneSample = -1;
        // 最小采样率
        int nMinOneSample = -1;
        if (!lstRate.isEmpty()) {
            nMinOneSample = lstRate.get(0).getNOneSample();
            int tmpOneSample;
            for (RateDTO rateDTO : lstRate) {
                tmpOneSample = rateDTO.getNOneSample();
                //YXB 2025-08-27  32->16
                if (tmpOneSample >= 16) {
                    if (nMinOneSample > tmpOneSample) {
                        nMinOneSample = tmpOneSample;
                    }
                }
            }
        }
        /********************************************************
         * iFlag == 0  高级算法的要求，采样率只能是32-128
         * iFlag == 1  普通展示，采样率按照cfg里面最小的（大于32）
         * iFlag == 2  App抽点要求，采样率抽点成32
         * iFlag == 3  高级算法原始波形（大于32）
         ********************************************************/
        switch (iType) {
            case 0:
                if (nMinOneSample < 32) {
                    nFinalOneSample = 32;
                } else if (nMinOneSample > 128) {
                    nFinalOneSample = 128;
                } else {
                    nFinalOneSample = nMinOneSample;
                }
                break;
            case 2:
                nFinalOneSample = 32;
                break;

            default:
                nFinalOneSample = nMinOneSample;
                break;

        }
        return nFinalOneSample;
    }


    /*********************************
     * 离线波形导入时获取突变量算法
     * param tmpListWave 波形原始数据
     * param finalSampleRate 最终采样率
     **********************************/
    private MutationDTO getMutationValue(List<List<Float>> lstWave, float finalSampleRate) {
        MutationDTO mutationDTO = new MutationDTO();
        // 计算有效值
        double fSumA = 0.0, fSumB = 0.0, fSumC = 0.0;
        double fValidA, fValidB, fValidC;
        double fValue = 0.0;
        // 全波有效值 ； (int)fs / 2;//半波有效值
        int HalfTs = (int) finalSampleRate;
        //瞬时波形数据_瞬时---前推周波的值_瞬时----周波的值_突变量----前推周波的值_突变量
        List<Float> tmpRealValue, forwardRealValue, tblValue, forwardTblValue;
        // 计算有效值算法
        for (int i = 0; i < lstWave.size(); i++) {
            //获取每一项的值
            tmpRealValue = lstWave.get(i);
            //包含了时间、A、B、C三相
            if (tmpRealValue.size() >= 4) {
                fSumA += Math.pow(tmpRealValue.get(1), 2);
                fSumB += Math.pow(tmpRealValue.get(2), 2);
                fSumC += Math.pow(tmpRealValue.get(3), 2);
                // 计算有效值
                List<Float> tmpRmsValue = new ArrayList<>();
                if (i >= finalSampleRate) {
                    forwardRealValue = lstWave.get(i - HalfTs);
                    fSumA -= Math.pow(forwardRealValue.get(1), 2);
                    fSumB -= Math.pow(forwardRealValue.get(2), 2);
                    fSumC -= Math.pow(forwardRealValue.get(3), 2);
                }
                // 计算突变量值
                List<Float> tmpTblValue = new ArrayList<>();
                //获取时间
                tmpTblValue.add(tmpRealValue.get(0));
                if (i >= HalfTs) {
                    //获取前推周波的值
                    tblValue = lstWave.get(i);
                    //获取前推周波的值
                    forwardTblValue = lstWave.get(i - HalfTs);
                    tmpTblValue.add(tblValue.get(1) - forwardTblValue.get(1));
                    tmpTblValue.add(tblValue.get(2) - forwardTblValue.get(2));
                    tmpTblValue.add(tblValue.get(3) - forwardTblValue.get(3));
                } else {
                    tmpTblValue.add(0f);
                    tmpTblValue.add(0f);
                    tmpTblValue.add(0f);
                }
                fValidA = Math.sqrt(fSumA / HalfTs);
                fValidB = Math.sqrt(fSumB / HalfTs);
                fValidC = Math.sqrt(fSumC / HalfTs);

                if (i >= finalSampleRate) {
                    if (fValidA < mutationDTO.getFMinMagA()) {
                        mutationDTO.setFMinMagA(fValidA);
                    }
                    if (fValidB < mutationDTO.getFMinMagB()) {
                        mutationDTO.setFMinMagB(fValidB);
                    }
                    if (fValidC < mutationDTO.getFMinMagC()) {
                        mutationDTO.setFMinMagC(fValidC);
                    }
                }
                //RMS获取//获取时间
                tmpRmsValue.add(tmpRealValue.get(0));
                tmpRmsValue.add((float) fValidA);
                tmpRmsValue.add((float) fValidB);
                tmpRmsValue.add((float) fValidC);
                mutationDTO.getListRms_Offline().add(tmpRmsValue);

                //RMS获取
                mutationDTO.getListTBL_Offline().add(tmpTblValue);
            }
        }
        return mutationDTO;
    }

    /*********************************
     * 离线波形导入时获取暂降特征值的算法
     * param lstWave 波形原始数据
     * param tblWave 突变量波形数据
     * param rmstWave RMS数据
     * param comtradeCfgDTO 波形CFG配置参数
     * param blType 计算方式
     * List<List<Float>>  返回暂降数据
     **********************************/
    private List<EigenvalueDTO> getEventValue(List<List<Float>> lstWave, MutationDTO mutationDTO, ComtradeCfgDTO comtradeCfgDTO, boolean blType) {
        List<List<Float>> tblWave = mutationDTO.getListTBL_Offline();
        List<List<Float>> rmstWave = mutationDTO.getListRms_Offline();
        //额定电压
        float fBase = 57.74f;
        //假如所选的是380V，那么PT变比是1:1，因此额定电压要选220 //模拟量通道记录
        List<AnalogDTO> lstAnalogDTO = comtradeCfgDTO.getLstAnalogDTO();
        if (!lstAnalogDTO.isEmpty()) {
            if (lstAnalogDTO.get(0).getFPrimary() / lstAnalogDTO.get(0).getFSecondary() <= 1) {
                fBase = 220f;
            }
        }
        //采样率
        int nSJ = comtradeCfgDTO.getFinalSampleRate().intValue();
        /*********************************
         * 0是特征幅值（残余电压百分比）
         * 1是特征幅值（残余电压）
         * 2额定定压（动态电压）
         * 3是持续时间
         **********************************/
        //ABC三相分析结果
        List<EigenvalueDTO> lstEigenvalueDTO = new ArrayList<>();
        for (int i = 0; i < 3; i++) {
            //低电压和郭电压标识值
            int iDDY = 0, iGDY;
            //某一项分析结果
            EigenvalueDTO eigenvalueDTO = new EigenvalueDTO();
            iDDY = App_Disturb_DDY1(lstWave, tblWave, rmstWave, nSJ, i, blType);
            if (Disturb_Val == 0 && Disturb_SJ == 0) {
                //判断A相的暂态事件类型是否为短时中断或电压暂降
                iGDY = App_Disturb_GDY1(lstWave, tblWave, rmstWave, nSJ, i, blType);
                if (iGDY != 0) {
                    if (Disturb_Val != 0) {
                        if (blType) {
                            //征幅值（残余电压百分比）
                            eigenvalueDTO.setAmplitude(Disturb_Val / rmstWave.get(nSJ + 2).get(i + 1));
                            //特征幅值（残余电压）
                            eigenvalueDTO.setResidualVoltage(Disturb_Val);
                            //额定定压（动态电压）
                            eigenvalueDTO.setRatedVoltage(rmstWave.get(nSJ + 2).get(i + 1));
                        } else {
                            //征幅值（残余电压百分比）
                            eigenvalueDTO.setAmplitude(Disturb_Val / 57.74f);
                            //特征幅值（残余电压）
                            eigenvalueDTO.setResidualVoltage(Disturb_Val);
                            //额定定压（动态电压）
                            eigenvalueDTO.setRatedVoltage(57.74f);
                        }
                    }
                }
                //如果都没有找到，那么需要从曲线里面找出比较小的值来计算
                else {
                    double rate = 0f;
                    //残余电压
                    double residualVoltage = 0.f;
                    switch (i) {
                        case 0:
                            residualVoltage = mutationDTO.getFMinMagA();
                            break;
                        case 1:
                            residualVoltage = mutationDTO.getFMinMagB();
                            break;
                        case 2:
                            residualVoltage = mutationDTO.getFMinMagC();
                            break;
                        default:
                            break;
                    }

                    if (residualVoltage != -1) {
                        rate = residualVoltage / fBase > 1 ? 1.0f : residualVoltage / fBase;
                    }
                    //征幅值（残余电压百分比）
                    eigenvalueDTO.setAmplitude((float) rate);
                    //特征幅值（残余电压）
                    eigenvalueDTO.setResidualVoltage((float) residualVoltage);
                    //额定定压（动态电压）
                    eigenvalueDTO.setRatedVoltage(fBase);
                }
            } else {
                if (Disturb_Val != 0) {
                    if (blType) {
                        //征幅值（残余电压百分比）
                        eigenvalueDTO.setAmplitude(Disturb_Val / rmstWave.get(nSJ + 2).get(i + 1));
                        //特征幅值（残余电压）
                        eigenvalueDTO.setResidualVoltage(Disturb_Val);
                        //额定定压（动态电压）
                        eigenvalueDTO.setRatedVoltage(rmstWave.get(nSJ + 2).get(i + 1));
                    } else {
                        //征幅值（残余电压百分比）
                        eigenvalueDTO.setAmplitude(Disturb_Val / 57.74f);
                        //特征幅值（残余电压）
                        eigenvalueDTO.setResidualVoltage(Disturb_Val);
                        //额定定压（动态电压）
                        eigenvalueDTO.setRatedVoltage(57.74f);
                    }
                }
            }
            //持续时间
            eigenvalueDTO.setDurationTime(Disturb_SJ / nSJ * 20.0f);
            lstEigenvalueDTO.add(eigenvalueDTO);
        }
        return lstEigenvalueDTO;
    }

    /***
     * 暂降幅值
     */
    private float Disturb_Val = 0;
    /***
     * 持续时间
     */
    private double Disturb_Time = 0;
    /***
     * 暂态启动点号
     */
    private float Disturb_SJ = 0;

    /***
     * 暂降幅值90%
     */
    private float Un09 = (0.90f * 57.74f);
    /***
     * 暂降幅值2%
     */
    private float Un002 = (0.02f * 57.74f);
    /***
     * 暂降幅值110%
     */
    private float Un110 = (1.10f * 57.74f);

    /************************************
     *低电压的判据 包含了暂降和中断
     * @param realWave  原始波形数据
     * @param tblWave   突变量波形数据
     * @param rmstWave  RMS波形数据
     * @param nCirclePoint 采样率
     * @param nType  类别 0：A相，1：B相，2：C相
     * @param blFlag 浮动门槛和固定门槛
     *************************************/
    private int App_Disturb_DDY1(List<List<Float>> realWave, List<List<Float>> tblWave, List<List<Float>> rmstWave, int nCirclePoint, int nType, boolean blFlag) {
        Disturb_Val = 0;
        Disturb_Time = 0;
        Disturb_SJ = 0;

        /****************************
         * ADC 临时的突变量判据
         * Disturb_JS_Val 事件启动点时刻的有效值
         ****************************/
        double temp, ADC, Disturb_JS_Val = 0;
        int iTbl = 0;
        long Disturb_QD = 0;
        //nSJ就是全波的采样率,nHalfSJ是半波的采样率
        int nSJ = nCirclePoint, nHalfSJ = nCirclePoint / 2;
        //定义90%和20%额定电压
        float fUN09 = Un09, fUN002 = Un002;
        //增加浮动门槛判断
        if (blFlag) {
            /****************************
             * 计算值去掉一个前一个周波后
             * 取第二个周波的第二个有效值
             * 第一个值是时间、A,B,C三相
             ****************************/
            if (rmstWave.size() > nSJ + 2) {
                fUN09 = rmstWave.get(nSJ + 2).get(nType + 1) * 0.9f;
                fUN002 = rmstWave.get(nSJ + 2).get(nType + 1) * 0.02f;
            }
        }
        /****************************
         * 从第二个周波开始
         ****************************/
        for (int i = nSJ; i < realWave.size(); i++) {
            //获取RMS有效值
            float rmsValue = rmstWave.get(i).get(nType + 1);
            //电压扰动启动判别
            if (Disturb_QD == 0) {
                //有效值小于90%
                if (rmsValue < fUN09) {
                    Disturb_QD = 0xff;
                    Disturb_Val = rmsValue;
                    Disturb_JS_Val = rmsValue;
                    //寻找突变点
                    for (int j = 0; j < nHalfSJ; j++) {
                        //临时的突变量
                        ADC = tblWave.get(i - nHalfSJ + j).get(nType + 1);
                        //临时的突变量小于0的时候取绝对值
                        if (ADC < 0) {
                            ADC = 0 - ADC;
                        }
                        if (ADC > fUN002) {
                            Disturb_SJ += (nHalfSJ - j);
                            iTbl = (i - nHalfSJ + j);
                            break;
                        }
                    }
                }
            }
            //电压扰动返回判别
            else {
                if (rmsValue < (fUN09 + fUN002)) {
                    Disturb_SJ++;
                    if (Disturb_Val > rmsValue) {
                        Disturb_Val = rmsValue;
                    }
                    Disturb_JS_Val = rmsValue;
                } else {
                    if (Disturb_SJ >= (nSJ + nHalfSJ)) {
                        //20%突变量标志
                        int iFlag = 0;
                        for (int j = 0; j < nHalfSJ; j++) {
                            iFlag = j;
                            //临时的突变量
                            ADC = tblWave.get(i - nHalfSJ + j).get(nType + 1);
                            //临时的突变量小于0的时候取绝对值
                            if (ADC < 0) {
                                ADC = 0 - ADC;
                            }
                            if (ADC > fUN002) {
                                break;
                            }
                        }
                        Disturb_SJ -= (nHalfSJ - iFlag);
                        Disturb_Time = ((double) Disturb_SJ) * 20 / nSJ;
                        return iTbl;
                    } else {
                        Disturb_SJ++;
                        ADC = realWave.get(i).get(nType + 1);
                        if (ADC < 0) {
                            ADC = 0 - ADC;
                        }
                        temp = rmsValue - Disturb_JS_Val;
                        if (temp < 0) {
                            temp = 0 - temp;
                        }
                        if ((ADC > 100) && (temp < 0.1)) {
                            Disturb_SJ -= (nHalfSJ + 1);
                            Disturb_Time = ((double) Disturb_SJ) * 20 / nSJ + 1;
                            return iTbl;
                        }
                    }
                    Disturb_JS_Val = rmsValue;
                }
            }
        }
        return iTbl;
    }


    /************************************
     *过电压的判据
     * @param realWave  原始波形数据
     * @param tblWave   突变量波形数据
     * @param rmstWave  RMS波形数据
     * @param nCirclePoint 采样率
     * @param nType  类别 0：A相，1：B相，2：C相
     * @param blFlag 浮动门槛和固定门槛
     * @return
     *************************************/
    private int App_Disturb_GDY1(List<List<Float>> realWave, List<List<Float>> tblWave, List<List<Float>> rmstWave, int nCirclePoint, int nType, boolean blFlag) {
        Disturb_Val = 0;
        Disturb_Time = 0;
        Disturb_SJ = 0;

        /****************************
         * ADC 临时的突变量判据
         * Disturb_JS_Val 事件启动点时刻的有效值
         ****************************/
        double temp, ADC, Disturb_JS_Val = 0;
        int iTbl = 0;
        long Disturb_QD = 0;
        //nSJ就是全波的采样率,nHalfSJ是半波的采样率
        int nSJ = nCirclePoint, nHalfSJ = nCirclePoint / 2;
        //定义110%和20%额定电压
        float fUN110 = Un110, fUN002 = Un002;
        //增加浮动门槛判断
        if (blFlag) {
            /****************************
             * 计算值去掉一个前一个周波后
             * 取第二个周波的第二个有效值
             * 第一个值是时间、A,B,C三相
             ****************************/
            if (rmstWave.size() > nSJ + 2) {
                fUN110 = rmstWave.get(nSJ + 2).get(nType + 1) * 1.1f;
                fUN002 = rmstWave.get(nSJ + 2).get(nType + 1) * 0.02f;
            }
        }
        /****************************
         * 从第二个周波开始
         ****************************/
        for (int i = nSJ; i < realWave.size(); i++) {
            //获取RMS有效值
            float rmsValue = rmstWave.get(i).get(nType + 1);
            //电压扰动启动判别
            if (Disturb_QD == 0) {
                if (rmsValue > fUN110) {
                    Disturb_QD = 0xff;
                    Disturb_Val = rmsValue;
                    Disturb_JS_Val = rmsValue;
                    //寻找突变点
                    for (int j = 0; j < nHalfSJ; j++) {
                        //临时的突变量
                        ADC = tblWave.get(i - nHalfSJ + j).get(nType + 1);
                        //临时的突变量小于0时候取绝对值
                        if (ADC < 0) {
                            ADC = 0 - ADC;
                        }
                        if (ADC > fUN002) {
                            Disturb_SJ += (nHalfSJ - j);
                            iTbl = (int) (i - nHalfSJ + j);
                            break;
                        }
                    }
                }
            }
            //电压扰动返回判别
            else {
                if (rmsValue > (fUN110 - fUN002)) {
                    Disturb_SJ++;
                    if (Disturb_Val < rmsValue) {
                        Disturb_Val = rmsValue;
                    }
                    Disturb_JS_Val = rmsValue;
                } else {
                    if (Disturb_SJ >= (nSJ + nHalfSJ)) {
                        int iFlag = 0;
                        for (int j = 0; j < nHalfSJ; j++) {
                            iFlag = j;
                            ADC = tblWave.get(i - nHalfSJ + j).get(nType + 1);
                            if (ADC < 0) {
                                ADC = 0 - ADC;
                            }
                            if (ADC > fUN002) {
                                break;
                            }
                        }
                        Disturb_SJ -= (nHalfSJ - iFlag);
                        Disturb_Time = (double) Disturb_SJ * 20 / nSJ;
                        return iTbl;
                    } else {
                        Disturb_SJ++;
                        ADC = realWave.get(i).get(nType + 1);
                        if (ADC < 0) {
                            ADC = 0 - ADC;
                        }
                        temp = rmsValue - Disturb_JS_Val;
                        if (temp < 0) {
                            temp = 0 - temp;
                        }
                        if ((ADC > 100) && (temp < 0.1)) {
                            Disturb_SJ -= (nHalfSJ + 1);
                            Disturb_Time = Disturb_SJ * 20 / nSJ + 1;
                            return iTbl;
                        }
                    }
                    Disturb_JS_Val = rmsValue;
                }
            }
        }
        return iTbl;
    }


    /*********************************
     * 获取波形标题的方法
     * param tmpComtradeCfgDTO 文件路径
     * return  返回List<String>返回数据格式说明
     **********************************/
    private void getWaveTitle(WaveDataDTO waveDataDTO, ComtradeCfgDTO comtradeCfgDTO) {
        //编辑数据标题 YXB2020-10-09 去除相别为N相的数据//存储数据标题
        List<String> tmpWaveTitle = new ArrayList<>();
        List<String> channelName = new ArrayList<>();
        // 模拟量通道记录类
        AnalogDTO analogDTO;
        tmpWaveTitle.add("Time");
        channelName.add("/");
        String strUnit;
        for (int j = 0; j < comtradeCfgDTO.getNAnalogNum(); j++) {
            analogDTO = comtradeCfgDTO.getLstAnalogDTO().get(j);
            // 假如为N相则跳过
            if (!StrUtil.equals(analogDTO.getSzPhasicName().toUpperCase(), "N")) {
                if ("A".equalsIgnoreCase(analogDTO.getSzUnitName())) {
                    strUnit = "I";
                } else {
                    strUnit = "U";
                }
                tmpWaveTitle.add(strUnit + analogDTO.getSzPhasicName().toUpperCase() + "相");
                channelName.add(analogDTO.getSzChannleName());
            }
        }
        waveDataDTO.setWaveTitle(tmpWaveTitle);
        waveDataDTO.setChannelNames(channelName);
    }

    /*********************************
     * 由.cfg 路径更换成 .dat
     * param strFilePath 文件路径
     * return  String返回.dat文件的路径
     **********************************/
    private String getDatFilePath(String strFilePath) {
        String strDatFilePath;
        //替换前的
        String strOriginally = ".cfg";
        //替换后的
        String strReplace = ".dat";
        //截取.之后字符串
        String strIntercept = strFilePath.substring(strFilePath.lastIndexOf(".") + 1);
        switch (strIntercept) {
            case "cfg":
                strOriginally = ".cfg";
                strReplace = ".dat";
                break;
            case "CFG":
                strOriginally = ".CFG";
                strReplace = ".DAT";
                break;
            case "Cfg":
                strOriginally = ".Cfg";
                strReplace = ".Dat";
                break;
            case "CFg":
                strOriginally = ".CFg";
                strReplace = ".DAt";
                break;
            case "cFg":
                strOriginally = ".cFg";
                strReplace = ".dAt";
                break;
            case "cFG":
                strOriginally = ".cFG";
                strReplace = ".dAT";
                break;
            default:
                break;
        }
        //把.cfg换成.dat
        strDatFilePath = strFilePath.replace(strOriginally, strReplace);
        return strDatFilePath;
    }

    public static void main(String[] args) {
        /********************************************************
         * iFlag == 0  高级算法的要求，采样率只能是32-128
         * iFlag == 1  普通展示，采样率按照cfg里面最小的（大于32）
         * iFlag == 2  App抽点要求，采样率抽点成32
         * iFlag == 3  高级算法原始波形（大于32）
         ********************************************************/
        /** 输出格式: 2014-5-05 00:00:00 大写H为24小时制 */
        DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String s;
        Date d = new Date();
        s = sdf.format(d);
        System.out.println(s);
        WaveFileComponent waveFileComponent = new WaveFileComponent();
        InputStream cfgStream = waveFileComponent.getFileInputStreamByFilePath("C:\\Users\\无名\\Desktop\\月报\\2026\\202603\\文档\\暂态事件及波形\\新建文件夹 (3)\\Comtrade\\Comtrade\\10.95.0.201\\PQMonitor_PQM1_001183_20260320_175042_316.CFG");
        InputStream datStream = waveFileComponent.getFileInputStreamByFilePath("C:\\Users\\无名\\Desktop\\月报\\2026\\202603\\文档\\暂态事件及波形\\新建文件夹 (3)\\Comtrade\\Comtrade\\10.95.0.201\\PQMonitor_PQM1_001183_20260320_175042_316.DAT");
        // 获取瞬时波形 //获取原始波形值
        WaveDataDTO waveDataDTO = waveFileComponent.getComtradeNoAddPoints(cfgStream, datStream, 0);
        d = new Date();
        s = sdf.format(d);
        System.out.println(s);
        // 获取RMS波形
        WaveDataDTO waveDataDTO1 = waveFileComponent.getValidData(waveDataDTO);
        d = new Date();
        s = sdf.format(d);
        System.out.println(s);
        // 获取特征值
        List<EigenvalueDTO> lstEigenvalueDTO = waveFileComponent.getEigenvalue(waveDataDTO, true);
        System.out.println(1);
    }

}
