-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.py
More file actions
133 lines (104 loc) · 5.81 KB
/
Copy pathmain.py
File metadata and controls
133 lines (104 loc) · 5.81 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
"""
Главный исполняемый модуль.
Запускать из папки adasim/ (например, `python main.py`) — как и раньше, только
теперь код разложен по core/ltspice_io/report вместо одной плоской папки.
Загружает конфигурацию (YAML), выполняет расчёт номиналов, читает .asc через
asc_parser (с именами пинов из .asy — см. asy_parser.py), запускает LTspice,
строит и сохраняет графики, генерирует итоговый отчёт.
"""
from pathlib import Path
from logger_config import logger, setup_logging
from config import load_config
from core.calculation import select_components
from ltspice_io.runner import LTspiceRunner
from ltspice_io.asc_parser import parse_asc
from ltspice_io.readable_report import generate_readable_report
from report.plotting import plot_time_domain, plot_spectrum, plot_degradation, plot_input_currents
from report.text_report import generate_report
def select_best_combination(params: dict) -> dict:
"""Выбирает лучшую комбинацию номиналов из рассчитанных."""
combinations = select_components(params)
chosen = combinations[0].copy()
chosen['R_load'] = params['R_load']
chosen['R_TIA'] = params['R_TIA']
logger.info(f"Выбрана комбинация: Ra={chosen['Ra']} Ом, Rf={chosen['Rf_e96']} Ом, "
f"Rb={chosen['Rb_e96']} Ом, Cf={chosen['Cf']} пФ, R_TIA={chosen['R_TIA']} Ом")
return chosen
def build_readable_schematic_report(config: dict) -> Path | None:
"""Строит читаемый отчёт по .asc напрямую (без промежуточного .net от LTspice)."""
sch_cfg = config.get('schematic', {})
nl_cfg = config.get('netlist_generator', {})
if not nl_cfg.get('generate_netlist', False):
return None
asc_path = sch_cfg['path']
search_paths = sch_cfg.get('symbol_search_paths', ['.'])
schematic = parse_asc(asc_path, search_paths)
output_dir = Path(nl_cfg.get('output_dir', 'net'))
readable_path = output_dir / f"{Path(asc_path).stem}_readable.txt"
generate_readable_report(schematic, Path(asc_path).name, readable_path)
logger.info(f"Читаемый отчёт по схеме (с именами пинов): {readable_path}")
return readable_path
def setup_runner(config: dict) -> LTspiceRunner:
return LTspiceRunner(
schematic_path=config['schematic']['path'],
ltspice_exe=config['ltspice']['executable'],
temp_dir=config['simulation']['temp_dir'],
output_dir=config['simulation']['output_dir']
)
def run_single_simulation(runner: LTspiceRunner, chosen: dict, freq: float) -> tuple:
raw_path, log_path = runner.run(chosen, freq)
csv_path = runner.export_raw_to_csv(raw_path)
thd = runner.get_thd(log_path)
harmonics, amplitudes = runner.get_fourier_data(log_path)
return raw_path, log_path, csv_path, thd, harmonics, amplitudes
def generate_plots(plots_cfg: dict, output_dir: str, csv_path: str, harmonics: list, amplitudes: list,
thd: str, frequencies: list, thd_results: list = None, r_tia: float = None):
save = plots_cfg.get('save', True)
show = plots_cfg.get('show', False)
if plots_cfg.get('time_domain', False):
plot_time_domain(csv_path, output_dir, save=save, show=show)
if plots_cfg.get('spectrum', False):
plot_spectrum(harmonics, amplitudes, thd, output_dir, save=save, show=show)
if plots_cfg.get('input_currents', False) and r_tia is not None:
plot_input_currents(csv_path, r_tia, output_dir, save=save, show=show)
if plots_cfg.get('degradation', False) and thd_results is not None:
plot_degradation(frequencies, thd_results, output_dir, save=save, show=show)
def main():
setup_logging("simulation.log")
config = load_config("config.yaml")
# 1. Читаемый отчёт по схеме (имена пинов, не номера)
readable_net_path = build_readable_schematic_report(config)
# 2. Подбор номиналов
chosen = select_best_combination(config['params'])
chosen.update(config.get('tran_settings', {}))
# 3. Раннер
runner = setup_runner(config)
r_tia = chosen['R_TIA']
# 4. Одиночная симуляция на первой частоте
first_freq = config['frequencies'][0]
raw_path, log_path, csv_path, thd, harmonics, amplitudes = run_single_simulation(
runner, chosen, first_freq
)
# 5. Графики (сохраняются в output_dir, по умолчанию без блокирующего show())
plots_cfg = config.get('plots', {})
generate_plots(plots_cfg, config['simulation']['output_dir'], csv_path,
harmonics, amplitudes, thd, None, None, r_tia)
# 6. Свип по частотам для деградации (если запрошено)
thd_results = None
if plots_cfg.get('degradation', False):
logger.info("Запуск sweep по частотам для оценки деградации THD...")
thd_results = runner.degradation_sweep(chosen, config['frequencies'])
plot_degradation(config['frequencies'], thd_results, config['simulation']['output_dir'],
save=plots_cfg.get('save', True), show=plots_cfg.get('show', False))
# 7. Отчёт
sim_info = {
'freq': first_freq,
'thd': thd,
'csv_path': csv_path,
'log_path': log_path,
'readable_net_path': readable_net_path,
}
generate_report(config, chosen, sim_info, config['simulation']['output_dir'])
logger.info("=== Процесс завершён успешно ===")
if __name__ == "__main__":
main()