|
@@ -3,6 +3,7 @@ package crontab
|
|
|
import (
|
|
|
"fmt"
|
|
|
"kpt-pasture/model"
|
|
|
+ "kpt-pasture/util"
|
|
|
"math"
|
|
|
"time"
|
|
|
|
|
@@ -41,11 +42,17 @@ func (e *Entry) EntryUpdateActiveHabit(pastureId int64) (err error) {
|
|
|
if err != nil {
|
|
|
return xerr.WithStack(err)
|
|
|
}
|
|
|
+
|
|
|
+ // 未配置的滤波数据不参与计算
|
|
|
+ if xToday == nil {
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+
|
|
|
var processIds []int64
|
|
|
// 更新活动滤波
|
|
|
processIds, err = e.FirstFilterUpdate(pastureId, xToday)
|
|
|
if err != nil {
|
|
|
- zaplog.Error("NeckRingCalculate", zap.Any("FirstFilterUpdate", err), zap.Any("xToday", xToday))
|
|
|
+ zaplog.Error("NeckRingCalculate", zap.Any("pastureId", pastureId), zap.Any("FirstFilterUpdate", err), zap.Any("xToday", xToday))
|
|
|
}
|
|
|
|
|
|
zaplog.Info("NeckRingCalculate", zap.Any("xToday", xToday), zap.Any("processIds", processIds))
|
|
@@ -56,7 +63,7 @@ func (e *Entry) EntryUpdateActiveHabit(pastureId int64) (err error) {
|
|
|
e.WeeklyUpdateActiveHabit(pastureId, processIds, xToday)
|
|
|
|
|
|
// 二次更新滤波
|
|
|
- e.SecondUpdateChangeFilter(pastureId, xToday)
|
|
|
+ e.SecondUpdateChangeFilter(pastureId, processIds, xToday)
|
|
|
|
|
|
// 活动量校正系数和健康评分
|
|
|
e.FilterCorrectAndScoreUpdate(pastureId, processIds, xToday)
|
|
@@ -80,16 +87,18 @@ func (e *Entry) EntryUpdateActiveHabit(pastureId int64) (err error) {
|
|
|
|
|
|
// FirstFilterUpdate 首次更新活动滤波
|
|
|
func (e *Entry) FirstFilterUpdate(pastureId int64, xToDay *XToday) (processIds []int64, err error) {
|
|
|
+ limit := e.Cfg.NeckRingLimit
|
|
|
+ if limit <= 0 {
|
|
|
+ limit = defaultLimit
|
|
|
+ }
|
|
|
newNeckActiveHabitList := make([]*model.NeckActiveHabit, 0)
|
|
|
if err = e.DB.Model(new(model.NeckActiveHabit)).
|
|
|
- Where("heat_date >= ?", "2025-03-01").
|
|
|
+ Where("heat_date >= ?", time.Now().AddDate(0, 0, -1).Format(model.LayoutDate2)).
|
|
|
Where("pasture_id = ?", pastureId).
|
|
|
Where("is_show = ?", pasturePb.IsShow_No).
|
|
|
- //Where("record_count = ?", model.DefaultRecordCount).
|
|
|
Where(e.DB.Where("high >= ?", xToDay.High).Or("rumina >= ?", xToDay.Rumina)).
|
|
|
- Where("cow_id > ?", 0).
|
|
|
Order("heat_date,neck_ring_number,frameid").
|
|
|
- Limit(int(defaultLimit)).
|
|
|
+ Limit(int(limit)).
|
|
|
Find(&newNeckActiveHabitList).Error; err != nil {
|
|
|
return nil, xerr.WithStack(err)
|
|
|
}
|
|
@@ -110,8 +119,8 @@ func (e *Entry) FirstFilterUpdate(pastureId int64, xToDay *XToday) (processIds [
|
|
|
}
|
|
|
|
|
|
// 8小时数据不全的不参与滤波
|
|
|
- activeTime, _ := time.Parse(model.LayoutTime, v.ActiveTime)
|
|
|
- if v.RecordCount != model.DefaultRecordCount && activeTime.Sub(time.Now()).Hours() < 8 {
|
|
|
+ activeTime, _ := util.TimeParseLocal(model.LayoutTime, v.ActiveTime)
|
|
|
+ if v.RecordCount != model.DefaultRecordCount && time.Now().Sub(activeTime).Hours() < 8 {
|
|
|
continue
|
|
|
}
|
|
|
|
|
@@ -119,7 +128,7 @@ func (e *Entry) FirstFilterUpdate(pastureId int64, xToDay *XToday) (processIds [
|
|
|
heatDate := v.HeatDate
|
|
|
if v.Frameid == 0 {
|
|
|
frameId = 11
|
|
|
- heatDateParse, _ := time.Parse(model.LayoutDate2, heatDate)
|
|
|
+ heatDateParse, _ := util.TimeParseLocal(model.LayoutDate2, heatDate)
|
|
|
heatDate = heatDateParse.AddDate(0, 0, -1).Format(model.LayoutDate2)
|
|
|
} else {
|
|
|
frameId -= 1
|
|
@@ -182,17 +191,15 @@ func (e *Entry) FirstFilterUpdate(pastureId int64, xToDay *XToday) (processIds [
|
|
|
}
|
|
|
|
|
|
// SecondUpdateChangeFilter 第二次更新变化趋势滤波
|
|
|
-func (e *Entry) SecondUpdateChangeFilter(pastureId int64, xToday *XToday) {
|
|
|
+func (e *Entry) SecondUpdateChangeFilter(pastureId int64, processIds []int64, xToday *XToday) {
|
|
|
newChangeFilterList := make([]*ChangeFilterData, 0)
|
|
|
if err := e.DB.Model(new(model.NeckActiveHabit)).
|
|
|
- Select("id", "neck_ring_number", "change_high", "change_filter", "rumina_filter", "change_rumina",
|
|
|
- "chew_filter", "change_chew", "heat_date", "frameid", "IF(lact = 0, 0.8, 1) as xlc_dis_count").
|
|
|
- Where("heat_date >= ?", time.Now().AddDate(0, 0, -2).Format(model.LayoutDate2)).
|
|
|
+ Select("id", "neck_ring_number", "change_high", "change_filter", "rumina_filter", "change_rumina", "chew_filter", "change_chew", "heat_date", "frameid", "IF(lact = 0, 0.8, 1) as xlc_dis_count").
|
|
|
Where("pasture_id = ?", pastureId).
|
|
|
+ Where("id IN (?)", processIds).
|
|
|
Where("change_filter = ?", model.InitChangeFilter).
|
|
|
Where("change_high > ?", MinChangeHigh).
|
|
|
Order("neck_ring_number,heat_date,frameid").
|
|
|
- Limit(int(defaultLimit)).
|
|
|
Find(&newChangeFilterList).Error; err != nil {
|
|
|
zaplog.Error("SecondUpdateChangeFilter", zap.Any("error", err), zap.Any("xToday", xToday))
|
|
|
return
|
|
@@ -203,63 +210,52 @@ func (e *Entry) SecondUpdateChangeFilter(pastureId int64, xToday *XToday) {
|
|
|
heatDate := v.HeatDate
|
|
|
if v.FrameId == 0 {
|
|
|
frameId = 11
|
|
|
- heatDateParse, _ := time.Parse(model.LayoutDate2, heatDate)
|
|
|
+ heatDateParse, _ := util.TimeParseLocal(model.LayoutDate2, heatDate)
|
|
|
heatDate = heatDateParse.AddDate(0, 0, -1).Format(model.LayoutDate2)
|
|
|
} else {
|
|
|
frameId -= 1
|
|
|
}
|
|
|
|
|
|
+ xChangeDiscount := float64(xToday.XChangeDiscount) / 10
|
|
|
+ xRuminaDisc := float64(xToday.XRuminaDisc) / 10
|
|
|
secondFilterData := e.FindFilterData(pastureId, v.NeckRingNumber, heatDate, frameId)
|
|
|
- if v.ChangeFilter > MinChangeFilter {
|
|
|
- secondFilterData.ChangeFilter = v.ChangeFilter
|
|
|
- } else {
|
|
|
- if v.NeckRingNumber == secondFilterData.NeckRingNumber {
|
|
|
- changeFilter := float64(secondFilterData.ChangeFilter)*(1-(float64(xToday.XChangeDiscount)/10)*v.XlcDisCount) +
|
|
|
- math.Min(float64(v.ChangeHigh), float64(secondFilterData.ChangeFilter)+135)*(float64(xToday.XChangeDiscount)/10)*v.XlcDisCount
|
|
|
- secondFilterData.ChangeFilter = int32(changeFilter)
|
|
|
- } else {
|
|
|
- secondFilterData.ChangeFilter = 0
|
|
|
- }
|
|
|
+ if secondFilterData.ChangeFilter <= MinChangeFilter {
|
|
|
+ secondFilterData.ChangeFilter = 0
|
|
|
}
|
|
|
|
|
|
- if v.RuminaFilter > MinRuminaFilter {
|
|
|
- secondFilterData.RuminaFilter = v.ChangeFilter
|
|
|
- } else {
|
|
|
- if v.NeckRingNumber == secondFilterData.NeckRingNumber {
|
|
|
- discount := float64(xToday.XRuminaDisc) / 10 * v.XlcDisCount
|
|
|
- if math.Abs(float64(v.ChangeRumina)) > 60 {
|
|
|
- discount *= 0.5
|
|
|
- }
|
|
|
- secondFilterData.RuminaFilter = int32(float64(secondFilterData.RuminaFilter)*(1-discount) + float64(v.ChangeRumina)*discount)
|
|
|
- } else {
|
|
|
- secondFilterData.RuminaFilter = 0
|
|
|
- }
|
|
|
+ if secondFilterData.RuminaFilter <= MinRuminaFilter {
|
|
|
+ secondFilterData.RuminaFilter = 0
|
|
|
}
|
|
|
|
|
|
- secondFilterData.RuminaFilter = int32(math.Min(50, float64(secondFilterData.RuminaFilter)))
|
|
|
+ if secondFilterData.ChewFilter <= MinChewFilter {
|
|
|
+ secondFilterData.ChewFilter = 0
|
|
|
+ }
|
|
|
|
|
|
- if v.ChewFilter > MinChewFilter {
|
|
|
- secondFilterData.ChewFilter = v.ChangeChew
|
|
|
- } else {
|
|
|
- if v.NeckRingNumber == secondFilterData.NeckRingNumber {
|
|
|
- discount := float64(xToday.XRuminaDisc) / 10
|
|
|
- if math.Abs(float64(v.ChangeChew)) > 60 {
|
|
|
- discount *= 0.5
|
|
|
- }
|
|
|
- secondFilterData.ChewFilter = int32(float64(secondFilterData.ChewFilter)*(1-discount) + float64(v.ChangeChew)*discount)
|
|
|
- } else {
|
|
|
- secondFilterData.ChewFilter = 0
|
|
|
- }
|
|
|
+ changeFilter := float64(v.ChangeFilter)
|
|
|
+ if v.ChangeFilter <= MinChangeFilter {
|
|
|
+ changeFilter = float64(secondFilterData.ChangeFilter)*(1-xChangeDiscount*v.XlcDisCount) + math.Min(float64(v.ChangeHigh), float64(secondFilterData.ChangeFilter)+135)*xChangeDiscount*v.XlcDisCount
|
|
|
+ }
|
|
|
+
|
|
|
+ ruminaFilter := float64(v.RuminaFilter)
|
|
|
+ discount := xRuminaDisc * v.XlcDisCount
|
|
|
+ if math.Abs(float64(v.ChangeRumina)) > 60 {
|
|
|
+ discount *= 0.5
|
|
|
}
|
|
|
+ ruminaFilter = float64(secondFilterData.RuminaFilter)*(1-discount) + float64(v.ChangeRumina)*discount
|
|
|
|
|
|
- secondFilterData.ChewFilter = int32(math.Min(50, float64(secondFilterData.ChewFilter)))
|
|
|
+ chewFilter := float64(v.ChewFilter)
|
|
|
+ chewFilterDiscount := float64(1)
|
|
|
+ if math.Abs(float64(v.ChangeChew)) > 60 {
|
|
|
+ chewFilterDiscount = 0.5
|
|
|
+ }
|
|
|
+ chewFilter = float64(secondFilterData.ChewFilter)*(1-xRuminaDisc*chewFilterDiscount) + float64(v.ChangeChew)*xRuminaDisc*chewFilterDiscount
|
|
|
if err := e.DB.Model(new(model.NeckActiveHabit)).
|
|
|
Select("change_filter", "rumina_filter", "chew_filter").
|
|
|
Where("id = ?", v.Id).
|
|
|
Updates(map[string]interface{}{
|
|
|
- "change_filter": secondFilterData.ChangeFilter,
|
|
|
- "rumina_filter": secondFilterData.RuminaFilter,
|
|
|
- "chew_filter": secondFilterData.ChewFilter,
|
|
|
+ "change_filter": int32(changeFilter),
|
|
|
+ "rumina_filter": int32(math.Min(50, ruminaFilter)),
|
|
|
+ "chew_filter": int32(math.Min(50, chewFilter)),
|
|
|
}).Error; err != nil {
|
|
|
zaplog.Error("SecondUpdateChangeFilter", zap.Any("error", err), zap.Any("secondFilterData", secondFilterData))
|
|
|
}
|
|
@@ -291,7 +287,7 @@ func (e *Entry) FilterCorrectAndScoreUpdate(pastureId int64, processIds []int64,
|
|
|
Where(e.DB.Where("high > ?", xToday.High).Or("rumina >= ?", xToday.Rumina)).
|
|
|
Where("active_time <= ?", beginDayDate.Add(-12*time.Hour).Format(model.LayoutTime)).
|
|
|
Where("change_filter > ?", MinChangeFilter).
|
|
|
- Where("neck_ring_number = ?").
|
|
|
+ Where("neck_ring_number = ?", v.NeckRingNumber).
|
|
|
Having("nb > ?", DefaultNb).
|
|
|
First(&activityVolume).Error; err != nil {
|
|
|
zaplog.Error("ActivityVolumeChanges-0", zap.Any("error", err), zap.Any("xToday", xToday))
|
|
@@ -349,43 +345,33 @@ func (e *Entry) UpdateFilterCorrect(pastureId int64, processIds []int64) {
|
|
|
|
|
|
// UpdateChangeAdJust 更新群体校正数据
|
|
|
func (e *Entry) UpdateChangeAdJust(pastureId int64, xToday *XToday) {
|
|
|
- /*-- 插入群体校正表
|
|
|
- INSERT INTO data_bar_change(heatdate, frameid, intCurBar, intCurBarName, nb, highchange, changefilter)
|
|
|
- SELECT h.heatdate, h.frameid, c.intCurBar, c.intCurBarName, COUNT(*) nb, ROUND(AVG(h.highchange)) highchange, ROUND(AVG(h.changefilter) ) changefilter
|
|
|
- FROM h_activehabit h JOIN cow c ON h.intCowId=c.intCowId
|
|
|
- WHERE h.heatdate>=(CURDATE() -INTERVAL 1 DAY )
|
|
|
- GROUP BY h.heatdate, h.frameid, c.intCurBar
|
|
|
- ORDER BY h.heatdate, h.frameid, c.intCurBarName
|
|
|
- ON DUPLICATE KEY UPDATE nb = VALUES(nb), highchange = VALUES(highchange), changefilter = VALUES(changefilter);
|
|
|
-
|
|
|
- UPDATE h_activehabit h
|
|
|
- JOIN cow c ON h.intCowId=c.intCowId
|
|
|
- JOIN data_bar_change cg ON h.heatdate=cg.heatdate AND h.frameid=cg.frameid AND c.intCurBar=cg.intCurBar
|
|
|
- SET h.changeadjust=cg.changefilter
|
|
|
- WHERE h.id>xBeg_update_act_Id AND h.heatdate>=CURRENT_DATE() - INTERVAL 1 DAY AND ABS(cg.changefilter)>=10;
|
|
|
- */
|
|
|
res := make([]*model.NeckRingBarChange, 0)
|
|
|
oneDayAgo := time.Now().AddDate(0, 0, -1).Format(model.LayoutDate2)
|
|
|
if err := e.DB.Table(fmt.Sprintf("%s as h", new(model.NeckActiveHabit).TableName())).
|
|
|
- Select("h.neck_ring_number,h.heat_date, h.frameid, c.pen_id, c.pen_name, COUNT(*) as nb, ROUND(AVG(h.change_high)) as change_high, ROUND(AVG(h.change_filter)) as change_filter").
|
|
|
+ Select(`h.neck_ring_number,h.heat_date, h.frameid, c.pen_id, c.pen_name, COUNT(*) as nb,
|
|
|
+ ROUND(AVG(h.change_high)) as change_high, ROUND(AVG(h.change_filter)) as change_filter`).
|
|
|
Joins("JOIN cow as c ON h.neck_ring_number = c.neck_ring_number").
|
|
|
Where("h.pasture_id = ?", pastureId).
|
|
|
Where("h.heat_date >= ?", oneDayAgo).
|
|
|
+ Where("h.is_show = ?", pasturePb.IsShow_Ok).
|
|
|
Where("h.cow_id >= ?", 0).
|
|
|
+ Where("c.pen_id > ?", 0).
|
|
|
Group("h.heat_date, h.frameid, c.pen_id").
|
|
|
- Order("h.heat_date, h.frameid, c.pen_name").
|
|
|
+ Order("h.heat_date, h.frameid, c.pen_id").
|
|
|
Find(&res).Error; err != nil {
|
|
|
zaplog.Error("UpdateChangeAdJust", zap.Any("error", err), zap.Any("xToday", xToday))
|
|
|
}
|
|
|
|
|
|
- // todo ABS(cg.changefilter)>=10;
|
|
|
for _, v := range res {
|
|
|
+ if math.Abs(float64(v.ChangeFilter)) < 10 {
|
|
|
+ continue
|
|
|
+ }
|
|
|
if err := e.DB.Model(new(model.NeckActiveHabit)).
|
|
|
- Where("id > ?", xToday.LastMaxHabitId).
|
|
|
+ Where("pasture_id = ?", pastureId).
|
|
|
+ Where("neck_ring_number = ?", v.NeckRingNumber).
|
|
|
Where("heat_date = ?", v.HeatDate).
|
|
|
Where("frameid = ?", v.FrameId).
|
|
|
- Where("neck_ring_number = ?", v.NeckRingNumber).
|
|
|
- Update("change_adjust", v.ChangeHigh).Error; err != nil {
|
|
|
+ Update("change_adjust", v.ChangeFilter).Error; err != nil {
|
|
|
zaplog.Error("UpdateChangeAdJust-1", zap.Any("error", err), zap.Any("xToday", xToday))
|
|
|
}
|
|
|
}
|
|
@@ -406,6 +392,11 @@ func (e *Entry) XToday(pastureId int64) (*XToday, error) {
|
|
|
if err != nil {
|
|
|
return nil, xerr.WithStack(err)
|
|
|
}
|
|
|
+
|
|
|
+ if len(systemConfigureList) <= 0 {
|
|
|
+ return nil, nil
|
|
|
+ }
|
|
|
+
|
|
|
for _, v := range systemConfigureList {
|
|
|
switch v.Name {
|
|
|
case model.MaxHabit:
|
|
@@ -499,6 +490,7 @@ func (e *Entry) SumUpdateActiveHabit(pastureId int64, newNeckActiveHabitList []*
|
|
|
func (e *Entry) ActiveChange(pastureId int64, processIds []int64, xToDay *XToday) {
|
|
|
newNeckActiveHabitList := make([]*model.NeckActiveHabit, 0)
|
|
|
if err := e.DB.Model(new(model.NeckActiveHabit)).
|
|
|
+ Where("pasture_id = ?", pastureId).
|
|
|
Where("id IN (?)", processIds).
|
|
|
Where("high_habit > ?", 0).
|
|
|
Where(e.DB.Where("high >= ?", xToDay.High).Or("rumina >= ?", xToDay.Rumina)).
|
|
@@ -507,20 +499,16 @@ func (e *Entry) ActiveChange(pastureId int64, processIds []int64, xToDay *XToday
|
|
|
}
|
|
|
|
|
|
for _, v := range newNeckActiveHabitList {
|
|
|
- highDiff := v.FilterHigh - v.HighHabit
|
|
|
- denominator := float64(v.WeekHigh)*0.6 + float64(v.HighHabit)*0.2 + float64(xToDay.WeeklyActive)*0.2
|
|
|
- if highDiff > 0 {
|
|
|
- v.ChangeHigh = int32(math.Round((float64(highDiff) / denominator / float64(v.HighHabit)) * 100))
|
|
|
- } else {
|
|
|
- v.ChangeHigh = int32(math.Round(float64(highDiff) / float64(v.HighHabit) * 100))
|
|
|
- }
|
|
|
+ changeHigh := calculateChangeHigh(v, xToDay.WeeklyActive)
|
|
|
+ changeRumina := int32(0)
|
|
|
+ changeChew := int32(0)
|
|
|
|
|
|
if v.RuminaHabit != 0 {
|
|
|
- v.ChangeRumina = int32(math.Round(float64(v.FilterRumina-v.RuminaHabit) / float64(v.RuminaHabit) * 100))
|
|
|
+ changeRumina = int32(math.Round(float64(v.FilterRumina-v.RuminaHabit) / float64(v.RuminaHabit) * 100))
|
|
|
}
|
|
|
|
|
|
if v.ChewHabit != 0 {
|
|
|
- v.ChangeChew = int32(math.Round(float64(v.FilterChew-v.ChewHabit) / float64(v.ChewHabit) * 100))
|
|
|
+ changeChew = int32(math.Round(float64(v.FilterChew-v.ChewHabit) / float64(v.ChewHabit) * 100))
|
|
|
}
|
|
|
|
|
|
// 更新过滤值
|
|
@@ -528,14 +516,13 @@ func (e *Entry) ActiveChange(pastureId int64, processIds []int64, xToDay *XToday
|
|
|
Select("change_high", "change_rumina", "change_chew").
|
|
|
Where("id = ?", v.Id).
|
|
|
Updates(map[string]interface{}{
|
|
|
- "change_high": v.ChangeHigh,
|
|
|
- "change_rumina": v.ChangeRumina,
|
|
|
- "change_chew": v.ChangeChew,
|
|
|
+ "change_high": changeHigh,
|
|
|
+ "change_rumina": changeRumina,
|
|
|
+ "change_chew": changeChew,
|
|
|
}).Error; err != nil {
|
|
|
- zaplog.Error("WeeklyUpdateActiveHabit",
|
|
|
- zap.Error(err),
|
|
|
+ zaplog.Error("ActiveChange",
|
|
|
+ zap.Any("err", err),
|
|
|
zap.Any("NeckActiveHabit", v),
|
|
|
- zap.Any("pastureId", pastureId),
|
|
|
)
|
|
|
}
|
|
|
}
|
|
@@ -571,3 +558,16 @@ func (e *Entry) Before3DaysNeckActiveHabit(pastureId int64, processIds []int64)
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+// calculateChangeHigh 计算活动量变化
|
|
|
+func calculateChangeHigh(data *model.NeckActiveHabit, weeklyActive int32) int32 {
|
|
|
+ highDiff := data.FilterHigh - data.HighHabit
|
|
|
+ changeHigh := int32(0)
|
|
|
+ if highDiff > 0 {
|
|
|
+ denominator := float64(data.WeekHigh)*0.6 + float64(data.HighHabit)*0.2 + float64(weeklyActive)*0.2
|
|
|
+ changeHigh = int32(math.Round((float64(highDiff) / denominator) * 100))
|
|
|
+ } else {
|
|
|
+ changeHigh = int32(math.Round(float64(highDiff) / float64(data.HighHabit) * 100))
|
|
|
+ }
|
|
|
+ return changeHigh
|
|
|
+}
|