Source code for pyrfu.mms.estimate_phase_speed

#!/usr/bin/env python
# -*- coding: utf-8 -*-

# 3rd party imports
import numpy as np
from scipy.optimize import curve_fit

__author__ = "Louis Richard"
__email__ = "louisr@irfu.se"
__copyright__ = "Copyright 2020-2023"
__license__ = "MIT"
__version__ = "2.4.2"
__status__ = "Prototype"


[docs]def estimate_phase_speed(f_k_power, freq, k, f_min: float = 100.0): r"""Simple function to estimate the phase speed from the frequency wave number power spectrum. Fits :math:`f = v k/ 2 \\pi` to the power spectrum. Parameters ---------- f_k_power : ndarray 2D array of powers. freq : ndarray 1D array of frequencies. k : ndarray 1D array of wave numbers. f_min : float, Optional Set low frequency threshold of points used to estimate the speed. Default ``f_min`` = 100. Returns ------- vph : float Estimated phase speed by fitting linear dispersion relation to data. Notes ----- Draft version but seems to work well. Does not yet handle multiple modes in the same power spectrum. See also -------- pyrfu.mms.fk_power_spectrum : Calculates the frequency-wave number power spectrum pyrfu.mms.probe_align_times : Returns times when f-a electrostatic waves can be characterized. """ # Remove spurious points; specifically at large k. k_max = 2.0 * np.max(k) / 3.0 power_temp = f_k_power rm_k = np.where(abs(k) > k_max) rm_f = np.where(freq < f_min) power_temp[:, rm_k] = 0.0 power_temp[rm_f, :] = 0.0 power_temp[np.isnan(power_temp)] = 0.0 # Find position of maximum power to guess vph max_pos = np.unravel_index(np.argmax(power_temp), power_temp.shape) k_mat, f_mat = np.meshgrid(k, freq) max_f, max_k = [f_mat[max_pos], k_mat[max_pos]] # Initial guess vph_guess = max_f / max_k if vph_guess > 0.0: power_temp[:, k < 0.0] = 0 else: power_temp[:, k > 0.0] = 0 vph_range = [vph_guess / 3, vph_guess * 3] # Find all points around this guess vph highppos = np.where(power_temp > 0.3 * np.max(power_temp)) p_power = power_temp[highppos] f_power = f_mat[highppos] k_power = k_mat[highppos] p_power2, f_power2, k_power2 = [[], [], []] for i, p_pow in enumerate(p_power): if ( np.abs(vph_range[0]) < np.abs(f_power[i] / k_power[i]) < np.abs(vph_range[1]) ): p_power2.append(p_pow) f_power2.append(f_power[i]) k_power2.append(k_power[i]) p_power2 = np.array(p_power2) f_power2 = np.array(f_power2) k_power2 = np.array(k_power2) weights = 1 + np.log10(p_power2 / np.max(p_power2)) def fun(k_pow, f_pow): return f_pow * k_pow res = curve_fit(fun, k_power2, f_power2, p0=vph_guess, sigma=weights) vph = res[0][0] * 2 * np.pi return vph