package com.njcn.advance.event.cause.algorithm;


import com.njcn.advance.event.cause.model.VecStruct;

/**
 * DQ变换算法实现
 * 对应C语言中的dq_delay.c文件
 */
public class DQTransform {
    private static final double PI = Math.PI;

    /**
     * DQ变换延时处理
     * @param Va A相电压数组
     * @param t 时间数组
     * @param samplePoint 一个周期的采样点数
     * @param n 数据个数
     * @param f 频率
     * @param ua 输出幅值数组
     * @param angleUa 输出相角数组
     * @param vecU 输出相量数组
     */
    public static void dqDelay(float[] Va, float[] t, int samplePoint, int n, float f,
                              float[] ua, float[] angleUa, VecStruct[] vecU) {
        
        int delay = (int) (samplePoint / 6.0 + 0.5);  // 延时量实际是超前60°
        float ang = (float) delay / samplePoint;
        
        float[] upd1 = new float[n];
        float[] upq1 = new float[n];
        float[] upd = new float[n];
        float[] upq = new float[n];
        
        // 延时计算dq变换
        for (int i = delay; i < n; i++) {
            float Vo = Va[i - delay];
            float Vc = -(1.0f / 2.0f) * Va[i] + 
                      (float) (Math.sqrt(3) / 2.0) * 
                      (Va[i] * (float) Math.cos(ang * 2 * PI) - Vo) / 
                      (float) Math.sin(ang * 2 * PI);
            float Vb = -Va[i] - Vc;
            
            DQResult result = dqTransform(Va[i], Vb, Vc, t[i], f);
            upd1[i] = result.upd;
            upq1[i] = result.upq;
        }
        
        // 延时段缺失值用第一个有效值填充
        for (int i = 0; i < delay; i++) {
            upd1[i] = upd1[delay];
            upq1[i] = upq1[delay];
        }
        
        // 滤波处理
        int win = samplePoint / 4 + 1;
        MathUtils.lowPassFilter(upd1, upd, n, win);
        MathUtils.lowPassFilter(upq1, upq, n, win);
        
        // 计算最终结果
        for (int i = 0; i < n; i++) {
            ua[i] = (float) (0.57735 * Math.sqrt(upd[i] * upd[i] + upq[i] * upq[i]));
            angleUa[i] = (float) (Math.atan2(upq[i], upd[i]) / PI * 180);
            
            vecU[i] = new VecStruct(upd[i] * 0.57735f, upq[i] * 0.57735f);
        }
    }

    /**
     * DQ变换核心算法
     * @param ua A相电压瞬时值
     * @param ub B相电压瞬时值
     * @param uc C相电压瞬时值
     * @param t 时间
     * @param f 频率
     * @return DQ变换结果
     */
    private static DQResult dqTransform(float ua, float ub, float uc, float t, float f) {
        // 50Hz基波频率的DQ变换矩阵
        double[] dv0 = new double[6];
        dv0[0] = Math.cos(2 * PI * f * t);
        dv0[2] = Math.cos(2 * PI * f * t - 2.0943951023931953);  // -120°
        dv0[4] = Math.cos(2 * PI * f * t + 2.0943951023931953);  // +120°
        dv0[1] = -Math.sin(2 * PI * f * t);
        dv0[3] = -Math.sin(2 * PI * f * t - 2.0943951023931953);
        dv0[5] = -Math.sin(2 * PI * f * t + 2.0943951023931953);

        // Clarke变换矩阵
        double[][] dv1 = {
            {2.0/3.0, -1.0/3.0, -1.0/3.0},
            {0.0, 1.0/Math.sqrt(3), -1.0/Math.sqrt(3)}
        };

        float[] bUa = {ua, ub, uc};

        // 计算DQ分量
        float upd = 0, upq = 0;
        for (int i = 0; i < 3; i++) {
            upd += (float) (dv0[2*i] * dv1[0][i] * bUa[i]);
            upq += (float) (dv0[2*i+1] * dv1[1][i] * bUa[i]);
        }

        return new DQResult(upd, upq);
    }

    /**
     * 正序分量计算
     * @param vUa A相相量
     * @param vUb B相相量
     * @param vUc C相相量
     * @return 正序分量
     */
    public static VecStruct calculatePositiveSequence(VecStruct vUa, VecStruct vUb, VecStruct vUc) {
        // 正序分量计算公式: U1 = 1/3 * (Ua + a*Ub + a²*Uc)
        // a = e^(j*2π/3) = -0.5 + j*sqrt(3)/2
        // a² = e^(j*4π/3) = -0.5 - j*sqrt(3)/2
        
        float a_real = -0.5f;
        float a_imag = (float) (Math.sqrt(3) / 2);
        float a2_real = -0.5f;
        float a2_imag = (float) (-Math.sqrt(3) / 2);
        
        // Ua
        float real1 = vUa.getR();
        float imag1 = vUa.getX();
        
        // a * Ub
        float real2 = a_real * vUb.getR() - a_imag * vUb.getX();
        float imag2 = a_real * vUb.getX() + a_imag * vUb.getR();
        
        // a² * Uc
        float real3 = a2_real * vUc.getR() - a2_imag * vUc.getX();
        float imag3 = a2_real * vUc.getX() + a2_imag * vUc.getR();
        
        // 求和并除以3
        float resultReal = (real1 + real2 + real3) / 3.0f;
        float resultImag = (imag1 + imag2 + imag3) / 3.0f;
        
        return new VecStruct(resultReal, resultImag);
    }

    /**
     * 负序分量计算
     * @param vUa A相相量
     * @param vUb B相相量  
     * @param vUc C相相量
     * @return 负序分量
     */
    public static VecStruct calculateNegativeSequence(VecStruct vUa, VecStruct vUb, VecStruct vUc) {
        // 负序分量计算公式: U2 = 1/3 * (Ua + a²*Ub + a*Uc)
        float a_real = -0.5f;
        float a_imag = (float) (Math.sqrt(3) / 2);
        float a2_real = -0.5f;
        float a2_imag = (float) (-Math.sqrt(3) / 2);
        
        // Ua
        float real1 = vUa.getR();
        float imag1 = vUa.getX();
        
        // a² * Ub
        float real2 = a2_real * vUb.getR() - a2_imag * vUb.getX();
        float imag2 = a2_real * vUb.getX() + a2_imag * vUb.getR();
        
        // a * Uc
        float real3 = a_real * vUc.getR() - a_imag * vUc.getX();
        float imag3 = a_real * vUc.getX() + a_imag * vUc.getR();
        
        // 求和并除以3
        float resultReal = (real1 + real2 + real3) / 3.0f;
        float resultImag = (imag1 + imag2 + imag3) / 3.0f;
        
        return new VecStruct(resultReal, resultImag);
    }

    /**
     * 零序分量计算
     * @param vUa A相相量
     * @param vUb B相相量
     * @param vUc C相相量
     * @return 零序分量
     */
    public static VecStruct calculateZeroSequence(VecStruct vUa, VecStruct vUb, VecStruct vUc) {
        // 零序分量计算公式: U0 = 1/3 * (Ua + Ub + Uc)
        float resultReal = (vUa.getR() + vUb.getR() + vUc.getR()) / 3.0f;
        float resultImag = (vUa.getX() + vUb.getX() + vUc.getX()) / 3.0f;
        
        return new VecStruct(resultReal, resultImag);
    }

    /**
     * DQ变换结果内部类
     */
    private static class DQResult {
        final float upd;
        final float upq;
        
        DQResult(float upd, float upq) {
            this.upd = upd;
            this.upq = upq;
        }
    }
}