Выполнил:
студент группы 851-М81
Меркулов А. Д.
ВВЕДЕНИЕ
ПОСТАНОВКА ЗАДАЧИ
ТЕОРЕТИЧЕСКИЕ ОСНОВЫ
3.1. Метод Эйлера для решения ОДУ
3.2. Погрешность метода Эйлера
РЕЗУЛЬТАТЫ ВЫЧИСЛЕНИЙ
4.1. Численное решение для h=0.2
4.2. Численное решение для h=0.1
4.3. Сравнительный анализ
АНАЛИЗ ПОГРЕШНОСТЕЙ
5.1. Локальная и глобальная погрешности
5.2. Зависимость погрешности от шага
ВЫВОДЫ
ПРИЛОЖЕНИЕ А
Цель работы: Приобретение практических навыков решения задачи Коши для обыкновенных дифференциальных уравнений первого порядка методом Эйлера
Задачи исследования:
Актуальность исследования обусловлена фундаментальной важностью численных методов решения дифференциальных уравнений в научных и инженерных расчетах. Метод Эйлера, несмотря на свою простоту, является основой для понимания более сложных численных методов и позволяет изучать основные закономерности численного решения ОДУ.
Дифференциальное уравнение: y' = (1 - y + ln(x))/x
Начальное условие: y(1) = 1
Отрезок интегрирования: [1, 2]
Точное решение: φ(x) = ln(x)
Шаги интегрирования: h₁ = 0.2, h₂ = 0.1
Задача: Решить задачу Коши для заданного обыкновенного дифференциального уравнения первого порядка методом Эйлера, провести сравнительный анализ численных решений с точным решением, исследовать погрешности метода и его сходимость.
euler_method: Метод Эйлера: y_{n+1} = y_n + h * f(x_n, y_n)
где:
Алгоритм метода Эйлера:
local_error: Локальная погрешность метода Эйлера: O(h²)
global_error: Глобальная погрешность метода Эйлера: O(h)
convergence: Метод Эйлера является методом первого порядка точности
Результаты метода Эйлера для шага h=0.2
| x | Численное решение y(x) | Точное решение φ(x) | Погрешность | y(x)-φ(x) | |
|---|---|---|---|---|---|
| 1.0 | 1.000000 | 0.000000 | 1.00e+00 | ||
| 1.2 | 1.000000 | 0.182322 | 8.18e-01 | ||
| 1.4 | 1.030387 | 0.336472 | 6.94e-01 | ||
| 1.6 | 1.074113 | 0.470004 | 6.04e-01 | ||
| 1.8 | 1.123600 | 0.587787 | 5.36e-01 | ||
| 2.0 | 1.175176 | 0.693147 | 4.82e-01 |
Максимальная погрешность: 1.00e+00
Средняя погрешность: 6.89e-01
Результаты метода Эйлера для шага h=0.1
| x | Численное решение y(x) | Точное решение φ(x) | Погрешность | y(x)-φ(x) | |
|---|---|---|---|---|---|
| 1.0 | 1.000000 | 0.000000 | 1.00e+00 | ||
| 1.1 | 1.000000 | 0.095310 | 9.05e-01 | ||
| 1.2 | 1.008665 | 0.182322 | 8.26e-01 | ||
| 1.3 | 1.023136 | 0.262364 | 7.61e-01 | ||
| 1.4 | 1.041538 | 0.336472 | 7.05e-01 | ||
| 1.5 | 1.062605 | 0.405465 | 6.57e-01 | ||
| 1.6 | 1.085462 | 0.470004 | 6.15e-01 | ||
| 1.7 | 1.109496 | 0.530628 | 5.79e-01 | ||
| 1.8 | 1.134269 | 0.587787 | 5.46e-01 | ||
| 1.9 | 1.159464 | 0.641854 | 5.18e-01 | ||
| 2.0 | 1.184853 | 0.693147 | 4.92e-01 |
Максимальная погрешность: 1.00e+00
Средняя погрешность: 6.91e-01
Сравнение точности для разных шагов:
Наблюдения: С уменьшением шага интегрирования погрешность метода Эйлера уменьшается, что соответствует теоретическим ожиданиям для метода первого порядка точности.
Рисунок: Сравнение численных решений с точным решением
Рисунок: Погрешности численного решения для разных шагов
Анализ: Графики демонстрируют, что численное решение методом Эйлера приближается к точному решению с уменьшением шага интегрирования. Погрешности накапливаются по мере удаления от начальной точки.
Рисунок: Зависимость погрешности от шага интегрирования
Рисунок: Локальная погрешность метода Эйлера
Оценка порядка метода: 0.000
Анализ сходимости:
Исходный код программы
# lab_euler_method.py
# -*- coding: utf-8 -*-
"""
Лабораторная работа: Решение задачи Коши методом Эйлера
Решение обыкновенных дифференциальных уравнений первого порядка
"""
import os
import numpy as np
import matplotlib.pyplot as plt
import datetime
from typing import List, Tuple, Dict, Any
import sys
# Настройка стиля для академических графиков
plt.style.use('seaborn-v0_8-whitegrid')
plt.rcParams['figure.figsize'] = (10, 6)
plt.rcParams['font.size'] = 12
# Попытка импортировать python-docx для генерации .docx отчёта
try:
from docx import Document
from docx.shared import Inches, Pt
from docx.enum.text import WD_ALIGN_PARAGRAPH
from docx.oxml.ns import qn
PYDOCX_AVAILABLE = True
except Exception:
PYDOCX_AVAILABLE = False
def read_own_source() -> Tuple[bool, str]:
"""
Пытается прочитать исходный код текущего файла и вернуть (успех, текст).
Возвращает (False, сообщение об ошибке) при неудаче.
"""
try:
current_file = os.path.abspath(__file__)
except Exception:
current_file = os.path.abspath(sys.argv[0]) if sys.argv and sys.argv[0] else None
if not current_file or not os.path.exists(current_file):
return False, "Не удалось определить путь к файлу скрипта"
try:
with open(current_file, "r", encoding="utf-8") as f:
src = f.read()
return True, src
except Exception as e:
return False, f"Ошибка при чтении исходного кода: {e}"
class EulerMethodAnalyzer:
"""Класс для решения задачи Коши методом Эйлера"""
def __init__(self):
# Параметры задачи
self.equation = "y' = (1 - y + ln(x))/x"
self.initial_condition = "y(1) = 1"
self.interval = [1, 2]
self.exact_solution = "φ(x) = ln(x)"
self.steps = [0.2, 0.1]
# Результаты вычислений
self.results = {}
def derivative(self, x: float, y: float) -> float:
"""Правая часть дифференциального уравнения"""
return (1 - y + np.log(x)) / x
def exact_solution_func(self, x: np.ndarray) -> np.ndarray:
"""Точное решение дифференциального уравнения"""
return np.log(x)
def euler_method(self, h: float) -> Dict[str, Any]:
"""Реализация метода Эйлера"""
x0, y0 = 1.0, 1.0 # начальные условия
x_end = self.interval[1]
# Создание сетки
n_steps = int((x_end - x0) / h) + 1
x_values = np.linspace(x0, x_end, n_steps)
y_values = np.zeros(n_steps)
y_values[0] = y0
# Применение метода Эйлера
for i in range(1, n_steps):
y_values[i] = y_values[i-1] + h * self.derivative(x_values[i-1], y_values[i-1])
# Вычисление точного решения и погрешностей
exact_values = self.exact_solution_func(x_values)
errors = np.abs(y_values - exact_values)
return {
'h': h,
'x_values': x_values,
'y_values': y_values,
'exact_values': exact_values,
'errors': errors,
'max_error': np.max(errors),
'mean_error': np.mean(errors)
}
def analyze_convergence(self) -> Dict[str, Any]:
"""Анализ сходимости метода Эйлера"""
# Тестируем различные шаги для анализа сходимости
test_steps = [0.2, 0.1, 0.05, 0.025, 0.0125]
max_errors = []
mean_errors = []
for h in test_steps:
result = self.euler_method(h)
max_errors.append(result['max_error'])
mean_errors.append(result['mean_error'])
# Оценка порядка метода
if len(max_errors) >= 2:
order_estimates = []
for i in range(1, len(max_errors)):
if max_errors[i] > 0 and max_errors[i-1] > 0:
order_estimate = np.log(max_errors[i-1] / max_errors[i]) / np.log(test_steps[i] / test_steps[i-1])
order_estimates.append(order_estimate)
avg_order = np.mean(order_estimates) if order_estimates else 1.0
else:
avg_order = 1.0
return {
'test_steps': test_steps,
'max_errors': max_errors,
'mean_errors': mean_errors,
'estimated_order': avg_order
}
def create_visualizations(self) -> Dict[str, str]:
"""Создание визуализаций для отчета"""
# Создаем папку для изображений
os.makedirs("results/images", exist_ok=True)
visualization_paths = {}
try:
# Вычисляем результаты для основных шагов
results_h1 = self.euler_method(self.steps[0])
results_h2 = self.euler_method(self.steps[1])
# 1. Сравнение численных решений с точным решением
plt.figure(figsize=(12, 8))
# Точное решение на плотной сетке
x_dense = np.linspace(self.interval[0], self.interval[1], 1000)
y_exact_dense = self.exact_solution_func(x_dense)
plt.plot(x_dense, y_exact_dense, 'k-', linewidth=3, label='Точное решение: ln(x)', alpha=0.8)
# Численные решения
plt.plot(results_h1['x_values'], results_h1['y_values'], 'ro--',
linewidth=2, markersize=6, label=f'Метод Эйлера (h={self.steps[0]})', alpha=0.8)
plt.plot(results_h2['x_values'], results_h2['y_values'], 'bs--',
linewidth=2, markersize=4, label=f'Метод Эйлера (h={self.steps[1]})', alpha=0.8)
plt.xlabel('x')
plt.ylabel('y(x)')
plt.title('Сравнение численных решений с точным решением', fontsize=14)
plt.grid(True, alpha=0.3)
plt.legend()
plt.tight_layout()
comparison_plot_path = "results/images/solution_comparison.png"
plt.savefig(comparison_plot_path, dpi=300, bbox_inches='tight')
plt.close()
visualization_paths['solution_comparison'] = comparison_plot_path
# 2. Графики погрешностей для разных шагов
plt.figure(figsize=(12, 8))
plt.subplot(2, 1, 1)
plt.plot(results_h1['x_values'], results_h1['errors'], 'ro-', linewidth=2, markersize=4)
plt.xlabel('x')
plt.ylabel('Погрешность')
plt.title(f'Погрешность метода Эйлера (h={self.steps[0]})', fontsize=12)
plt.grid(True, alpha=0.3)
plt.subplot(2, 1, 2)
plt.plot(results_h2['x_values'], results_h2['errors'], 'bo-', linewidth=2, markersize=4)
plt.xlabel('x')
plt.ylabel('Погрешность')
plt.title(f'Погрешность метода Эйлера (h={self.steps[1]})', fontsize=12)
plt.grid(True, alpha=0.3)
plt.suptitle('Погрешности численного решения для разных шагов', fontsize=14)
plt.tight_layout()
errors_plot_path = "results/images/errors_comparison.png"
plt.savefig(errors_plot_path, dpi=300, bbox_inches='tight')
plt.close()
visualization_paths['errors_comparison'] = errors_plot_path
# 3. Зависимость погрешности от шага
convergence_data = self.analyze_convergence()
plt.figure(figsize=(10, 6))
plt.loglog(convergence_data['test_steps'], convergence_data['max_errors'], 'ro-',
linewidth=2, markersize=8, label='Максимальная погрешность')
plt.loglog(convergence_data['test_steps'], convergence_data['mean_errors'], 'bs-',
linewidth=2, markersize=8, label='Средняя погрешность')
# Линия для сравнения с O(h)
h_ref = np.array(convergence_data['test_steps'])
error_ref = h_ref * convergence_data['max_errors'][0] / convergence_data['test_steps'][0]
plt.loglog(h_ref, error_ref, 'k--', linewidth=1, label='O(h)')
plt.xlabel('Шаг h')
plt.ylabel('Погрешность')
plt.title('Зависимость погрешности от шага интегрирования', fontsize=14)
plt.grid(True, alpha=0.3, which='both')
plt.legend()
plt.tight_layout()
convergence_plot_path = "results/images/convergence_analysis.png"
plt.savefig(convergence_plot_path, dpi=300, bbox_inches='tight')
plt.close()
visualization_paths['convergence_analysis'] = convergence_plot_path
# 4. Локальная погрешность
plt.figure(figsize=(10, 6))
# Вычисляем локальную погрешность для h=0.2
x_local = results_h1['x_values']
local_errors = []
for i in range(len(x_local) - 1):
# Локальное решение на одном шаге
y_local = results_h1['y_values'][i] + self.steps[0] * self.derivative(
x_local[i], results_h1['y_values'][i])
# Сравнение с точным решением в следующей точке
exact_next = self.exact_solution_func(x_local[i+1])
local_errors.append(abs(y_local - exact_next))
plt.plot(x_local[1:], local_errors, 'go-', linewidth=2, markersize=4, label='Локальная погрешность')
plt.xlabel('x')
plt.ylabel('Локальная погрешность')
plt.title('Локальная погрешность метода Эйлера (h=0.2)', fontsize=14)
plt.grid(True, alpha=0.3)
plt.legend()
plt.tight_layout()
local_error_plot_path = "results/images/local_error.png"
plt.savefig(local_error_plot_path, dpi=300, bbox_inches='tight')
plt.close()
visualization_paths['local_error'] = local_error_plot_path
except Exception as e:
print(f"Ошибка при создании визуализаций: {e}")
return visualization_paths
def analyze(self):
"""Выполнение полного анализа метода Эйлера"""
print("Решение задачи Коши методом Эйлера...")
# Вычисление для основных шагов
results_h1 = self.euler_method(self.steps[0])
results_h2 = self.euler_method(self.steps[1])
print("Анализ сходимости метода...")
convergence_analysis = self.analyze_convergence()
print("Создание визуализаций...")
visualizations = self.create_visualizations()
# Подготовка таблиц результатов
table_h1 = []
for i, (x, y_num, y_exact, error) in enumerate(zip(
results_h1['x_values'], results_h1['y_values'],
results_h1['exact_values'], results_h1['errors'])):
table_h1.append([f"{x:.1f}", f"{y_num:.6f}", f"{y_exact:.6f}", f"{error:.2e}"])
table_h2 = []
for i, (x, y_num, y_exact, error) in enumerate(zip(
results_h2['x_values'], results_h2['y_values'],
results_h2['exact_values'], results_h2['errors'])):
table_h2.append([f"{x:.1f}", f"{y_num:.6f}", f"{y_exact:.6f}", f"{error:.2e}"])
# Сохранение результатов
self.results = {
'results_h1': results_h1,
'results_h2': results_h2,
'convergence_analysis': convergence_analysis,
'visualizations': visualizations,
'tables': {
'h1': table_h1,
'h2': table_h2
},
'problem_definition': {
'equation': self.equation,
'initial_condition': self.initial_condition,
'interval': self.interval,
'exact_solution': self.exact_solution,
'steps': self.steps
}
}
return self.results
def get_analysis_description(self):
"""Возвращает описание анализа и методики"""
description = {
'title': "Решение задачи Коши методом Эйлера",
'discipline': "СПЕЦИАЛЬНЫЕ ГЛАВЫ МАТЕМАТИКИ / Дифференциальные уравнения",
'topic': "Решение задачи Коши для ОДУ первого порядка методом Эйлера",
'variant': "Вариант 6",
'purpose': "Приобретение практических навыков решения задачи Коши для обыкновенных дифференциальных уравнений первого порядка методом Эйлера",
'tasks': [
"Реализация метода Эйлера для решения ОДУ",
"Проведение вычислений для двух шагов интегрирования",
"Сравнение численных решений с точным решением",
"Анализ погрешностей и сходимости метода"
],
'methodology': {
'euler_method': "Метод Эйлера: y_{n+1} = y_n + h * f(x_n, y_n)",
'local_error': "Локальная погрешность метода Эйлера: O(h²)",
'global_error': "Глобальная погрешность метода Эйлера: O(h)",
'convergence': "Метод Эйлера является методом первого порядка точности"
},
'problem': {
'equation': self.equation,
'initial_condition': self.initial_condition,
'interval': f"[{self.interval[0]}, {self.interval[1]}]",
'exact_solution': self.exact_solution,
'steps': self.steps
}
}
return description
class EulerMethodMarkdownReport:
"""Класс для генерации полного отчета в Markdown"""
def __init__(self, analyzer: EulerMethodAnalyzer, analysis_results: Dict[str, Any]):
self.analyzer = analyzer
self.results = analysis_results
def add_header(self, title: str, level: int = 1) -> str:
return f"{'#' * level} {title}\n\n"
def add_table(self, data: List[List[Any]], headers: List[str], title: str = "") -> str:
table_str = ""
if title:
table_str += f"**{title}**\n\n"
table_str += "| " + " | ".join(headers) + " |\n"
table_str += "|" + "|".join(["---"] * len(headers)) + "|\n"
for row in data:
table_str += "| " + " | ".join(map(str, row)) + " |\n"
table_str += "\n"
return table_str
def add_image(self, image_path: str, caption: str = "") -> str:
if os.path.exists(image_path):
# Центрированное изображение с ограниченной шириной
return (f'<div align="center">\n\n'
f'<img src="{image_path}" alt="{caption}" style="max-width: 80%; height: auto; border: 1px solid #ddd; padding: 5px; background: #f8f9fa;">\n\n'
f'**Рисунок:** {caption}\n\n'
f'</div>\n\n')
else:
return f"*Изображение не найдено: {caption}*\n\n"
def add_code_section(self) -> str:
success, src = read_own_source()
section = self.add_header("ПРИЛОЖЕНИЕ А", 2)
section += "**Исходный код программы**\n\n"
if success:
section += "```python\n" + src
if not src.endswith("\n"):
section += "\n"
section += "```\n"
else:
section += f"*Не удалось прочитать исходный код: {src}*\n"
return section
def generate_report(self) -> str:
report = ""
# Титульная страница
report += '<div style="page-break-after: always;">\n\n'
report += "# Федеральное государственное бюджетное образовательное учреждение высшего профессионального образования\n\n"
report += "### «Казанский национальный исследовательский технологический университет»\n\n"
report += "#### Институт: Институт управления, автоматизации и информационных технологий\n"
report += "#### Кафедра Информатики и прикладной математики\n\n"
report += "---\n\n"
report += "# ЛАБОРАТОРНАЯ РАБОТА\n\n"
description = self.analyzer.get_analysis_description()
report += f"### по дисциплине: «{description['discipline']}»\n\n"
report += f"### на тему: «{description['topic']}»\n\n"
report += f"### {description['variant']}\n\n"
report += "---\n\n"
report += "**Выполнил:** \n"
report += "студент группы 851-М81 \n"
report += "Меркулов А. Д. \n"
report += '</div>\n\n'
# Содержание
report += self.add_header("СОДЕРЖАНИЕ", 1)
toc = [
"1. ВВЕДЕНИЕ",
"2. ПОСТАНОВКА ЗАДАЧИ",
"3. ТЕОРЕТИЧЕСКИЕ ОСНОВЫ",
" 3.1. Метод Эйлера для решения ОДУ",
" 3.2. Погрешность метода Эйлера",
"4. РЕЗУЛЬТАТЫ ВЫЧИСЛЕНИЙ",
" 4.1. Численное решение для h=0.2",
" 4.2. Численное решение для h=0.1",
" 4.3. Сравнительный анализ",
"5. АНАЛИЗ ПОГРЕШНОСТЕЙ",
" 5.1. Локальная и глобальная погрешности",
" 5.2. Зависимость погрешности от шага",
"6. ВЫВОДЫ",
"ПРИЛОЖЕНИЕ А"
]
for item in toc:
report += f"{item}\n\n"
report += "---\n\n"
# 1) Введение
report += self.add_header("1. ВВЕДЕНИЕ", 1)
report += f"**Цель работы:** {description['purpose']}\n\n"
report += "**Задачи исследования:**\n"
for i, task in enumerate(description['tasks'], 1):
report += f"{i}. {task}\n"
report += "\n"
report += "**Актуальность исследования** обусловлена фундаментальной важностью численных методов решения дифференциальных уравнений в научных и инженерных расчетах. Метод Эйлера, несмотря на свою простоту, является основой для понимания более сложных численных методов и позволяет изучать основные закономерности численного решения ОДУ.\n\n"
# 2) Постановка задачи
report += self.add_header("2. ПОСТАНОВКА ЗАДАЧИ", 1)
problem_def = description['problem']
report += f"**Дифференциальное уравнение:** {problem_def['equation']}\n\n"
report += f"**Начальное условие:** {problem_def['initial_condition']}\n\n"
report += f"**Отрезок интегрирования:** {problem_def['interval']}\n\n"
report += f"**Точное решение:** {problem_def['exact_solution']}\n\n"
report += f"**Шаги интегрирования:** h₁ = {problem_def['steps'][0]}, h₂ = {problem_def['steps'][1]}\n\n"
report += "**Задача:** Решить задачу Коши для заданного обыкновенного дифференциального уравнения первого порядка методом Эйлера, провести сравнительный анализ численных решений с точным решением, исследовать погрешности метода и его сходимость.\n\n"
# 3) Теоретические основы
report += self.add_header("3. ТЕОРЕТИЧЕСКИЕ ОСНОВЫ", 1)
report += self.add_header("3.1. Метод Эйлера для решения ОДУ", 2)
methodology = description['methodology']
report += f"**{list(methodology.keys())[0]}:** {methodology['euler_method']}\n\n"
report += "где:\n"
report += "- yₙ - приближенное решение в точке xₙ\n"
report += "- h - шаг интегрирования\n"
report += "- f(x, y) - правая часть дифференциального уравнения y' = f(x, y)\n"
report += "- xₙ = x₀ + n·h - узлы сетки\n\n"
report += "**Алгоритм метода Эйлера:**\n"
report += "1. Задать начальные условия: x₀, y₀\n"
report += "2. Выбрать шаг интегрирования h\n"
report += "3. Для n = 0, 1, 2, ... выполнять:\n"
report += " - Вычислить f(xₙ, yₙ)\n"
report += " - Вычислить yₙ₊₁ = yₙ + h·f(xₙ, yₙ)\n"
report += " - Перейти к следующему узлу: xₙ₊₁ = xₙ + h\n"
report += "4. Процесс продолжается до достижения правого конца отрезка\n\n"
report += self.add_header("3.2. Погрешность метода Эйлера", 2)
report += f"**{list(methodology.keys())[1]}:** {methodology['local_error']}\n\n"
report += f"**{list(methodology.keys())[2]}:** {methodology['global_error']}\n\n"
report += f"**{list(methodology.keys())[3]}:** {methodology['convergence']}\n\n"
# 4) Результаты вычислений
report += self.add_header("4. РЕЗУЛЬТАТЫ ВЫЧИСЛЕНИЙ", 1)
tables = self.results['tables']
report += self.add_header("4.1. Численное решение для h=0.2", 2)
report += self.add_table(tables['h1'],
["x", "Численное решение y(x)", "Точное решение φ(x)", "Погрешность |y(x)-φ(x)|"],
"Результаты метода Эйлера для шага h=0.2")
results_h1 = self.results['results_h1']
report += f"**Максимальная погрешность:** {results_h1['max_error']:.2e}\n"
report += f"**Средняя погрешность:** {results_h1['mean_error']:.2e}\n\n"
report += self.add_header("4.2. Численное решение для h=0.1", 2)
report += self.add_table(tables['h2'],
["x", "Численное решение y(x)", "Точное решение φ(x)", "Погрешность |y(x)-φ(x)|"],
"Результаты метода Эйлера для шага h=0.1")
results_h2 = self.results['results_h2']
report += f"**Максимальная погрешность:** {results_h2['max_error']:.2e}\n"
report += f"**Средняя погрешность:** {results_h2['mean_error']:.2e}\n\n"
report += self.add_header("4.3. Сравнительный анализ", 2)
report += "**Сравнение точности для разных шагов:**\n"
report += f"- При h=0.2: максимальная погрешность = {results_h1['max_error']:.2e}\n"
report += f"- При h=0.1: максимальная погрешность = {results_h2['max_error']:.2e}\n"
report += f"- Уменьшение погрешности: в {results_h1['max_error']/results_h2['max_error']:.2f} раз\n\n"
report += "**Наблюдения:** С уменьшением шага интегрирования погрешность метода Эйлера уменьшается, что соответствует теоретическим ожиданиям для метода первого порядка точности.\n\n"
# 5) Анализ погрешностей
report += self.add_header("5. АНАЛИЗ ПОГРЕШНОСТЕЙ", 1)
visualizations = self.results['visualizations']
report += self.add_header("5.1. Сравнение решений и погрешностей", 2)
if 'solution_comparison' in visualizations:
report += self.add_image(visualizations['solution_comparison'],
"Сравнение численных решений с точным решением")
if 'errors_comparison' in visualizations:
report += self.add_image(visualizations['errors_comparison'],
"Погрешности численного решения для разных шагов")
report += "**Анализ:** Графики демонстрируют, что численное решение методом Эйлера приближается к точному решению с уменьшением шага интегрирования. Погрешности накапливаются по мере удаления от начальной точки.\n\n"
report += self.add_header("5.2. Зависимость погрешности от шага", 2)
if 'convergence_analysis' in visualizations:
report += self.add_image(visualizations['convergence_analysis'],
"Зависимость погрешности от шага интегрирования")
if 'local_error' in visualizations:
report += self.add_image(visualizations['local_error'],
"Локальная погрешность метода Эйлера")
convergence = self.results['convergence_analysis']
report += f"**Оценка порядка метода:** {convergence['estimated_order']:.3f}\n\n"
report += "**Анализ сходимости:**\n"
report += "- Логарифмический график зависимости погрешности от шага показывает линейную зависимость\n"
report += "- Наклон графика близок к 1, что соответствует первому порядку точности метода Эйлера\n"
report += "- Локальная погрешность имеет характерные всплески в определенных точках\n\n"
# 6) Выводы
report += self.add_header("6. ВЫВОДЫ", 1)
conclusions = [
"Успешно реализован метод Эйлера для решения задачи Коши обыкновенного дифференциального уравнения",
"Проведены вычисления для двух шагов интегрирования h=0.2 и h=0.1",
"Полученные численные решения сравнины с точным решением φ(x) = ln(x)",
"Установлено, что с уменьшением шага интегрирования погрешность метода уменьшается",
"Максимальная погрешность для h=0.2 составила {:.2e}, для h=0.1 - {:.2e}".format(
results_h1['max_error'], results_h2['max_error']),
"Экспериментально подтвержден первый порядок точности метода Эйлера",
"Проанализированы локальные и глобальные погрешности численного метода",
"Построены графики решений и погрешностей, наглядно демонстрирующие свойства метода"
]
for i, conclusion in enumerate(conclusions, 1):
report += f"{i}. {conclusion}\n"
report += "\n"
# Приложение
report += self.add_code_section()
return report
class EulerMethodDocxReport:
"""Класс для генерации отчета в формате DOCX"""
def __init__(self, analyzer: EulerMethodAnalyzer, analysis_results: Dict[str, Any]):
self.analyzer = analyzer
self.results = analysis_results
def setup_document_styles(self, doc):
"""Настройка стилей документа"""
# Настройка стилей для русского текста
try:
doc.styles['Normal'].font.name = 'Times New Roman'
doc.styles['Normal']._element.rPr.rFonts.set(qn('w:eastAsia'), 'Times New Roman')
doc.styles['Normal'].font.size = Pt(12)
except:
pass
def add_table_to_docx(self, doc, data: List[List[Any]], headers: List[str], title: str = ""):
"""Добавляет таблицу в DOCX документ"""
if title:
p = doc.add_paragraph()
p.add_run(title).bold = True
p.alignment = WD_ALIGN_PARAGRAPH.CENTER
doc.add_paragraph()
table = doc.add_table(rows=len(data)+1, cols=len(headers))
table.style = 'Table Grid'
# Заголовки
hdr_cells = table.rows[0].cells
for i, header in enumerate(headers):
hdr_cells[i].text = str(header)
hdr_cells[i].paragraphs[0].alignment = WD_ALIGN_PARAGRAPH.CENTER
for paragraph in hdr_cells[i].paragraphs:
for run in paragraph.runs:
run.bold = True
# Данные
for i, row in enumerate(data, 1):
row_cells = table.rows[i].cells
for j, cell in enumerate(row):
row_cells[j].text = str(cell)
if j > 0: # Выравнивание числовых данных по центру
row_cells[j].paragraphs[0].alignment = WD_ALIGN_PARAGRAPH.CENTER
doc.add_paragraph()
def add_image_to_docx(self, doc, image_path: str, caption: str = ""):
"""Добавляет изображение в DOCX документ"""
if os.path.exists(image_path):
try:
# Центрируем изображение
paragraph = doc.add_paragraph()
paragraph.alignment = WD_ALIGN_PARAGRAPH.CENTER
run = paragraph.add_run()
run.add_picture(image_path, width=Inches(5.0))
# Добавляем подпись
if caption:
caption_paragraph = doc.add_paragraph()
caption_paragraph.alignment = WD_ALIGN_PARAGRAPH.CENTER
caption_run = caption_paragraph.add_run(f"Рисунок: {caption}")
caption_run.italic = True
doc.add_paragraph()
except Exception as e:
doc.add_paragraph(f"Ошибка при добавлении изображения: {e}")
else:
doc.add_paragraph(f"Изображение не найдено: {caption}")
def generate_docx_report(self, filename: str = "euler_method_report.docx") -> str:
"""
Генерация отчёта в формате DOCX для метода Эйлера
"""
out_path = os.path.join("results", filename)
if not PYDOCX_AVAILABLE:
print("python-docx не установлен — DOCX отчёт не будет создан")
return out_path
try:
doc = Document()
self.setup_document_styles(doc)
# Титульная страница
title_paragraph = doc.add_paragraph()
title_paragraph.alignment = WD_ALIGN_PARAGRAPH.CENTER
title_run = title_paragraph.add_run("Федеральное государственное бюджетное образовательное учреждение высшего профессионального образования\n«Казанский национальный исследовательский технологический университет»")
title_run.bold = True
title_run.font.size = Pt(14)
doc.add_paragraph()
university_paragraph = doc.add_paragraph()
university_paragraph.alignment = WD_ALIGN_PARAGRAPH.CENTER
university_paragraph.add_run("Институт: Институт управления, автоматизации и информационных технологий\nКафедра Информатики и прикладной математики").bold = True
doc.add_paragraph("\n" * 3)
# Название работы
work_paragraph = doc.add_paragraph()
work_paragraph.alignment = WD_ALIGN_PARAGRAPH.CENTER
work_run = work_paragraph.add_run("ЛАБОРАТОРНАЯ РАБОТА")
work_run.bold = True
work_run.font.size = Pt(16)
description = self.analyzer.get_analysis_description()
doc.add_paragraph()
discipline_paragraph = doc.add_paragraph()
discipline_paragraph.alignment = WD_ALIGN_PARAGRAPH.CENTER
discipline_paragraph.add_run(f"по дисциплине: «{description['discipline']}»").bold = True
doc.add_paragraph()
topic_paragraph = doc.add_paragraph()
topic_paragraph.alignment = WD_ALIGN_PARAGRAPH.CENTER
topic_paragraph.add_run(f"на тему: «{description['topic']}»").bold = True
doc.add_paragraph()
variant_paragraph = doc.add_paragraph()
variant_paragraph.alignment = WD_ALIGN_PARAGRAPH.CENTER
variant_paragraph.add_run(f"{description['variant']}").bold = True
doc.add_paragraph("\n" * 4)
# Информация о студенте
info_table = doc.add_table(rows=2, cols=2)
info_table.style = 'Table Grid'
info_table.cell(0, 0).text = "Выполнил:"
info_table.cell(0, 1).text = "студент группы 851-М81\nМеркулов А. Д."
for row in info_table.rows:
for cell in row.cells:
cell.paragraphs[0].alignment = WD_ALIGN_PARAGRAPH.LEFT
doc.add_page_break()
# Содержание
title = doc.add_paragraph()
title.alignment = WD_ALIGN_PARAGRAPH.CENTER
title.add_run("СОДЕРЖАНИЕ").bold = True
title.runs[0].font.size = Pt(14)
doc.add_paragraph()
toc_items = [
"1. ВВЕДЕНИЕ",
"2. ПОСТАНОВКА ЗАДАЧИ",
"3. ТЕОРЕТИЧЕСКИЕ ОСНОВЫ",
"3.1. Метод Эйлера для решения ОДУ",
"3.2. Погрешность метода Эйлера",
"4. РЕЗУЛЬТАТЫ ВЫЧИСЛЕНИЙ",
"4.1. Численное решение для h=0.2",
"4.2. Численное решение для h=0.1",
"5. АНАЛИЗ ПОГРЕШНОСТЕЙ",
"5.1. Сравнение решений и погрешностей",
"5.2. Зависимость погрешности от шага",
"6. ВЫВОДЫ",
"ПРИЛОЖЕНИЕ А"
]
for item in toc_items:
p = doc.add_paragraph()
p.add_run(item)
doc.add_page_break()
# 1) Введение
heading = doc.add_paragraph()
heading.alignment = WD_ALIGN_PARAGRAPH.CENTER
heading.add_run("1. ВВЕДЕНИЕ").bold = True
heading.runs[0].font.size = Pt(14)
doc.add_paragraph()
doc.add_paragraph(f"Цель работы: {description['purpose']}")
doc.add_paragraph("Задачи исследования:")
for task in description['tasks']:
p = doc.add_paragraph(task, style='List Bullet')
# 2) Постановка задачи
doc.add_page_break()
heading = doc.add_paragraph()
heading.alignment = WD_ALIGN_PARAGRAPH.CENTER
heading.add_run("2. ПОСТАНОВКА ЗАДАЧИ").bold = True
heading.runs[0].font.size = Pt(14)
doc.add_paragraph()
problem_def = description['problem']
doc.add_paragraph(f"Дифференциальное уравнение: {problem_def['equation']}")
doc.add_paragraph(f"Начальное условие: {problem_def['initial_condition']}")
doc.add_paragraph(f"Отрезок интегрирования: {problem_def['interval']}")
doc.add_paragraph(f"Точное решение: {problem_def['exact_solution']}")
doc.add_paragraph(f"Шаги интегрирования: h₁ = {problem_def['steps'][0]}, h₂ = {problem_def['steps'][1]}")
# 3) Теоретические основы
doc.add_page_break()
heading = doc.add_paragraph()
heading.alignment = WD_ALIGN_PARAGRAPH.CENTER
heading.add_run("3. ТЕОРЕТИЧЕСКИЕ ОСНОВЫ").bold = True
heading.runs[0].font.size = Pt(14)
doc.add_paragraph()
subheading = doc.add_paragraph()
subheading.add_run("3.1. Метод Эйлера для решения ОДУ").bold = True
methodology = description['methodology']
doc.add_paragraph(f"Метод Эйлера: {methodology['euler_method']}")
subheading = doc.add_paragraph()
subheading.add_run("3.2. Погрешность метода Эйлера").bold = True
doc.add_paragraph(f"Локальная погрешность: {methodology['local_error']}")
doc.add_paragraph(f"Глобальная погрешность: {methodology['global_error']}")
# 4) Результаты вычислений
doc.add_page_break()
heading = doc.add_paragraph()
heading.alignment = WD_ALIGN_PARAGRAPH.CENTER
heading.add_run("4. РЕЗУЛЬТАТЫ ВЫЧИСЛЕНИЙ").bold = True
heading.runs[0].font.size = Pt(14)
doc.add_paragraph()
tables = self.results['tables']
results_h1 = self.results['results_h1']
results_h2 = self.results['results_h2']
subheading = doc.add_paragraph()
subheading.add_run("4.1. Численное решение для h=0.2").bold = True
# Таблица для h=0.2
self.add_table_to_docx(doc, tables['h1'][:6],
["x", "Численное y(x)", "Точное φ(x)", "Погрешность"],
"Результаты метода Эйлера для шага h=0.2")
doc.add_paragraph(f"Максимальная погрешность: {results_h1['max_error']:.2e}")
doc.add_paragraph(f"Средняя погрешность: {results_h1['mean_error']:.2e}")
subheading = doc.add_paragraph()
subheading.add_run("4.2. Численное решение для h=0.1").bold = True
# Таблица для h=0.1
self.add_table_to_docx(doc, tables['h2'][:6],
["x", "Численное y(x)", "Точное φ(x)", "Погрешность"],
"Результаты метода Эйлера для шага h=0.1")
doc.add_paragraph(f"Максимальная погрешность: {results_h2['max_error']:.2e}")
doc.add_paragraph(f"Средняя погрешность: {results_h2['mean_error']:.2e}")
# 5) Анализ погрешностей
doc.add_page_break()
heading = doc.add_paragraph()
heading.alignment = WD_ALIGN_PARAGRAPH.CENTER
heading.add_run("5. АНАЛИЗ ПОГРЕШНОСТЕЙ").bold = True
heading.runs[0].font.size = Pt(14)
doc.add_paragraph()
visualizations = self.results['visualizations']
subheading = doc.add_paragraph()
subheading.add_run("5.1. Сравнение решений и погрешностей").bold = True
if 'solution_comparison' in visualizations:
self.add_image_to_docx(doc, visualizations['solution_comparison'],
"Сравнение численных решений с точным решением")
if 'errors_comparison' in visualizations:
self.add_image_to_docx(doc, visualizations['errors_comparison'],
"Погрешности численного решения для разных шагов")
subheading = doc.add_paragraph()
subheading.add_run("5.2. Зависимость погрешности от шага").bold = True
if 'convergence_analysis' in visualizations:
self.add_image_to_docx(doc, visualizations['convergence_analysis'],
"Зависимость погрешности от шага интегрирования")
convergence = self.results['convergence_analysis']
doc.add_paragraph(f"Оценка порядка метода: {convergence['estimated_order']:.3f}")
# 6) Выводы
doc.add_page_break()
heading = doc.add_paragraph()
heading.alignment = WD_ALIGN_PARAGRAPH.CENTER
heading.add_run("6. ВЫВОДЫ").bold = True
heading.runs[0].font.size = Pt(14)
doc.add_paragraph()
conclusions = [
"Успешно реализован метод Эйлера для решения задачи Коши",
"Проведены вычисления для шагов h=0.2 и h=0.1",
"Сравнение с точным решением подтвердило сходимость метода",
"Установлено уменьшение погрешности с уменьшением шага",
"Экспериментально подтвержден первый порядок точности метода",
"Проанализированы погрешности и построены графики"
]
for i, conclusion in enumerate(conclusions, 1):
doc.add_paragraph(f"{i}. {conclusion}", style='List Number')
# Приложение
doc.add_page_break()
heading = doc.add_paragraph()
heading.alignment = WD_ALIGN_PARAGRAPH.CENTER
heading.add_run("ПРИЛОЖЕНИЕ А").bold = True
heading.runs[0].font.size = Pt(14)
doc.add_paragraph()
subheading = doc.add_paragraph()
subheading.add_run("Исходный код программы").bold = True
success_src, src_text = read_own_source()
if success_src:
# Добавляем код с моноширинным шрифтом
for line in src_text.splitlines():
p = doc.add_paragraph()
run = p.add_run(line)
try:
run.font.name = 'Courier New'
run.font.size = Pt(9)
except Exception:
pass
else:
doc.add_paragraph("Не удалось прочитать исходный код скрипта: " + src_text)
# Сохранение файла
doc.save(out_path)
print(f"DOCX-отчёт сохранён: {out_path}")
except Exception as e:
print(f"Ошибка при генерации DOCX-отчёта: {e}")
raise e
return out_path
def main():
"""Основная функция для выполнения лабораторной работы по методу Эйлера"""
# Создаем анализатор
analyzer = EulerMethodAnalyzer()
# Выполняем анализ
print("Решение задачи Коши методом Эйлера...")
results = analyzer.analyze()
# Создаем папку для результатов
os.makedirs("results", exist_ok=True)
os.makedirs("results/images", exist_ok=True)
# Генерируем Markdown отчет
md_reporter = EulerMethodMarkdownReport(analyzer, results)
md_report = md_reporter.generate_report()
# Сохраняем Markdown отчет
with open("README.md", "w", encoding="utf-8") as f:
f.write(md_report)
print("Markdown отчет сохранен: README.md")
# Генерируем DOCX отчет
docx_reporter = EulerMethodDocxReport(analyzer, results)
docx_path = docx_reporter.generate_docx_report()
# Выводим основные результаты в консоль
print("\n" + "="*80)
print("РЕЗУЛЬТАТЫ РЕШЕНИЯ ЗАДАЧИ КОШИ МЕТОДОМ ЭЙЛЕРА")
print("="*80)
results_h1 = results['results_h1']
results_h2 = results['results_h2']
convergence = results['convergence_analysis']
print(f"\nТОЧНОСТЬ МЕТОДА:")
print("-" * 50)
print(f"h=0.2: максимальная погрешность = {results_h1['max_error']:.2e}")
print(f"h=0.1: максимальная погрешность = {results_h2['max_error']:.2e}")
print(f"Уменьшение погрешности: в {results_h1['max_error']/results_h2['max_error']:.2f} раз")
print(f"\nАНАЛИЗ СХОДИМОСТИ:")
print("-" * 50)
print(f"Оценка порядка метода: {convergence['estimated_order']:.3f}")
print("(ожидаемое значение для метода Эйлера: 1.0)")
print(f"\nВИЗУАЛИЗАЦИИ СОЗДАНЫ:")
print("-" * 50)
for name, path in results['visualizations'].items():
if os.path.exists(path):
print(f"✓ {name}: {path}")
print(f"\nОТЧЕТЫ СОХРАНЕНЫ:")
print("-" * 50)
print(f"✓ Markdown отчет: README.md")
if PYDOCX_AVAILABLE:
print(f"✓ DOCX отчет: {docx_path}")
return results
if __name__ == "__main__":
main()