-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathplot_soft.py
More file actions
209 lines (167 loc) · 7.01 KB
/
plot_soft.py
File metadata and controls
209 lines (167 loc) · 7.01 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
import matplotlib.pyplot as plt
import pandas as pd
import os
import numpy as np
from scipy.special import erfc
from datetime import datetime # 新增:用于获取时间
# ================= 用户配置区域 =================
# 路径配置
csv_dir = "csv"
img_dir = "pictures"
# 自定义绘图参数
PLOT_CONFIG = {
# 1. 输出文件名
# 若设为 None,则自动生成格式: "曲线名1_曲线名2_日期_时间.png"
# 若设为字符串 (如 "my_plot.png"),则直接使用该文件名
"output_filename": "Soft Decision Viterbi",
# 2. 图表标题
# 软判决,消息长度65536,帧数10000 比较不同卷积码的性能
"title": "Soft Decision Viterbi Decoding for Different Convolutional Codes\nMessage Length = 65536, Frames = 10000",
# 3. X轴范围 (min, max),设置为 None 则自动调整
"xlim": None,
# 4. Y轴范围 (min, max),设置为 None 则自动调整
"ylim": None
}
# 要画的曲线 (Label : Filename)
curves = {
'Conv. $(7,5)_8$ Soft Viterbi': "soft_75.csv",
'Conv. $(15,13)_8$ Soft Viterbi': "soft_1513.csv",
'Conv. $(1,5/7)_8$ Soft Viterbi': "soft_rsc.csv",
"Uncoded BPSK (Theory)": "theory"
}
# =================================================
def set_academic_style():
"""设置学术画图风格 (Times New Roman, Serif)"""
plt.rcParams.update(plt.rcParamsDefault)
plt.style.use('classic')
plt.rcParams['font.family'] = 'serif'
plt.rcParams['font.serif'] = ['Times New Roman']
plt.rcParams['font.size'] = 14
plt.rcParams['axes.unicode_minus'] = False
plt.rcParams['lines.linewidth'] = 1.5
plt.rcParams['axes.linewidth'] = 1.5
plt.rcParams['grid.linestyle'] = ':'
plt.rcParams['grid.linewidth'] = 0.5
plt.rcParams['grid.alpha'] = 0.5
def get_data_bounds(curve_dict, csv_directory):
"""预读取数据以确定自动坐标轴范围"""
min_snr, max_snr = 0, 10
min_ber = 1e-5
snr_values = []
ber_values = []
for label, filename in curve_dict.items():
if filename == "theory":
continue
filepath = os.path.join(csv_directory, filename)
if os.path.exists(filepath):
try:
df = pd.read_csv(filepath)
valid_df = df[(df['BER'] > 0) & (df['BER'] <= 1.0)]
if not valid_df.empty:
snr_values.extend(valid_df['SNR'].values)
ber_values.extend(valid_df['BER'].values)
except:
pass
if snr_values:
min_snr = np.min(snr_values)
max_snr = np.max(snr_values)
if ber_values:
min_ber = np.min(ber_values)
return (min_snr, max_snr), min_ber
def plot_ber():
set_academic_style()
colors = ['black', 'black', 'black', 'black', 'black']
markers = ['o', '^', 's', 'D', 'v', 'x']
linestyles = ['-', '--', '-', '--']
idx = 0
plotted_curves_names = [] # 记录实际画了哪些线,用于文件名生成
fig, ax = plt.subplots(figsize=(8, 6))
# --- 1. 确定坐标轴范围 ---
(data_min_snr, data_max_snr), data_min_ber = get_data_bounds(curves, csv_dir)
if PLOT_CONFIG["xlim"] is None:
x_start = np.floor(data_min_snr)-0.2
x_end = np.ceil(data_max_snr) + 1
current_xlim = (x_start, x_end)
else:
current_xlim = PLOT_CONFIG["xlim"]
if PLOT_CONFIG["ylim"] is None:
y_bottom = pow(10, np.floor(np.log10(data_min_ber)) - 1)
current_ylim = (y_bottom, 1.0)
else:
current_ylim = PLOT_CONFIG["ylim"]
# --- 2. 绘制理论线 ---
if "Uncoded BPSK (Theory)" in curves:
snr_db_theory = np.linspace(current_xlim[0] + 0.2, current_xlim[1], 300)
snr_linear = 10 ** (snr_db_theory / 10.0)
ber_theory = 0.5 * erfc(np.sqrt(snr_linear))
ax.semilogy(snr_db_theory, ber_theory,
color='black', linestyle='-', linewidth=1.5,
label='Uncoded BPSK (Theory)', zorder=1)
# 理论线一般不计入文件名,除非你想加
# --- 3. 绘制仿真线 ---
for label, filename in curves.items():
if filename == "theory":
continue
filepath = os.path.join(csv_dir, filename)
if os.path.exists(filepath):
try:
df = pd.read_csv(filepath)
df = df[df['BER'] > 0]
c = colors[idx % len(colors)]
m = markers[idx % len(markers)]
ls = linestyles[idx % len(linestyles)]
ax.semilogy(df['SNR'], df['BER'],
marker=m,
markersize=7,
markeredgewidth=1.0,
markerfacecolor='none',
markeredgecolor='black',
linestyle=ls,
linewidth=1.5,
color=c,
label=label,
zorder=10,
clip_on=False)
idx += 1
plotted_curves_names.append(label) # 记录成功绘制的曲线名
except Exception as e:
print(f"Error reading {filename}: {e}")
# --- 4. 装饰 ---
if PLOT_CONFIG["title"]:
ax.set_title(PLOT_CONFIG["title"], pad=15)
ax.set_xlabel(r'$E_b/N_0\ (\mathrm{dB})$')
ax.set_ylabel('Bit Error Rate (BER)')
ax.minorticks_on()
ax.grid(which='major', linestyle='-', linewidth=0.5, color='gray', alpha=0.5)
ax.grid(which='minor', linestyle=':', linewidth=0.5, color='gray', alpha=0.3)
ax.set_xlim(current_xlim)
ax.set_ylim(current_ylim)
legend = ax.legend(loc='best', frameon=True, fontsize=12)
legend.get_frame().set_edgecolor('black')
legend.get_frame().set_linewidth(0.8)
legend.get_frame().set_alpha(1.0)
# --- 5. 保存文件 (处理文件名逻辑) ---
if not os.path.exists(img_dir):
os.makedirs(img_dir)
# 核心逻辑:判断是否自定义文件名
if PLOT_CONFIG["output_filename"]:
final_filename = PLOT_CONFIG["output_filename"]
else:
# 默认:曲线名拼接 + 时间戳
# 去除空格,防止文件名中有空格
clean_names = [name.replace(" ", "") for name in plotted_curves_names]
# 如果曲线太多,名字会很长,这里可以截断或者直接连接
names_str = "_".join(clean_names)
# 获取当前时间
time_str = datetime.now().strftime("%Y%m%d_%H%M%S")
# 拼接
if names_str:
final_filename = f"{names_str}_{time_str}.png"
else:
final_filename = f"BER_Plot_{time_str}.png" # 防止没画任何曲线的情况
save_path = os.path.join(img_dir, final_filename)
plt.savefig(save_path, dpi=600, bbox_inches='tight')
print(f"Plot saved to: {save_path}")
plt.show()
if __name__ == "__main__":
plot_ber()