【农气项目】基于适宜度的产量预报

news2025/4/25 22:01:06

直接上干货(复制到开发工具即可运行的代码)

1. 适宜度模型及作物適宜度计算方法

2. 产量分离

3. 基于适宜度计算产量预报

1. 适宜度模型及作物適宜度计算方法

    // 三基点温度配置
    private final double tempMin;
    private final double tempOpt;
    private final double tempMax;

    // 降水/日照理想值
    private final double idealPrecipitation;
    private final double idealSunshineRatio;

    // 权重配置
    private final double tempWeight;
    private final double precWeight;
    private final double sunWeight;

    public SimpleCropSuitability(
            double tempMin, double tempOpt, double tempMax,
            double idealPrecipitation, double idealSunshineRatio,
            double tempWeight, double precWeight, double sunWeight) {

        // 参数校验
        if (tempMin >= tempOpt || tempOpt >= tempMax) {
            throw new IllegalArgumentException("温度参数必须满足: tMin < tOpt < tMax");
        }
        if (idealPrecipitation <= 0 || idealSunshineRatio <= 0) {
            throw new IllegalArgumentException("降水和日照理想值必须大于0");
        }

        this.tempMin = tempMin;
        this.tempOpt = tempOpt;
        this.tempMax = tempMax;
        this.idealPrecipitation = idealPrecipitation;
        this.idealSunshineRatio = idealSunshineRatio;
        this.tempWeight = tempWeight;
        this.precWeight = precWeight;
        this.sunWeight = sunWeight;
    }

    // 温度适宜度(三基点模型)
    private double calculateTempScore(double meanTemp) {
        if (meanTemp <= tempMin || meanTemp >= tempMax) {
            return 0;
        }
        return (meanTemp < tempOpt)
                ? (meanTemp - tempMin) / (tempOpt - tempMin)  // 低温区间线性增长
                : 1 - (meanTemp - tempOpt) / (tempMax - tempOpt); // 高温区间线性衰减
    }

    // 降水适宜度(新线性模型)
    private double calculatePrecipitationScore(double precipitation) {
        return Math.min(precipitation / idealPrecipitation, 1.0);
    }

    // 日照适宜度(新线性模型)
    private double calculateSunshineScore(double sunshineRatio) {
        return Math.min(sunshineRatio / idealSunshineRatio, 1.0);
    }

    /**
     * 综合适宜度计算
     *
     * @param meanTemp      旬平均温度(℃)
     * @param precipitation 旬累计降水(mm)
     * @param sunshineRatio 旬日照比率(实际日照/理论最大日照)
     * @return 0-1标准化适宜度
     */
    public double evaluate(double meanTemp, double precipitation, double sunshineRatio) {
        double tScore = calculateTempScore(meanTemp);
        double pScore = calculatePrecipitationScore(precipitation);
        double sScore = calculateSunshineScore(sunshineRatio);

        // 加权求和(权重自动归一化)
        double totalWeight = tempWeight + precWeight + sunWeight;
        return (tScore * tempWeight + pScore * precWeight + sScore * sunWeight) / totalWeight;
    }

    public static void main(String[] args) {
        // 配置小麦抽穗期参数
        SimpleCropSuitability wheatModel = new SimpleCropSuitability(
                10, 22, 35,    // 温度三基点(℃)
                60,            // 旬理想降水(mm)
                0.65,          // 理想日照比率
                0.4, 0.4, 0.2  // 温度、降水、日照权重
        );

        // 测试不同场景
        testCase(wheatModel, 22, 60, 0.65);  // 理想条件
        testCase(wheatModel, 15, 30, 0.5);   // 各项不足
        testCase(wheatModel, 25, 80, 0.7);   // 降水日照超额
    }

    private static void testCase(SimpleCropSuitability model,
                                 double temp, double prec, double sun) {
        double suitability = model.evaluate(temp, prec, sun);
        System.out.printf(
                "温度=%.1f℃ 降水=%.1fmm 日照=%.2f → 适宜度=%.2f\n",
                temp, prec, sun, suitability
        );
    }

这里的降水和日照都是只有适宜值,如果也类似气温一样有最高最低气温和适宜值,那么按照气温修改一下即可使用 

2. 产量分离

根据历年的产量计算出趋势产量和气象产量

    public enum SmoothingOption {
        THREE_YEAR(3), FIVE_YEAR(5);

        public final int windowSize;
        SmoothingOption(int size) { this.windowSize = size; }
    }

    public static class YieldData {
        private final int year;
        private final double yield;

        public YieldData(int year, double yield) {
            this.year = year;
            this.yield = yield;
        }
        public int getYear() { return year; }
        public double getYield() { return yield; }
    }

    public static class DecomposedYield {
        private final int year;
        private final Double socialYield;
        private final Double trendYield;
        private final Double weatherYield;
        private final Double relativeYield;

        public DecomposedYield(int year, Double social, Double trend,
                             Double weather, Double relative) {
            this.year = year;
            this.socialYield = social;
            this.trendYield = trend;
            this.weatherYield = weather;
            this.relativeYield = relative;
        }

        @Override
        public String toString() {
            return String.format("%d\t%s\t%s\t%s\t%s",
                    year,
                    socialYield != null ? String.format("%.2f", socialYield) : "",
                    trendYield != null ? String.format("%.2f", trendYield) : "",
                    weatherYield != null ? String.format("%.2f", weatherYield) : "",
                    relativeYield != null ? String.format("%.1f%%", relativeYield) : "");
        }
    }

    public static void main(String[] args) {
        // 示例数据(2011-2020)
        List<YieldData> yields = Arrays.asList(
            new YieldData(2011, 5.2), new YieldData(2012, 5.5),
            new YieldData(2013, 5.1), new YieldData(2014, 5.8),
            new YieldData(2015, 6.0), new YieldData(2016, 5.7),
            new YieldData(2017, 6.2), new YieldData(2018, 6.5),
            new YieldData(2019, 6.3), new YieldData(2020, 6.4)
        );

        // 预报年份设置
        Integer forecastYear = null;

        // 3年滑动窗口分析
        System.out.println("=== 3年滑动窗口分析 ===");
        process(yields, SmoothingOption.THREE_YEAR, forecastYear);

        // 5年滑动窗口分析
        System.out.println("\n=== 5年滑动窗口分析 ===");
//        process(yields, SmoothingOption.FIVE_YEAR, forecastYear);
    }

    private static void process(List<YieldData> yields, SmoothingOption option, Integer forecastYear) {
        // 1. 产量分解
        List<DecomposedYield> decomposition = decomposeYield(yields, option);

        // 2. 获取建模有效数据(排除窗口期不足的年份)
        List<YieldData> modelData = yields.subList(option.windowSize - 1, yields.size());

        // 3. 打印趋势产量公式
        printTrendFormula(modelData);

        // 4. 预报指定年份
        if (forecastYear != null){
            double forecast = calculateTrendForecast(modelData, forecastYear);
            System.out.printf("预报 %d 年趋势产量: %.2f\n", forecastYear, forecast);
        }
        // 5. 打印分解结果
        printDecompositionResults(decomposition);
    }

    private static List<DecomposedYield> decomposeYield(List<YieldData> yields, SmoothingOption option) {
        List<DecomposedYield> results = new ArrayList<>();
        int windowSize = option.windowSize;

        // 计算趋势产量(仅使用有效数据)
        List<YieldData> modelData = yields.subList(windowSize - 1, yields.size());
        Map<Integer, Double> trendYields = calculateTrendYield(modelData);

        for (int i = 0; i < yields.size(); i++) {
            YieldData current = yields.get(i);
            Double social = (i >= windowSize - 1) ?
                calculateMovingAverage(yields, i, windowSize) : null;

            if (social == null) {
                results.add(new DecomposedYield(current.year, current.yield, null, null, null));
            } else {
                Double trend = trendYields.get(current.year);
                Double weather = trend != null ? current.yield - social : null;
                Double relative = weather != null ? (weather / social) * 100 : null;
                results.add(new DecomposedYield(current.year, social, trend, weather, relative));
            }
        }
        return results;
    }

    private static double calculateMovingAverage(List<YieldData> yields, int endIndex, int windowSize) {
        return yields.subList(endIndex - windowSize + 1, endIndex + 1)
                   .stream()
                   .mapToDouble(YieldData::getYield)
                   .average()
                   .orElse(0);
    }

    private static Map<Integer, Double> calculateTrendYield(List<YieldData> yields) {
        double[] coeff = calculateRegressionCoefficients(yields);
        int baseYear = yields.get(0).getYear();
        return yields.stream().collect(Collectors.toMap(
            YieldData::getYear,
            yd -> coeff[0] + coeff[1] * (yd.getYear() - baseYear)
        ));
    }

    private static double[] calculateRegressionCoefficients(List<YieldData> yields) {
        int n = yields.size();
        int baseYear = yields.get(0).getYear();

        double sumX = 0, sumY = 0, sumXY = 0, sumX2 = 0;

        for (YieldData yd : yields) {
            double x = yd.getYear() - baseYear;
            double y = yd.getYield();
            sumX += x;
            sumY += y;
            sumXY += x * y;
            sumX2 += x * x;
        }

        double b = (n * sumXY - sumX * sumY) / (n * sumX2 - sumX * sumX);
        double a = (sumY - b * sumX) / n;

        return new double[]{a, b};
    }

    private static double calculateTrendForecast(List<YieldData> yields, int year) {
        double[] coeff = calculateRegressionCoefficients(yields);
        return coeff[0] + coeff[1] * (year - yields.get(0).getYear());
    }

    private static void printTrendFormula(List<YieldData> yields) {
        double[] coeff = calculateRegressionCoefficients(yields);
        System.out.printf("趋势产量公式: y = %.4f + %.4f * (年份 - %d)\n",
                coeff[0], coeff[1], yields.get(0).getYear());
    }

    private static void printDecompositionResults(List<DecomposedYield> results) {
        System.out.println("\n产量分解结果:");
        System.out.println("年份\t社会产量\t趋势产量\t气象产量\t相对产量");
        results.forEach(System.out::println);
    }

一般都会进行滑动操作如果不需要删除相关代码即可

3. 基于适宜度计算产量预报


	/**
	 * 基于适宜度的产量预报,根据适宜度和产量,计算一元一次回归方程,并计算其相关系数和Significance F值
	 * @param args
	 */
    public static void main(String[] args) {
        // 历史数据:适宜度(X)和产量(Y)
        double[] suitability = {0.714202, 1.2389059999999996, 0.9274519999999999, 1.175564, 1.150908, 0.9320140000000001, 1.207076, 1.012762, 1.321816};
        double[] yield = {272.288, 119.1564, 27.4286, 217.9705, 58.2261, 9.9326, -83.3608, -101.6542, -115.4477};

        // 创建并拟合回归模型
        SimpleRegression regression = new SimpleRegression();
        for (int i = 0; i < suitability.length; i++) {
            regression.addData(suitability[i], yield[i]);
        }

        // 获取回归系数
        double intercept = regression.getIntercept();
        double slope = regression.getSlope();

        // 计算F统计量
        double ssr = regression.getRegressionSumSquares();
        double sse = regression.getSumSquaredErrors();
        int n = suitability.length;
        int k = 1;
        double fStatistic = (ssr / k) / (sse / (n - k - 1));

        // 计算Significance F (p值)
        FDistribution fDist = new FDistribution(k, n - k - 1);
        double significanceF = 1 - fDist.cumulativeProbability(fStatistic);

        // 设置4位小数格式
        DecimalFormat df = new DecimalFormat("0.0000");

        // 处理极小的p值
        String formattedPValue;
        if (significanceF < 0.0001) {
            formattedPValue = "<0.0001";
        } else {
            formattedPValue = df.format(significanceF);
        }

        // 输出结果
        System.out.println("回归方程: Y = " + slope + " * X + " + intercept);
        System.out.println("相关系数(R): " + regression.getR());
        System.out.println("决定系数(R²): " + regression.getRSquare());
        System.out.println("F统计量: " + fStatistic);
        System.out.println("Significance F (p值): " + formattedPValue);

        // 模型显著性判断
        double alpha = 0.05;
        if (significanceF < alpha) {
            System.out.println("结论: 回归模型显著 (p < " + alpha + ")");
        } else {
            System.out.println("结论: 回归模型不显著 (p ≥ " + alpha + ")");
        }
    }

根据方法三我们可以拿到气象产量公式,结合方法二的趋势产量公式代入年份进行计算即可计算出基于适宜度的产量预报

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2342729.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

3台CentOS虚拟机部署 StarRocks 1 FE+ 3 BE集群

背景&#xff1a;公司最近业务数据量上去了&#xff0c;需要做一个漏斗分析功能&#xff0c;实时性要求较高&#xff0c;mysql已经已经不在适用&#xff0c;做了个大数据技术栈选型调研后&#xff0c;决定使用StarRocks StarRocks官网&#xff1a;StarRocks | A High-Performa…

【HCIA】简易的两个VLAN分别使用DHCP分配IP

前言 之前我们通过 静态ip地址实现了Vlan间通信 &#xff0c;现在我们添加一个常用的DHCP功能。 文章目录 前言1. 配置交换机2. 接口模式3. 全局模式后记修改记录 1. 配置交换机 首先&#xff0c;使用DHCP&#xff0c;需要先启动DHCP服务&#xff1a; [Huawei]dhcp enable I…

艾蒙顿桌面app下载-Emotn UI下载安装-emotn ui官方tv版安卓固件

在智能电视桌面应用的领域里&#xff0c;Emotn UI 凭借其简洁无广告、可自定义等特点&#xff0c;赢得了不少用户的关注。然而&#xff0c;小编深入了解后发现了一款更好用的电视桌面——乐看家桌面在诸多方面更具优势&#xff0c;能为你带来更优质的大屏体验。 乐看家桌面内置…

3、ArkTS语言介绍

目录 基础知识函数函数声明可选参数Rest参数返回类型箭头函数&#xff08;又名Lambda函数&#xff09;闭包 类字段字段初始化getter和setter继承父类访问方法重写方法重载签名可见性修饰符&#xff08;Public、Private、protected&#xff09; 基础知识 ArkTS是一种为构建高性…

修改了Element UI中组件的样式,打包后样式丢失

修改了Element UI中组件的样式&#xff0c;在本地运行没有问题&#xff0c;但是打包到线上发现样式丢失&#xff08;样式全部不生效、或者有一部分生效&#xff0c;一部分不生效&#xff09;&#xff0c;问题在于css的加载顺序导致代码编译后样式被覆盖了&#xff0c; 解决办法…

【springsecurity oauth2授权中心】jwt令牌更换成自省令牌 OpaqueToken P4

前言 前面实现了授权中心授权&#xff0c;客户端拿到access_token后就能请求资源服务器接口 权限的校验都是在资源服务器上进行的&#xff0c;授权服务器颁发的access_token有限期是2小时&#xff0c;也就是说在2小时之内&#xff0c;不管授权服务器那边用户的权限如何变更都…

诱骗协议芯片支持PD2.0/3.0/3.1/PPS协议,支持使用一个Type-C与电脑传输数据和快充取电功能

快充是由充电器端的充电协议和设备端的取电协议进行握手通讯进行协议识别来完成的&#xff0c;当充电器端的充电协议和设备端的取电协议握手成功后&#xff0c;设备会向充电器发送电压请求&#xff0c;充电器会根据设备的需求发送合适的电压给设备快速供电。 设备如何选择快充…

变量在template里不好使,在setup好使?

问题&#xff1a; 自定义的一个函数 &#xff0c;import导入后 setup里面使用正常 &#xff0c;在template里面说未定义 作用域问题 在 Vue 的模板语法中&#xff0c;模板&#xff08;template &#xff09;里能直接访问的是组件实例上暴露的属性和方法。从代码看&#xff0c…

OpenCV 图形API(53)颜色空间转换-----将 RGB 图像转换为灰度图像函数RGB2Gray()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 将图像从 RGB 色彩空间转换为灰度。 R、G 和 B 通道值的常规范围是 0 到 255。生成的灰度值计算方式如下&#xff1a; dst ( I ) 0.299 ∗ src…

Trae+DeepSeek学习Python开发MVC框架程序笔记(四):使用sqlite存储查询并验证用户名和密码

继续通过Trae向DeepSeek发问并修改程序&#xff0c;实现程序运行时生成数据库&#xff0c;用户在系统登录页面输入用户名和密码后&#xff0c;控制器通过模型查询用户数据库表来验证用户名和密码&#xff0c;验证通过后显示登录成功页面&#xff0c;验证失败则显示登录失败页面…

超详细mac上用nvm安装node环境,配置npm

一、安装NVM 打开终端&#xff0c;运行以下命令来安装NVM&#xff1a; curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.5/install.sh | bash 然后就会出现如下代码&#xff1a; > Profile not found. Tried ~/.bashrc, ~/.bash_profile, ~/.zprofile, ~/.…

hi3516cv610构建音频sample工程代码步骤

hi3516cv610构建音频sample工程代码步骤 sdk版本&#xff1a;Hi3516CV610_SDK_V1.0.1.0 硬件&#xff1a;非es8388 工程代码&#xff1a; 通过网盘分享的文件&#xff1a;audio_easy.zip 链接: https://pan.baidu.com/s/1gx61S_F3-pf6hPyfbGaRXg 提取码: 4gbg --来自百度网盘…

12.QT-Combo Box|Spin Box|模拟点餐|从文件中加载选项|调整点餐份数(C++)

Combo Box QComboBox 表⽰下拉框 核⼼属性 属性说明currentText当前选中的⽂本currentIndex当前选中的条⽬下标.从0开始计算.如果当前没有条⽬被选中,值为-1editable是否允许修改设为true时, QComboBox 的⾏为就⾮常接近 QLineEdit ,也可以 设置 validatoriconSize下拉框图标…

UML 顺序图:电子图书馆管理系统的交互之道

目录 一、初识 UML 顺序图 二、电子图书馆管理系统顺序图解析 &#xff08;一&#xff09;借阅流程 &#xff08;二&#xff09;归还流程 三、顺序图绘画 四、顺序图的优势与价值 五、总结 UML 顺序图是描绘系统组件交互的有力工具。顺序图直观展示消息传递顺序与对象协…

访问者模式:分离数据结构与操作的设计模式

访问者模式&#xff1a;分离数据结构与操作的设计模式 一、模式核心&#xff1a;将操作从数据结构中分离&#xff0c;支持动态添加新操作 在软件开发中&#xff0c;当数据结构&#xff08;如树、集合&#xff09;中的元素类型固定&#xff0c;但需要频繁添加新的操作&#xf…

【AI训练环境搭建】在IDE(Pycharm或VSCode)上使用WSL2+Ubuntu22.04+Conda+Tensorflow+GPU进行机器学习训练

本次实践将在IDE&#xff08;Pycharm或VSCode&#xff09;上使用WSL2Ubuntu22.04TensorflowGPU进行机器学习训练。基本原理是在IDE中拉起WSL2中的Python解释器&#xff0c;并运行Python程序。要运行CondaTensorflowGPU你可能需要进行以下准备工作。 1. 此示例中将使用一个mnis…

Leetcode19(亚马逊真题):删除链表的倒是第N个节点

题目分析 删除节点关键&#xff1a;找到被删节点的前一个节点&#xff0c;指针指向 虚拟头节点&#xff0c;方便删除头结点&#xff0c;形成统一操作 为啥要让快指针先行&#xff1f; 我认为更好懂的一种解释&#xff1a;快指针先行n步&#xff0c;这样快慢指针之间形成了一…

Hadoop+Spark 笔记 2025/4/21

读书笔记 定义 1. 大数据&#xff08;Big Data&#xff09; - 指传统数据处理工具难以处理的海量、高速、多样的数据集合&#xff0c;通常具备3V特性&#xff08;Volume体量大、Velocity速度快、Variety多样性&#xff09;。扩展后还包括Veracity&#xff08;真实性&#x…

Redis从入门到实战基础篇

前言&#xff1a;Redis的安装包含在Redis从入门到实战先导篇中&#xff0c;需要的可移步至此节 目录 1.Redis简单介绍 2.初始Redis 2.1.认识NoSQL 2.2.认识Redis 2.3.安装Redis 3.Redis常见命令 3.1 Redis数据结构 3.2 通用命令 3.3 String命令 3.4 Key的层级结构 3…

Java虚拟机(JVM)家族发展史及版本对比

Java虚拟机&#xff08;JVM&#xff09;家族发展史及版本对比 一、JVM家族发展史 1. 早期阶段&#xff08;1996-2000&#xff09; Classic VM&#xff08;Java 1.0-1.1&#xff09;&#xff1a; 厂商&#xff1a;Sun Microsystems&#xff08;Oracle前身&#xff09;。特点&…