This commit is contained in:
che
2026-07-13 11:17:57 +05:00
parent e3490e5d2e
commit 6fff682f74
18 changed files with 411 additions and 453 deletions
+15 -8
View File
@@ -1,13 +1,20 @@
package analize
import "gorm.io/gorm"
import (
"time"
"gorm.io/gorm"
)
type Analize struct {
gorm.Model
Name string `json:"name"`
CaseID uint `json:"case_id"`
CaseName string `json:"case_name"`
PsiMax float64 `json:"psi_max"`
PsiLMax float64 `json:"psi_l_max"`
Omega float64 `json:"omega"`
ID uint `gorm:"primaryKey" json:"id"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
DeletedAt gorm.DeletedAt `gorm:"index" json:"deleted_at,omitempty"`
Name string `json:"name"`
CaseID uint `json:"case_id"`
CaseName string `json:"case_name"`
PsiMax float64 `json:"psi_max"`
PsiLMax float64 `json:"psi_l_max"`
Omega float64 `json:"omega"`
}
+8 -158
View File
@@ -1,17 +1,12 @@
package analize
import (
"encoding/csv"
"errors"
"fmt"
"math"
"os"
"strconv"
"strings"
"time"
"control/control_case"
"gonum.org/v1/gonum/dsp/fourier"
"control/series"
"gorm.io/gorm"
)
@@ -40,81 +35,27 @@ func RunAnalyzeWorker(db *gorm.DB) {
}
func AnalyzeCSV(db *gorm.DB, caseID uint, caseName, csvPath string) (*Analize, error) {
file, err := os.Open(csvPath)
data, err := series.ReadCSV(csvPath)
if err != nil {
return nil, err
}
defer file.Close()
reader := csv.NewReader(file)
records, err := reader.ReadAll()
if err != nil {
return nil, err
}
if len(records) < 2 {
if len(data.Rows) == 0 {
return nil, fmt.Errorf("csv has no data rows")
}
headers := make(map[string]int, len(records[0]))
for i, header := range records[0] {
headers[strings.ToLower(strings.TrimSpace(header))] = i
}
getIndex := func(name string) (int, error) {
idx, ok := headers[strings.ToLower(name)]
if !ok {
return -1, fmt.Errorf("missing column %q", name)
}
return idx, nil
}
tIndex, err := getIndex("t")
columns, err := data.NumericColumns("t", "psi_m", "psi_l")
if err != nil {
return nil, err
}
psiMIndex, err := getIndex("psi_m")
if err != nil {
return nil, err
}
psiLIndex, err := getIndex("psi_l")
if err != nil {
return nil, err
}
times := make([]float64, 0, len(records)-1)
psiM := make([]float64, 0, len(records)-1)
psiL := make([]float64, 0, len(records)-1)
for _, record := range records[1:] {
if len(record) <= maxInt(tIndex, psiMIndex, psiLIndex) {
continue
}
t, err := parseFloat(record[tIndex])
if err != nil {
continue
}
m, err := parseFloat(record[psiMIndex])
if err != nil {
continue
}
l, err := parseFloat(record[psiLIndex])
if err != nil {
continue
}
times = append(times, t)
psiM = append(psiM, m)
psiL = append(psiL, l)
}
times, psiM, psiL := columns[0], columns[1], columns[2]
if len(psiL) == 0 {
return nil, fmt.Errorf("no numeric rows found in csv")
}
psiMax := maxFloat(psiM)
psiLMax := maxFloat(psiL)
omega := mainAngularFrequency(times, psiL)
psiMax := series.MaxLastHalf(psiM)
psiLMax := series.MaxLastHalf(psiL)
omega := series.MainAngularFrequency(times, psiL)
result := &Analize{
Name: fmt.Sprintf("analysis-%d", caseID),
@@ -143,94 +84,3 @@ func AnalyzeCSV(db *gorm.DB, caseID uint, caseName, csvPath string) (*Analize, e
}
return result, nil
}
func parseFloat(value string) (float64, error) {
return strconv.ParseFloat(strings.TrimSpace(value), 64)
}
func maxInt(values ...int) int {
max := 0
for _, v := range values {
if v > max {
max = v
}
}
return max
}
func maxFloat(values []float64) float64 {
if len(values) == 0 {
return 0
}
max := values[len(values)-1]
for _, v := range values[len(values):] {
if v > max {
max = v
}
}
return max
}
func mainAngularFrequency(times, values []float64) float64 {
if len(values) < 2 || len(times) < 2 {
return 0
}
dt := averageDelta(times)
if dt <= 0 {
return 0
}
centered := make([]float64, len(values))
mean := 0.0
for _, v := range values {
mean += v
}
mean /= float64(len(values))
for i, v := range values {
centered[i] = v - mean
}
fft := fourier.NewFFT(len(centered))
coeffs := fft.Coefficients(nil, centered)
if len(coeffs) < 2 {
return 0
}
bestIndex := 1
bestAmp := 0.0
for i := 1; i < len(coeffs); i++ {
amp := absComplex(coeffs[i])
if amp > bestAmp {
bestAmp = amp
bestIndex = i
}
}
frequencyHz := fft.Freq(bestIndex) / dt
return 2 * math.Pi * frequencyHz
}
func absComplex(v complex128) float64 {
return math.Hypot(real(v), imag(v))
}
func averageDelta(times []float64) float64 {
if len(times) < 2 {
return 0
}
total := 0.0
count := 0
for i := 1; i < len(times); i++ {
delta := times[i] - times[i-1]
if delta <= 0 {
continue
}
total += delta
count++
}
if count == 0 {
return 0
}
return total / float64(count)
}