Engee 文档
Notebook

定点数据类型

在这个例子中,让我们看看在脚本和模型中与定点数交互的可能性。

定点数是其二进制表示受其整数和小数部分大小限制的数字。 这些数字不具有改变一个点在一个数字的位表示中的位置的能力。

让我们来看看在Engee中呈现的实现。 要确定定点数,使用函数 fi(Value, Sign, Total_bits, Fractional_bits). 它允许您在单个命令中设置任何数字,并且它也不绑定到每个字的固定位数,因此,这允许您获得具有最佳内存成本的算法。

现在我们来看看这个函数的参数是什么意思。

  1. 值-原始数字的值。
  2. Sign-一个符号(1-有符号,0-无符号类型)。
  3. Total_bits-全字大小。
  4. 分数_bits-小数部分的大小。
In [ ]:
Value = 128.9
Sign = 1;
Total_bits = 16;
Fractional_bits = 7;

println("fi: $(fi(Value, Sign, Total_bits, Fractional_bits))")
fi: 128.8984375

让我们运行一些测试 fi() .

让我们设置一个无符号的7位数字与零整数部分。

In [ ]:
x = fi(0.8,0,7,7)
Out[0]:
fi(0.796875, 0, 7, 7)

现在添加一个带有整数部分的数字。 正如我们所看到的,数字类型被自动重新分配。

In [ ]:
x + fi(2.8,0,8,6)
Out[0]:
fi(3.59375, 0, 10, 7)

现在让我们声明一个负8位数,每个小数部分有5位。

In [ ]:
x = fi(-1.8,1,8,5)
Out[0]:
fi(-1.8125, 1, 8, 5)

乘以3。 正如我们所看到的,最终数字为整个部分分配了64位更多的内存。 这是由于三重具有Int64数据类型。

In [ ]:
3x
Out[0]:
fi(-5.4375, 1, 72, 5)

因此,如果我们执行减法运算,数据类型也将被重新定义。

In [ ]:
fi(2.8,1,16,11)-x
Out[0]:
fi(4.6123046875, 1, 17, 11)

此外,我们可以自己显式地重新分配数字类型。

In [ ]:
x = fi(x,1,7,5)
Out[0]:
fi(-1.8125, 1, 7, 5)

正如我们所看到的,在Engee中实现的表示是一个真正通用和抗溢出的工具,因为它会根据用于特定数字的数据类型自动向单词添加位。

定点计算在模型中的应用

现在让我们继续在模型中使用定点数。 为此,Engee提供了在块设置中选择输出数据类型的选项。 下图显示了其中一个块的接口。

在本例中,使用定点逻辑实现PID控制器模型。
比例-积分-微分调节器是反馈控制电路中的器件。 自动控制系统中的PID控制器提供精度好、质量高的控制信号。

下图显示了我们实现的模型。

让我们继续推出这个模型。

In [ ]:
function run_model( name_model, path_to_folder )
    
    Path = path_to_folder * "/" * name_model * ".engee"
    
    if name_model in [m.name for m in engee.get_all_models()] # Проверка условия загрузки модели в ядро
        model = engee.open( name_model ) # Открыть модель
        model_output = engee.run( model, verbose=true ); # Запустить модель
    else
        model = engee.load( Path, force=true ) # Загрузить модель
        model_output = engee.run( model, verbose=true ); # Запустить модель
        engee.close( name_model, force=true ); # Закрыть модель
    end

    return model_output
end
Out[0]:
run_model (generic function with 1 method)
In [ ]:
# Запуск модели
run_model( "simple_model_pid_fixed", @__DIR__ )
Building...
Progress 0%
Progress 78%
Progress 100%
Out[0]:
SimulationResult(
    "SubSystem.command" => WorkspaceArray{Fixed{1, 16, 13, Int16}}("simple_model_pid_fixed/SubSystem.command")

)

接下来,要处理CSV中记录的模拟数据,我们需要连接两个库–DataFramesCSV。 要显示此数据,请使用Plots库。

In [ ]:
# Подключение библиотек
using CSV
using DataFrames
using Plots

现在让我们从CSV中读取数据,绘制结果图并分析这些数据。

In [ ]:
command_fixed = Matrix(CSV.read("$(@__DIR__)/command_fixed.csv", DataFrame)); #загрузка данных
command_fixed = (command_fixed[:,2]);

让我们来看看记录数据的结构。 正如我们在下面看到的,记录的数据以标准格式呈现,不需要额外的处理。

In [ ]:
dump(command_fixed[101])
Float64 3.0198974609375

我们将绘制记录的数据,以及根据建模过程中记录的浮点数据进行分析,并比较它们的准确性。

In [ ]:
command = Matrix(CSV.read("$(@__DIR__)/command.csv", DataFrame)); #загрузка данных
# Построение графиков 
plot(command[:,2]) 
plot!(command_fixed)
Out[0]:

正如我们所看到的,图表大致相同。 为了准确地确定误差,我们将找到它们的差异。

In [ ]:
sum(command[:,2]-command_fixed)
Out[0]:
0.0

事实证明,差异为零。 也可以看出,结果,我们使用的定点数的逻辑并没有影响PID控制器的工作原理。 尽管精度损失,系统趋于平衡。

结论

在这个例子中,我们分析了在脚本和模型中使用定点逻辑的可能性。 我们还发现了如何从模型中保存它们,并在脚本中进行分析或进一步处理。