1. Add CLI parser, 2. add python script for visualisation data

This commit is contained in:
Danila Gamkov 2025-01-29 18:04:02 +03:00
parent 2abb435f87
commit b94b2c623f
8 changed files with 453 additions and 68466 deletions

41
Cargo.lock generated
View File

@ -124,6 +124,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "769b0145982b4b48713e01ec42d61614425f27b7058bda7180a3a41f30104796"
dependencies = [
"clap_builder",
"clap_derive",
]
[[package]]
@ -138,6 +139,18 @@ dependencies = [
"strsim",
]
[[package]]
name = "clap_derive"
version = "4.5.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "54b755194d6389280185988721fffba69495eed5ee9feeee9a599b53db80318c"
dependencies = [
"heck",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "clap_lex"
version = "0.7.4"
@ -156,6 +169,12 @@ version = "0.8.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
[[package]]
name = "heck"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]]
name = "iana-time-zone"
version = "0.1.61"
@ -222,6 +241,17 @@ version = "2.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
[[package]]
name = "mvn_accomp_csv"
version = "0.1.0"
dependencies = [
"chrono",
"clap",
"lazy_static",
"regex",
"walkdir",
]
[[package]]
name = "num-traits"
version = "0.2.19"
@ -311,17 +341,6 @@ version = "0.9.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
[[package]]
name = "spinx_tm_sens"
version = "0.1.0"
dependencies = [
"chrono",
"clap",
"lazy_static",
"regex",
"walkdir",
]
[[package]]
name = "strsim"
version = "0.11.1"

View File

@ -1,11 +1,13 @@
[package]
name = "spinx_tm_sens"
name = "mvn_accomp_csv"
version = "0.1.0"
edition = "2021"
authors = ["Danila Gamkov <danila_gamkov@cosmos.ru>"]
description = "Raw accompanying MVN data parser. The parser reads T1MBH, T2MBH, T3MBH, T4MBH sensors data from files like MVN_010125_A-000.txt (see <sd> directory in science MVN data) and saves this data in csv-format files"
[dependencies]
chrono = "0.4"
clap = "4.*"
clap = { version = "4.*", features = ["derive"] }
lazy_static = {version = "1.5.0", features = ["spin_no_std"]}
regex = "1.7.0"
walkdir = "2.3.2"

100
README.markdown Normal file
View File

@ -0,0 +1,100 @@
# mvn_accomp_csv
Raw accompanying MVN data parser. The parser reads T1MBH, T2MBH, T3MBH, T4MBH sensors data from files like MVN_010125_A-000.txt (see <sd> directory in science MVN data) and saves this data in csv-format files
## Contents
- **Setup**
- **Using**
- parsing accompanying MVN data file
- parsing all accompanying MVN data files in specified directory and subdirectories
- plot data in python
- **Output mvn_accomp_csv data files description**
- **Contacts**
## Setup
1. Install Rust compiler (if you don't have).
Installation on Linux:
```
curl --proto '=https' --tlsv1.2 https://sh.rustup.rs -sSf | sh
```
Installation on Windows:
Go to address https://www.rust-lang.org/tools/install and follow instructions
For more detailed information you can go to: https://doc.rust-lang.ru/book/ch01-01-installation.html
**Instruction for setup mvn_accomp_csv project**
2. Clone the repo to your computer:
```
git clone http://heagit.cosmos.ru/gamkov/mvn_accomp_csv.git
```
3. Enter the repo and compile it:
```
cd <PATH_TO_MVN_ACCOMP_CSV>
cargo build --release
```
After running this commands you will get an execution file (mvn_accomp_csv) in the following directory:
\<PATH_TO_MVN_ACCOMP_CSV\>/target/release/
## Using
### Parsing accompanying MVN data file
1. Donwload data from science data server to directory \<PATH_TO_MVN_ACCOMPANY_DATA\>.
If you don't have MVN data, you might download it from server with science SRG data (IP: 193.232.11.95).
For questions about downloading science data contact Shtykovsky A. (a.shtykovsky@cosmos.ru) or Chelovekov I. (chelovekov@cosmos.ru)
2. Run program mvn_accomp_csv:
```
cd <PATH_TO_MVN_ACCOMP_CSV>/target/release/
./mvn_accomp_csv -f <PATH_TO_MVN_ACCOMPANY_DATA>/MVN_010125_A-000.txt
```
csv data are ready to use in directory:
\<PATH_TO_MVN_ACCOMP_CSV\>/target/release/
### Parsing all accompanying MVN data files in specified directory and subdirectories
1. Donwload data from science data server to directory \<PATH_TO_MVN_ACCOMPANY_DATA\>.
If you don't have MVN data, you might download it from server with science SRG data (IP: 193.232.11.95).
For questions about downloading science data contact Shtykovsky A. (a.shtykovsky@cosmos.ru) or Chelovekov I. (chelovekov@cosmos.ru)
2. Run program mvn_accomp_csv:
```
cd <PATH_TO_MVN_ACCOMP_CSV>/target/release/
./mvn_accomp_csv -d <PATH_TO_MVN_ACCOMPANY_DATA>
```
csv data are ready to use in directory:
\<PATH_TO_MVN_ACCOMP_CSV\>/target/release/
### Plot csv data in Python
If you want to plot csv data you might use \<PATH_TO_MVN_ACCOMP_CSV\>/data/**plot_flight_all.py** python-script directly for set different configurations.
## Output mvn_accomp_csv data files description
**description:**
MVN_data_T1MBH.csv - temperature data in channel T1MBH (in Celsius)
MVN_data_T2MBH.csv - temperature data in channel T2MBH (in Celsius)
MVN_data_T3MBH.csv - temperature data in channel T3MBH (in Celsius)
MVN_data_T4MBH.csv - temperature data in channel T4MBH (in Celsius)
**file data csv fromat:**
column 1: date
column 2: time
column 3 - temperature from sensor channel
## Contatcs
For questions about the program, please contact Danila Gamkov, mail: danila_gamkov@cosmos.ru
```
```
```
```
```
```
```
```
```
```
```
```
```
```

BIN
data/mvn_accomp_csv Executable file

Binary file not shown.

114
data/plot_flight_all.py Normal file
View File

@ -0,0 +1,114 @@
import matplotlib.pyplot as plt
from matplotlib import dates
import pandas as pd
from datetime import datetime
import sys
font = 10
print_width = 20
print_height = 12
width = 1
plot_windows = 1
channels = [1, 1, 1, 1]
path = '/home/danila/Danila/work/MVN/Soft/mvn_accomp_csv/data/'
fname = [path + 'MVN_data_T1MVN.csv',
path + 'MVN_data_T2MVN.csv',
path + 'MVN_data_T3MVN.csv',
path + 'MVN_data_T4MVN.csv']
pict_name = path + "T1_4MVN"
ox_dtime_format = '%d.%m.%Y %H:%M'
legend=['T1МВН', 'T2МВН', 'T3МВН', 'T4МВН']
ch_names=['T1MVN', 'T2MVN', 'T3MVN', 'T4MVN']
width=[1, 1, 1, 1]
marker = ['-', '-', '-', '-'];
width_arr = [1, 0.5, 0.2, 0.1]
dateparse = lambda x: datetime.strptime(x, "%d.%m.%Y %H:%M:%S.%f")
data = [pd.read_csv(fname[0], sep=';', parse_dates=['timestamp'], date_parser=dateparse),
pd.read_csv(fname[1], sep=';', parse_dates=['timestamp'], date_parser=dateparse),
pd.read_csv(fname[2], sep=';', parse_dates=['timestamp'], date_parser=dateparse),
pd.read_csv(fname[3], sep=';', parse_dates=['timestamp'], date_parser=dateparse)]
# data_dict = {"temp": ch, "pow": ch, "time": []}
# data_dict["time"] = data[0]['timestamp']
# col=['ch1', 'ch2', 'ch3', 'ch4', 'ch5', 'ch6', 'ch7']
# for j in range(2):
# for index, row, in data[j].iterrows():
# for i in range(6):
# ch[i].append(float(row[col[i]]))
# data_dict[ch_signs[j]] = ch
# ch= [[], [], [], [], [], []]
if plot_windows == 1:
fig, ax = plt.subplots(figsize=(print_width, print_height), dpi=200)
i = 0
for elem in data:
if channels[i] == 1:
plt.plot(elem['timestamp'], elem[ch_names[i]], marker[i], linewidth=width[i], label=legend[i])
i += 1
# ax.axvline(x = data['timestamp'][300], color='r', linestyle='-.', label="power=100")
# ax.axvline(x = data['timestamp'][1500], color='b', linestyle='dotted', label="power=0")
ax.tick_params(axis="both", width=1, labelsize=font)
ax.grid(visible=True, linestyle = 'dotted')
ax.set_ylabel('Температура, $^\circ$C', fontsize=font)
ax.set_xlabel('Время', fontsize=font)
ax.legend(fontsize=font)
date_formatter = dates.DateFormatter(ox_dtime_format)
ax.xaxis.set_major_formatter(date_formatter)
plt.tight_layout()
fig.savefig(pict_name)
plt.show()
sys.exit()
# elif plot_windows == 2:
# fig = plt.figure(figsize=(print_width, print_height), dpi=200)
# ax1 = fig.add_subplot(2, 1, 1)
# ax2 = fig.add_subplot(2, 1, 2, sharex=ax1)
# i = 0
# for elem in data_dict['temp']:
# if channels[i] == 1:
# ax1.plot(data_dict['time'][begin:end], elem[begin:end], marker[i], linewidth=width[i], label=legend[i])
# i += 1
# i = 0
# for elem in data_dict['pow']:
# if channels[i] == 1:
# ax2.plot(data_dict['time'][begin:end], elem[begin:end], marker[i], linewidth=width[i], label=legend[i])
# i += 1
# # ax1.axvline(x = data['timestamp'][300], color='r', linestyle='-.', label="power=100")
# # ax.axvline(x = data['timestamp'][1500], color='b', linestyle='dotted', label="power=0")
# ax1.tick_params(axis="both", width=1, labelsize=font)
# ax1.grid(visible=True, linestyle = 'dotted')
# ax1.set_ylabel('Температура, $^\circ$C', fontsize=font)
# ax1.set_xlabel('Время', fontsize=font)
# ax1.legend(fontsize=font)
# date_formatter = dates.DateFormatter('%d.%m.%Y %H')
# ax1.xaxis.set_major_formatter(date_formatter)
# ax2.tick_params(axis="both", width=1, labelsize=font)
# ax2.grid(visible=True, linestyle = 'dotted')
# ax2.set_ylabel('Мощность, %', fontsize=font)
# ax2.set_xlabel('Время', fontsize=font)
# ax2.legend(fontsize=font)
# date_formatter = dates.DateFormatter(ox_dtime_format)
# ax2.xaxis.set_major_formatter(date_formatter)
# plt.tight_layout()
# fig.savefig(pict_name)
# plt.show()

132
src/.vimrc Normal file
View File

@ -0,0 +1,132 @@
set tabstop=4
set softtabstop=4
set shiftwidth=4
set noexpandtab
set colorcolumn=90
highlight ColorColumnt ctermbg=darkgray
augroup project
autocmd!
autocmd BufRead,BufNewFile *.h,*.c set filetype=c.doxygen
augroup END
let &path.="src/include, src/source,"
" Включаем использование системного буфера
set clipboard=unnamedplus
" Работа с текстом
" Python использует 4 пробела для отступов
autocmd FileType python setlocal tabstop=4 shiftwidth=4
" Кодировка текста
set encoding=utf-8
set fileencoding=utf-8
set fileencodings=utf-8,cp1251,koi8-r,cp866
" Поиск по тексту
set hlsearch " подсвечивать результаты поиска
" Перемещение по тексту
" Когда достигаем границ строки, то перемещаемся на предыдующую/следующую
set whichwrap+=h,l,<,>,[,]
set number
" Настройки автодополнения
set completeopt=menu,menuone,noselect
" Разделение экрана
set splitbelow " разбивать вниз
set splitright " разбивать вправо
" сочетание клавиш
" Использование h, j, k, l для перемещения с зажатым Ctrl в режиме
" редактирования
inoremap <C-h> <Left>
inoremap <C-j> <Down>
inoremap <C-k> <Up>
inoremap <C-l> <Right>
let g:mapleader = "\<Space>"
" Переключение между вкладками
nnoremap <leader>t :tabnext<CR>
nnoremap <leader>T :tabprevious<CR>
" Список вкладок
nnoremap <leader>tl :tabs<CR>
" nnoremap <leader>tn :tabnew<CR>
nnoremap <leader>tc :tabclose<CR>
nnoremap <leader>to :tabonly<CR>
nnoremap <leader>tm :tabmove<CR>
" Редактировать файл в новой вкладке
nnoremap <leader>te :tabedit |
" Выбор вкладки
nnoremap <leader>1 1gt
nnoremap <leader>2 2gt
nnoremap <leader>3 3gt
nnoremap <leader>4 4gt
nnoremap <leader>5 5gt
nnoremap <leader>6 6gt
nnoremap <leader>7 7gt
nnoremap <leader>8 8gt
nnoremap <leader>9 9gt
nnoremap <leader>0 :tablast<CR>
" Разбиение окон
nnoremap <leader>s :split<CR>
nnoremap <leader>v :vsplit<CR>
" Выбор окна
nnoremap <C-h> <C-w>h
nnoremap <C-j> <C-w>j
nnoremap <C-k> <C-w>k
nnoremap <C-l> <C-w>l
" Размер окна
nnoremap <C-u> <C-w>+
nnoremap <C-d> <C-w>-
nnoremap <C-p> <C-w><
nnoremap <C-n> <C-w>>
" Vimspector
" nnoremap <leader><F2> <F10>
" nnoremap <leader>q <F11>
nmap <Leader><Right> <Plug>VimspectorStepOver
nmap <Leader><Down> <Plug>VimspectorStepInto
nmap <Leader><Up> <Plug>VimspectorStepOut
nmap <Leader><Tab> <Plug>VimspectorDisassemble
" Сделать окна одного размера
nnoremap <leader>= <C-w>=
" Переключения между буферами
" nnoremap <leader>b :bnext<CR>
" nnoremap <leader>B :bprevious<CR>
" nnoremap <leader>l :ls<CR>
" nnoremap <leader>d :bd<CR>
" " Скрыть/раскрыть блок кода
" nnoremap <leader>z za
" настройка плагинов
" настройки для отступов
" let g:indent_guides_enable_on_vim_startup = 1
" Настройки для разноцветной подсветки скобок
let g:rainbow_active = 1
" Настройки для vim-airline
let g:airline#extensions#tabline#enabled = 1
let g:airline#extensions#tabline#buffer_nr_show = 1
let g:airline#extensions#tabline#formatter = 'unique_tail'
let g:airline_powerline_fonts = 1
let g:airline_solarized_bg = 'luna'
let g:vimspector_enable_mappings = 'HUMAN'

68371
src/data.txt

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
use clap::{Arg, Command};
use clap::{Parser};
pub mod mvn_tm_temp {
use std::fs::File;
@ -44,12 +44,19 @@ pub mod mvn_tm_temp {
tm.push("T4MBH".to_string());
tm
};
pub static ref tm_idx_write: Vec<String> = {
let mut tm = Vec::new();
tm.push("T1MVN".to_string());
tm.push("T2MVN".to_string());
tm.push("T3MVN".to_string());
tm.push("T4MVN".to_string());
tm
};
}
pub fn parse_data_file(filename_full: &str,
save_data: bool,
disp_data: bool,
silent_mode: bool) -> Result<(), String> {
pub fn parse_data_file(filename_full: &str, disp: bool) -> Result<(), String> {
let filename = match filename_full.rfind('/') {
Some(idx) => filename_full[idx+1..filename_full.len()].to_string(),
_ => filename_full.to_string(),
@ -61,29 +68,24 @@ pub mod mvn_tm_temp {
read_data(filename_full, &mut tm_data_v)?;
sort_data(&mut tm_data_v);
if save_data == true {
for (i, &ref elem) in tm_data_v.iter().enumerate() {
let fname = filename.replace(".txt", &format!("_{}{}", tm_idx[i], ".csv"));
save_data_csv(&elem, &fname, disp_data)?;
if disp { disp_data(&tm_data_v)?; }
for (i, &ref elem) in tm_data_v.iter().enumerate() {
let fname = filename.replace(".txt", &format!("_{}{}", tm_idx_write[i], ".csv"));
save_data_csv(&elem, &fname, &tm_idx_write[i])?;
if silent_mode == false {
println!("save csv data to file {}", fname);
}
}
}
return Ok(());
}
pub fn parse_data_dir(dir: &str,
save_data: bool,
disp_data: bool,
silent_mode: bool) -> Result<(), String> {
pub fn parse_data_dir(dir: &str, disp: bool) -> Result<(), String> {
let mut tm_data_v: [Vec<TMtemp>; 4] =
[Vec::new(), Vec::new(), Vec::new(), Vec::new()];
if silent_mode == false {
println!("parsing data from directory: {} ...", dir);
}
println!("parsing data from directory: {}", dir);
let files = find_files_regex(dir, &pattern_fname)?;
for file in files {
@ -91,17 +93,14 @@ pub mod mvn_tm_temp {
}
sort_data(&mut tm_data_v);
if disp { disp_data(&tm_data_v)?; }
if save_data == true {
for (i, &ref elem) in tm_data_v.iter().enumerate() {
let fname = format!("MVN_data_{}{}", tm_idx[i], ".csv");
save_data_csv(&elem, &fname, disp_data)?;
let fname = format!("MVN_data_{}{}", tm_idx_write[i], ".csv");
save_data_csv(&elem, &fname, &tm_idx_write[i])?;
if silent_mode == false {
println!("save csv data to file {}", fname);
}
}
}
return Ok(());
}
@ -157,13 +156,11 @@ pub mod mvn_tm_temp {
},
};
let mut val: Vec<String> = Vec::new();
for (j, elem) in data_buf.iter().enumerate() {
for (i, idx) in tm_idx.clone().into_iter().enumerate() {
if elem.contains(&idx)
{
val = match elem.split_whitespace()
let val: Vec<String> = match elem.split_whitespace()
.map(|elem| elem.parse::<String>())
.collect() {
Ok(_line) => _line,
@ -208,16 +205,24 @@ pub mod mvn_tm_temp {
}
}
fn save_data_csv(data: &Vec<TMtemp>, fname: &str, disp_flag: bool) -> Result<(), String> {
fn disp_data(data: &[Vec<TMtemp>; 4]) -> Result<(), String> {
for (i, sens) in data.iter().enumerate() {
println!("{}\t{}", "timestamp", tm_idx_write[i]);
for elem in sens {
println!("{} {}\t{}", elem.date, elem.time, elem.val);
}
}
return Ok(());
}
fn save_data_csv(data: &Vec<TMtemp>, fname: &str, idx: &str) -> Result<(), String> {
let mut data_v: Vec<String> = Vec::new();
data_v.push(format!("{};{}", "timestamp", idx));
for elem in data {
let s = format!("{};{};{}", elem.date, elem.time, elem.val);
if disp_flag == true {
println!("{}", s);
}
data_v.push(s);
data_v.push(format!("{} {};{}", elem.date, elem.time, elem.val));
}
match std::fs::write(fname, data_v.join("\n")) {
@ -233,56 +238,42 @@ pub mod mvn_tm_temp {
}
#[derive(Parser, Debug)]
#[command(version, author, about, long_about = None)]
struct Cli {
/// file with accompanying MVN data
#[arg(long, short = 'f', value_name = "FILE_DATA")]
filename: Option<String>,
/// directory with accompanying MVN data
#[arg(long, short = 'd', value_name = "DIRECTORY_DATA")]
directory: Option<String>,
/// show data in console
#[arg(short = 's')]
show: bool,
}
fn main() {
use crate::mvn_tm_temp::*;
let arguments = Command::new("mvn_accomp_csv")
.version("0.1.0")
.author("Danila Gamkov <danila_gamkov@cosmos.ru>")
.about("raw accompanying MVN data parser")
.arg(
Arg::new("file")
.short('f')
.long("filename")
.help(format!("file with accompanying MVN data ({})", pattern_fname.to_string()))
let cli = Cli::parse();
let show = cli.show;
)
.arg(
Arg::new("dir")
.short('d')
.long("directory")
.help(format!("directory with accompanying MVN data"))
)
.get_matches();
match arguments.get_one::<String>("file") {
Some(fname) => {
match parse_data_file(&fname.clone(), true, true, false) {
if let Some(fname) = &cli.filename {
match parse_data_file(&fname.clone(), show) {
Ok(elem) => elem,
Err(msg) => { println!("{}", msg); return; }
}
return;
},
_ => { }
}
};
match arguments.get_one::<String>("dir") {
Some(path) => {
match parse_data_dir(path, true, true, false) {
Ok(_) => {}
if let Some(dir) = &cli.directory {
match parse_data_dir(&dir.clone(), show) {
Ok(elem) => elem,
Err(msg) => { println!("{}", msg); return; }
}
return;
},
_ => { }
}
println!("Unexpected command. Type --help for more iformation");