def METHOD_NAME(self, n_candidates) -> list[dict]:
    if n_candidates != 1:
        raise NotImplementedError(
            "extremum seeking can only produce one candidate at a time"
        )
    # Initial data point
    if self.data is None:
        return [dict(zip(self.vocs.variable_names, self._p_ave.reshape(-1, 1)))]
    p_n = self.p_normalize(self._last_input)
    # ES step for each parameter
    p_next_n = np.zeros(self._nES)
    # Loop through each parameter
    for j in np.arange(self._nES):
        # Use the same frequency for each two parameters
        # Alternating Sine and Cosine
        jw = int(np.floor(j / 2))
        if not j % 2:
            p_next_n[j] = p_n[j] + self._amplitude * self._dtES * np.cos(
                self._dtES * self._i * self._wES[jw] + self.k * self._last_outcome
            ) * np.sqrt(self._aES[j] * self._wES[jw])
        else:
            p_next_n[j] = p_n[j] + self._amplitude * self._dtES * np.sin(
                self._dtES * self._i * self._wES[jw] + self.k * self._last_outcome
            ) * np.sqrt(self._aES[j] * self._wES[jw])
        # For each new ES value, check that we stay within min/max constraints
        if p_next_n[j] < -1.0:
            p_next_n[j] = -1.0
        if p_next_n[j] > 1.0:
            p_next_n[j] = 1.0
    p_next = self.p_un_normalize(p_next_n)
    self._amplitude *= self.decay_rate  # decay the osc amplitude
    # Return the next value
    return [dict(zip(self.vocs.variable_names, p_next.reshape(-1, 1)))]