125 lines
4.8 KiB
Python
125 lines
4.8 KiB
Python
# 原始文件 cosmic行星波参数全年逐日绘图
|
|
# 此代码是对数据处理后的txt数据进行行星波参数提取绘图
|
|
|
|
import pandas as pd
|
|
import numpy as np
|
|
from scipy.optimize import curve_fit
|
|
import matplotlib.pyplot as plt
|
|
|
|
# 定义拟合函数
|
|
# 解决绘图中中文不能显示的问题
|
|
import matplotlib
|
|
|
|
from CONSTANT import DATA_BASEPATH
|
|
# 设置中文显示和负号正常显示
|
|
matplotlib.rcParams['font.sans-serif'] = ['SimHei'] # 显示中文
|
|
matplotlib.rcParams['axes.unicode_minus'] = False # 正常显示负号
|
|
# 读取一年的数据文件
|
|
|
|
|
|
def cosmic_planetw_daily_plot(
|
|
df: pd.DataFrame,
|
|
T=16,
|
|
k=0
|
|
):
|
|
def u_func(x, *params):
|
|
a1, b1, a2, b2, a3, b3, a4, b4, a5, b5, a6, b6, a7, b7, a8, b8, a9, b9 = params
|
|
return (
|
|
a1 * np.sin((2 * np.pi / T) * t - 4 * x + b1)
|
|
+ a2 * np.sin((2 * np.pi / T) * t - 3 * x + b2)
|
|
+ a3 * np.sin((2 * np.pi / T) * t - 2 * x + b3)
|
|
+ a4 * np.sin((2 * np.pi / T) * t - x + b4)
|
|
+ a5 * np.sin((2 * np.pi / T) * t + b5)
|
|
+ a6 * np.sin((2 * np.pi / T) * t + x + b6)
|
|
+ a7 * np.sin((2 * np.pi / T) * t + 2 * x + b7)
|
|
+ a8 * np.sin((2 * np.pi / T) * t + 3 * x + b8)
|
|
+ a9 * np.sin((2 * np.pi / T) * t + 4 * x + b9)
|
|
)
|
|
|
|
# 删除有 NaN 的行
|
|
df = df.dropna(subset=['Temperature'])
|
|
# 设置初始参数
|
|
# initial_guess = [1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0] # v0, a1, b1, a2, b2, a3, b3
|
|
initial_guess = [0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5,
|
|
0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5] # 9个 a 和 9个 b 参数
|
|
|
|
# 设置参数界限
|
|
bounds = (
|
|
[0, -np.inf, 0, -np.inf, 0, -np.inf, 0, -np.inf, 0, -np.inf,
|
|
0, -np.inf, 0, -np.inf, 0, -np.inf, 0, -np.inf], # 下界
|
|
[np.inf, np.inf, np.inf, np.inf, np.inf, np.inf, np.inf, np.inf, np.inf, np.inf, np.inf, np.inf, np.inf, np.inf, np.inf,
|
|
np.inf, np.inf, np.inf]) # 上界
|
|
|
|
# 用于存储拟合参数结果的列表
|
|
all_fit_results = []
|
|
|
|
# 设置最小数据量的阈值
|
|
min_data_points = 36
|
|
|
|
# 进行多个时间窗口的拟合
|
|
# T应该取5、10、16
|
|
if T not in [5, 10, 16]:
|
|
raise ValueError("T should be 5, 10, or 16")
|
|
for start_day in range(0, 365-3*T): # 最后一个窗口为[351, 366]
|
|
end_day = start_day + 3 * T # 每个窗口的结束时间为 start_day + 3*T
|
|
|
|
# 选择当前窗口的数据
|
|
df_8 = df[(df['Time'] >= start_day) & (df['Time'] <= end_day)]
|
|
|
|
# 检查当前窗口的数据量
|
|
if len(df_8) < min_data_points:
|
|
# 输出数据量不足的警告
|
|
print(f"数据量不足,无法拟合:{start_day} 到 {end_day},数据点数量:{len(df_8)}")
|
|
# 将拟合参数设置为 NaN
|
|
all_fit_results.append([np.nan] * 18)
|
|
continue # 跳过当前时间窗口,继续下一个窗口
|
|
|
|
# 提取时间、经度、温度数据
|
|
t = np.array(df_8['Time']) # 时间
|
|
x = np.array(df_8['Longitude_Radians']) # 经度弧度制
|
|
temperature = np.array(df_8['Temperature']) # 温度,因变量
|
|
|
|
# 用T进行拟合
|
|
popt, pcov = curve_fit(u_func, x, temperature,
|
|
p0=initial_guess, bounds=bounds, maxfev=50000)
|
|
|
|
# 将拟合结果添加到列表中
|
|
all_fit_results.append(popt)
|
|
|
|
# 将结果转换为DataFrame
|
|
columns = ['a1', 'b1', 'a2', 'b2', 'a3', 'b3', 'a4', 'b4',
|
|
'a5', 'b5', 'a6', 'b6', 'a7', 'b7', 'a8', 'b8', 'a9', 'b9']
|
|
fit_df = pd.DataFrame(all_fit_results, columns=columns) # fit_df即为拟合的参数汇总
|
|
|
|
# -------------------------------画图----------------------------
|
|
# a1-a9,对应波数-4、-3、-2、-1、0、1、2、3、4的行星波振幅
|
|
a_columns = ['a1', 'a2', 'a3', 'a4', 'a5', 'a6', 'a7', 'a8', 'a9']
|
|
k_values = list(range(-4, 5)) # 从 -4 到 4
|
|
|
|
# 创建一个字典映射 k 值到 a_columns
|
|
k_to_a = {f'k={k}': a for k, a in zip(k_values, a_columns)}
|
|
|
|
# 获取索引并转换为 numpy 数组
|
|
x_values = fit_df.index.to_numpy()
|
|
|
|
# 对每一列生成独立的图
|
|
# for k, col in k_to_a.items():
|
|
col = k_to_a[f'k={k}']
|
|
plt.figure(figsize=(8, 6)) # 创建新的图形
|
|
plt.plot(x_values, fit_df[col].values)
|
|
plt.title(f'k={k} 振幅图')
|
|
plt.xlabel('天')
|
|
plt.ylabel('振幅')
|
|
|
|
# 设置横坐标的动态调整
|
|
adjusted_x_values = x_values + (3 * T + 1) / 2
|
|
if len(adjusted_x_values) > 50:
|
|
step = 30
|
|
tick_positions = adjusted_x_values[::step] # 选择每30个点
|
|
tick_labels = [f'{int(val)}' for val in tick_positions]
|
|
else:
|
|
tick_positions = adjusted_x_values
|
|
tick_labels = [f'{int(val)}' for val in tick_positions]
|
|
|
|
plt.xticks(ticks=tick_positions, labels=tick_labels)
|