first commit

This commit is contained in:
2026-05-26 16:26:04 +03:00
parent c94a6b6884
commit da329d6272
7 changed files with 309 additions and 1 deletions

5
.gitignore vendored
View File

@@ -1,3 +1,6 @@
/build
/dist
.GCRAS_logo_rus_curves.ico
GCRAS_logo_rus_curves.ico
/data
/.idea
/.git

8
about.md Normal file
View File

@@ -0,0 +1,8 @@
# GSM-19 (.g file)
| | time | lon | lat | magnetic field | gradient |
|:--------------:|:---------:|:-----------------------------------------------------------:|:-----------------------------------------------------------:|:--------------:|:--------:|
| <b>units</b> | HHMMSS.ss | DDMMmmmmm | DDMMmmmmm | nT | nT / m |
| <b>comment</b> | | D - degrees, <br/> M - minutes, <br/> m - decimal minutes | D - degrees, <br/> M - minutes, <br/> m - decimal minutes | | |

48
functions.py Normal file
View File

@@ -0,0 +1,48 @@
def convert_deg(x):
x = str(x)
if x != "0":
return int(x[0:2]) + ( int( x[2:4] ) + int( x[4:] ) / 100000) / 60
return x
def time_to_seconds(time):
# Разделяем на целую и дробную часть
time_str = str(time)
if '.' in time_str:
main, frac = time_str.split('.')
frac_seconds = float(f'0.{frac}')
else:
main = time_str
frac_seconds = 0.0
# Дополняем до 6 цифр (добавляем ведущий ноль если нужно)
main = main.zfill(6)
hours = int(main[0:2])
minutes = int(main[2:4])
seconds = int(main[4:6])
return hours * 3600 + minutes * 60 + seconds + frac_seconds
def datetime_to_seconds(time_str):
"""
Преобразует время в формате HH:MM:SS.sss в секунды от полуночи
Пример: '14:40:00.000' -> 52800.0
"""
# Разделяем на основное время и миллисекунды
if '.' in time_str:
hms, ms = time_str.split('.')
milliseconds = int(ms)
else:
hms = time_str
milliseconds = 0
# Парсим часы, минуты, секунды
parts = hms.split(':')
hours = int(parts[0])
minutes = int(parts[1])
seconds = int(parts[2]) if len(parts) > 2 else 0
return hours * 3600 + minutes * 60 + seconds + milliseconds / 1000

166
main.py Normal file
View File

@@ -0,0 +1,166 @@
import tkinter as tk
from tkinter import filedialog, messagebox
import os
from prog import calculate_anomaly
# Меню выбора файла GSM-19, устанавливает пусть к файлу в окошко
def select_gsm_file(entry_var):
filetypes = (
("Файлы GSM-19", "*.g"),
("Все файлы", "*.*")
)
filename = filedialog.askopenfilename(
title="Выберите файл градиентометра",
filetypes=filetypes
)
if filename:
entry_var.set(filename)
status_label.config(text=f"Выбран файл: {os.path.basename(filename)}", fg="blue")
# Меню выбора файла базовой станции, устанавливает пусть к файлу в окошко
def select_base_file(entry_var):
filetypes = (
("Текстовые файлы", "*.txt"),
("Все файлы", "*.*")
)
filename = filedialog.askopenfilename(
title="Выберите файл базовой станции",
filetypes=filetypes
)
if filename:
entry_var.set(filename)
status_label.config(text=f"Выбран файл: {os.path.basename(filename)}", fg="blue")
# Обработка введенных файлов
def process_files():
"""Основная функция обработки файлов"""
# Получаем пути к файлам
gsm_file = file1_path.get()
base_file = file2_path.get()
# Проверяем, что оба файла выбраны
if not gsm_file or not base_file:
messagebox.showwarning("Внимание", "Пожалуйста, выберите оба файла!")
return
# Проверяем, что файлы существуют
if not os.path.exists(gsm_file):
messagebox.showerror("Ошибка", f"Файл не найден:\n{gsm_file}")
return
if not os.path.exists(base_file):
messagebox.showerror("Ошибка", f"Файл не найден:\n{base_file}")
return
#
try:
# Вызываем логику обработки
result = calculate_anomaly(gsm_file, base_file)
result.to_csv("result.csv", index=False)
# Показываем результат
messagebox.showinfo("Успех", f"Обработка завершена!")
status_label.config(text="Обработка завершена успешно", fg="green")
except Exception as e:
messagebox.showerror("Ошибка", f"Произошла ошибка при обработке:\n{str(e)}")
status_label.config(text="Ошибка при обработке", fg="red")
finally:
# Возвращаем интерфейс в исходное состояние
process_btn.config(state="normal", text="Обработать")
# Создаём главное окно
root = tk.Tk()
root.title("Обработчик файлов")
root.geometry("550x210")
root.resizable(False, False)
# Переменные для хранения путей к файлам
file1_path = tk.StringVar()
file2_path = tk.StringVar()
# === Рамка для первого файла ===
frame1 = tk.Frame(root)
frame1.pack(pady=20, padx=20, fill="x")
# Надпись "Файл градиентометра"
tk.Label(
frame1, # В каком окне
text="Файл градиентометра:", # Текст надписи
width=20, # Ширина
anchor="w" # Выравнивание надписи слева по центру
) \
.pack(side="left") # Прижим к левому краю
# Окошко ввода для градиентометра
entry1 = tk.Entry(
frame1, # В каком окне
textvariable=file1_path, # Надпись внутри окошка
width=50 # Ширина окошка
)
entry1.pack(
side="left", # Выравнивание слева
padx=5 # Отступ по горизонтали
)
# Кнопка для выбора файла для окошка
tk.Button(
frame1, # В каком окне
text="Обзор", # Текст кнопки
command=lambda: select_gsm_file( # Команда по нажатию
file1_path
)
) \
.pack(side="left") # Выравнивание по левому краю
# === Рамка для второго файла ===
frame2 = tk.Frame(root)
frame2.pack(pady=10, padx=20, fill="x")
tk.Label(
frame2,
text="Файл базовой станции:",
width=20,
anchor="w"
) \
.pack(side="left")
entry2 = tk.Entry(
frame2,
textvariable=file2_path,
width=50
)
entry2.pack(
side="left",
padx=5
)
tk.Button(
frame2,
text="Обзор",
command=lambda: select_base_file(
file2_path
)
) \
.pack(side="left")
# === Кнопка обработки ===
process_btn = tk.Button(
root,
text="Обработать",
command=process_files,
padx=20,
pady=5
)
process_btn.pack(pady=20)
# === Статусная строка ===
status_label = tk.Label(root, text="Готов к работе", fg="gray")
status_label.pack(pady=5)
# Запускаем приложение
root.mainloop()

39
main.spec Normal file
View File

@@ -0,0 +1,39 @@
# -*- mode: python ; coding: utf-8 -*-
a = Analysis(
['main.py'],
pathex=['functions.py', 'prog.py'],
binaries=[],
datas=[],
hiddenimports=[],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
noarchive=False,
optimize=0,
)
pyz = PYZ(a.pure)
exe = EXE(
pyz,
a.scripts,
a.binaries,
a.datas,
[],
name='gradientometr',
icon='GCRAS_logo_rus_curves.ico',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=False,
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
)

42
prog.py Normal file
View File

@@ -0,0 +1,42 @@
import pandas as pd
from functions import *
def calculate_anomaly(gsm_file, base_file):
df_gsm = pd.read_csv(
gsm_file,
delimiter=" ",
skiprows=1,
names=["time", "lon", "lat", "f", "grad", "_", "quality"]
)
df_gsm["lon"] = df_gsm["lon"].apply(convert_deg)
df_gsm["lat"] = df_gsm["lat"].apply(convert_deg)
df_gsm["time"] = df_gsm["time"].apply(time_to_seconds)
df_gsm = df_gsm[["time", "lon", "lat", "f", "grad", "quality"]]
df_gsm["time"] = df_gsm["time"].apply(round).astype(float)
df_base = pd.read_csv(
base_file,
sep=r"\s+",
skiprows=22,
names=["date", "time", "doy", "x", "y", "z", "f"]
)
df_base = df_base[df_base["f"] < 88000]
df_base["time"] = df_base["time"].apply(datetime_to_seconds)
result_df = pd.merge_asof(
df_gsm,
df_base[['time', 'f']], # берем только нужные колонки
left_on='time',
right_on='time',
direction='nearest',
suffixes=('_grad', '_base')
)
result_df["delta_f"] = result_df["f_grad"] - result_df["f_base"]
result_df = result_df[["lon", "lat", "time", "f_grad", "delta_f", "grad"]]
result_df = result_df.rename(columns={"f_grad": "f", "grad": "grad_f"})
return result_df

2
requirements.txt Normal file
View File

@@ -0,0 +1,2 @@
pandas==1.3.5
pyinstaller==6.20