使用回调自动计算日出和日落时间
该示例描述了基于给定时间和坐标计算日出和日落时间的模型。 该模型应该作为"物联网"设备模型的子系统。 它的回调积极参与模型算法的自动计算和测试。 这允许模型在不使用脚本的情况下自动确定当前日期、位置和时区。
导言
模型开发的主要目标是创建一个子系统,用于计算太阳运动的参数,并使用当前日期和坐标的各种可能设置。 这种子系统的使用方向是各种物联网设备,这些设备支持从实时时钟或NTP服务器接收当前日期,静态坐标设置或自动GPS检测。
为了测试这样一个子系统的算法,有必要改变设置当前日期的方式。 模型使用[回调](https://engee.com/helpcenter/stable/ru/modeling/callbacks-engee.html ),允许您自动确定必要的输入参数,以进行各种设置。
示例模型
示例模型 - IoT_sunrise_sunset.engee. 它的主要计算块是子系统*"时间方程","太阳赤纬","小时角"和"日出,日落时间"*。
街区 Multiport Switch (紫色)用于切换计算模型的输入数据。 街区 Constant (2)-将常量和变量从工作区传递到模型。 街区 Inport 和 Outport (橙色)用作子系统的输入和输出,用于在控制器程序中交换值。 座 Ramp 生成模拟当天序列号变化的变化信号,以测试算法全年的运行情况。 以下模块还用于在计算子系统之间转换测量单位: Gain.
计算日出和日落时间
根据以下表达式在模型的子系统中执行计算:
子系统*"时间方程"*(Equation_of_Time):
哪里
-时间方程,min;
-辅助变量,rad;
-本年度;
-sidereal年;
-当前日期(按年份顺序,其中第1天是1月1日)。
子系统*"太阳赤纬"*(Declination):
哪里 -地球在1天内在轨道上行进的角度,rad;
-从冬至开始的当天地球在轨道上通过的角度为rad;
-地球轨道的偏心率;
-辅助变量,rad;
-地球自转轴的倾斜,rad;
-太阳赤纬,我很高兴。
子系统*"时钟角度"*(hour_angle):
哪里 -观测点的纬度,rad;
-小时角,小时。
这个表达式没有考虑到水平视差、视半径和太阳折射的影响。
子系统*"日出,日落时间"*(Sunrise_Suncet_time):
哪里 -日出时间,一小时;
-日落时间,一小时;
-赤经,小时;
-观测点的经度,度;
-时区,小时。
计算的表达式是从示例末尾给出的文学来源获得的。
设置输入参数
示例模型支持几种设置输入变量的方法:
- -可以设置为变量
current_year从工作区或从子系统端口from_MCU_Y. 它们之间的切换由变量的值执行year_set_mode从工作区。 默认情况下,year_set_mode = 1; - -可由变量向量指定
latitude,longitude和time_zone从工作区或从子系统端口from_MCU_GCS. 它们之间的切换由变量的值执行GCS_set_mode从工作区。 默认情况下,GCS_set_mode = 1; - -可以设置为块
Ramp,变量day_number从工作区或从子系统端口from_MCU_D. 它们之间的切换由变量的值执行day_number_set_mode从工作区。 默认情况下,day_number_set_mode = 1;块Ramp它有一个斜率=1,因此,在366秒的模拟时间内,以1秒的模拟步骤,将为每一天模拟计算,以便整个指定年份。
表达式中给出的常量在回调中设置。
模型回调
[回调](https://engee.com/helpcenter/stable/ru/modeling/callbacks-engee.html 此示例中的模型用于自动获取相关变量、在所有指定模式下进行测试以及为各种任务进行配置。
标签 </> PostLoadFunc 回调代码包含以下代码:
``'茱莉亚
天文常数
偏心=偏心=0.0167;#地球的偏心,2017
倾斜轴=Axial_tilt=23.4372*pi/180;#地球自转轴的倾斜,弧度(23°26'14")
days_in_year=365.256;#地球绕太阳的自转周期,日
使用包含代码生成标志连接文件
("/user/start/examples/codegen/iot_sunrise_sunset_callbacks/CG_start。jl")
if(CG_start==0)#无需初始化变量生成代码
#声明变量
当前_年=0
当前_月=0
当前日=0
日数=0
纬度=0.0
经度=0.0
time_zone=0
#设置模型的默认操作模式
day_number_set_mode=1
year_set_mode=1
GCS_set_mode=1
#按IP计算
##加载库
进口Pkg;
Pkg。添加("Gumbo")
Pkg。添加("HTTP")
Pkg。添加("抽象树")
##连接库
使用HTTP,Gumbo,AbstractTrees
##从网上获取网页
网站=HTTP.get("https://ip2geolocation.com /");
site code_=parsehtml(String(site.体));
站点主体=站点代码。根[2];
##从页面中选择您感兴趣的数据
LATITUDE_IR=body_site[1][1][2][2][1][1][3][8][1][1][1][1][1][10][2][1]. 文本[16:22]
纵向_ir=身体_site[1][1][2][2][1][1][3][8][1][1][1][1][1][11][2][1]. 文本[16:22]
LATITUDE_IR=parse(Float64,纬度)
经度=解析(Float64,经度)
clock_point=body_site[1][1][2][2][1][1][3][8][1][1][1][1][1][12][2][1].文本[20:22]
watch_box=parse(Int64,watch_box)
#默认时间和位置
设置纬度=latitude_ir
经度=经度_ir
time_zone=clock_range
current_year=year_such=日期。值(年(现在()))
结束
从代码注释中可以看出,这个回调函数声明了常量和变量,为变量定义了常量和默认值。 您应该注意这样一个事实,即要确定位置和时区,模型访问外部站点,该站点使用IP连接点确定地理坐标,并将页面作为HTML对象传输到Engee工作区。 与此同时,在代码生成期间,您可以设置标志 CG_start = 1 在文件中 CG_start.jl 以便手动定义用于设置变量的通道。
标签 </> PresaveFunc 回调代码包含以下代码:
``'茱莉亚
如果(day_number_set_mode==1)
year_such=current_year=日期。值(年(现在()))
纬度=latitude_p
经度=经度_p
time_zone=小时
结束
如果(day_number_set_mode==2)
year_such=current_year=日期。值(年(现在()))
month_such=current_month=日期。值(月(现在()))
day_such=current_day=日期。值(日(现在()))
N1=楼层(275*月/9);
N2=楼层((month_such+9)/12);
N3=(1+floor((year_number-4*floor(year_number/ 4) + 2) / 3));
day_number=day_number=Int(N1-(N2*N3)+day_such-30)
纬度=latitude_p
经度=经度_p
time_zone=小时
结束
此函数执行辅助角色-更改当前日期的任务模式时,必须更新输入变量的值。 因此,在更改任务模式并保存模型后,新的变量值将传输到工作区。
标签 </> CloseFunc 回调包含函数 engee.clear(),"包装"在一个代码生成标志检查循环。 因此,当模型关闭时,工作区将被自动清除,并且作为代码生成的结果执行此回调函数将不会清除工作区。
全周期模型测试
让我们继续测试模型算法。 让我们加载并执行模型。
# @markdown **Загрузка и открытие модели:**
# @markdown Требуется ввести только имя модели
имя_модели = "IoT_sunrise_sunset" # @param {type:"string"}
папка_модели = "$(@__DIR__)/"
if имя_модели in [m.name for m in engee.get_all_models()]
модель = engee.open( имя_модели );
# модель = engee.gcm()
else
модель = engee.load( папка_модели*имя_модели*".engee" );
# модель = engee.gcm()
end
данные = engee.run(модель);
拥有一年中每一天的时间方程值的向量,您可以绘制其图形。:
# @markdown **Построение графиков:**
# @markdown Библиотека `Plots.jl`, бэкэнд `plotly()`
using Plots
plotly()
Ширина = 900 # @param {type:"integer"}
Высота = 300 # @param {type:"integer"}
Сигнал_X = "all_days" # @param {type:"string"}
Сигнал_Y = "discrepancy_min" # @param {type:"string"}
Заголовок = "Уравнение времени" # @param {type:"string"}
Подпись_X = "День по порядку" # @param {type:"string"}
Подпись_Y = "Уравнение времени, мин" # @param {type:"string"}
plot(size = (Ширина, Высота), legend = :none, title=Заголовок, xlabel=Подпись_X, ylabel=Подпись_Y)
plot!(данные[Сигнал_X].value, данные[Сигнал_Y].value;
lw = 2, line=:stem)
从一年中太阳的时间和赤纬方程的值的向量,可以为给定的观测点构造太阳的分析:
# @markdown **Построение графиков:**
# @markdown Библиотека `Plots.jl`, бэкэнд `plotly()`
using Plots
plotly()
Ширина = 900 # @param {type:"integer"}
Высота = 300 # @param {type:"integer"}
Сигнал_X = "discrepancy_min" # @param {type:"string"}
Сигнал_Y = "declination" # @param {type:"string"}
Заголовок = "Аналемма" # @param {type:"string"}
Подпись_X = "Уравнение времени, мин" # @param {type:"string"}
Подпись_Y = "Склонение, рад" # @param {type:"string"}
plot(size = (Ширина, Высота), xlims=(-45,45), legend = :none, title=Заголовок, xlabel=Подпись_X, ylabel=Подпись_Y)
plot!(данные[Сигнал_X].value, данные[Сигнал_Y].value;
lw = 2, seriestype=:scatter, color=:yellow, background_color_subplot = :cyan)
在测试算法结束时,我们将为IP确定的观测点坐标绘制当年每一天的日出和日落时间图:
# @markdown **Построение графиков:**
# @markdown Библиотека `Plots.jl`, бэкэнд `plotly()`
using Plots
plotly()
Ширина = 900 # @param {type:"integer"}
Высота = 300 # @param {type:"integer"}
Сигнал_X = "all_days" # @param {type:"string"}
Сигнал_Y1 = "sunrise" # @param {type:"string"}
Подпись_1 = "Время восхода" # @param {type:"string"}
Сигнал_Y2 = "sunset" # @param {type:"string"}
Подпись_2 = "Время заката" # @param {type: "string"}
Расположение_подписей = :topleft # @param [":none", ":topleft", ":top", ":topright", ":left", ":right", ":bottomleft",":bottom",":bottomright", ":outerright", ":outerleft", ":outertop", ":outerbottom", ":outertopright", ":outertopleft", ":outerbottomright", :outerbottomleft] {type:"raw"}
Заголовок = "Восходы и закаты" # @param {type:"string"}
Подпись_X = "День по порядку" # @param {type:"string"}
Подпись_Y = "Время, ч" # @param {type:"string"}
plot(size = (Ширина, Высота), legend = Расположение_подписей, title=Заголовок, xlabel=Подпись_X, ylabel=Подпись_Y)
plot!(данные[Сигнал_X].value, данные[Сигнал_Y1].value;
label = Подпись_1, lw = 2, fillcolor = :darkblue, fillrange = 0)
plot!(данные[Сигнал_X].value, данные[Сигнал_Y2].value;
label = Подпись_2, lw = 2, fillcolor = :yellow, fillrange = 0.01)
plot!(данные[Сигнал_X].value, 24*ones(366);
label = :none, lw = 2, fillcolor = :darkblue, fillrange = 0.01, color = :darkblue)
考虑到上面的假设,描述给定观测点的太阳位置的图表与预期的图表相对应。
确定今天的日出和日落时间
要确定太阳位置的特征,包括今天的日出和日落时间,请切换到当前日期的适当设置模式,然后保存:
day_number_set_mode = 2;
engee.save(модель, папка_модели*имя_модели*".engee"; force = true);
为了控制模型的计算,我们使用[软件控制]功能(https://engee.com/helpcenter/stable/ru/modeling/programmatic-modeling-functions.html )。
现在让我们打印一条消息,以确保模型获取当前日期的单个值。:
import Printf
Printf.@printf "Сегодня %i день по порядку, где день №1 - 01.01.%i" день_по_порядку год_сейчас
让我们运行一个模型来计算今天的日出和日落时间。:
данные = engee.run( модель );
我们将接收到的日出和日落时间值从十进制小时格式转换为整小时,分钟和秒的格式,之后我们将显示带有设置和接收值的消息。:
(дробная_в, часы_в) = modf(данные["sunrise"].value[день_по_порядку])
минуты_в = дробная_в*60
(дробная_в, минуты_в) = modf(минуты_в)
секунды_в = Int(round(дробная_в*60))
часы_в=Int(часы_в)
минуты_в=Int(минуты_в)
(дробная_з, часы_з) = modf(данные["sunset"].value[день_по_порядку])
минуты_з = дробная_з*60
(дробная_з, минуты_з) = modf(минуты_з)
секунды_з = Int(round(дробная_з*60))
часы_з=Int(часы_з)
минуты_з=Int(минуты_з)
Printf.@printf "Сегодня, %i-%i-%i г.\n" день_сейчас месяц_сейчас год_сейчас
Printf.@printf "в текущих координатах: %.2f с.ш. %.2f в.д.\n" широта_IP долгота_IP
Printf.@printf "в часовом поясе UTC+%i \n" часовой_пояс
Printf.@printf "время восхода Солнца - %i:%i:%i \n" часы_в минуты_в секунды_в
Printf.@printf "время заката Солнца - %i:%i:%i \n" часы_з минуты_з секунды_з
考虑到以前接受的假设,给定观测点的日出和日落时间与预期时间相对应。
使用指定坐标确定给定日期的日出和日落时间
可以使用脚本设置当前日期、年份和观测点的变量。 例如,考虑模型如何处理以下数据:
current_year = 2024
day_number = 256 # День программиста
latitude, longitude = (67.048060, 64.060560);
由于设置输入变量的模式没有变化,因此无需保存模型。 让我们用新的输入变量运行模型:
данные = engee.run(модель);
我们将接收到的日出和日落时间值从十进制小时格式转换为整小时,分钟和秒的格式,之后我们将显示带有设置和接收值的消息。:
(дробная_в, часы_в) = modf(данные["sunrise"].value[день_по_порядку])
минуты_в = дробная_в*60
(дробная_в, минуты_в) = modf(минуты_в)
секунды_в = Int(round(дробная_в*60))
часы_в=Int(часы_в)
минуты_в=Int(минуты_в)
(дробная_з, часы_з) = modf(данные["sunset"].value[день_по_порядку])
минуты_з = дробная_з*60
(дробная_з, минуты_з) = modf(минуты_з)
секунды_з = Int(round(дробная_з*60))
часы_з=Int(часы_з)
минуты_з=Int(минуты_з)
println("В день программиста")
Printf.@printf "в координатах: %.2f с.ш. %.2f в.д. \n" latitude longitude
Printf.@printf "в часовом поясе UTC+%i \n" часовой_пояс
Printf.@printf "время восхода Солнца - %i:%i:%i \n" часы_в минуты_в секунды_в
Printf.@printf "время заката Солнца - %i:%i:%i \n" часы_з минуты_з секунды_з
考虑到以前接受的假设,给定观测点的日出和日落时间与预期时间相对应。
配置子系统以从控制器的外围设置坐标和时间
作为模型开发和测试的结果,让我们继续进行模型的最终配置-确定从微控制器设置输入变量的模式。:
# в начале устанавливаем флаг генерации кода из модели
write(папка_модели*"CG_start.jl", "CG_start = 1")
# определяем каналы получения входных переменных
day_number_set_mode = 3
GCS_set_mode = 2
year_set_mode = 2;
从模型生成代码:
# @markdown **Генерация кода:**
# @markdown Папка для результатов генерации кода будет создана в папке скрипта:
папка = "code" # @param {type:"string"}
# @markdown Генерация кода для подсистемы:
включить = false # @param {type:"boolean"}
if(включить)
подсистема = "" # @param {type:"string"}
engee.generate_code( папка_модели*имя_модели*".engee", папка_модели*папка;
subsystem_name = подсистема)
else
engee.generate_code( папка_модели*имя_модели*".engee", папка_модели*папка)
end
# Сбрасываем флаг генерации кода
write(папка_модели*"CG_start.jl", "CG_start = 0");
通过打开生成的文件,您可以确保输入变量是从指定的通道确定的。:
结论
在这个演示中,我们讨论了使用Engee模型的回调来有效地操作和自动化模型的参数化、配置、测试和代码生成过程的方法和可能性。 所描述的算法基于接受的假设再现指定的计算,并且模型可以被重新配置用于各种测试和代码生成任务。
资料来源一览表
- 2019年的天文历法。 第19期(116)/S.M.Ponomarev,N.I.Lapin,M.A.Faddeev,A.P.Gazhulina;s.M.ponomarev编辑。 -诺夫哥罗德:N.I.Lobachevsky国立研究大学出版社,2018。 -351页
- 一般天文学课程/P.I.Bakulin,E.V.Kononovich,V.I.Moroz。 -M.:Nauka,1976。
- Cherny M.A.航空天文学。 -M.:运输,1978年。 -208页
- 计算机年鉴,1990年由航海年鉴办公室出版美国海军天文台华盛顿20392