# 修复后的完整代码(重点修复数据处理和动画初始化逻辑) import pandas as pd import numpy as np from scipy.optimize import linprog from scipy.interpolate import interp1d import matplotlib.pyplot as plt import matplotlib.animation as animation # 加载功率和风速数据(无表头+整数时间序列) def load_power_and_wind_data(file_path): df = pd.read_excel(file_path, header=None) if df.shape[1] < 3: raise ValueError("输入文件至少需要3列数据(时间/调度指令/风速)") time = df.iloc[:, 0].astype(int) power_dispatch = df.iloc[:, 1] wind_speed = df.iloc[:, 2] time_diff = 1 # 假设时间间隔为1秒 n_turbines = len(power_dispatch) // 2000 remainder = len(power_dispatch) % 2000 if remainder != 0: print(f"警告:文件行数{len(power_dispatch)}不能被2000整除,余{remainder}行将被忽略") turbine_data = [] for i in range(n_turbines): start_idx = i * 2000 end_idx = start_idx + 2000 turbine_data.append({ 'time': time[start_idx:end_idx], 'power': power_dispatch[start_idx:end_idx], 'wind': wind_speed[start_idx:end_idx] }) return turbine_data, n_turbines, time_diff # 加载并对齐损伤数据(无表头+整数时间) def load_and_align_damage_data(damage_file, n_turbines, target_time): try: main_damage_df = pd.read_excel(damage_file, sheet_name='MainShaft', header=None, skiprows=1) tower_damage_df = pd.read_excel(damage_file, sheet_name='Tower', header=None, skiprows=1) except Exception as e: print(f"读取Excel文件失败: {e}") return np.zeros((len(target_time), n_turbines)), np.zeros((len(target_time), n_turbines)) source_time = main_damage_df.iloc[:, 0].astype(int) aligned_main = [] aligned_tower = [] for i in range(n_turbines): try: source_main = main_damage_df.iloc[:, i+1].values source_tower = tower_damage_df.iloc[:, i+1].values f_main = interp1d(source_time, source_main, kind='linear', fill_value='extrapolate') f_tower = interp1d(source_time, source_tower, kind='linear', fill_value='extrapolate') aligned_main.append(f_main(target_time)) aligned_tower.append(f_tower(target_time)) except Exception as e: print(f"第{i}台风机插值失败: {e}") aligned_main.append(np.zeros(len(target_time))) aligned_tower.append(np.zeros(len(target_time))) return np.array(aligned_main).T, np.array(aligned_tower).T # 优化有功功率分配 def optimize_active_power(turbine_data, main_damage, tower_damage): n_points = len(turbine_data[0]['time']) optimal_power = [] for i in range(n_points): total_power = turbine_data[0]['power'][i] if total_power <= 0: optimal_power.append([0]*len(turbine_data)) continue A_eq = np.array([[1]*len(turbine_data)]) b_eq = np.array([total_power]) bounds = [(0, 2000) for _ in turbine_data] damage_weights = main_damage[i] + tower_damage[i] result = linprog(damage_weights, A_eq=A_eq, b_eq=b_eq, bounds=bounds) if result.success and np.sum(result.x) > 0: optimal_power.append(result.x) else: # 按等比例分配替代默认满发 optimal_power.append([total_power/len(turbine_data)]*len(turbine_data)) return np.array(optimal_power) # 创建动态可视化 def create_animation(original_damage, optimized_damage, time_data): fig, ax = plt.subplots(figsize=(12, 6)) x = np.arange(len(time_data)) line1, = ax.plot([], [], label='Original Damage', color='red', lw=2) line2, = ax.plot([], [], label='Optimized Damage', color='blue', lw=2) time_text = ax.text(0.02, 0.95, '', transform=ax.transAxes, fontsize=12, bbox=dict(facecolor='white', alpha=0.8)) ax.set_xlabel('Time Step', fontsize=10) ax.set_ylabel('Cumulative Damage', fontsize=10) ax.tick_params(axis='both', labelsize=8) ax.grid(True, linestyle='--', alpha=0.7) ax.legend(fontsize=8) def init(): non_zero = original_damage > 1e-9 if np.any(non_zero): max_val = max(max(original_damage), max(optimized_damage)) y_range = max_val * 1.2 else: y_range = 1.0 ax.set_xlim(0, len(time_data)-1) ax.set_ylim(0, y_range) return line1, line2, time_text def update(frame): if frame == 0: line1.set_data([], []) line2.set_data([], []) time_text.set_text('') return line1, line2, time_text valid = original_damage[:frame] > 1e-9 if np.any(valid): y_min = min(original_damage[:frame][valid]) y_max = max(original_damage[:frame][valid]) else: y_min, y_max = 0, 1.0 ax.set_ylim(y_min - 0.1, y_max * 1.2) line1.set_data(x[:frame], original_damage[:frame]) line2.set_data(x[:frame], optimized_damage[:frame]) time_text.set_text(f'Processing: Step {time_data[frame]}') return line1, line2, time_text ani = animation.FuncAnimation(fig, update, frames=len(time_data), init_func=init, blit=True, interval=20) return ani # 主程序 if __name__ == "__main__": power_wind_file = 'output_data.xlsx' damage_file = '附件5-问题一答案表.xlsx' # 1. 加载调度指令和风速数据 turbine_data, n_turbines, time_interval = load_power_and_wind_data(power_wind_file) # 2. 加载并对齐损伤数据 target_time = turbine_data[0]['time'].values main_damage, tower_damage = load_and_align_damage_data(damage_file, n_turbines, target_time) # 3. 执行优化计算 optimal_power = optimize_active_power(turbine_data, main_damage, tower_damage) # 4. 计算损伤累积(示例逻辑) original_damage = np.sum(main_damage + tower_damage, axis=1) optimized_damage = np.sum((main_damage + tower_damage) * optimal_power/2000, axis=1) # 5. 添加数据验证 print(f"原始损伤数据形状: {original_damage.shape}, 前3个值: {original_damage[:3]}") print(f"优化后损伤数据形状: {optimized_damage.shape}, 前3个值: {optimized_damage[:3]}") print(f"时间序列长度: {len(target_time)}, 前3个时间点: {target_time[:3]}") # 6. 创建动画 ani = create_animation(original_damage, optimized_damage, target_time) # 7. 保存动画文件(离线模式) try: ani.save('damage_comparison.gif', writer='pillow', fps=10) plt.close() print("动画已成功保存为 damage_comparison.gif") except Exception as e: print(f"保存动画失败: {e}") plt.show() 代码中的动画改为每秒进行一次功率分配含有计时器的动图,优化前和优化后所有风机的累积疲劳损伤总和的折线对比图
时间: 2025-07-20 17:24:41 浏览: 18
<think>好的,用户希望将之前的代码中的动画改为每秒进行一次功率分配,并且包含计时器的动图,同时展示优化前和优化后的所有风机累积疲劳损伤总和的折线对比图。首先,我需要理解用户的需求。原来的代码生成的是损伤对比动画,现在需要改成每秒更新的功率分配动画,并且包含计时器显示当前时间。
首先,我需要检查现有的代码结构。原来的create_animation函数是用于绘制损伤累积的折线图,但现在需要改为显示功率分配。用户提到要使用条形图来表示每台风机的功率输出,同时每秒更新一次,并且显示当前时间。
接下来,我需要修改create_animation函数。原来的函数使用折线图,现在需要改成条形图。每个时间点,所有风机的功率输出应该用条形图展示,并且在图中添加计时器文本。同时,动画的更新频率需要调整为每秒一帧,这可能涉及到interval参数的设置,但要注意FuncAnimation的interval参数是以毫秒为单位的,所以设置为1000毫秒。
然后,主程序部分需要生成优化前和优化后的功率数据。原来的代码已经调用了optimize_active_power函数得到优化后的功率,但用户可能需要同时显示优化前和优化后的功率对比。不过用户的问题中提到的是“优化前和优化后所有风机的累积疲劳损伤总和的折线对比图”,但之前的代码中已经计算了original_damage和optimized_damage,所以可能需要将这两个数据用折线图展示,同时每秒更新一次。
不过用户现在的请求是“每秒进行一次功率分配含有计时器的动图,优化前和优化后所有风机的累积疲劳损伤总和的折线对比图”。这里可能存在混淆。用户可能希望两种不同的动画:一种是展示每秒功率分配的条形图,另一种是展示累积损伤的折线图。或者,用户可能希望在一个动画中同时展示这两者?需要进一步确认,但根据问题描述,可能用户希望生成两个不同的动画,或者修改现有动画以包含这些元素。
不过根据用户提供的示例回复,之前的回复已经将动画改为每秒更新的功率分配条形图,并包含计时器。因此,可能需要将原来的损伤对比动画替换为新的功率分配动画,同时保留累积损伤的折线对比图。或者用户希望将两个动画合并?
仔细阅读用户的问题,用户要求“代码中的动画改为每秒进行一次功率分配含有计时器的动图,优化前和优化后所有风机的累积疲劳损伤总和的折线对比图”。这里的“动图”可能指的是一个动画,同时展示功率分配和累积损伤对比。但通常动画只能展示一种类型的数据。因此,可能需要创建两个独立的动画,或者在一个图中分开展示。
但根据用户提供的示例回复,之前的回复已经将动画改为功率分配的条形图,并且用户现在可能希望将累积损伤的折线图作为另一个动画。或者用户希望将两个动画合并到一个图中?
根据用户提供的示例回复中的代码,他们可能希望生成一个动画,展示每秒更新的功率分配条形图,并且同时显示累积损伤的折线图。这可能比较复杂,但可能用户只需要一个动画,展示功率分配,而另一个动画展示损伤对比。不过用户的问题可能更倾向于前者,即功率分配的动画。
回到代码修改,原来的create_animation函数生成的是损伤对比的折线图,现在需要改为功率分配的条形图,并且每秒更新一次,包含计时器。因此,需要重新设计create_animation函数,使用条形图,并在每个时间点更新所有条形图的高度,同时更新计时器文本。
此外,原来的代码中优化后的功率是通过optimize_active_power函数得到的,而用户可能需要同时展示优化前和优化后的功率分配?或者只是优化后的?根据用户的问题描述,可能只需要展示优化后的功率分配,因为之前的代码已经进行了优化计算。但用户提到“优化前和优化后所有风机的累积疲劳损伤总和的折线对比图”,这可能意味着在另一个动画中展示这两个损伤曲线的对比。不过用户现在的问题可能希望将动画改为功率分配的,而损伤对比可能作为另一个独立的动画。
不过根据用户的问题,他们可能希望将原来的损伤对比动画替换为新的功率分配动画,并且生成该动画。因此,需要修改create_animation函数,使其生成功率分配的条形图动画,并且每秒更新一次,同时显示当前时间。
在修改create_animation函数时,需要注意以下几点:
1. 使用条形图(bar chart)来表示每台风机的功率输出。
2. 每个时间点更新所有条形图的高度。
3. 添加计时器文本,显示当前时间戳。
4. 设置动画的interval为1000毫秒(即每秒一帧)。
5. 保存为GIF文件时,设置正确的fps参数,确保播放速度正确。
此外,主程序部分需要确保optimal_power数据是正确的,即已经通过optimize_active_power函数计算得到。原来的代码中已经计算了optimal_power,因此可以直接使用。
在之前的回复中,用户提供的代码示例已经实现了这些功能,但需要确认是否满足当前需求。例如,在示例代码中,create_power_animation函数生成了功率分配的条形图动画,每秒一帧,并包含计时器。因此,可能需要将原来的create_animation函数替换为这个新的函数,并调整主程序中的调用部分。
此外,用户可能需要同时保留累积损伤的折线图动画,但根据问题描述,可能只需要生成功率分配的动画。因此,在修改后的代码中,可能需要移除原来的create_animation调用,替换为新的create_power_animation函数。
总结修改步骤:
1. 将原来的create_animation函数替换为生成功率分配条形图的函数。
2. 调整动画的interval参数为1000毫秒。
3. 在动画中添加计时器文本,显示当前时间戳。
4. 确保主程序中调用正确的动画生成函数。
5. 保存动画为GIF文件,并处理可能的异常。
另外,需要确保时间数据是正确的,例如target_time或time_data是否以秒为单位,并且与动画的帧数匹配。例如,在create_power_animation函数中,time_data应该是每个时间点的时间戳,动画每帧对应一个时间点,并在计时器中显示。
最后,测试代码以确保动画正确生成,并且每秒更新一次,计时器显示正确的时间。</think>```python
import pandas as pd
import numpy as np
from scipy.optimize import linprog
from scipy.interpolate import interp1d
import matplotlib.pyplot as plt
import matplotlib.animation as animation
# 加载功率和风速数据(无表头+整数时间序列)
def load_power_and_wind_data(file_path):
df = pd.read_excel(file_path, header=None)
if df.shape[1] < 3:
raise ValueError("输入文件至少需要3列数据(时间/调度指令/风速)")
time = df.iloc[:, 0].astype(int)
power_dispatch = df.iloc[:, 1]
wind_speed = df.iloc[:, 2]
time_diff = 1 # 假设时间间隔为1秒
n_turbines = len(power_dispatch) // 2000
remainder = len(power_dispatch) % 2000
if remainder != 0:
print(f"警告:文件行数{len(power_dispatch)}不能被2000整除,余{remainder}行将被忽略")
turbine_data = []
for i in range(n_turbines):
start_idx = i * 2000
end_idx = start_idx + 2000
turbine_data.append({
'time': time[start_idx:end_idx],
'power': power_dispatch[start_idx:end_idx],
'wind': wind_speed[start_idx:end_idx]
})
return turbine_data, n_turbines, time_diff
# 加载并对齐损伤数据(无表头+整数时间)
def load_and_align_damage_data(damage_file, n_turbines, target_time):
try:
main_damage_df = pd.read_excel(damage_file, sheet_name='MainShaft', header=None, skiprows=1)
tower_damage_df = pd.read_excel(damage_file, sheet_name='Tower', header=None, skiprows=1)
except Exception as e:
print(f"读取Excel文件失败: {e}")
return np.zeros((len(target_time), n_turbines)), np.zeros((len(target_time), n_turbines))
source_time = main_damage_df.iloc[:, 0].astype(int)
aligned_main = []
aligned_tower = []
for i in range(n_turbines):
try:
source_main = main_damage_df.iloc[:, i+1].values
source_tower = tower_damage_df.iloc[:, i+1].values
f_main = interp1d(source_time, source_main, kind='linear', fill_value='extrapolate')
f_tower = interp1d(source_time, source_tower, kind='linear', fill_value='extrapolate')
aligned_main.append(f_main(target_time))
aligned_tower.append(f_tower(target_time))
except Exception as e:
print(f"第{i}台风机插值失败: {e}")
aligned_main.append(np.zeros(len(target_time)))
aligned_tower.append(np.zeros(len(target_time)))
return np.array(aligned_main).T, np.array(aligned_tower).T
# 优化有功功率分配
def optimize_active_power(turbine_data, main_damage, tower_damage):
n_points = len(turbine_data[0]['time'])
optimal_power = []
for i in range(n_points):
total_power = turbine_data[0]['power'][i]
if total_power <= 0:
optimal_power.append([0]*len(turbine_data))
continue
A_eq = np.array([[1]*len(turbine_data)])
b_eq = np.array([total_power])
bounds = [(0, 2000) for _ in turbine_data]
damage_weights = main_damage[i] + tower_damage[i]
result = linprog(damage_weights, A_eq=A_eq, b_eq=b_eq, bounds=bounds)
if result.success and np.sum(result.x) > 0:
optimal_power.append(result.x)
else:
# 按等比例分配替代默认满发
optimal_power.append([total_power/len(turbine_data)]*len(turbine_data))
return np.array(optimal_power)
# 创建动态可视化(功率分配+损伤对比)
def create_power_damage_animation(optimal_power, original_damage, optimized_damage, time_data):
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(12, 8), gridspec_kw={'height_ratios': [3, 1]})
# 功率分配子图(条形图)
bars = ax1.bar(range(len(optimal_power[0])), optimal_power[0], color='skyblue', edgecolor='black')
time_text = ax1.text(0.02, 0.95, '', transform=ax1.transAxes, fontsize=14,
bbox=dict(facecolor='white', alpha=0.8))
ax1.set_title('Real-time Power Distribution', fontsize=12)
ax1.set_ylabel('Power Output (kW)', fontsize=10)
ax1.set_ylim(0, 2000)
ax1.grid(True, linestyle='--', alpha=0.7)
# 损伤对比子图(折线图)
x = np.arange(len(time_data))
line1, = ax2.plot([], [], label='Original Damage', color='red', lw=2)
line2, = ax2.plot([], [], label='Optimized Damage', color='blue', lw=2)
ax2.set_title('Cumulative Fatigue Damage', fontsize=12)
ax2.set_xlabel('Time Step', fontsize=10)
ax2.set_ylabel('Damage Index', fontsize=10)
ax2.grid(True, linestyle='--', alpha=0.7)
ax2.legend(fontsize=8)
def update(frame):
# 更新功率分配条形图
for i, bar in enumerate(bars):
bar.set_height(optimal_power[frame, i])
time_text.set_text(f'Time: {time_data[frame]}s')
# 更新损伤对比折线图
line1.set_data(x[:frame+1], original_damage[:frame+1])
line2.set_data(x[:frame+1], optimized_damage[:frame+1])
# 动态调整Y轴范围
if frame > 0:
max_val = max(max(original_damage[:frame+1]), max(optimized_damage[:frame+1]))
ax2.set_ylim(0, max_val * 1.2)
return bars + [time_text, line1, line2]
ani = animation.FuncAnimation(fig, update, frames=len(time_data),
interval=1000, blit=True, repeat=False)
return ani
# 主程序
if __name__ == "__main__":
power_wind_file = 'output_data.xlsx'
damage_file = '附件5-问题一答案表.xlsx'
# 1. 加载调度指令和风速数据
turbine_data, n_turbines, time_interval = load_power_and_wind_data(power_wind_file)
# 2. 加载并对齐损伤数据
target_time = turbine_data[0]['time'].values
main_damage, tower_damage = load_and_align_damage_data(damage_file, n_turbines, target_time)
# 3. 执行优化计算
optimal_power = optimize_active_power(turbine_data, main_damage, tower_damage)
# 4. 计算损伤累积(示例逻辑)
original_damage = np.sum(main_damage + tower_damage, axis=1)
optimized_damage = np.sum((main_damage + tower_damage) * optimal_power/2000, axis=1)
# 5. 创建联合动画(功率分配+损伤对比)
ani = create_power_damage_animation(optimal_power, original_damage, optimized_damage, target_time)
# 6. 保存动画文件(离线模式)
try:
ani.save('power_damage_comparison.gif', writer='pillow', fps=1)
plt.close()
print("动画已成功保存为 power_damage_comparison.gif")
except Exception as e:
print(f"保存动画失败: {e}")
plt.show()
```
阅读全文
相关推荐


















