File size: 6,508 Bytes
252c4ba
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ddc9a3f
252c4ba
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4a2dcb9
252c4ba
 
 
 
 
 
 
 
 
 
 
 
 
 
bc3e10a
252c4ba
 
4a2dcb9
 
 
252c4ba
9261c3f
252c4ba
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
04abd90
252c4ba
04abd90
252c4ba
 
b395bd7
252c4ba
 
 
 
b395bd7
ddc9a3f
 
 
 
252c4ba
04abd90
252c4ba
 
 
 
 
bc3e10a
 
13b3f84
 
 
 
252c4ba
 
bc3e10a
252c4ba
bc3e10a
 
b491fa7
252c4ba
3a7adc8
252c4ba
e0c8439
ddc9a3f
252c4ba
 
 
 
ddc9a3f
252c4ba
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
from fmpy import *
from fmpy import read_model_description, extract
from fmpy.fmi2 import FMU2Slave
import numpy as np
import shutil
import pandas as pd
import random
import plotly.graph_objects as go
def add_noise(min, max, std, mean):
        return np.clip(np.random.normal(mean, std), min, max)

def gen_pulsive_noise(count, min_val, max_val):
    pulse = 0
    n = count // 100  # Use integer division to get the floor of count / 100
    start = 100 * n
    end = start + 50
    if (count > start and count < end and n % 15 == 0):
        pulse = random.randint(min_val, max_val)
    
    return pulse
def simulation(input_noise, output_noise, min, max, std, mean, min_pul, max_pul, kp, ki, kd, show_original):
    vrs = {}
    fmu = 'Pharmacokinetics_4_comportmental_model_PI_ref_FMU_base4_OAAS_lnx.fmu'
    model_description = read_model_description(fmu)
    for variable in model_description.modelVariables:
        vrs[variable.name] = variable.valueReference
    start_time = 0.0
    stop_time = 7000
    step_size = 1
    unzipdir = extract(fmu)

    fmu = FMU2Slave(guid=model_description.guid,
                    unzipDirectory=unzipdir,
                    modelIdentifier=model_description.coSimulation.modelIdentifier,
                    instanceName='instance1')

    # initialize
    fmu.instantiate()
    fmu.setupExperiment(startTime=start_time)
    fmu.enterInitializationMode()
    fmu.exitInitializationMode()

    fmu.setReal([vrs["amesim_interface.Age_year"]], [60])
    fmu.setReal([vrs["amesim_interface.BIS0"]], [95.6])
    fmu.setReal([vrs["amesim_interface.BISmin"]], [8.9])
    fmu.setReal([vrs["amesim_interface.Drug_concentration_mgmL"]], [20])
    fmu.setReal([vrs["amesim_interface.EC50"]], [2.23])
    fmu.setReal([vrs["amesim_interface.Gamma"]], [1.58])
    fmu.setReal([vrs["amesim_interface.Gender_0male_1female"]], [1])
    fmu.setReal([vrs["amesim_interface.Height_cm"]], [168])
    fmu.setReal([vrs["amesim_interface.Infusion_rate_mLh"]], [200])
    fmu.setReal([vrs["amesim_interface.Weight_kg"]], [75])
    vr_input = vrs["amesim_interface.Infusion_rate_mLh"]
    vr_output = vrs["amesim_interface.BIS_Index"]

    
    rows = []  # list to record the results
    time = start_time
    infusion_rate = 200
    i = 0
    target = 30
    last_error = 0
    # simulation loop
    while time < stop_time:

        if time >= 2.4e3 and time < 4.5e3:
            target = 70
            p = 0
            i = 0
        if time >= 4.5e3:
            target = 30
            p = 0
            i = 0

        bis = fmu.getReal([int(vr_output)])[0] if time > step_size else 95.6
        if input_noise:
            bis += add_noise(min, max, std, mean)
        p = bis - target
        i = i + p
        d = p - last_error
        last_error = p
        infusion_rate = np.clip(kp*p + ki*i + kd*d, 0, 200)
        if output_noise:
            infusion_rate += gen_pulsive_noise(time, min_pul, max_pul)
        
        fmu.setReal([vr_input], [int(infusion_rate)])
            
        # perform one step
        fmu.doStep(currentCommunicationPoint=time, communicationStepSize=step_size)

        # advance the time
        time += step_size
        # get the values for 'inputs' and 'outputs[4]'
        inputs, outputs = fmu.getReal([int(vr_input), int(vr_output)])

        # append the results
        rows.append((time, bis, inputs))

    fmu.terminate()
    fmu.freeInstance()
    shutil.rmtree(unzipdir, ignore_errors=True)
    result = np.array(rows, dtype=np.dtype([('time', np.float64), ('BIS', np.float64), ('Infusion', np.float64)]))
    result_baseline = np.load("result.npy")
    df = pd.DataFrame(result)  
    df_original = pd.DataFrame(result_baseline)
    trace1 = go.Scatter(x=df.index, y=df['BIS'], mode='lines', name='BIS')
    fig1 = go.Figure(data=trace1)
    fig1.update_layout(height=400, width=1200, title_text="BIS evolution")

    # Add a line trace for column_2 in the second subplot
    trace2 = go.Scatter(x=df.index, y=df['Infusion'], mode='lines', name='Infusion')
    fig2 = go.Figure(data=trace2)
    fig2.update_layout(height=400, width=1200, title_text="Infusion evolution")
    
    if show_original:
        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))
        fig2.add_trace(go.Scatter(x=df_original.index, y=df_original['Infusion'], mode='lines', name='Infusion original',  line=dict(color="red"), opacity=0.5))

    return fig1, fig2    
import gradio as gr 
with gr.Blocks() as demo:
    with gr.Row():
        with gr.Column(scale=1):
            gr.Markdown("**BIS noise**")
            input_noise = gr.inputs.Checkbox(label="Add Gaussian noise")
            with gr.Accordion("noise range"):
                    min_gaussian = gr.inputs.Slider(minimum=0, maximum=20, step=1, default=5, label="noise min")
                    max_gaussian = gr.inputs.Slider(minimum=0, maximum=20, step=1, default=10, label="noise max")
                    std_gaussian = gr.inputs.Slider(minimum=0, maximum=10, step=1, default=2, label="noise standard deviation")
                    mean_gaussian = gr.inputs.Slider(minimum=0, maximum=20, step=1, default=7, label="noise mean")
            gr.Markdown("**Infusion noise**")
            with gr.Blocks():
                output_noise = gr.inputs.Checkbox(label="Add Pulsive noise")
                with gr.Accordion("noise range"):
                    min_pul = gr.inputs.Slider(minimum=0, maximum=50, step=1, default=50, label="noise min")
                    max_pul = gr.inputs.Slider(minimum=0, maximum=150, step=1, default=150, label="noise max")
            gr.Markdown("**PID controller paramters**")
            with gr.Blocks():
                kp_slider = gr.inputs.Slider(minimum=0, maximum=20, default=4, label="kp")
                ki_slider = gr.inputs.Slider(minimum=0, maximum=1, default=0.01, label="ki")
                kd_slider = gr.inputs.Slider(minimum=0, maximum=200, default=120, label="kd")
            show_original = gr.inputs.Checkbox(label="Show original")
            button = gr.Button("Simulate")
        with gr.Column(scale=5):
            plot1 = gr.Plot(label="BIS evolution")
            plot2 = gr.Plot(label="Infusion evolution")
    button.click(simulation, inputs=[input_noise, output_noise, min_gaussian, max_gaussian, std_gaussian, mean_gaussian, min_pul, max_pul, kp_slider, ki_slider, kd_slider, show_original], outputs=[plot1, plot2])
demo.launch()