Hugo HE commited on
Commit
5d762cb
1 Parent(s): d49e297

add custom BIS target and noise level

Browse files
Files changed (5) hide show
  1. app.py +113 -61
  2. data.csv +0 -0
  3. profile_processed.csv +32 -0
  4. saved_data/patient-0.json +0 -0
  5. 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
- def add_noise(min, max, std, mean):
10
- return np.clip(np.random.normal(mean, std), min, max)
11
-
12
- def gen_pulsive_noise(count, min_val, max_val):
13
- pulse = 0
14
- n = count // 100 # Use integer division to get the floor of count / 100
15
- start = 100 * n
16
- end = start + 50
17
- if (count > start and count < end and n % 15 == 0):
18
- pulse = random.randint(min_val, max_val)
19
-
20
- return pulse
21
- def simulation(input_noise, output_noise, min, max, std, mean, min_pul, max_pul, kd, show_original, derivative_control, moving_average, window_size):
 
 
 
 
 
 
 
 
 
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"]], [60])
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"]], [1])
50
- fmu.setReal([vrs["amesim_interface.Height_cm"]], [168])
51
  fmu.setReal([vrs["amesim_interface.Infusion_rate_mLh"]], [200])
52
- fmu.setReal([vrs["amesim_interface.Weight_kg"]], [75])
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 = 30
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 = 70
73
  p = 0
74
  i = 0
75
  if time >= 4.5e3:
76
- target = 30
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
- if output_noise:
92
- infusion_rate += gen_pulsive_noise(time, min_pul, max_pul)
 
 
 
 
 
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
- df = pd.DataFrame(result)
 
 
 
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
- if input_noise:
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("**BIS noise**")
135
- input_noise = gr.inputs.Checkbox(label="Add Gaussian noise")
136
- with gr.Accordion("noise range", default_open=False):
137
- min_gaussian = gr.inputs.Slider(minimum=0, maximum=20, step=1, default=5, label="noise min")
138
- max_gaussian = gr.inputs.Slider(minimum=0, maximum=20, step=1, default=10, label="noise max")
139
- std_gaussian = gr.inputs.Slider(minimum=0, maximum=10, step=1, default=2, label="noise standard deviation")
140
- mean_gaussian = gr.inputs.Slider(minimum=0, maximum=20, step=1, default=7, label="noise mean")
141
- gr.Markdown("**Infusion noise**")
 
 
 
 
 
 
142
  with gr.Blocks():
143
- output_noise = gr.inputs.Checkbox(label="Add Pulsive noise")
144
- with gr.Accordion("noise range", default_open=False):
145
- min_pul = gr.inputs.Slider(minimum=0, maximum=50, step=1, default=50, label="noise min")
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.inputs.Checkbox(label="Show original")
 
 
 
158
  with gr.Column(scale=5):
159
  plot1 = gr.Plot(label="BIS evolution")
160
  plot2 = gr.Plot(label="Infusion rate evolution")
161
- button.click(simulation, inputs=[input_noise, output_noise, min_gaussian, max_gaussian, std_gaussian, mean_gaussian, min_pul, max_pul, kd_slider, show_original, derivative_control, moving_average, window_size], outputs=[plot1, plot2])
 
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