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

import java.util.Arrays;

/**
 * 数学工具类
 * 提供各种数学计算功能
 */
public class MathUtils {

    /**
     * 计算数组的RMS有效值（滑动窗口）
     * @param input 输入数组
     * @param output 输出数组
     * @param smp 采样点数（窗口大小）
     * @param len 数据长度
     */
    public static void rmsCalculate(float[] input, float[] output, int smp, int len) {
        for (int i = smp - 1; i < len; i++) {
            float sum = 0;
            for (int j = 0; j < smp; j++) {
                float value = input[i - j];
                sum += value * value;
            }
            output[i] = (float) Math.sqrt(sum / smp);
        }
        
        // 填充前面的数据
        for (int i = 0; i < smp - 1; i++) {
            output[i] = output[smp - 1];
        }
    }

    /**
     * 计算直方图统计
     * @param data 输入数据
     * @param n 数据个数
     * @param div 分组数
     * @param yy 输出统计结果
     */
    public static void histogram(float[] data, int n, int div, int[] yy) {
        Arrays.fill(yy, 0);
        
        // 找到最大最小值
        float min = Float.MAX_VALUE;
        float max = Float.MIN_VALUE;
        
        for (int i = 0; i < n; i++) {
            if (data[i] < min) min = data[i];
            if (data[i] > max) max = data[i];
        }
        
        // 计算间隔
        float interval = (max - min) / div;
        
        // 统计数据分布
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < div; j++) {
                if (data[i] >= (min + j * interval) && data[i] < (min + (j + 1) * interval)) {
                    yy[j]++;
                }
            }
        }
        
        // 边界值需要加到最后一个统计中
        if (yy.length > div) {
            yy[div]++;
        }
    }

    /**
     * 计算标准差
     * @param data 输入数据
     * @param num 数据个数
     * @param flag 计算方式标志（0: n-1, 1: n）
     * @return 标准差
     */
    public static float standardDeviation(float[] data, int num, int flag) {
        float sum = 0;
        for (int i = 0; i < num; i++) {
            sum += data[i];
        }
        float avg = sum / num;
        
        float sumSquares = 0;
        for (int i = 0; i < num; i++) {
            float diff = data[i] - avg;
            sumSquares += diff * diff;
        }
        
        float divisor = (flag == 0) ? (num - 1) : num;
        return (float) Math.sqrt(sumSquares / divisor);
    }

    /**
     * 计算偏度（Skewness）
     * @param data 输入数据
     * @param num 数据个数
     * @return 偏度
     */
    public static float skewness(float[] data, int num) {
        float sum = 0;
        for (int i = 0; i < num; i++) {
            sum += data[i];
        }
        float avg = sum / num;
        
        float sum1 = 0;  // 二阶矩
        float sum2 = 0;  // 三阶矩
        
        for (int i = 0; i < num; i++) {
            float diff = data[i] - avg;
            sum1 += diff * diff;
            sum2 += diff * diff * diff;
        }
        
        float variance = sum1 / num;
        float sigma = (float) Math.sqrt(variance);
        
        if (Math.abs(sigma) < 1e-10) {
            return 0;
        }
        
        return (sum2 / num) / (sigma * sigma * sigma);
    }

    /**
     * 计算峭度（Kurtosis）
     * @param data 输入数据
     * @param num 数据个数
     * @return 峭度
     */
    public static float kurtosis(float[] data, int num) {
        float sum = 0;
        for (int i = 0; i < num; i++) {
            sum += data[i];
        }
        float avg = sum / num;
        
        float sum1 = 0;  // 二阶矩
        float sum2 = 0;  // 四阶矩
        
        for (int i = 0; i < num; i++) {
            float diff = data[i] - avg;
            sum1 += diff * diff;
            sum2 += diff * diff * diff * diff;
        }
        
        float variance = sum1 / num;
        
        if (Math.abs(variance) < 1e-10) {
            return 0;
        }
        
        return (sum2 / num) / (variance * variance);
    }

    /**
     * 计算中位数
     * @param array 输入数组
     * @param len 数组长度
     * @return 中位数
     */
    public static float median(float[] array, int len) {
        float[] sorted = new float[len];
        System.arraycopy(array, 0, sorted, 0, len);
        Arrays.sort(sorted);
        
        if (len % 2 == 0) {
            return (sorted[len / 2 - 1] + sorted[len / 2]) / 2.0f;
        } else {
            return sorted[len / 2];
        }
    }

    /**
     * 低通滤波（简单移动平均）
     * @param signal 输入信号
     * @param filtered 输出滤波信号
     * @param n 信号长度
     * @param window 窗口大小
     */
    public static void lowPassFilter(float[] signal, float[] filtered, int n, int window) {
        for (int i = 0; i < n; i++) {
            float sum = 0;
            int count = 0;
            
            for (int j = Math.max(0, i - window + 1); j <= Math.min(n - 1, i + window - 1); j++) {
                sum += signal[j];
                count++;
            }
            
            filtered[i] = sum / count;
        }
    }

    /**
     * 找到数组中的最大值
     */
    public static float max(float a, float b) {
        return a > b ? a : b;
    }

    /**
     * 找到数组中的最小值
     */
    public static float min(float a, float b) {
        return a < b ? a : b;
    }
}