Engee 文档
Notebook

定点数据类型

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

定点数是其二进制表示受整数部分和小数部分大小限制的数。这些数字无法改变点在数字位表示中的位置。

为了与此类数字交互,Julia 使用了FixedPointNumbers库,而Engee则有自己的内置方法来实现定点,因此我们的演示将旨在比较这两种指定此类数字的方法。

定点数

定点数库有两个主要命令 **Nifj 和 Qifj,用于指定定点数:

i 和 j 是分配给整数和小数部分的位数;

2.2. N - 表示数字是无符号的;

3.Q - 表示数字的一位分配给符号。

*注意:分配给一个数字的所有位的总和必须等于 8、16、32 或 64 位。

In [ ]:
Pkg.add(["FixedPointNumbers", "CSV"])
   Resolving package versions...
  No Changes to `~/.project/Project.toml`
  No Changes to `~/.project/Manifest.toml`
In [ ]:
using FixedPointNumbers # Подключение библиотеки

接下来,让我们举几个定义和应用此类数字的例子。第一个变例是定义一个无符号小数,其整数部分被分配 0 位。

In [ ]:
x = N0f8(0.8)
Out[0]:
0.8N0f8

然后,我们在这个数上添加一个整数,整数部分分配 2 位。 我们可以看到,最终的数据类型的整数部分和小数部分都有 8 位。因此,我们可以看到数字的位数容量自动增加,这是为了防止溢出。

In [ ]:
x + N2f6(2.8)
Out[0]:
3.592N8f8

接下来,考虑一个带符号的数字,它的整数部分有 2 位,小数部分有 5 位,符号有 1 位。

In [ ]:
x = Q2f5(-1.8)
Out[0]:
-1.81Q2f5

如果将这个数字增加三次,整数部分就会出现溢出,从而丢失数字的符号。

In [ ]:
3x
Out[0]:
2.56Q2f5

为了避免溢出,我们可以强制类型。在这种情况下,我们将用一个具有不同点位置和不同数字维度的数字进行加法运算。当两个数字相加时,产生的数据类型将根据位数较大的数字来分配。

In [ ]:
Q4f11(2.8)-x
Out[0]:
4.6123Q4f11

如果要对一个无符号数和一个有符号数进行运算,我们需要将无符号数转换为分配了符号位的数。float 命令就是用于此目的。

In [ ]:
x=Q2f5(float(N2f6(2.8)))
Out[0]:
2.78Q2f5
In [ ]:
Q4f11(2.8)+x
Out[0]:
5.5811Q4f11

定点执行器

现在让我们看看 Engee 提供的实现方法。```fi(Value, Sign, Total_bits, Fractional_bits)` `` 函数用于定义定点数。它比 Julia 库的功能更多,允许你在一条指令中定义任何数字,而且它不受每字位数的限制,因此,你可以得到内存成本最优的算法。

现在让我们来看看这个函数的参数意味着什么。 1.值 - 原始数字的值。 Sign - 符号(1-符号,0-无符号类型)。 Total_bits - 字的总位数容量。 Fractional_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

让我们重复之前对 Julia 库进行的测试,看看```fi()` `` 是否是一个更通用的命令。

In [ ]:
# x = N0f8(0.8)
x = fi(0.8,0,8,8)
Out[0]:
fi(0.80078125, 0, 8, 8)
In [ ]:
# x + N2f6(2.8)
x + fi(2.8,0,8,6)
Out[0]:
fi(3.59765625, 0, 11, 8)
In [ ]:
# x = Q2f5(-1.8)
x = fi(-1.8,1,8,5)
Out[0]:
fi(-1.8125, 1, 8, 5)
In [ ]:
3x
Out[0]:
fi(-5.4375, 1, 72, 5)
In [ ]:
# Q4f11(2.8)-x
fi(2.8,1,16,11)-x
Out[0]:
fi(4.6123046875, 1, 17, 11)
In [ ]:
# x = Q2f5(float(N2f6(2.8)))
x = fi(fi(2.8,0,8,6),1,8,5)
Out[0]:
fi(2.8125, 1, 8, 5)
In [ ]:
# Q4f11(2.8) + x
fi(2.8,1,16,11) + x
Out[0]:
fi(5.6123046875, 1, 17, 11)

我们可以看到,Engee 实现的表示法确实更通用,也更能防止溢出,因为它会根据特定数字使用的数据类型自动为字添加位。

在模型中使用定点计算

现在让我们继续在模型中使用定点数。为此,在Engee块设置中可以选择输出数据类型。下图显示了其中一个程序块的界面。

image_4.png

本示例使用定点逻辑实现 PID 控制器模型。 比例积分微分控制器是反馈控制回路中的一个装置。它在自动控制系统中用于形成控制信号,以获得瞬态过程所需的精度和质量。

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

image_3.png

下面让我们来看看这款机型的发布情况。

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 控制器的工作原理。尽管精度有所下降,但系统仍趋于平衡。

结论

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

示例中使用的块