Browse Source

更新数据库脚本

xiaoguohua 6 hours from now
parent
commit
4f4cf9b0c8

+ 182 - 0
doc/数据库脚本/mock-data-electricity-local.sql

@@ -0,0 +1,182 @@
+-- ============================================================
+-- 脚本名称: 插入电气数据测试数据
+-- 功能: 向 data_electricity_local 表中插入指定时间范围的测试数据
+-- 数据精度: 5分钟
+-- 参数说明:
+--   - start_time: 开始时间 (格式: 'YYYY-MM-DD HH:MI:SS' 或 'YYYY-MM-DD')
+--   - end_time: 结束时间 (格式: 'YYYY-MM-DD HH:MI:SS' 或 'YYYY-MM-DD')
+--   - station_id: 场站ID (默认: 1)
+--   - installed_capacity: 装机容量 kW (默认: 50000,即 50MW)
+-- ============================================================
+
+DO $$
+DECLARE
+    -- ========== 可配置参数 ==========
+    v_start_time        TIMESTAMPTZ := '2026-08-05 00:00:00';  -- 开始时间
+    v_end_time          TIMESTAMPTZ := '2026-08-06 00:00:00';  -- 结束时间(不包含)
+    v_station_id        BIGINT      := 1;                       -- 场站ID
+    v_installed_capacity DOUBLE PRECISION := 50000;            -- 装机容量 kW
+    -- ================================
+
+    v_current_time    TIMESTAMPTZ;
+    v_hour_of_day     INTEGER;
+    v_day_of_year     INTEGER;
+    v_base_irradiance DOUBLE PRECISION;
+    v_random_factor   DOUBLE PRECISION;
+
+    -- 辐照度参数
+    v_irradiance_max  DOUBLE PRECISION := 1200;  -- 最大辐照度 W/m²
+
+    -- 系统效率参数
+    v_efficiency      DOUBLE PRECISION := 0.85;   -- 综合效率(含逆变器、线损等)
+    v_degradation     DOUBLE PRECISION := 0.98;  -- 衰减系数
+    v_temp_coeff      DOUBLE PRECISION := 0.004; -- 温度系数(每升高1℃损失0.4%)
+
+    -- 声明变量用于存储计算值
+    v_actual_power      DOUBLE PRECISION;
+    v_theoretical_power DOUBLE PRECISION;
+    v_curtailment_power DOUBLE PRECISION;
+    v_availability      DOUBLE PRECISION;
+    v_device_status     SMALLINT;
+    v_grid_status       SMALLINT;
+
+    v_temperature       DOUBLE PRECISION;
+    v_curtail_flag      DOUBLE PRECISION;
+    v_fault_flag        DOUBLE PRECISION;
+
+    v_counter INTEGER := 0;
+BEGIN
+    -- 参数验证
+    IF v_start_time >= v_end_time THEN
+        RAISE EXCEPTION '开始时间必须早于结束时间';
+    END IF;
+
+    -- 如果结束时间超过当前时间,发出警告
+    IF v_end_time > NOW() THEN
+        RAISE WARNING '结束时间 (%) 晚于当前时间,将插入未来数据', v_end_time;
+    END IF;
+
+    -- 初始化当前时间为开始时间
+    v_current_time := v_start_time;
+
+    RAISE NOTICE '开始插入数据: 场站ID=%, 时间范围: % 至 %, 装机容量=% kW',
+                 v_station_id, v_start_time, v_end_time, v_installed_capacity;
+
+    -- 循环插入数据,步长5分钟
+    WHILE v_current_time < v_end_time LOOP
+        -- 计算时间相关因子(分钟数,用于模拟日变化规律)
+        v_hour_of_day := EXTRACT(HOUR FROM v_current_time) * 60 + EXTRACT(MINUTE FROM v_current_time);
+        v_day_of_year := EXTRACT(DOY FROM v_current_time);
+
+        -- 模拟辐照度的日变化(正弦曲线,夜间为0)
+        -- 峰值在正午12:00 (720分钟),范围 0-1200 W/m²
+        IF v_hour_of_day >= 300 AND v_hour_of_day <= 1140 THEN  -- 5:00 到 19:00
+            v_base_irradiance := SIN((v_hour_of_day - 300) * PI() / 840) * v_irradiance_max;
+        ELSE
+            v_base_irradiance := 0;
+        END IF;
+
+        -- 添加随机波动 (±15%)
+        v_random_factor := 0.85 + (random() * 0.30);
+        v_base_irradiance := v_base_irradiance * v_random_factor;
+
+        -- 组件温度:日变化,夜间低白天高,范围 -20~45℃
+        -- 最低温在凌晨4点,最高温在下午14点
+        v_temperature := 15 + COS((v_hour_of_day - 240) * PI() / 720) * 15 + (random() - 0.5) * 6;
+        v_temperature := GREATEST(-20, LEAST(45, v_temperature));
+
+        -- 理论发电功率:基于辐照度的理想输出
+        -- P_theoretical = (G / 1000) * P_installed * (1 - temp_coeff * (T - 25))
+        IF v_base_irradiance > 0 THEN
+            v_theoretical_power := (v_base_irradiance / 1000) * v_installed_capacity
+                                   * (1 - v_temp_coeff * (v_temperature - 25));
+            v_theoretical_power := GREATEST(0, v_theoretical_power);
+        ELSE
+            v_theoretical_power := 0;
+        END IF;
+
+        -- 实际发电功率:理论功率乘以综合效率和衰减
+        v_actual_power := v_theoretical_power * v_efficiency * v_degradation
+                          * (0.97 + random() * 0.06);  -- 额外 ±3% 波动
+        v_actual_power := GREATEST(0, v_actual_power);
+
+        -- 限电功率:大部分时间为0,偶尔有限电(5% 概率,白天才有)
+        v_curtail_flag := random();
+        IF v_base_irradiance > 0 AND v_curtail_flag < 0.05 THEN
+            v_curtailment_power := v_actual_power * (0.1 + random() * 0.3);  -- 限掉 10%~40%
+            v_actual_power := v_actual_power - v_curtailment_power;
+        ELSE
+            v_curtailment_power := 0;
+        END IF;
+
+        -- 可用率:正常 95%~100%,故障时下降
+        v_fault_flag := random();
+        IF v_fault_flag < 0.005 THEN  -- 0.5% 概率设备故障
+            v_availability := 70 + random() * 20;  -- 70%~90%
+        ELSE
+            v_availability := 95 + random() * 5;   -- 95%~100%
+        END IF;
+
+        -- 设备状态(0=正常,1=停机,2=限电,3=检修,4=故障)
+        IF v_fault_flag < 0.005 THEN
+            v_device_status := 4;  -- 故障
+        ELSIF v_curtailment_power > 0 THEN
+            v_device_status := 2;  -- 限电
+        ELSIF v_fault_flag > 0.995 THEN  -- 0.5% 概率检修
+            v_device_status := 3;  -- 检修
+        ELSE
+            v_device_status := 0;  -- 正常
+        END IF;
+
+        -- 并网状态(1=并网,0=离网)
+        -- 白天发电时并网,夜间或故障时离网
+        IF v_device_status = 4 OR v_device_status = 1 THEN
+            v_grid_status := 0;
+        ELSIF v_base_irradiance > 0 THEN
+            v_grid_status := 1;
+        ELSE
+            v_grid_status := 0;  -- 夜间离网
+        END IF;
+
+        -- 插入数据
+        INSERT INTO data_electricity_local (
+            tm,
+            config_station_id,
+            actual_power,
+            theoretical_power,
+            curtailment_power,
+            availability,
+            device_status,
+            grid_status
+        ) VALUES (
+            v_current_time,
+            v_station_id,
+            ROUND(v_actual_power::NUMERIC, 2),
+            ROUND(v_theoretical_power::NUMERIC, 2),
+            ROUND(v_curtailment_power::NUMERIC, 2),
+            ROUND(v_availability::NUMERIC, 2),
+            v_device_status,
+            v_grid_status
+        );
+
+        v_counter := v_counter + 1;
+
+        -- 每1000条输出一次进度
+        IF v_counter % 1000 = 0 THEN
+            RAISE NOTICE '已插入 % 条数据,当前时间: %', v_counter, v_current_time;
+        END IF;
+
+        -- 时间增加5分钟
+        v_current_time := v_current_time + INTERVAL '5 minutes';
+    END LOOP;
+
+    RAISE NOTICE '数据插入完成!共插入 % 条数据', v_counter;
+
+    -- 显示插入数据统计
+    RAISE NOTICE '数据统计:';
+    RAISE NOTICE '  - 总记录数: %', v_counter;
+    RAISE NOTICE '  - 开始时间: %', v_start_time;
+    RAISE NOTICE '  - 结束时间: %', v_end_time;
+    RAISE NOTICE '  - 场站ID: %', v_station_id;
+    RAISE NOTICE '  - 装机容量: % kW', v_installed_capacity;
+END $$;

+ 5 - 1
doc/数据库脚本/gateway-data-sample.sql → doc/数据库脚本/mock-data-weather-local.sql

@@ -105,9 +105,11 @@ END IF;
 INSERT INTO data_weather_local (
     tm,
     config_station_id,
-    horizontal_irradiance,
+    irradiance,
     inclined_irradiance,
+    daily_irradiance,
     temperature,
+    board_temperature,
     pressure,
     humidity,
     wind_speed,
@@ -117,7 +119,9 @@ INSERT INTO data_weather_local (
              v_station_id,
              ROUND(v_horizontal_irradiance::NUMERIC, 2),
              ROUND(v_inclined_irradiance::NUMERIC, 2),
+             ROUND(v_horizontal_irradiance::NUMERIC*1.5, 2),
              ROUND(v_temperature::NUMERIC, 2),
+             ROUND(v_temperature::NUMERIC, 2) + 3,
              ROUND(v_pressure::NUMERIC, 2),
              ROUND(v_humidity::NUMERIC, 2),
              ROUND(v_wind_speed::NUMERIC, 2),

+ 31 - 0
gateway/forecast-south/src/main/java/cn/oleauto/south/xml/Book.java

@@ -0,0 +1,31 @@
+package cn.oleauto.south.xml;
+
+public class Book {
+    private String id;
+    private String title;
+    private String author;
+    private double price;
+    private int year;
+
+    // Getter 和 Setter 方法
+    public String getId() { return id; }
+    public void setId(String id) { this.id = id; }
+
+    public String getTitle() { return title; }
+    public void setTitle(String title) { this.title = title; }
+
+    public String getAuthor() { return author; }
+    public void setAuthor(String author) { this.author = author; }
+
+    public double getPrice() { return price; }
+    public void setPrice(double price) { this.price = price; }
+
+    public int getYear() { return year; }
+    public void setYear(int year) { this.year = year; }
+
+    @Override
+    public String toString() {
+        return String.format("Book{id='%s', title='%s', author='%s', price=%.2f, year=%d}",
+                id, title, author, price, year);
+    }
+}

+ 84 - 0
gateway/forecast-south/src/main/java/cn/oleauto/south/xml/BookHandler.java

@@ -0,0 +1,84 @@
+package cn.oleauto.south.xml;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.DefaultHandler;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class BookHandler extends DefaultHandler {
+
+    private List<Book> bookList = new ArrayList<>();
+    private Book currentBook;
+    private String currentElement;
+    private StringBuilder content = new StringBuilder();
+
+    // 获取解析结果
+    public List<Book> getBookList() {
+        return bookList;
+    }
+
+    @Override
+    public void startDocument() throws SAXException {
+        System.out.println("开始解析XML文档...");
+    }
+
+    @Override
+    public void endDocument() throws SAXException {
+        System.out.println("XML文档解析完成,共解析 " + bookList.size() + " 本书");
+    }
+
+    @Override
+    public void startElement(String uri, String localName, String qName, Attributes attributes)
+            throws SAXException {
+        // 清空内容缓冲区
+        content.setLength(0);
+        currentElement = qName;
+
+        if ("book".equals(qName)) {
+            currentBook = new Book();
+            // 读取属性
+            String id = attributes.getValue("id");
+            currentBook.setId(id);
+            System.out.println("开始解析图书: ID=" + id);
+        }
+    }
+
+    @Override
+    public void endElement(String uri, String localName, String qName) throws SAXException {
+        String text = content.toString().trim();
+
+        if (currentBook != null) {
+            switch (qName) {
+                case "title":
+                    currentBook.setTitle(text);
+                    break;
+                case "author":
+                    currentBook.setAuthor(text);
+                    break;
+                case "price":
+                    currentBook.setPrice(Double.parseDouble(text));
+                    break;
+                case "year":
+                    currentBook.setYear(Integer.parseInt(text));
+                    break;
+                case "book":
+                    bookList.add(currentBook);
+                    System.out.println("完成解析图书: " + currentBook.getTitle());
+                    currentBook = null;
+                    break;
+            }
+        }
+    }
+
+    @Override
+    public void characters(char[] ch, int start, int length) throws SAXException {
+        content.append(ch, start, length);
+    }
+
+    @Override
+    public void error(org.xml.sax.SAXParseException e) throws SAXException {
+        System.err.println("解析错误: " + e.getMessage());
+    }
+}

+ 41 - 0
gateway/forecast-south/src/main/java/cn/oleauto/south/xml/SAXParserDemo.java

@@ -0,0 +1,41 @@
+package cn.oleauto.south.xml;
+
+import org.xml.sax.SAXException;
+
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+import java.io.IOException;
+import java.util.List;
+
+public class SAXParserDemo {
+    public static void main(String[] args) {
+        try {
+            // 1. 创建 SAXParserFactory
+            SAXParserFactory factory = SAXParserFactory.newInstance();
+
+            // 2. 创建 SAXParser
+            SAXParser parser = factory.newSAXParser();
+
+            // 3. 创建自定义处理器
+            BookHandler handler = new BookHandler();
+
+            // 4. 解析 XML 文件
+            parser.parse("books.xml", handler);
+
+            // 5. 获取并显示结果
+            List<Book> books = handler.getBookList();
+            System.out.println("\n=== 解析结果 ===");
+            for (Book book : books) {
+                System.out.println(book);
+            }
+
+        } catch (ParserConfigurationException e) {
+            System.err.println("解析器配置错误: " + e.getMessage());
+        } catch (SAXException e) {
+            System.err.println("SAX解析异常: " + e.getMessage());
+        } catch (IOException e) {
+            System.err.println("文件读取错误: " + e.getMessage());
+        }
+    }
+}

+ 57 - 0
gateway/forecast-south/src/main/java/cn/oleauto/south/xml/SimpleSAXDemo.java

@@ -0,0 +1,57 @@
+package cn.oleauto.south.xml;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.helpers.DefaultHandler;
+
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+
+public class SimpleSAXDemo {
+
+    public static void main(String[] args) throws Exception {
+        SAXParserFactory factory = SAXParserFactory.newInstance();
+        SAXParser parser = factory.newSAXParser();
+
+        DefaultHandler handler = new DefaultHandler() {
+            private String element = "";
+            private int depth = 0;
+
+            @Override
+            public void startElement(String uri, String localName, String qName,
+                                     Attributes attributes) {
+                depth++;
+                element = qName;
+                StringBuilder indent = new StringBuilder();
+                for (int i = 0; i < depth; i++) indent.append("  ");
+                System.out.print(indent + "<" + qName);
+
+                // 输出属性
+                for (int i = 0; i < attributes.getLength(); i++) {
+                    System.out.print(" " + attributes.getQName(i) + "=\""
+                            + attributes.getValue(i) + "\"");
+                }
+                System.out.println(">");
+            }
+
+            @Override
+            public void characters(char[] ch, int start, int length) {
+                String text = new String(ch, start, length).trim();
+                if (!text.isEmpty()) {
+                    StringBuilder indent = new StringBuilder();
+                    for (int i = 0; i < depth + 1; i++) indent.append("  ");
+                    System.out.println(indent + text);
+                }
+            }
+
+            @Override
+            public void endElement(String uri, String localName, String qName) {
+                StringBuilder indent = new StringBuilder();
+                for (int i = 0; i < depth; i++) indent.append("  ");
+                System.out.println(indent + "</" + qName + ">");
+                depth--;
+            }
+        };
+
+        parser.parse("books.xml", handler);
+    }
+}