diff --git a/scripts/acoustics.py b/scripts/acoustics.py
new file mode 100755
index 0000000000000000000000000000000000000000..661cf324ea2b992bee7a7f1910d6c76d0861ca97
--- /dev/null
+++ b/scripts/acoustics.py
@@ -0,0 +1,393 @@
+#!/usr/bin/env python
+# coding=utf-8
+"""
+Online Acoustic Monitoring
+
+Usage:
+    acoustics.py [options]
+    acoustics.py (-h | --help)
+
+Options:
+    -d DET_ID       Detector ID.
+    -o PLOT_DIR     The directory to save the plot [default: plots].
+    -h --help       Show this screen.
+
+"""
+from datetime import datetime
+import os
+import time
+
+import matplotlib
+matplotlib.use("Agg")
+import matplotlib.pyplot as plt
+from matplotlib import colors
+import numpy as np
+import km3pipe as kp
+from docopt import docopt
+
+
+def diff(first, second):
+    second = set(second)
+    return [item for item in first if item not in second]
+
+
+def duplicates(lst, item):
+    return [i for i, x in enumerate(lst) if x == item]
+
+
+args = docopt(__doc__)
+
+detid = args['-d']
+directory = args['-o']
+
+db = kp.db.DBManager()
+sds = kp.db.StreamDS()
+
+ACOUSTIC_BEACONS = [12, 14, 16]
+N_DOMS = 18
+N_ABS = 3
+DOMS = range(N_DOMS + 1)
+DUS = kp.hardware.Detector(det_id=detid).dus
+DUS_cycle = list(np.arange(max(DUS)) + 1)
+
+TIT = 600  # Time Interval between Trains of acoustic pulses)
+SSW = 160  # Signal Security Window (Window size with signal)
+
+clbmap = kp.db.CLBMap(detid)
+
+check = True
+while check:
+
+    minrun = None
+    while minrun is None:
+        try:
+            table = db.run_table(detid)
+            minrun = table["RUN"][len(table["RUN"]) - 1]
+            ind, = np.where((table["RUN"] == minrun))
+            mintime1 = table['UNIXSTARTTIME'][ind]
+            mintime = mintime1.values
+            maxrun = table["RUN"][len(table["RUN"]) - 1]
+            now = time.time()
+            now = now - 600
+            if (now - mintime / 1000) < TIT:
+                minrun = table["RUN"][len(table["RUN"]) - 1] - 1
+            print(now)
+        except:
+            pass
+
+    N_Pulses_Indicator = [
+    ]  # Matrix indicating how many pulses each piezo reveals
+    for du in DUS_cycle:
+        N_Pulses_Indicator_DU = [
+        ]  # Array indicating for each DU how many pulses each piezo reveals.
+        for dom in DOMS:
+            UTB_MIN = []
+            QF_MAX = []
+            for ab in ACOUSTIC_BEACONS:
+                try:
+                    domID = clbmap.omkeys[(du, dom)].dom_id
+                except (KeyError, AttributeError):
+                    N_Pulses_Indicator_DU.append(-1.5)
+                    continue
+
+                try:
+                    toas_all = sds.toashort(detid=detid,
+                                            minrun=minrun,
+                                            maxrun=maxrun,
+                                            domid=domID,
+                                            emitterid=ab)
+                    QF_abdom = toas_all["QUALITYFACTOR"]
+                    UTB_abdom = toas_all["UNIXTIMEBASE"]
+                    TOAS_abdom = toas_all["TOA_S"]
+                    UTB_abdom = UTB_abdom.values
+                    up = np.where(UTB_abdom > (now - TIT))
+                    down = np.where(UTB_abdom < (now))
+                    intr = np.intersect1d(up, down)
+                    UTB_abdom = UTB_abdom[intr]
+                    QF_abdom = QF_abdom[intr]
+                    QF_abdom = QF_abdom.values
+                    QFlist = QF_abdom.tolist()
+                    QFlist.sort(reverse=True)
+                    QF_max = max(QF_abdom)
+                    QF_max_index = np.where(QF_abdom == QF_max)
+                    UTB_signal_min = UTB_abdom[QF_max_index[0][0]] - SSW / 2
+                    UTB_signal_max = UTB_abdom[QF_max_index[0][0]] + SSW / 2
+                    temp1 = np.where(UTB_abdom > (UTB_signal_min))
+                    temp2 = np.where(UTB_abdom < (UTB_signal_max))
+                    inter = np.intersect1d(temp1, temp2)
+                    inter = inter.tolist()
+                    signal_index = inter
+
+                    # Define the signal index if the the pings are splitted in two parts inside the window
+
+                    if UTB_signal_min < (now - TIT):
+                        temp1 = np.where(UTB_abdom > (now - TIT))
+                        temp2 = np.where(UTB_abdom < (UTB_signal_max))
+                        inter1 = np.intersect1d(temp1, temp2)
+                        inter1 = inter1.tolist()
+                        temp11 = np.where(UTB_abdom < (now))
+                        temp22 = np.where(UTB_abdom > (now - SSW / 2))
+                        inter2 = np.intersect1d(temp11, temp22)
+                        inter2 = inter2.tolist()
+                        inter = np.union1d(inter1, inter2)
+                        inter = inter.tolist()
+                        signal_index = inter
+                        signal_index = np.array(signal_index)
+                        signal_index = signal_index.astype(int)
+                        signal_index = signal_index.tolist()
+
+                    if UTB_signal_max > now:
+                        temp1 = np.where(UTB_abdom < (now))
+                        temp2 = np.where(UTB_abdom > (UTB_signal_min))
+                        inter1 = np.intersect1d(temp1, temp2)
+                        inter1 = inter1.tolist()
+                        temp11 = np.where(UTB_abdom > ((now - TIT)))
+                        temp22 = np.where(UTB_abdom < ((now - TIT) + SSW / 2))
+                        inter2 = np.intersect1d(temp11, temp22)
+                        inter2 = inter2.tolist()
+                        inter = np.union1d(inter1, inter2)
+                        inter = inter.tolist()
+                        signal_index = inter
+                        signal_index = np.array(signal_index)
+                        signal_index = signal_index.astype(int)
+                        signal_index = signal_index.tolist()
+
+                    QF_abdom_index = np.where(QF_abdom)
+                    all_data_index = QF_abdom_index[0].tolist()
+                    noise_index = diff(all_data_index, signal_index)
+                    SIGNAL = QF_abdom[signal_index]
+                    UTB_SIGNAL = UTB_abdom[signal_index]
+                    TOA_SIGNAL = TOAS_abdom[signal_index]
+                    NOISE = QF_abdom[noise_index]
+                    NOISElist = NOISE.tolist()
+                    NOISElist.sort(reverse=True)
+                    NOISE = NOISE.tolist()
+                    NOISE.sort(reverse=True)
+                    noise_threshold = max(
+                        NOISE)  # To be sure not to take signal
+
+                    # First filter: 22 greatest
+
+                    Security_Number = 22  # To be sure to take all the pulses
+
+                    SIGNAL = SIGNAL.tolist()
+                    SIGNAL_OLD = np.array(SIGNAL)
+                    SIGNAL.sort(reverse=True)
+                    QF_first = SIGNAL[0:Security_Number]
+
+                    # Second filter: delete duplicates (Delete if Unixtimebase + ToA is the same)
+
+                    QF_second = QF_first
+
+                    R = []
+                    for r in np.arange(len(QF_first)):
+                        R.append(np.where(SIGNAL_OLD == QF_first[r])[0][0])
+                    UTB_first = np.array(UTB_SIGNAL.tolist())[R]
+                    TOA_first = np.array(TOA_SIGNAL.tolist())[R]
+
+                    UNIX_TOA = UTB_first + TOA_first
+                    UNIX_TOA = UNIX_TOA.tolist()
+
+                    UNIX_TOA_index = []
+                    for x in set(UNIX_TOA):
+                        if UNIX_TOA.count(x) > 1:
+                            UNIX_TOA_index.append(duplicates(UNIX_TOA, x))
+
+                    ind_del = []
+                    for i in range(len(UNIX_TOA_index)):
+                        ind_del.append(UNIX_TOA_index[i][0])
+
+                    for ide in sorted(ind_del, reverse=True):
+                        del QF_second[ide]
+
+                    QF_second.sort(reverse=True)
+
+                    # Old second filter
+
+                    #                    QF_second = np.unique(QF_first)
+                    #                    QF_second = QF_second.tolist()
+                    #                    QF_second.sort(reverse = True)
+
+                    # Third filter: If there are more than 11 elements I will eliminate the worst
+
+                    if len(QF_second) > 11:
+                        QF_second = np.array(QF_second)
+                        QF_third = [
+                            k for k in QF_second
+                            if (np.where(QF_second == k)[0][0] < 11)
+                        ]
+                    else:
+                        QF_third = QF_second
+
+                    # Fourth filter: I remove the data if it is below the maximum noise
+
+                    QF_fourth = [
+                        k for k in QF_third
+                        if k > (noise_threshold + (10 * np.std(NOISE)))
+                    ]
+
+                    # Fifth filter: Check if the clicks are interspersed in the right way
+
+                    QF_fifth = QF_fourth
+                    Q = []
+                    for q in np.arange(len(QF_fifth)):
+                        Q.append(np.where(SIGNAL_OLD == QF_fifth[q])[0][0])
+                    UTB_fourth = np.array(UTB_SIGNAL.tolist())[Q]
+                    UTB_fourth_l = UTB_fourth.tolist()
+                    D = []
+                    for g in np.arange(len(UTB_fourth_l)):
+                        if ((np.mod((UTB_fourth_l[g] - UTB_fourth_l[0]), 5) > 2
+                             and np.mod(
+                                 (UTB_fourth_l[g] - UTB_fourth_l[0]), 5) < 4)
+                                or
+                            (np.mod(
+                                (UTB_fourth_l[g] - UTB_fourth_l[0]), 5) > 5)):
+                            D.append(g)
+                    for d in sorted(D, reverse=True):
+                        del QF_fifth[d]
+
+                    # Sixth filter:
+
+                    QF_sixth = [
+                        k for k in QF_fifth
+                        if (abs(k - max(QF_fifth)) < abs(k - noise_threshold))
+                    ]
+
+                    QF_OK = QF_sixth
+
+                    P = []
+                    for p in np.arange(len(QF_OK)):
+                        P.append(np.where(SIGNAL_OLD == QF_OK[p])[0][0])
+                    UTB_OK = np.array(UTB_SIGNAL.tolist())[P]
+                    UTB_OK_l = UTB_OK.tolist()
+
+                    UTB_MIN.append(min(UTB_OK_l))
+
+                    max_QF = max(QF_OK)
+
+                    QF_MAX.append(max_QF)
+
+                    NUM = len(QF_OK)  # Number of pulses
+                    print(NUM)
+
+                    if (NUM > 7):
+                        N_Pulses_Indicator_DU.append(1.5)
+                    elif (NUM < 8 and NUM > 3):
+                        N_Pulses_Indicator_DU.append(0.5)
+                    elif (NUM < 4 and NUM > 0):
+                        N_Pulses_Indicator_DU.append(-0.5)
+                    elif (NUM == 0):
+                        N_Pulses_Indicator_DU.append(-1.5)
+
+                except (
+                        TypeError, ValueError
+                ):  # TypeError if no data found for a certain piezo, ValueError if there are zero data for a certain piezo
+                    N_Pulses_Indicator_DU.append(-1.5)
+
+            # To avoid to take wrong beacon signals
+
+            dim = np.size(QF_MAX)
+            pulse_inter = 5.04872989654541
+
+            for i in range(dim - 1):
+                if (np.mod((UTB_MIN[i] - UTB_MIN[i + 1]), pulse_inter) == 0
+                        or np.mod(
+                            (UTB_MIN[i] - UTB_MIN[i + 1]), pulse_inter) > 5):
+                    if QF_MAX[i] < QF_MAX[i + 1]:
+                        N_Pulses_Indicator_DU[3 * dom + i] = -1.5
+                    else:
+                        N_Pulses_Indicator_DU[3 * dom + i + 1] = -1.5
+                if i == 0 and dim == 3:
+                    if (np.mod(
+                        (UTB_MIN[i] -
+                         UTB_MIN[i + 2]), pulse_inter) == 0 or np.mod(
+                             (UTB_MIN[i] - UTB_MIN[i + 2]), pulse_inter) > 5):
+                        if QF_MAX[i] < QF_MAX[i + 2]:
+                            N_Pulses_Indicator_DU[3 * dom + i] = -1.5
+                        else:
+                            N_Pulses_Indicator_DU[3 * dom + i + 2] = -1.5
+
+        N_Pulses_Indicator.append(N_Pulses_Indicator_DU)
+
+    fig = plt.figure()
+    ax = fig.add_subplot(111)
+
+    duab = []
+    DUs = []
+    for du in DUS_cycle:
+        duabdu = []
+        duab1 = (du - 0.2) * np.ones(N_DOMS + 1)
+        duab2 = (du) * np.ones(N_DOMS + 1)
+        duab3 = (du + 0.2) * np.ones(N_DOMS + 1)
+        duabdu.append(duab1)
+        duabdu.append(duab2)
+        duabdu.append(duab3)
+        duab.append(duabdu)
+        DUs.append(np.array(N_Pulses_Indicator[du - 1]))
+
+    iAB1 = []
+    iAB2 = []
+    iAB3 = []
+    for i in DOMS:
+        iAB1.append(3 * i)
+        iAB2.append(3 * i + 1)
+        iAB3.append(3 * i + 2)
+
+    colorsList = [(0, 0, 0), (1, 0.3, 0), (1, 1, 0), (0.2, 0.9, 0)]
+    CustomCmap = matplotlib.colors.ListedColormap(colorsList)
+    bounds = [-2, -1, 0, 1, 2]
+    norma = colors.BoundaryNorm(bounds, CustomCmap.N)
+    for du in DUS:
+        color = ax.scatter(duab[du - 1][0],
+                           DOMS,
+                           s=20,
+                           c=DUs[du - 1][iAB1],
+                           norm=norma,
+                           marker='s',
+                           cmap=CustomCmap)
+        color = ax.scatter(duab[du - 1][1],
+                           DOMS,
+                           s=20,
+                           c=DUs[du - 1][iAB2],
+                           norm=norma,
+                           marker='s',
+                           cmap=CustomCmap)
+        color = ax.scatter(duab[du - 1][2],
+                           DOMS,
+                           s=20,
+                           c=DUs[du - 1][iAB3],
+                           norm=norma,
+                           marker='s',
+                           cmap=CustomCmap)
+
+    cbar = plt.colorbar(color)
+    cbar.ax.get_yaxis().set_ticks([])
+    for j, lab in enumerate(
+        ['$0. pings$', '$1-3 pings$', '$4-7 pings$', '$>7. pings$']):
+        cbar.ax.text(3.5, (2 * j + 1) / 8.0, lab, ha='center', va='center')
+    cbar.ax.get_yaxis().labelpad = 18
+
+    matplotlib.pyplot.xticks(np.arange(1, max(DUS) + 1, step=1))
+    matplotlib.pyplot.yticks(np.arange(0, 19, step=1))
+    matplotlib.pyplot.grid(color='k', linestyle='-', linewidth=0.2)
+    ax.set_xlabel('DUs', fontsize=18)
+    ax.set_ylabel('Floors', fontsize=18)
+    ts = now + 3600
+    DATE = datetime.utcfromtimestamp(ts).strftime('%Y-%m-%d %H:%M:%S')
+    ax.set_title(
+        r' %.16s Detection of the pings emitted by autonomous beacons' % DATE,
+        fontsize=10)
+
+    my_path = os.path.abspath(directory)
+    my_file = 'Online_Acoustic_Monitoring.png'
+
+    fig.savefig(os.path.join(my_path, my_file))
+
+    print(time.time())
+
+    check = False
+    check_time = time.time() - now
+    print(check_time)
+
+    time.sleep(abs(2 * TIT - check_time))
+    check = True
diff --git a/supervisord_template.conf b/supervisord_template.conf
index ea8a7f69229a753676e23ea51cef764df2d097e7..e0bf5bc280626fb4353b5efb63e32d46c38c011b 100644
--- a/supervisord_template.conf
+++ b/supervisord_template.conf
@@ -79,6 +79,11 @@ priority=10
 stdout_logfile=logs/%(program_name)s.out.log        ; stdout log path, NONE for none; default AUTO
 stderr_logfile=logs/%(program_name)s.err.log        ; stderr log path, NONE for none; default AUTO
 
+[program:acoustics]
+command=python -u scripts/acoustics.py -d %(ENV_DETECTOR_ID)s
+stdout_logfile=logs/%(program_name)s.out.log        ; stdout log path, NONE for none; default AUTO
+stderr_logfile=logs/%(program_name)s.err.log        ; stderr log path, NONE for none; default AUTO
+
 [program:ahrs_calibration]
 command=python -u scripts/ahrs_calibration.py -d %(ENV_DETECTOR_ID)s -p %(ENV_MONITORING_LIGIER_PORT)s
 ;process_name=%(program_name)s ; process_name expr (default %(program_name)s)
@@ -172,7 +177,7 @@ programs=weblog,msg_dumper,chatbot
 priority=200
 
 [group:monitoring_process]
-programs=ahrs_calibration,dom_activity,dom_rates,pmt_rates,trigger_rates,triggermap,ztplot,rttc
+programs=acoustics,ahrs_calibration,dom_activity,dom_rates,pmt_rates,trigger_rates,triggermap,ztplot,rttc
 priority=500
 
 [group:alerts]