def membership_f(mf, x, abcd): """ Returns y values corresponding to type of type of Membership fn. arguments: mf - string containing type of Membership function x - x axis values """ if mf == "zmf": return fuzz.zmf(x, abcd[0], abcd[1]) # zmf(x, a, b) elif mf == "trimf": return fuzz.trimf(x, abcd[0:3]) # trimf(x, abc) elif mf == "dsigmf": return fuzz.dsigmf(x, abcd[0], abcd[1], abcd[2], abcd[3]) # dsigmf(x, b1, c1, b2, c2) elif mf == "gauss2mf": return fuzz.gauss2mf(x, abcd[0], abcd[1], abcd[2], abcd[3]) # gauss2mf(x, mean1, sigma1, mean2, sigma2) elif mf == "gaussmf": return fuzz.gaussmf(x, abcd[0], abcd[1]) # gaussmf(x, mean, sigma) elif mf == "gbellmf": return fuzz.gbellmf(x, abcd[0], abcd[1], abcd[2]) # gbellmf(x, a, b, c) elif mf == "piecemf": return fuzz.piecemf(x, abcd[0:3]) # piecemf(x, abc) elif mf == "pimf": return fuzz.pimf(x, abcd[0], abcd[1], abcd[2], abcd[3]) # pimf(x, a, b, c, d) elif mf == "psigmf": return fuzz.psigmf(x, abcd[0], abcd[1], abcd[2], abcd[3]) # psigmf(x, b1, c1, b2, c2) elif mf == "sigmf": return fuzz.sigmf(x, abcd[0], abcd[1]) # sigmf(x, b, c) elif mf == "smf": return fuzz.smf(x, abcd[0], abcd[1]) # smf(x, a, b) elif mf == "trapmf": return fuzz.trapmf(x, abcd) # trapmf(x, abcd)
def membership_f(mf, x, abcd): """ Returns y values corresponding to type of type of Membership fn. arguments: mf - string containing type of Membership function x - x axis values """ if mf == 'zmf': return fuzz.zmf(x, abcd[0], abcd[1]) # zmf(x, a, b) elif mf == 'trimf': return fuzz.trimf(x, abcd[0:3]) # trimf(x, abc) elif mf == 'dsigmf': return fuzz.dsigmf(x, abcd[0], abcd[1], abcd[2], abcd[3]) # dsigmf(x, b1, c1, b2, c2) elif mf == 'gauss2mf': return fuzz.gauss2mf( x, abcd[0], abcd[1], abcd[2], abcd[3]) # gauss2mf(x, mean1, sigma1, mean2, sigma2) elif mf == 'gaussmf': return fuzz.gaussmf(x, abcd[0], abcd[1]) # gaussmf(x, mean, sigma) elif mf == 'gbellmf': return fuzz.gbellmf(x, abcd[0], abcd[1], abcd[2]) # gbellmf(x, a, b, c) elif mf == 'piecemf': return fuzz.piecemf(x, abcd[0:3]) # piecemf(x, abc) elif mf == 'pimf': return fuzz.pimf(x, abcd[0], abcd[1], abcd[2], abcd[3]) # pimf(x, a, b, c, d) elif mf == 'psigmf': return fuzz.psigmf(x, abcd[0], abcd[1], abcd[2], abcd[3]) # psigmf(x, b1, c1, b2, c2) elif mf == 'sigmf': return fuzz.sigmf(x, abcd[0], abcd[1]) # sigmf(x, b, c) elif mf == 'smf': return fuzz.smf(x, abcd[0], abcd[1]) # smf(x, a, b) elif mf == 'trapmf': return fuzz.trapmf(x, abcd) # trapmf(x, abcd)
def calcularParticaoGaussiana(self, index): pontoMedio = self.ponto_referencial + self.largura_entre_pontos_inferiores desvio = self.largura_entre_pontos_inferiores / 3.5 if index == 0: self.pontosCentrais.append(self.inicio) return fuzz.gauss2mf(self.eixo_x, self.inicio, 0.1, self.inicio, desvio) elif index == len(self.tiposConjunto) - 1: self.pontosCentrais.append(self.fim) return fuzz.gauss2mf(self.eixo_x, self.fim, desvio, self.fim, 0.1) else: self.pontosCentrais.append(pontoMedio) self.pontosIniciais.append("GAUSS") self.pontosFinais.append("GAUSS") self.ponto_referencial += self.largura_entre_pontos_inferiores #return fuzz.gauss2mf(self.eixo_x, pontoMedio, desvio * 2, self.fim, 0.1) return fuzz.gaussmf(self.eixo_x, pontoMedio, desvio)
def game_type(player, comp): """ A fuzzy algorithm to define the offensiveness and/or defensiveness of the game. Determines how aggressive the fuzzy player is""" score_diff = float(player-comp) ### Inputs ### # Input Variable Domain score = np.arange(-21, 21, 1) # Input membership functions score_ahead = fuzz.gaussmf(score, -21, 8.823) score_tied = fuzz.gaussmf(score, 0, 9.012) score_behind = fuzz.gaussmf(score, 21, 8.823) # Fuzzifying the current input def score_category(sc): score_cat_ahead = fuzz.interp_membership(score, score_ahead, sc) score_cat_tied = fuzz.interp_membership(score, score_tied, sc) score_cat_behind = fuzz.interp_membership(score, score_behind, sc) return dict(ahead = score_cat_ahead, tied = score_cat_tied, behind = score_cat_behind) ### Outputs ### # Output Variable Domain game = np.arange(0, 1, 1) # Output membership functions game_defensive = fuzz.gaussmf(game, 0, 0.162899) game_offensive = fuzz.gauss2mf(game, 0.30291, 0.090976, 1.31, 0.416) ### Rules ### current_score = score_category(score_diff) # Going to make this a hard opponent, so if the score is tied or # if the human is winning, it will play offensively rule1 = current_score['ahead'] rule2 = np.fmax(current_score['tied'], current_score['behind']) # Apply implication operator (Mamdami) imp1 = np.fmin(rule1, game_defensive) imp2 = np.fmin(rule2, game_offensive) # Aggregate outputs using max aggregate_membership = np.fmax(imp1, imp2) # Defuzzify using centroid and return the result result_game = fuzz.defuzz(game, aggregate_membership, 'centroid') return result_game
def membership_f(mf, x, abc = [0,0,0], a = 1, b = 2, c = 3, d = 4, abcd = [0,0,0,0]): return { 'trimf' : fuzz.trimf(x, abc), # trimf(x, abc) 'dsigmf' : fuzz.dsigmf(x, a, b, c, d), # dsigmf(x, b1, c1, b2, c2) 'gauss2mf': fuzz.gauss2mf(x, a, b, c, d), # gauss2mf(x, mean1, sigma1, mean2, sigma2) 'gaussmf' : fuzz.gaussmf(x, a, b), # gaussmf(x, mean, sigma) 'gbellmf' : fuzz.gbellmf(x, a, b, c), # gbellmf(x, a, b, c) 'piecemf' : fuzz.piecemf(x, abc), # piecemf(x, abc) 'pimf' : fuzz.pimf(x, a, b, c, d), # pimf(x, a, b, c, d) 'psigmf' : fuzz.psigmf(x, a, b, c, d), # psigmf(x, b1, c1, b2, c2) 'sigmf' : fuzz.sigmf(x, a, b), # sigmf(x, b, c) 'smf' : fuzz.smf(x, a, b), # smf(x, a, b) 'trapmf' : fuzz.trapmf(x, abcd), # trapmf(x, abcd) 'zmf' : fuzz.zmf(x, a, b), # zmf(x, a, b) }[mf]
def membership_f(mf, x, abc=[0, 0, 0], a=1, b=2, c=3, d=4, abcd=[0, 0, 0, 0]): """ Returns y values corresponding to type of type of Membership fn. arguments: mf - string containing type of Membership function x - x axis values abc - list containing triangular edge point x-values """ return { "trimf": fuzz.trimf(x, abc), # trimf(x, abc) "dsigmf": fuzz.dsigmf(x, a, b, c, d), # dsigmf(x, b1, c1, b2, c2) "gauss2mf": fuzz.gauss2mf(x, a, b, c, d), # gauss2mf(x, mean1, sigma1, mean2, sigma2) "gaussmf": fuzz.gaussmf(x, a, b), # gaussmf(x, mean, sigma) "gbellmf": fuzz.gbellmf(x, a, b, c), # gbellmf(x, a, b, c) "piecemf": fuzz.piecemf(x, abc), # piecemf(x, abc) "pimf": fuzz.pimf(x, a, b, c, d), # pimf(x, a, b, c, d) "psigmf": fuzz.psigmf(x, a, b, c, d), # psigmf(x, b1, c1, b2, c2) "sigmf": fuzz.sigmf(x, a, b), # sigmf(x, b, c) "smf": fuzz.smf(x, a, b), # smf(x, a, b) "trapmf": fuzz.trapmf(x, abcd), # trapmf(x, abcd) "zmf": fuzz.zmf(x, a, b), # zmf(x, a, b) }[mf]
def membership_f(mf, x, abc = [0,0,0], a = 1, b = 2, c = 3, d = 4, abcd = [0,0,0,0]): """ Returns y values corresponding to type of type of Membership fn. arguments: mf - string containing type of Membership function x - x axis values abc - list containing triangular edge point x-values """ return { 'trimf' : fuzz.trimf(x, abc), # trimf(x, abc) 'dsigmf' : fuzz.dsigmf(x, a, b, c, d), # dsigmf(x, b1, c1, b2, c2) 'gauss2mf': fuzz.gauss2mf(x, a, b, c, d), # gauss2mf(x, mean1, sigma1, mean2, sigma2) 'gaussmf' : fuzz.gaussmf(x, a, b), # gaussmf(x, mean, sigma) 'gbellmf' : fuzz.gbellmf(x, a, b, c), # gbellmf(x, a, b, c) 'piecemf' : fuzz.piecemf(x, abc), # piecemf(x, abc) 'pimf' : fuzz.pimf(x, a, b, c, d), # pimf(x, a, b, c, d) 'psigmf' : fuzz.psigmf(x, a, b, c, d), # psigmf(x, b1, c1, b2, c2) 'sigmf' : fuzz.sigmf(x, a, b), # sigmf(x, b, c) 'smf' : fuzz.smf(x, a, b), # smf(x, a, b) 'trapmf' : fuzz.trapmf(x, abcd), # trapmf(x, abcd) 'zmf' : fuzz.zmf(x, a, b), # zmf(x, a, b) }[mf]
def fuzz_UpperMemFunc(x_var, typeOfMf, lst): ''' returns Upper membership values. keyword arguments: x_var -- x range of variable var typeOfMf -- type of membershi function lst -- list of values provided ''' if typeOfMf == 'trimf': return fuzz.trimf(x_var, lst) elif typeOfMf == 'gaussmf': mean, sigma = lst return fuzz.gaussmf(x_var, mean, sigma) elif typeOfMf == 'gauss2mf': mean1, sigma1, mean2, sigma2 = lst return fuzz.gauss2mf(x_var, mean1, sigma1, mean2, sigma2) elif typeOfMf == 'trapmf': return fuzz.trapmf(x_var, lst) elif typeOfMf == 'gbellmf': a, b, c = lst return fuzz.gbellmf(x_var, a, b, c)
def fuzzy_logic(path, max_I, max_Q, max_Qdot, max_dI, strom, waerme, Q_dot): data = pd.read_csv('C:/DA/Code/LVQ/Schweissdata.csv', index_col=0) data.Zustand.replace({-1: 0, 0: 1, 1: 2}, inplace=True) kalt = data.loc[data['Zustand'] == 0] normal = data.loc[data['Zustand'] == 1] spritzer = data.loc[data['Zustand'] == 2] kalt_I_sgm = np.std(kalt[['Strom']]) kalt_I_mu = np.mean(kalt[['Strom']]) normal_I_sgm = np.std(normal[['Strom']]) normal_I_mu = np.mean(normal[['Strom']]) spritzer_I_sgm = np.std(spritzer[['Strom']]) spritzer_I_mu = np.mean(spritzer[['Strom']]) kalt_Qpdot_sgm = np.std(kalt[['Qpdot']]) kalt_Qpdot_mu = np.mean(kalt[['Qpdot']]) normal_Qpdot_sgm = np.std(normal[['Qpdot']]) normal_Qpdot_mu = np.mean(normal[['Qpdot']]) spritzer_Qpdot_sgm = np.std(spritzer[['Qpdot']]) spritzer_Qpdot_mu = np.mean(spritzer[['Qpdot']]) kalt_Qges_sgm = np.std(kalt[['Qges']]) kalt_Qges_mu = np.mean(kalt[['Qges']]) normal_Qges_sgm = np.std(normal[['Qges']]) normal_Qges_mu = np.mean(normal[['Qges']]) spritzer_Qges_sgm = np.std(spritzer[['Qges']]) spritzer_Qges_mu = np.mean(spritzer[['Qges']]) unspritzer = data.loc[data['Zustand'] <= 1] spritzer = data.loc[data['Zustand'] == 2] unsp_di_sgm = np.std(unspritzer[['delta_I']]) unsp_di_mu = np.mean(unspritzer[['delta_I']]) sp_di_sgm = np.std(spritzer[['delta_I']]) sp_di_mu = np.mean(spritzer[['delta_I']]) I = np.arange(0, max_I + 0.01, 0.01) Q = np.arange(0, max_Q + 0.01, 0.01) Qdot = np.arange(0, max_Qdot + 0.01, 0.01) d_I = np.arange(0, max_dI + 0.01, 0.01) I_lo = fuzz.gauss2mf(I, min(I), 1, kalt_I_mu[0], kalt_I_sgm[0]) I_md = fuzz.gaussmf(I, normal_I_mu[0], normal_I_sgm[0]) I_hi = fuzz.gauss2mf(I, spritzer_I_mu[0], spritzer_I_sgm[0], max(I), 1) Q_lo = fuzz.gauss2mf(Q, min(Q), 1, kalt_Qges_mu[0], kalt_Qges_sgm[0]) Q_md = fuzz.gaussmf(Q, normal_Qges_mu[0], normal_Qges_sgm[0]) Q_hi = fuzz.gauss2mf(Q, spritzer_Qges_mu[0] + 0.5, spritzer_Qges_sgm[0], max(Q), 1) Qdot_lo = fuzz.gauss2mf(Qdot, min(Qdot), 1, kalt_Qpdot_mu[0], kalt_Qpdot_sgm[0]) Qdot_md = fuzz.gaussmf(Qdot, normal_Qpdot_mu[0], normal_Qpdot_sgm[0]) Qdot_hi = fuzz.gauss2mf(Qdot, spritzer_Qpdot_mu[0] + 0.5, spritzer_Qpdot_sgm[0], max(Qdot), 1) dI_lo = fuzz.gauss2mf(d_I, min(Q), 1, unsp_di_mu[0], unsp_di_sgm[0]) dI_hi = fuzz.gauss2mf(d_I, sp_di_mu[0], sp_di_sgm[0], max(Q), 1) # print(spritzer_Qges_mu[0]+0.5,spritzer_Qpdot_mu[0]+0.5) # fig, (ax0, ax1, ax2, ax3) = plt.subplots(nrows=4, figsize=(8, 9)) # ax0.plot(I, I_lo, 'b', linewidth=1.5, label='kalt') # ax0.plot(I, I_md, 'g', linewidth=1.5, label='normal') # ax0.plot(I, I_hi, 'r', linewidth=1.5, label='spritzer') # ax0.set_title('Strom') # ax0.legend() # ax1.plot(Q, Q_lo, 'b', linewidth=1.5, label='kalt') # ax1.plot(Q, Q_md, 'g', linewidth=1.5, label='normal') # ax1.plot(Q, Q_hi, 'r', linewidth=1.5, label='spritzer') # ax1.set_title('$Q_{ges}$') # ax1.legend() # ax2.plot(Qdot, Qdot_lo, 'b', linewidth=1.5, label='kalt') # ax2.plot(Qdot, Qdot_md, 'g', linewidth=1.5, label='normal') # ax2.plot(Qdot, Qdot_hi, 'r', linewidth=1.5, label='spritzer') # ax2.set_title('$\dot Q$') # ax2.legend() # ax3.plot(d_I, dI_lo, 'g', linewidth=1.5, label='kein spritzer') # ax3.plot(d_I, dI_hi, 'r', linewidth=1.5, label='spritzer') # ax3.set_title('$\Delta I$') # ax3.legend() # # Turn off top/right axes # for ax in (ax0, ax1, ax2, ax3): # ax.spines['top'].set_visible(False) # ax.spines['right'].set_visible(False) # ax.get_xaxis().tick_bottom() # ax.get_yaxis().tick_left() # plt.tight_layout() # plt.show() current = strom waerme = waerme Q_geschwi = Q_dot strom_level_lo = fuzz.interp_membership(I, I_lo, current) strom_level_md = fuzz.interp_membership(I, I_md, current) strom_level_hi = fuzz.interp_membership(I, I_hi, current) waerme_level_lo = fuzz.interp_membership(Q, Q_lo, waerme) waerme_level_md = fuzz.interp_membership(Q, Q_md, waerme) waerme_level_hi = fuzz.interp_membership(Q, Q_hi, waerme) Qdot_level_lo = fuzz.interp_membership(Qdot, Qdot_lo, Q_geschwi) Qdot_level_md = fuzz.interp_membership(Qdot, Qdot_md, Q_geschwi) Qdot_level_hi = fuzz.interp_membership(Qdot, Qdot_hi, Q_geschwi) regel1 = np.fmin(strom_level_hi, np.fmin(waerme_level_hi, Qdot_level_hi)) dI_hi1 = np.fmin(regel1, dI_hi) regel2 = np.fmin(strom_level_md, np.fmin(waerme_level_hi, Qdot_level_hi)) dI_hi2 = np.fmin(regel2, dI_hi) regel3 = np.fmin(strom_level_md, np.fmin(waerme_level_md, Qdot_level_md)) dI_lo1 = np.fmin(regel3, dI_lo) regel4 = np.fmin(strom_level_lo, np.fmin(waerme_level_lo, Qdot_level_lo)) dI_lo2 = np.fmin(regel4, dI_lo) regel5 = np.fmin(waerme_level_md, np.fmin(strom_level_lo, Qdot_level_lo)) dI_lo3 = np.fmin(regel5, dI_lo) # k = 5 # farben = cm.viridis(np.linspace(0,1,k)) # fig, ax0 = plt.subplots(figsize=(8, 3)) # d_I0 = np.zeros_like(d_I) # ax0.fill_between(d_I, d_I0, dI_hi1, facecolor=farben[0], alpha=0.7) # ax0.plot(d_I, dI_hi, color =farben[0], linewidth=1.5, linestyle='--', ) # ax0.fill_between(d_I, d_I0, dI_hi2, facecolor=farben[1], alpha=0.7) # ax0.plot(d_I, dI_hi, color =farben[0], linewidth=1.5, linestyle='--') # ax0.fill_between(d_I, d_I0, dI_lo1, facecolor=farben[2], alpha=0.7) # ax0.plot(d_I, dI_lo, color =farben[-1], linewidth=1.5, linestyle='--') # ax0.fill_between(d_I, d_I0, dI_lo2, facecolor=farben[3], alpha=0.7) # ax0.plot(d_I, dI_lo, color =farben[-1], linewidth=1.5, linestyle='--') # ax0.fill_between(d_I, d_I0, dI_lo3, facecolor=farben[4], alpha=0.7) # ax0.plot(d_I, dI_lo, color =farben[-1], linewidth=1.5, linestyle='--') # ax0.set_title('Output membership activity') # plt.show() aggregated = np.fmax( dI_lo3, np.fmax(np.fmax(dI_lo2, dI_lo1), np.fmax(dI_hi1, dI_hi2))) dI = fuzz.defuzz(d_I, aggregated, 'centroid') dI_activation = fuzz.interp_membership(d_I, aggregated, dI) dI_h_percent = fuzz.interp_membership(d_I, dI_hi, dI) dI_l_percent = fuzz.interp_membership(d_I, dI_lo, dI) # fig, ax0 = plt.subplots(figsize=(8, 3)) # ax0.plot(d_I, dI_hi, color = farben[0], linewidth=1.5, linestyle='--', ) # ax0.plot(d_I, dI_lo, color = farben[-1], linewidth=1.5, linestyle='--') # ax0.fill_between(d_I, d_I0, aggregated, facecolor='gray', alpha=0.3) # ax0.plot([dI, dI], [0, dI_activation], 'k', linewidth=1.5, alpha=0.9) # ax0.set_title('Aggregated membership and result (line)') # # Turn off top/right axes # for ax in (ax0,): # ax.spines['top'].set_visible(False) # ax.spines['right'].set_visible(False) # ax.get_xaxis().tick_bottom() # ax.get_yaxis().tick_left() # plt.tight_layout() # plt.show() return dI, dI_h_percent, dI_l_percent # dI, dI_h_percent, dI_l_percent = fuzzy_logic( # path = None, # max_I = 13, # max_Q = 15, # max_Qdot = 25, # max_dI = 0.6, # strom = 9.2, # waerme = 11.19 , # Q_dot = 19.27 # ) # print(dI, dI_h_percent, dI_l_percent)
def approximate_time_remaining_until_walk(hours_passed_after_pee, crying_intensity): last_time_peed_raw = int(hours_passed_after_pee) crying_intensity_raw = int(crying_intensity) if last_time_peed_raw < 0: raise ValueError('Last time peed must be greater than 0') if crying_intensity_raw < 0 or crying_intensity_raw > 10: raise ValueError( 'Crying intensity must be greater than 0 and less than or equals than 10' ) if last_time_peed_raw > 10: exit('now') last_time_peed_range = np.arange(0, 11, 0.1) crying_intensity_range = np.arange(0, 11, 0.1) last_time_peed_now_function = fuzz.zmf(last_time_peed_range, 0, 1.5) last_time_peed_couple_of_hours_function = fuzz.gaussmf( last_time_peed_range, 0.75, 2.9) last_time_peed_many_hours_function = fuzz.smf(last_time_peed_range, 2.8, 4.5) crying_intensity_none_function = fuzz.zmf(crying_intensity_range, 0, 1.5) crying_intensity_slight_function = fuzz.gauss2mf(crying_intensity_range, 0.5, 0.6, 0.8, 1.7) crying_intensity_medium_function = fuzz.gaussmf(crying_intensity_range, 1.6, 4.5) crying_intensity_high_function = fuzz.smf(crying_intensity_range, 5, 7.9) walk_after_how_much_time_range = np.arange(0, 5, 0.1) walk_now_function = fuzz.zmf(walk_after_how_much_time_range, 0, 0.5) walk_after_a_while_function = fuzz.gaussmf(walk_after_how_much_time_range, 0.4, 0.8) walk_later_function = fuzz.gaussmf(walk_after_how_much_time_range, 0.6, 1.9) walk_after_couple_of_hours_function = fuzz.smf( walk_after_how_much_time_range, 2.3, 3.8) def convert_last_time_peed(last_time_peed_in_hours): now = fuzz.interp_membership(last_time_peed_range, last_time_peed_now_function, last_time_peed_in_hours) couple_of_hours = fuzz.interp_membership( last_time_peed_range, last_time_peed_couple_of_hours_function, last_time_peed_in_hours) many_hours = fuzz.interp_membership( last_time_peed_range, last_time_peed_many_hours_function, last_time_peed_in_hours) return [now, couple_of_hours, many_hours] def convert_crying_intensity(crying_intensity): none = fuzz.interp_membership(crying_intensity_range, crying_intensity_none_function, crying_intensity) slight = fuzz.interp_membership(crying_intensity_range, crying_intensity_slight_function, crying_intensity) medium = fuzz.interp_membership(crying_intensity_range, crying_intensity_medium_function, crying_intensity) high = fuzz.interp_membership(crying_intensity_range, crying_intensity_high_function, crying_intensity) return [none, slight, medium, high] last_time_peed_converted = convert_last_time_peed(last_time_peed_raw) crying_intensity_converted = convert_crying_intensity(crying_intensity_raw) rules = [ np.fmax(last_time_peed_converted[-1], crying_intensity_converted[-1]), np.fmin( last_time_peed_converted[0], np.fmax(crying_intensity_converted[1], crying_intensity_converted[0])), np.fmin(last_time_peed_converted[1], crying_intensity_converted[0]), np.fmin(last_time_peed_converted[1], crying_intensity_converted[2]), np.fmin(last_time_peed_converted[1], crying_intensity_converted[1]) ] walk_now = np.fmin(rules[0], walk_now_function) walk_after_a_while = np.fmin(rules[-2], walk_after_a_while_function) walk_later = np.fmin(rules[-1], walk_later_function) walk_after_couple_of_hours = np.fmin(rules[1], walk_after_couple_of_hours_function) aggregated = np.fmax( walk_now, np.fmax(walk_after_a_while, np.fmax(walk_later, walk_after_couple_of_hours))) result = fuzz.defuzz(walk_after_how_much_time_range, aggregated, 'centroid') return result