Spaces:
Runtime error
Runtime error
Hugo HE
commited on
Commit
•
5d762cb
1
Parent(s):
d49e297
add custom BIS target and noise level
Browse files- app.py +113 -61
- data.csv +0 -0
- profile_processed.csv +32 -0
- saved_data/patient-0.json +0 -0
- test.ipynb +0 -0
app.py
CHANGED
@@ -6,19 +6,28 @@ import shutil
|
|
6 |
import pandas as pd
|
7 |
import random
|
8 |
import plotly.graph_objects as go
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
22 |
vrs = {}
|
23 |
fmu = 'Pharmacokinetics_4_comportmental_model_PI_ref_FMU_base4_OAAS_lnx.fmu'
|
24 |
model_description = read_model_description(fmu)
|
@@ -40,16 +49,16 @@ def simulation(input_noise, output_noise, min, max, std, mean, min_pul, max_pul,
|
|
40 |
fmu.enterInitializationMode()
|
41 |
fmu.exitInitializationMode()
|
42 |
|
43 |
-
fmu.setReal([vrs["amesim_interface.Age_year"]], [
|
44 |
fmu.setReal([vrs["amesim_interface.BIS0"]], [95.6])
|
45 |
fmu.setReal([vrs["amesim_interface.BISmin"]], [8.9])
|
46 |
fmu.setReal([vrs["amesim_interface.Drug_concentration_mgmL"]], [20])
|
47 |
fmu.setReal([vrs["amesim_interface.EC50"]], [2.23])
|
48 |
fmu.setReal([vrs["amesim_interface.Gamma"]], [1.58])
|
49 |
-
fmu.setReal([vrs["amesim_interface.Gender_0male_1female"]], [
|
50 |
-
fmu.setReal([vrs["amesim_interface.Height_cm"]], [
|
51 |
fmu.setReal([vrs["amesim_interface.Infusion_rate_mLh"]], [200])
|
52 |
-
fmu.setReal([vrs["amesim_interface.Weight_kg"]], [
|
53 |
vr_input = vrs["amesim_interface.Infusion_rate_mLh"]
|
54 |
vr_output = vrs["amesim_interface.BIS_Index"]
|
55 |
|
@@ -58,38 +67,35 @@ def simulation(input_noise, output_noise, min, max, std, mean, min_pul, max_pul,
|
|
58 |
time = start_time
|
59 |
infusion_rate = 200
|
60 |
i = 0
|
61 |
-
target =
|
62 |
last_error = 0
|
63 |
-
last_bis = 0
|
64 |
-
bis_history = []
|
65 |
-
kp = 4
|
66 |
-
ki = 0.01
|
67 |
-
kd = kd if derivative_control else 0
|
68 |
# simulation loop
|
|
|
|
|
69 |
while time < stop_time:
|
70 |
|
71 |
if time >= 2.4e3 and time < 4.5e3:
|
72 |
-
target =
|
73 |
p = 0
|
74 |
i = 0
|
75 |
if time >= 4.5e3:
|
76 |
-
target =
|
77 |
p = 0
|
78 |
i = 0
|
79 |
|
80 |
bis = fmu.getReal([int(vr_output)])[0] if time > step_size else 95.6
|
81 |
-
if input_noise:
|
82 |
-
bis += add_noise(min, max, std, mean)
|
83 |
-
if moving_average:
|
84 |
-
bis_history.append(bis)
|
85 |
-
bis = bis if time <= window_size else np.mean(bis_history[-window_size:])
|
86 |
p = bis - target
|
87 |
i = i + p
|
88 |
d = p - last_error
|
89 |
last_error = p
|
90 |
infusion_rate = np.clip(kp*p + ki*i + kd*d, 0, 200)
|
91 |
-
|
92 |
-
|
|
|
|
|
|
|
|
|
|
|
93 |
|
94 |
fmu.setReal([vr_input], [int(infusion_rate)])
|
95 |
|
@@ -108,7 +114,10 @@ def simulation(input_noise, output_noise, min, max, std, mean, min_pul, max_pul,
|
|
108 |
fmu.freeInstance()
|
109 |
shutil.rmtree(unzipdir, ignore_errors=True)
|
110 |
result = np.array(rows, dtype=np.dtype([('time', np.float64), ('BIS', np.float64), ('Infusion', np.float64)]))
|
111 |
-
|
|
|
|
|
|
|
112 |
trace1 = go.Scatter(x=df.index, y=df['BIS'], mode='lines', name='BIS')
|
113 |
fig1 = go.Figure(data=trace1)
|
114 |
fig1.update_layout(height=400, width=1200, title_text="BIS evolution")
|
@@ -118,45 +127,88 @@ def simulation(input_noise, output_noise, min, max, std, mean, min_pul, max_pul,
|
|
118 |
fig2 = go.Figure(data=trace2)
|
119 |
fig2.update_layout(height=400, width=1200, title_text="Infusion rate evolution")
|
120 |
if show_original:
|
121 |
-
|
122 |
-
result_baseline = np.load("result_gaussian.npy")
|
123 |
-
elif output_noise:
|
124 |
-
result_baseline = np.load("result_pulsive.npy")
|
125 |
df_original = pd.DataFrame(result_baseline)
|
126 |
fig1.add_trace(go.Scatter(x=df_original.index, y=df_original['BIS'], mode='lines', name='BIS original', line=dict(color="red"), opacity=0.5))
|
127 |
fig2.add_trace(go.Scatter(x=df_original.index, y=df_original['Infusion'], mode='lines', name='Infusion rate original', line=dict(color="red"), opacity=0.5))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
128 |
|
129 |
-
return fig1, fig2
|
130 |
import gradio as gr
|
131 |
with gr.Blocks() as demo:
|
132 |
with gr.Row():
|
133 |
with gr.Column(scale=1):
|
134 |
-
gr.Markdown("
|
135 |
-
|
136 |
-
|
137 |
-
|
138 |
-
|
139 |
-
|
140 |
-
|
141 |
-
gr.
|
|
|
|
|
|
|
|
|
|
|
|
|
142 |
with gr.Blocks():
|
143 |
-
|
144 |
-
|
145 |
-
|
146 |
-
max_pul = gr.inputs.Slider(minimum=0, maximum=150, step=1, default=150, label="noise max")
|
147 |
-
gr.Markdown("**Advanced control**")
|
148 |
-
with gr.Tab("Smoothing algorithm"):
|
149 |
-
with gr.Row():
|
150 |
-
moving_average = gr.inputs.Checkbox(label="Moving average filter")
|
151 |
-
window_size = gr.inputs.Slider(minimum=0, maximum=200, default=0, label="Window size")
|
152 |
-
with gr.Tab("Derivative control"):
|
153 |
-
with gr.Row():
|
154 |
-
derivative_control = gr.inputs.Checkbox(label="Adding derivative term to PI controller")
|
155 |
-
kd_slider = gr.inputs.Slider(minimum=0, maximum=200, default=0, label="kd")
|
156 |
button = gr.Button("Simulate")
|
157 |
-
show_original = gr.
|
|
|
|
|
|
|
158 |
with gr.Column(scale=5):
|
159 |
plot1 = gr.Plot(label="BIS evolution")
|
160 |
plot2 = gr.Plot(label="Infusion rate evolution")
|
161 |
-
button.click(
|
|
|
162 |
demo.launch()
|
|
|
6 |
import pandas as pd
|
7 |
import random
|
8 |
import plotly.graph_objects as go
|
9 |
+
import json
|
10 |
+
|
11 |
+
from fmpy import *
|
12 |
+
from fmpy import read_model_description, extract
|
13 |
+
from fmpy.fmi2 import FMU2Slave
|
14 |
+
import numpy as np
|
15 |
+
import shutil
|
16 |
+
import pandas as pd
|
17 |
+
import random
|
18 |
+
import plotly.graph_objects as go
|
19 |
+
import json
|
20 |
+
|
21 |
+
df_profile = pd.read_csv("profile_processed.csv")
|
22 |
+
def getProfileFromID(id):
|
23 |
+
return df_profile[df_profile.ID==id].iloc[0, 1:].to_list()
|
24 |
+
|
25 |
+
def simulation(id, kp, ki, kd, bis_target=40, min_noise=50, max_noise=150):
|
26 |
+
profile = getProfileFromID(id)
|
27 |
+
age = profile[0]
|
28 |
+
weight = profile[1]
|
29 |
+
height = profile[2]
|
30 |
+
gender = profile[3]
|
31 |
vrs = {}
|
32 |
fmu = 'Pharmacokinetics_4_comportmental_model_PI_ref_FMU_base4_OAAS_lnx.fmu'
|
33 |
model_description = read_model_description(fmu)
|
|
|
49 |
fmu.enterInitializationMode()
|
50 |
fmu.exitInitializationMode()
|
51 |
|
52 |
+
fmu.setReal([vrs["amesim_interface.Age_year"]], [age])
|
53 |
fmu.setReal([vrs["amesim_interface.BIS0"]], [95.6])
|
54 |
fmu.setReal([vrs["amesim_interface.BISmin"]], [8.9])
|
55 |
fmu.setReal([vrs["amesim_interface.Drug_concentration_mgmL"]], [20])
|
56 |
fmu.setReal([vrs["amesim_interface.EC50"]], [2.23])
|
57 |
fmu.setReal([vrs["amesim_interface.Gamma"]], [1.58])
|
58 |
+
fmu.setReal([vrs["amesim_interface.Gender_0male_1female"]], [gender])
|
59 |
+
fmu.setReal([vrs["amesim_interface.Height_cm"]], [height])
|
60 |
fmu.setReal([vrs["amesim_interface.Infusion_rate_mLh"]], [200])
|
61 |
+
fmu.setReal([vrs["amesim_interface.Weight_kg"]], [weight])
|
62 |
vr_input = vrs["amesim_interface.Infusion_rate_mLh"]
|
63 |
vr_output = vrs["amesim_interface.BIS_Index"]
|
64 |
|
|
|
67 |
time = start_time
|
68 |
infusion_rate = 200
|
69 |
i = 0
|
70 |
+
target = bis_target
|
71 |
last_error = 0
|
|
|
|
|
|
|
|
|
|
|
72 |
# simulation loop
|
73 |
+
impulsive_noise = random.randint(min_noise, max_noise)
|
74 |
+
print("noise level:", impulsive_noise)
|
75 |
while time < stop_time:
|
76 |
|
77 |
if time >= 2.4e3 and time < 4.5e3:
|
78 |
+
target = 60
|
79 |
p = 0
|
80 |
i = 0
|
81 |
if time >= 4.5e3:
|
82 |
+
target = bis_target
|
83 |
p = 0
|
84 |
i = 0
|
85 |
|
86 |
bis = fmu.getReal([int(vr_output)])[0] if time > step_size else 95.6
|
|
|
|
|
|
|
|
|
|
|
87 |
p = bis - target
|
88 |
i = i + p
|
89 |
d = p - last_error
|
90 |
last_error = p
|
91 |
infusion_rate = np.clip(kp*p + ki*i + kd*d, 0, 200)
|
92 |
+
|
93 |
+
# add impulsive noise to infusion rate
|
94 |
+
n = time // 100
|
95 |
+
start = 100 * n
|
96 |
+
end = start + 50
|
97 |
+
if (time > start and time < end and n % 15 == 0):
|
98 |
+
infusion_rate += impulsive_noise
|
99 |
|
100 |
fmu.setReal([vr_input], [int(infusion_rate)])
|
101 |
|
|
|
114 |
fmu.freeInstance()
|
115 |
shutil.rmtree(unzipdir, ignore_errors=True)
|
116 |
result = np.array(rows, dtype=np.dtype([('time', np.float64), ('BIS', np.float64), ('Infusion', np.float64)]))
|
117 |
+
return result, impulsive_noise
|
118 |
+
|
119 |
+
def plot_result(result, show_original):
|
120 |
+
df = pd.DataFrame(result)
|
121 |
trace1 = go.Scatter(x=df.index, y=df['BIS'], mode='lines', name='BIS')
|
122 |
fig1 = go.Figure(data=trace1)
|
123 |
fig1.update_layout(height=400, width=1200, title_text="BIS evolution")
|
|
|
127 |
fig2 = go.Figure(data=trace2)
|
128 |
fig2.update_layout(height=400, width=1200, title_text="Infusion rate evolution")
|
129 |
if show_original:
|
130 |
+
result_baseline = np.load("result_impulsive.npy")
|
|
|
|
|
|
|
131 |
df_original = pd.DataFrame(result_baseline)
|
132 |
fig1.add_trace(go.Scatter(x=df_original.index, y=df_original['BIS'], mode='lines', name='BIS original', line=dict(color="red"), opacity=0.5))
|
133 |
fig2.add_trace(go.Scatter(x=df_original.index, y=df_original['Infusion'], mode='lines', name='Infusion rate original', line=dict(color="red"), opacity=0.5))
|
134 |
+
else:
|
135 |
+
np.save("result_impulsive.npy", result)
|
136 |
+
return fig1, fig2
|
137 |
+
|
138 |
+
def gradio_display_profile(id):
|
139 |
+
profile = getProfileFromID(id)
|
140 |
+
gender = "Male" if profile[3] == 0 else "Female"
|
141 |
+
data = {}
|
142 |
+
data["age"] = [profile[0]]
|
143 |
+
data["weight"] = [profile[1]]
|
144 |
+
data["height"] = [profile[2]]
|
145 |
+
data["gender"] = [gender]
|
146 |
+
df = pd.DataFrame(data)
|
147 |
+
return df
|
148 |
+
|
149 |
+
def gradio_simulation(id, kp, ki, kd, show_original, bis_target, min_noise, max_noise):
|
150 |
+
result, noise_level = simulation(id, kp, ki, kd, bis_target, min_noise, max_noise)
|
151 |
+
fig1, fig2 = plot_result(result, show_original)
|
152 |
+
return fig1, fig2, noise_level
|
153 |
+
|
154 |
+
def gradio_save(id, kp, ki, kd, bis_target, min_noise, max_noise):
|
155 |
+
result, noise_level = simulation(id, kp, ki, kd, bis_target, min_noise, max_noise)
|
156 |
+
patient_profile = getProfileFromID(id)
|
157 |
+
|
158 |
+
|
159 |
+
# Assuming patient_profile is a list of 4 integers, bis_trace is a list of 7000 floats, and kp, ki, kd are floats
|
160 |
+
data = {
|
161 |
+
'inputs': {
|
162 |
+
'patient_profile': {
|
163 |
+
'age': patient_profile[0],
|
164 |
+
'weight': patient_profile[1],
|
165 |
+
'height': patient_profile[2],
|
166 |
+
'gender': patient_profile[3]
|
167 |
+
},
|
168 |
+
'bis_trace': result['BIS'].tolist(),
|
169 |
+
'noise_level': noise_level
|
170 |
+
},
|
171 |
+
'outputs': {
|
172 |
+
'kp': kp,
|
173 |
+
'ki': ki,
|
174 |
+
'kd': kd
|
175 |
+
}
|
176 |
+
}
|
177 |
+
with open(f'saved_data/patient-{id}.json', 'w') as f:
|
178 |
+
json.dump(data, f)
|
179 |
+
return "Saved"
|
180 |
+
|
181 |
|
|
|
182 |
import gradio as gr
|
183 |
with gr.Blocks() as demo:
|
184 |
with gr.Row():
|
185 |
with gr.Column(scale=1):
|
186 |
+
gr.Markdown("# BIS Target")
|
187 |
+
bis_target = gr.Slider(minimum=0, maximum=100, step=1, value=30, label="BIS target")
|
188 |
+
gr.Markdown("# Impulsive noise range")
|
189 |
+
min_noise = gr.Slider(minimum=0, maximum=50, step=1, value=50, label="noise min")
|
190 |
+
max_noise = gr.Slider(minimum=0, maximum=150, step=1, value=150, label="noise max")
|
191 |
+
gr.Markdown("# Patient profile")
|
192 |
+
id = gr.Number(value=1, precision=0, label="Patient ID")
|
193 |
+
profile_output = gr.Dataframe(value=gradio_display_profile(1), label="Patient profile")
|
194 |
+
id.change(gradio_display_profile, inputs=[id], outputs=[profile_output])
|
195 |
+
# with gr.Blocks():
|
196 |
+
# with gr.Accordion("noise range"):
|
197 |
+
# min_pul = gr.Slider(minimum=0, maximum=50, step=1, value=50, label="noise min")
|
198 |
+
# max_pul = gr.Slider(minimum=0, maximum=150, step=1, value=150, label="noise max")
|
199 |
+
gr.Markdown("# PID parameters")
|
200 |
with gr.Blocks():
|
201 |
+
kp = gr.Slider(minimum=0, maximum=20, value=4, label="kp")
|
202 |
+
ki = gr.Slider(minimum=0, maximum=1, value=0.01, label="ki")
|
203 |
+
kd = gr.Slider(minimum=0, maximum=200, value=0, label="kd")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
204 |
button = gr.Button("Simulate")
|
205 |
+
show_original = gr.Checkbox(label="Show original")
|
206 |
+
gr.Markdown("# Save the best parameters")
|
207 |
+
save_result = gr.Button("Save")
|
208 |
+
save_output = gr.Textbox(label="Save status")
|
209 |
with gr.Column(scale=5):
|
210 |
plot1 = gr.Plot(label="BIS evolution")
|
211 |
plot2 = gr.Plot(label="Infusion rate evolution")
|
212 |
+
button.click(gradio_simulation, inputs=[id, kp, ki, kd, show_original, bis_target, min_noise, max_noise], outputs=[plot1, plot2])
|
213 |
+
save_result.click(gradio_save, inputs=[id, kp, ki, kd, bis_target, min_noise, max_noise], outputs=[save_output])
|
214 |
demo.launch()
|
data.csv
ADDED
The diff for this file is too large to render.
See raw diff
|
|
profile_processed.csv
ADDED
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
ID,AGE,WT,HT,Gender
|
2 |
+
0,60,75,168,1
|
3 |
+
1,59,64,166,1
|
4 |
+
2,62,75,183,0
|
5 |
+
3,57,106,171,0
|
6 |
+
4,53,77,170,0
|
7 |
+
5,73,82,168,0
|
8 |
+
6,69,50,166,1
|
9 |
+
7,53,80,170,0
|
10 |
+
8,53,72,165,0
|
11 |
+
9,58,84,190,0
|
12 |
+
10,58,81,177,0
|
13 |
+
11,69,89,201,0
|
14 |
+
12,57,83,180,0
|
15 |
+
13,71,77,170,0
|
16 |
+
14,49,90,171,0
|
17 |
+
15,77,75,175,0
|
18 |
+
16,63,84,178,0
|
19 |
+
17,62,83,180,0
|
20 |
+
18,77,68,170,0
|
21 |
+
19,73,85,178,0
|
22 |
+
20,74,66,170,0
|
23 |
+
21,71,85,178,0
|
24 |
+
22,58,122,198,0
|
25 |
+
23,79,86,182,0
|
26 |
+
24,75,68,168,1
|
27 |
+
25,60,91,179,0
|
28 |
+
26,44,75,160,1
|
29 |
+
27,48,79,178,0
|
30 |
+
28,78,84,157,1
|
31 |
+
29,68,93,178,0
|
32 |
+
30,64,76,175,0
|
saved_data/patient-0.json
ADDED
The diff for this file is too large to render.
See raw diff
|
|
test.ipynb
ADDED
The diff for this file is too large to render.
See raw diff
|
|