CodeWorld中如何将模拟动画与图形相结合?
How to combine simulated animation with graphs in CodeWorld?
我玩 CodeWorld 并使用“入口点”activityOf() 来模拟由坦克组成的物理系统。这里我们有一个水箱,其出口流量 qout(h) 取决于容积高度。当然,对于严肃的模拟工作,应该使用其他软件,但在这里做起来仍然很有趣!
program = activityOf(initial, change, tank_water)
composedOf = pictures
-- Initial value and parameter
initial(rs) = 5
g = 9.81
area = 0.015
-- Inlet flow
qin = 0.0
-- Dynamics using Euler approximation
qout(h) = area*sqrt(2*g*max(h,0))
change(h, TimePassing(dt)) = max(h,0) - qout(h)*dt + qin*dt
change(h, other) = h
-- Animation of system
tank_water(h) = composedOf [tank, water(h), graph, coordinatePlane]
tank = translated(thickRectangle(width,height,0.2),position,4)
width = 3
height = 8
position = -5
water(h) = translated(colored(solidPolygon [(-width/2, 0), (-width/2, h), (width/2, h), (width/2,0)],
light(blue)),position,0)
-- Graph of evolution of h(t) - here used monitored values and about 5 seconds between each data point
graph = polyline [(0,5), (1,3.7), (2,2.3), (3,1.3), (4,0.7), (5,0.2), (6, 0)]
出于教育目的,我认为将动画与图表结合起来显示身高随时间变化的图表是很好的。这里我在代码中输入了一个“假”图,因为它很容易测量(我也可以输入解析解使图适应参数)。
我想知道如何包含一个子系统,该子系统从动画中收集数据并在模拟过程中将其呈现在图表中。有什么想法吗?
我想到的一个麻烦的想法是扩展模型状态,其中包括在模拟过程中要收集的测量点。我们可以事先说我们收集了 10 个 h 和 t 的样本,时间距离为 5 秒,然后随着数据的到来扩展图表。
另一个想法是以某种方式将一些通用数据记录器“附加”到 activityOf() 程序中,该程序将数据存储在一个文件中,之后您可以使用任何软件研究该文件。也许这样的记录器已经在 Haskell 环境中可用?
但我不确定如何做到这一点,也许这里有一些更好、更通用的方法?
我将使用“常规”Haskell 环境中的语法和类型进行响应,https://code.world/haskell。
一个activityOf
的类型是:
activityOf ::
world ->
(Event -> world -> world) ->
(world -> Picture) ->
IO ()
正如您所观察到的,没有内置的方法来记录值并将它们绘制成图表。将其添加到 activityOf
似乎是错误的(我们可能想要添加的东西太多了)。
但是你想要这样的功能是什么类型的?可能是以下内容:
activityWithGraphOf ::
world ->
(Event -> world -> world) ->
(world -> Picture) ->
(world -> Double) ->
IO ()
考虑到这个抽象,我会去实现那个功能
- 它自己当然会使用
activityOf
- 它会跟踪
world
状态
- 它会记录时间
- 它会跟踪最近的图表值
- 也许它将传入的
TimePassing
一分为二,如果需要的话,以正确的间隔对图表进行采样。
- 并且它会将包装的 activity 提供的
Picture
与图形 组合起来
听起来是个有趣的练习。现在我有了一个通用函数,可以用于许多图形绘制模拟。
我用“麻烦”的方式解决了问题。希望我能从我得到的输入中更好地构建它。感谢改进建议,以便代码可以更短。我对元组处理感到笨拙。进一步创建 table 和后来的图表可以与罐过程更加分离。这将有助于重用到 CodeWorld 中的其他模拟任务。欢迎改进!
--
我现在更新了代码并使其更短,但还在 table 中添加了更多数据点。 state_and_table 必须是 CodeWorld 中的元组,并且无法使用索引处理元组。
此外,您现在可以使用上下箭头更改泵速 qin。
扩展到两个水箱(或更多)让控制水高变得更具挑战性并将其作为练习留给您!享受吧!
Link 到 运行 https://code.world/#P2uQaw2KBSbyspnQSn5E4Gw
program = activityOf(initial, change, tank_water)
-- Initial values of the total state, i.e. state_and_table
initial(rs) = state_and_table
state_and_table = (time_0, h_0, u_0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
time_0 = 0
h_0 = 7
u_0 = 0
-- Functions to read elements of state_and_table
time_of(time_value,_,_,_,_,_,_,_,_,_,_,_,_,
_,_,_,_,_,_,_,_,_,_) = time_value
h_of(_,h_value,_,_,_,_,_,_,_,_,_,_,_,
_,_,_,_,_,_,_,_,_,_) = h_value
u_of(_,_,u_value,_,_,_,_,_,_,_,_,_,_,
_,_,_,_,_,_,_,_,_,_) = u_value
table_entry((_,_,_,x1,x2,x3,x4,x5,x6,x7,x8,x9,x10,
x11,x12,x13,x14,x15,x16,x17,x18,x19,x20), k)
| k==1 = x1
| k==2 = x2
| k==3 = x3
| k==4 = x4
| k==5 = x5
| k==6 = x6
| k==7 = x7
| k==8 = x8
| k==9 = x9
| k==10 = x10
| k==11 = x11
| k==12 = x12
| k==13 = x13
| k==14 = x14
| k==15 = x15
| k==16 = x16
| k==17 = x17
| k==18 = x18
| k==19 = x19
| k==20 = x20
-- Events of recording state to table at the following times
table_time = [ 5*t-5 | t <- [1..20]]
-- Parameters related to the water flow
g = 9.81
area = 0.025
-- Parameters of the tank
width = 5
height = 8
position = -5
-- Inlet and outlet flow
qin(u) = max(u, 0)
qout(h) = area*sqrt(2*g*max(h,0)) -- Bernoulli's physical model
-- Change of state_and_table
change(state_and_table, TimePassing(dt)) =
-- Update time
(time_of(state_and_table) + dt,
-- Physical state equation -- Euler approximation of differantial equation
max(h_of(state_and_table),0) - qout(h_of(state_and_table))*dt + qin(u_of(state_and_table))*dt,
-- Control variable u
u_of(state_and_table),
-- Event of recording state to table at predfined times
table_update(state_and_table,1),
table_update(state_and_table,2),
table_update(state_and_table,3),
table_update(state_and_table,4),
table_update(state_and_table,5),
table_update(state_and_table,6),
table_update(state_and_table,7),
table_update(state_and_table,8),
table_update(state_and_table,9),
table_update(state_and_table,10),
table_update(state_and_table,11),
table_update(state_and_table,12),
table_update(state_and_table,13),
table_update(state_and_table,14),
table_update(state_and_table,15),
table_update(state_and_table,16),
table_update(state_and_table,17),
table_update(state_and_table,18),
table_update(state_and_table,19),
table_update(state_and_table,20))
-- Key input
change(state_and_table, KeyPress("Up")) =
(time_of(state_and_table),
h_of(state_and_table),
u_of(state_and_table)+0.1,
table_update(state_and_table,1),
table_update(state_and_table,2),
table_update(state_and_table,3),
table_update(state_and_table,4),
table_update(state_and_table,5),
table_update(state_and_table,6),
table_update(state_and_table,7),
table_update(state_and_table,8),
table_update(state_and_table,9),
table_update(state_and_table,10),
table_update(state_and_table,11),
table_update(state_and_table,12),
table_update(state_and_table,13),
table_update(state_and_table,14),
table_update(state_and_table,15),
table_update(state_and_table,16),
table_update(state_and_table,17),
table_update(state_and_table,18),
table_update(state_and_table,19),
table_update(state_and_table,20))
change(state_and_table, KeyPress("Down")) =
(time_of(state_and_table),
h_of(state_and_table),
u_of(state_and_table)-0.1,
table_update(state_and_table,1),
table_update(state_and_table,2),
table_update(state_and_table,3),
table_update(state_and_table,4),
table_update(state_and_table,5),
table_update(state_and_table,6),
table_update(state_and_table,7),
table_update(state_and_table,8),
table_update(state_and_table,9),
table_update(state_and_table,10),
table_update(state_and_table,11),
table_update(state_and_table,12),
table_update(state_and_table,13),
table_update(state_and_table,14),
table_update(state_and_table,15),
table_update(state_and_table,16),
table_update(state_and_table,17),
table_update(state_and_table,18),
table_update(state_and_table,19),
table_update(state_and_table,20))
-- Default equation
change(state_and_table, other) = state_and_table
table_update(state_and_table, k)
| time_of(state_and_table) > table_time # k && table_entry(state_and_table,k)==0 = h_of(state_and_table)
| otherwise = table_entry(state_and_table, k)
-- Animation of system
composedOf = pictures
tank_water(state_and_table) = composedOf [headline, pump(qin(u_of(state_and_table))),
tank, water(h_of(state_and_table)),
graph(state_and_table),
coordinatePlane]
headline = translated(lettering("Tank dynamics"),5,7.5)
pump(qin) = translated(composedOf [lettering("- pump rate ="), translated(lettering(printed(qin)),3.7,0)], 4.5,6.5)
tank = translated(thickRectangle(width,height,0.2),position,4)
water(h) = translated(colored(solidPolygon [(-width/2, 0), (-width/2, h), (width/2, h), (width/2,0)],
light(blue)), position,0)
-- Graph of evolution of h(t) - note time scale is 1 = 10 s etc
scale = 1/10
graph(state_and_table) = colored(polyline [(scale*table_time#k, table_entry(state_and_table, k))
| k <- [1..length(table_time)], table_entry(state_and_table, k) /=0],
light(blue))
我玩 CodeWorld 并使用“入口点”activityOf() 来模拟由坦克组成的物理系统。这里我们有一个水箱,其出口流量 qout(h) 取决于容积高度。当然,对于严肃的模拟工作,应该使用其他软件,但在这里做起来仍然很有趣!
program = activityOf(initial, change, tank_water)
composedOf = pictures
-- Initial value and parameter
initial(rs) = 5
g = 9.81
area = 0.015
-- Inlet flow
qin = 0.0
-- Dynamics using Euler approximation
qout(h) = area*sqrt(2*g*max(h,0))
change(h, TimePassing(dt)) = max(h,0) - qout(h)*dt + qin*dt
change(h, other) = h
-- Animation of system
tank_water(h) = composedOf [tank, water(h), graph, coordinatePlane]
tank = translated(thickRectangle(width,height,0.2),position,4)
width = 3
height = 8
position = -5
water(h) = translated(colored(solidPolygon [(-width/2, 0), (-width/2, h), (width/2, h), (width/2,0)],
light(blue)),position,0)
-- Graph of evolution of h(t) - here used monitored values and about 5 seconds between each data point
graph = polyline [(0,5), (1,3.7), (2,2.3), (3,1.3), (4,0.7), (5,0.2), (6, 0)]
出于教育目的,我认为将动画与图表结合起来显示身高随时间变化的图表是很好的。这里我在代码中输入了一个“假”图,因为它很容易测量(我也可以输入解析解使图适应参数)。
我想知道如何包含一个子系统,该子系统从动画中收集数据并在模拟过程中将其呈现在图表中。有什么想法吗?
我想到的一个麻烦的想法是扩展模型状态,其中包括在模拟过程中要收集的测量点。我们可以事先说我们收集了 10 个 h 和 t 的样本,时间距离为 5 秒,然后随着数据的到来扩展图表。
另一个想法是以某种方式将一些通用数据记录器“附加”到 activityOf() 程序中,该程序将数据存储在一个文件中,之后您可以使用任何软件研究该文件。也许这样的记录器已经在 Haskell 环境中可用?
但我不确定如何做到这一点,也许这里有一些更好、更通用的方法?
我将使用“常规”Haskell 环境中的语法和类型进行响应,https://code.world/haskell。
一个activityOf
的类型是:
activityOf ::
world ->
(Event -> world -> world) ->
(world -> Picture) ->
IO ()
正如您所观察到的,没有内置的方法来记录值并将它们绘制成图表。将其添加到 activityOf
似乎是错误的(我们可能想要添加的东西太多了)。
但是你想要这样的功能是什么类型的?可能是以下内容:
activityWithGraphOf ::
world ->
(Event -> world -> world) ->
(world -> Picture) ->
(world -> Double) ->
IO ()
考虑到这个抽象,我会去实现那个功能
- 它自己当然会使用
activityOf
- 它会跟踪
world
状态 - 它会记录时间
- 它会跟踪最近的图表值
- 也许它将传入的
TimePassing
一分为二,如果需要的话,以正确的间隔对图表进行采样。 - 并且它会将包装的 activity 提供的
Picture
与图形 组合起来
听起来是个有趣的练习。现在我有了一个通用函数,可以用于许多图形绘制模拟。
我用“麻烦”的方式解决了问题。希望我能从我得到的输入中更好地构建它。感谢改进建议,以便代码可以更短。我对元组处理感到笨拙。进一步创建 table 和后来的图表可以与罐过程更加分离。这将有助于重用到 CodeWorld 中的其他模拟任务。欢迎改进!
--
我现在更新了代码并使其更短,但还在 table 中添加了更多数据点。 state_and_table 必须是 CodeWorld 中的元组,并且无法使用索引处理元组。 此外,您现在可以使用上下箭头更改泵速 qin。
扩展到两个水箱(或更多)让控制水高变得更具挑战性并将其作为练习留给您!享受吧!
Link 到 运行 https://code.world/#P2uQaw2KBSbyspnQSn5E4Gw
program = activityOf(initial, change, tank_water)
-- Initial values of the total state, i.e. state_and_table
initial(rs) = state_and_table
state_and_table = (time_0, h_0, u_0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
time_0 = 0
h_0 = 7
u_0 = 0
-- Functions to read elements of state_and_table
time_of(time_value,_,_,_,_,_,_,_,_,_,_,_,_,
_,_,_,_,_,_,_,_,_,_) = time_value
h_of(_,h_value,_,_,_,_,_,_,_,_,_,_,_,
_,_,_,_,_,_,_,_,_,_) = h_value
u_of(_,_,u_value,_,_,_,_,_,_,_,_,_,_,
_,_,_,_,_,_,_,_,_,_) = u_value
table_entry((_,_,_,x1,x2,x3,x4,x5,x6,x7,x8,x9,x10,
x11,x12,x13,x14,x15,x16,x17,x18,x19,x20), k)
| k==1 = x1
| k==2 = x2
| k==3 = x3
| k==4 = x4
| k==5 = x5
| k==6 = x6
| k==7 = x7
| k==8 = x8
| k==9 = x9
| k==10 = x10
| k==11 = x11
| k==12 = x12
| k==13 = x13
| k==14 = x14
| k==15 = x15
| k==16 = x16
| k==17 = x17
| k==18 = x18
| k==19 = x19
| k==20 = x20
-- Events of recording state to table at the following times
table_time = [ 5*t-5 | t <- [1..20]]
-- Parameters related to the water flow
g = 9.81
area = 0.025
-- Parameters of the tank
width = 5
height = 8
position = -5
-- Inlet and outlet flow
qin(u) = max(u, 0)
qout(h) = area*sqrt(2*g*max(h,0)) -- Bernoulli's physical model
-- Change of state_and_table
change(state_and_table, TimePassing(dt)) =
-- Update time
(time_of(state_and_table) + dt,
-- Physical state equation -- Euler approximation of differantial equation
max(h_of(state_and_table),0) - qout(h_of(state_and_table))*dt + qin(u_of(state_and_table))*dt,
-- Control variable u
u_of(state_and_table),
-- Event of recording state to table at predfined times
table_update(state_and_table,1),
table_update(state_and_table,2),
table_update(state_and_table,3),
table_update(state_and_table,4),
table_update(state_and_table,5),
table_update(state_and_table,6),
table_update(state_and_table,7),
table_update(state_and_table,8),
table_update(state_and_table,9),
table_update(state_and_table,10),
table_update(state_and_table,11),
table_update(state_and_table,12),
table_update(state_and_table,13),
table_update(state_and_table,14),
table_update(state_and_table,15),
table_update(state_and_table,16),
table_update(state_and_table,17),
table_update(state_and_table,18),
table_update(state_and_table,19),
table_update(state_and_table,20))
-- Key input
change(state_and_table, KeyPress("Up")) =
(time_of(state_and_table),
h_of(state_and_table),
u_of(state_and_table)+0.1,
table_update(state_and_table,1),
table_update(state_and_table,2),
table_update(state_and_table,3),
table_update(state_and_table,4),
table_update(state_and_table,5),
table_update(state_and_table,6),
table_update(state_and_table,7),
table_update(state_and_table,8),
table_update(state_and_table,9),
table_update(state_and_table,10),
table_update(state_and_table,11),
table_update(state_and_table,12),
table_update(state_and_table,13),
table_update(state_and_table,14),
table_update(state_and_table,15),
table_update(state_and_table,16),
table_update(state_and_table,17),
table_update(state_and_table,18),
table_update(state_and_table,19),
table_update(state_and_table,20))
change(state_and_table, KeyPress("Down")) =
(time_of(state_and_table),
h_of(state_and_table),
u_of(state_and_table)-0.1,
table_update(state_and_table,1),
table_update(state_and_table,2),
table_update(state_and_table,3),
table_update(state_and_table,4),
table_update(state_and_table,5),
table_update(state_and_table,6),
table_update(state_and_table,7),
table_update(state_and_table,8),
table_update(state_and_table,9),
table_update(state_and_table,10),
table_update(state_and_table,11),
table_update(state_and_table,12),
table_update(state_and_table,13),
table_update(state_and_table,14),
table_update(state_and_table,15),
table_update(state_and_table,16),
table_update(state_and_table,17),
table_update(state_and_table,18),
table_update(state_and_table,19),
table_update(state_and_table,20))
-- Default equation
change(state_and_table, other) = state_and_table
table_update(state_and_table, k)
| time_of(state_and_table) > table_time # k && table_entry(state_and_table,k)==0 = h_of(state_and_table)
| otherwise = table_entry(state_and_table, k)
-- Animation of system
composedOf = pictures
tank_water(state_and_table) = composedOf [headline, pump(qin(u_of(state_and_table))),
tank, water(h_of(state_and_table)),
graph(state_and_table),
coordinatePlane]
headline = translated(lettering("Tank dynamics"),5,7.5)
pump(qin) = translated(composedOf [lettering("- pump rate ="), translated(lettering(printed(qin)),3.7,0)], 4.5,6.5)
tank = translated(thickRectangle(width,height,0.2),position,4)
water(h) = translated(colored(solidPolygon [(-width/2, 0), (-width/2, h), (width/2, h), (width/2,0)],
light(blue)), position,0)
-- Graph of evolution of h(t) - note time scale is 1 = 10 s etc
scale = 1/10
graph(state_and_table) = colored(polyline [(scale*table_time#k, table_entry(state_and_table, k))
| k <- [1..length(table_time)], table_entry(state_and_table, k) /=0],
light(blue))