estimates the current progress that is then used in _receive_signal

        :return: current progress in percent

def _estimate_progress(self):
        """
        estimates the current progress that is then used in _receive_signal

        :return: current progress in percent
        """
        estimate = True
        # ==== get the current subscript and the time it takes to execute it =====
        current_subscript = self._current_subscript_stage['current_subscript']

        # ==== get the number of subscripts =====
        num_subscripts = len(self.scripts)

        # ==== get number of iterations and loop index ======================
        if self.iterator_type == 'loop':
            num_iterations = self.settings['num_loops']
        elif self.iterator_type == 'sweep':
            sweep_range = self.settings['sweep_range']
            if self.settings['stepping_mode'] == 'value_step':
                num_iterations = int((sweep_range['max_value'] - sweep_range['min_value']) / sweep_range['N/value_step']) + 1
                # len(np.linspace(sweep_range['min_value'], sweep_range['max_value'],
                #                                        (sweep_range['max_value'] - sweep_range['min_value']) /
                #                                        sweep_range['N/value_step'] + 1, endpoint=True).tolist())
            elif self.settings['stepping_mode'] == 'N':
                num_iterations = sweep_range['N/value_step']
            else:
                raise KeyError('unknown key' + self.settings['stepping_mode'])

        else:
            print('unknown iterator type in Iterator receive signal - can\'t estimate ramining time')
            estimate = False


        if estimate:
            # get number of loops (completed + 1)
            loop_index = self.loop_index


            if num_subscripts > 1:
                # estimate the progress based on the duration the individual subscripts

                loop_execution_time = 0.  # time for a single loop execution in s
                sub_progress_time = 0.  # progress of current loop iteration in s

                # ==== get typical duration of current subscript ======================
                if current_subscript is not None:
                    current_subscript_exec_duration = self._current_subscript_stage['subscript_exec_duration'][
                        current_subscript.name].total_seconds()
                else:
                    current_subscript_exec_duration = 0.0


                current_subscript_elapsed_time = (datetime.datetime.now() - current_subscript.start_time).total_seconds()
                # estimate the duration of the current subscript if the script hasn't been executed once fully and subscript_exec_duration is 0
                if current_subscript_exec_duration == 0.0:
                    remaining_time = current_subscript.remaining_time.total_seconds()
                    current_subscript_exec_duration = remaining_time + current_subscript_elapsed_time

                # ==== get typical duration of one loop iteration ======================
                remaining_scripts = 0  # script that remain to be executed for the first time
                for subscript_name, duration in self._current_subscript_stage['subscript_exec_duration'].items():
                    if duration.total_seconds() == 0.0:
                        remaining_scripts += 1
                    loop_execution_time += duration.total_seconds()
                    # add the times of the subscripts that have been executed in the current loop
                    # ignore the current subscript, because that will be taken care of later
                    if self._current_subscript_stage['subscript_exec_count'][subscript_name] == loop_index \
                            and subscript_name is not current_subscript.name:
                        # this subscript has already been executed in this iteration
                        sub_progress_time += duration.total_seconds()

                # add the proportional duration of the current subscript given by the subscript progress
                sub_progress_time += current_subscript_elapsed_time

                # if there are scripts that have not been executed yet
                # assume that all the scripts that have not been executed yet take as long as the average of the other scripts
                if remaining_scripts == num_subscripts:
                    # none of the subscript has been finished. assume that all the scripts take as long as the first
                    loop_execution_time = num_subscripts * current_subscript_exec_duration
                elif remaining_scripts > 1:
                    loop_execution_time = 1. * num_subscripts / (num_subscripts - remaining_scripts)
                elif remaining_scripts == 1:
                    # there is only one script left which is the current script
                    loop_execution_time += current_subscript_exec_duration

                if loop_execution_time > 0:
                    progress_subscript = 100. * sub_progress_time / loop_execution_time
                else:
                    progress_subscript = 1. * progress_subscript / num_subscripts

            # print(' === script iterator progress estimation loop_index = {:d}/{:d}, progress_subscript = {:f}'.format(loop_index, number_of_iterations, progress_subscript))
            progress = 100. * (loop_index - 1. + 0.01 * progress_subscript) / num_iterations

        else:
            # if can't estimate the remaining time set to half
            progress = 50
        return progress