first commit
This commit is contained in:
5
.gitignore
vendored
5
.gitignore
vendored
@@ -1,3 +1,6 @@
|
||||
/build
|
||||
/dist
|
||||
.GCRAS_logo_rus_curves.ico
|
||||
GCRAS_logo_rus_curves.ico
|
||||
/data
|
||||
/.idea
|
||||
/.git
|
||||
|
||||
8
about.md
Normal file
8
about.md
Normal 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
48
functions.py
Normal 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
166
main.py
Normal 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
39
main.spec
Normal 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
42
prog.py
Normal 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
2
requirements.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
pandas==1.3.5
|
||||
pyinstaller==6.20
|
||||
Reference in New Issue
Block a user