From 2e8c902dd261f4c19f2aa06763084559e1a3c0e9 Mon Sep 17 00:00:00 2001 From: RB Date: Sat, 24 May 2025 19:59:53 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=9B=E5=BB=BA=E5=87=BD=E6=95=B0=E6=8B=9F?= =?UTF-8?q?=E5=90=88=E5=B7=A5=E5=85=B7=EF=BC=8C=E5=87=86=E5=A4=87=E5=88=9B?= =?UTF-8?q?=E5=BB=BAMR=E5=B7=A5=E5=85=B7=E7=AE=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .DS_Store | Bin 8196 -> 8196 bytes MR_Toolbox.py | 92 +++++++++++++++++ data.xlsx | Bin 0 -> 8674 bytes pitch.png | Bin 0 -> 23534 bytes polynomial.py | 276 ++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 368 insertions(+) create mode 100644 MR_Toolbox.py create mode 100644 data.xlsx create mode 100644 pitch.png create mode 100644 polynomial.py diff --git a/.DS_Store b/.DS_Store index e1626b4729911e528129367f61a49ae510997079..aae880c6919ccbe548cb9edc0e55dd17c3b7095f 100644 GIT binary patch delta 328 zcmZp1XmOa}FDk;oz`)4BAi%(o%#g^C$DqfM?3uH%a2or>2Hwr=94s8JAQhYpNesmd z1q|`Xs`8VQa`KaavOvuY>w#GBKNtX67&<1a2q>#_GNb_QC;?(Uh6;uppotZpIVh$$ z0(H*YY$H(0=*i9C%Miqn541QRs3o4Eh#?i|fP7R9j6XpdP^>Lr$ONiSX2<|qQULT& z`eY3Oc|{H&8(F*()f|TPn->Z0WMtevxj~?iOT4<;#MD4X!NhFx9|38`&dCyj@{C=R VMMT^;mTYI*%r3#m3gd2J0s!QwP>=us delta 115 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 E2~&-Gf&c&j literal 0 HcmV?d00001 diff --git a/polynomial.py b/polynomial.py new file mode 100644 index 0000000..c0b6805 --- /dev/null +++ b/polynomial.py @@ -0,0 +1,276 @@ +import tkinter as tk +from tkinter import filedialog, messagebox, ttk +import numpy as np +import pandas as pd +from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg +from matplotlib.figure import Figure + +class PolyFitApp: + def __init__(self, root): + self.root = root + self.root.title("多项式拟合工具") + self.data_x = [] + self.data_y = [] + self.last_coeffs = None + + # ===== 主布局 ===== + main_frame = ttk.Frame(root, padding=8) + main_frame.pack(fill="both", expand=True) + main_frame.columnconfigure(0, weight=0) + main_frame.columnconfigure(1, weight=1) + main_frame.rowconfigure(0, weight=1) + + # ===== 左侧区 ===== + left_frame = ttk.Frame(main_frame, width=320, height=580) # 设置固定宽度 + left_frame.grid(row=0, column=0, sticky="nsw") # 只贴左侧 + left_frame.columnconfigure(0, weight=1) + left_frame.grid_propagate(False) # 防止自动缩放 + + # --- 数据输入区 --- + input_frame = ttk.LabelFrame(left_frame, text="数据输入", padding=6) + input_frame.grid(row=0, column=0, sticky="ew", pady=(0, 8)) + input_frame.columnconfigure(0, weight=1) + + self.excel_btn = ttk.Button(input_frame, text="导入excel文件", command=self.load_excel) + self.excel_btn.grid(row=0, column=0, sticky="ew", padx=2, pady=2) + + # 滚动区域 + self.scroll_canvas = tk.Canvas(input_frame, height=200) + self.scroll_canvas.grid(row=1, column=0, sticky="ew", pady=4) + self.scrollbar = ttk.Scrollbar(input_frame, orient="vertical", command=self.scroll_canvas.yview) + self.scrollbar.grid(row=1, column=1, sticky="ns") + self.scroll_canvas.configure(yscrollcommand=self.scrollbar.set) + + self.manual_frame = ttk.Frame(self.scroll_canvas) + self.manual_frame.bind("", lambda e: self.scroll_canvas.configure(scrollregion=self.scroll_canvas.bbox("all"))) + self.scroll_canvas.create_window((0, 0), window=self.manual_frame, anchor="nw") + + self.point_rows = [] + self.add_row_btn = ttk.Button(input_frame, text="添加数据", command=self.add_point_row) + self.add_row_btn.grid(row=2, column=0, sticky="ew", padx=2, pady=2) + + # --- 参数区 --- + param_frame = ttk.LabelFrame(left_frame, text="拟合参数", padding=6) + param_frame.grid(row=1, column=0, sticky="ew", pady=(0, 8)) + ttk.Label(param_frame, text="选择多项式阶数:").grid(row=0, column=0, padx=2, pady=2, sticky="e") + self.order_spin = ttk.Spinbox(param_frame, from_=1, to=10, width=5) + self.order_spin.set(2) + self.order_spin.grid(row=0, column=1, padx=2, pady=2, sticky="w") + # 优化复选框和拟合按钮同一行 + self.fit_btn = ttk.Button(param_frame, text="拟合并显示", command=self.fit_and_plot) + self.fit_btn.grid(row=1, column=0, padx=2, pady=4, sticky="ew") + self.optimize_var = tk.BooleanVar(value=True) + self.optimize_check = ttk.Checkbutton(param_frame, text="优化曲线(防止突起)", variable=self.optimize_var) + self.optimize_check.grid(row=1, column=1, padx=2, pady=4, sticky="w") + + # --- 输出区 --- + output_frame = ttk.LabelFrame(left_frame, text="表达式与代码", padding=6) + output_frame.grid(row=2, column=0, sticky="ew") + self.output = tk.Text(output_frame, height=6, width=40, font=("Consolas", 10)) + self.output.grid(row=0, column=0, columnspan=3, padx=2, pady=2) + ttk.Label(output_frame, text="输出代码格式:").grid(row=1, column=0, padx=2, pady=2, sticky="e") + self.code_type = ttk.Combobox(output_frame, values=["C", "C++", "Python"], width=8) + self.code_type.set("C") + self.code_type.grid(row=1, column=1, padx=2, pady=2, sticky="w") + self.gen_code_btn = ttk.Button(output_frame, text="生成函数代码", command=self.generate_code) + self.gen_code_btn.grid(row=1, column=2, padx=2, pady=2, sticky="ew") + + # ===== 右侧区 ===== + right_frame = ttk.Frame(main_frame) + # right_frame.grid(row=0, column=1, sticky="nsew") # 填满剩余空间 + right_frame.grid(row=0, column=1, sticky="nsew", padx=(8, 0)) + right_frame.rowconfigure(0, weight=1) + right_frame.columnconfigure(0, weight=1) + + plot_frame = ttk.LabelFrame(right_frame, text="拟合曲线", padding=6) + plot_frame.grid(row=0, column=0, sticky="nsew") + plot_frame.rowconfigure(0, weight=1) + plot_frame.columnconfigure(0, weight=1) + self.figure = Figure(figsize=(5, 4)) + self.canvas = FigureCanvasTkAgg(self.figure, master=plot_frame) + self.canvas.get_tk_widget().pack(fill="both", expand=True) + self.scroll_canvas.bind_all("", self._on_mousewheel) + + + def _on_mousewheel(self, event): + # Windows下event.delta为120的倍数,负值向下 + self.scroll_canvas.yview_scroll(int(-1*(event.delta/120)), "units") + + def add_point_row(self, x_val="", y_val=""): + row = {} + idx = len(self.point_rows) + row['x'] = ttk.Entry(self.manual_frame, width=10) + row['x'].insert(0, str(x_val)) + row['y'] = ttk.Entry(self.manual_frame, width=10) + row['y'].insert(0, str(y_val)) + row['del'] = ttk.Button(self.manual_frame, text="删除", width=5, command=lambda r=idx: self.delete_point_row(r)) + row['x'].grid(row=idx, column=0, padx=1, pady=1) + row['y'].grid(row=idx, column=1, padx=1, pady=1) + row['del'].grid(row=idx, column=2, padx=1, pady=1) + self.point_rows.append(row) + self.refresh_point_rows() + + def delete_point_row(self, idx): + for widget in self.point_rows[idx].values(): + widget.grid_forget() + widget.destroy() + self.point_rows.pop(idx) + self.refresh_point_rows() + + def refresh_point_rows(self): + for i, row in enumerate(self.point_rows): + row['x'].grid(row=i, column=0, padx=1, pady=1) + row['y'].grid(row=i, column=1, padx=1, pady=1) + row['del'].config(command=lambda r=i: self.delete_point_row(r)) + row['del'].grid(row=i, column=2, padx=1, pady=1) + + def load_excel(self): + file = filedialog.askopenfilename(filetypes=[("Excel files", "*.xlsx *.xls")]) + if file: + try: + data = pd.read_excel(file, usecols=[0, 1]) + new_x = data.iloc[:, 0].values.tolist() + new_y = data.iloc[:, 1].values.tolist() + messagebox.showinfo("成功", "数据导入成功!") + for x, y in zip(new_x, new_y): + self.add_point_row(x, y) + except Exception as e: + messagebox.showerror("错误", f"读取Excel失败: {e}") + + def get_manual_points(self): + x_list, y_list = [], [] + for row in self.point_rows: + try: + x = float(row['x'].get()) + y = float(row['y'].get()) + x_list.append(x) + y_list.append(y) + except ValueError: + continue + return x_list, y_list + + + def fit_and_plot(self): + # 始终以手动输入区为准 + self.data_x, self.data_y = self.get_manual_points() + try: + order = int(self.order_spin.get()) + except ValueError: + messagebox.showwarning("输入错误", "阶数必须为整数!") + return + n_points = len(self.data_x) + if n_points < order + 1: + messagebox.showwarning("数据不足", "数据点数量不足以拟合该阶多项式!") + return + + # 阶数过高判断,只提示不强制修改 + max_order = max(2, min(6, n_points // 3)) + if order > max_order: + messagebox.showwarning("阶数过高", f"当前数据点数为{n_points},建议阶数不超过{max_order},否则容易出现异常突起!") + + x = np.array(self.data_x, dtype=np.float64) + y = np.array(self.data_y, dtype=np.float64) + + # ----------- 新增归一化 ----------- + x_min, x_max = x.min(), x.max() + if x_max - x_min == 0: + messagebox.showwarning("数据错误", "所有x值都相同,无法拟合!") + return + x_norm = (x - x_min) / (x_max - x_min) + # --------------------------------- + + try: + if self.optimize_var.get(): + # 优化:加大rcond,减少高阶影响 + coeffs = np.polyfit(x_norm, y, order, rcond=1e-3) + else: + coeffs = np.polyfit(x_norm, y, order) + except Exception as e: + messagebox.showerror("拟合错误", f"多项式拟合失败:{e}") + return + poly = np.poly1d(coeffs) + expr = "y = " + " + ".join([f"{c:.6g}*x_norm^{order-i}" for i, c in enumerate(coeffs)]) + self.output.delete(1.0, tk.END) + self.output.insert(tk.END, f"归一化x: x_norm=(x-{x_min:.6g})/({x_max:.6g}-{x_min:.6g})\n") + self.output.insert(tk.END, expr + "\n") + # 绘图 + self.figure.clear() + ax = self.figure.add_subplot(111) + ax.scatter(x, y, color='red', label='数据点') + x_fit = np.linspace(x_min, x_max, 200) + x_fit_norm = (x_fit - x_min) / (x_max - x_min) + y_fit = poly(x_fit_norm) + ax.plot(x_fit, y_fit, label='拟合曲线') + ax.legend() + self.canvas.draw() + self.last_coeffs = coeffs + self.last_xmin = x_min + self.last_xmax = x_max + + def generate_code(self): + if self.last_coeffs is None: + messagebox.showwarning("未拟合", "请先拟合数据!") + return + coeffs = self.last_coeffs + order = len(coeffs) - 1 + code_type = self.code_type.get() + if code_type == "C": + code = self.create_c_function(coeffs) + elif code_type == "C++": + code = self.create_cpp_function(coeffs) + else: + code = self.create_py_function(coeffs) + self.output.delete(1.0, tk.END) + self.output.insert(tk.END, code) + + def create_c_function(self, coeffs): + lines = ["#include ", "double polynomial(double x) {", " return "] + n = len(coeffs) + terms = [] + for i, c in enumerate(coeffs): + exp = n - i - 1 + if exp == 0: + terms.append(f"{c:.8g}") + elif exp == 1: + terms.append(f"{c:.8g}*x") + else: + terms.append(f"{c:.8g}*pow(x,{exp})") + lines[-1] += " + ".join(terms) + ";" + lines.append("}") + return "\n".join(lines) + + def create_cpp_function(self, coeffs): + lines = ["#include ", "double polynomial(double x) {", " return "] + n = len(coeffs) + terms = [] + for i, c in enumerate(coeffs): + exp = n - i - 1 + if exp == 0: + terms.append(f"{c:.8g}") + elif exp == 1: + terms.append(f"{c:.8g}*x") + else: + terms.append(f"{c:.8g}*pow(x,{exp})") + lines[-1] += " + ".join(terms) + ";" + lines.append("}") + return "\n".join(lines) + + def create_py_function(self, coeffs): + n = len(coeffs) + lines = ["def polynomial(x):", " return "] + terms = [] + for i, c in enumerate(coeffs): + exp = n - i - 1 + if exp == 0: + terms.append(f"{c:.8g}") + elif exp == 1: + terms.append(f"{c:.8g}*x") + else: + terms.append(f"{c:.8g}*x**{exp}") + lines[-1] += " + ".join(terms) + return "\n".join(lines) + +if __name__ == "__main__": + root = tk.Tk() + app = PolyFitApp(root) + root.mainloop() \ No newline at end of file