#include <string>
#include <memory>
#include <cmath>
+#include <vector>
+#include <queue>
+#include <iostream>
+#include <unordered_map>
#define GILROY_REGULAR_FONT "./font_library/gilroy-regular-3.ttf"
#define GILROY_BOLD_FONT "./font_library/gilroy-bold-4.ttf"
Exercisetype sportType; // 训练类型(0:健身类 1:跳舞类 2:休闲运动 3:球类 4:水上运动:5:冰上运动:6:极限运动:7:其他)
UIResourceTextId sportId; // 训练Id
ExerciseTag sportTagType; // 训练目标类型(0: 距离 1:时长 2:卡路里 3:步数)
- int apc; //平均配速
- int fpc; //最快配速
- int spc; //最慢配速
- int cdc; //步频
- int std; //步幅
+ int apc; // 平均配速
+ int fpc; // 最快配速
+ int spc; // 最慢配速
+ int cdc; // 步频
+ int std; // 步幅
void Initialize()
{
heart = 0;
avgheart = 0;
tag = 0;
- start_date = nullptr;
- start_time = nullptr;
- end_time = nullptr;
+ start_date = "";
+ start_time = "";
+ end_time = "";
sportType = Exercisetype::FITNESS;
sportId = UIResourceTextId::STR_EXTREME_SPORTS;
sportTagType = ExerciseTag::UNKNOW;
+ apc = 0;
+ fpc = 0;
+ spc = 0;
+ cdc = 0;
+ std = 0;
}
void Reset()
void SetSportdata(SportData *data);
/*获取运动卡路里*/
int GetCal();
- /*设置时间戳*/
- void SetTimestamp();
/*解析时间戳*/
std::string AnalysisTimestamp(uint64_t timestamp);
/*获取运动总时长*/
/*平均心率计算*/
int CalculateAverageHeartRate(int newHeartRate);
+ /*显示心率计算*/
+ int CalculateFilteredHeartRate(int newHeartRate);
/*保存训练记录到json文件*/
bool CheckDataJson();
/*获取训练类Id*/
UIResourceTextId GetSportTypeId(Exercisetype type);
+ /*重新初始化训练配置*/
+ void ResetSharedTrainingData();
+ /*设置训练开始与结束*/
+ void SetTimestamp();
+ /*设置开始时间*/
+ void SetStartDateTime();
+ /*设置结束时间*/
+ void SetEndTime();
+ /*获取日期*/
+ bool GetFormattedDate(std::string &dateOutput, const char *errorMsg);
+ /*获取时间*/
+ bool GetFormattedTime(std::string &timeOutput, const char *errorMsg);
+ /*保存数据*/
+ void RecordSportData();
+
private:
TraingModel(const TraingModel &) = delete;
TraingModel &operator=(const TraingModel &) = delete;
ExerciseTag sportTagType_ = ExerciseTag::UNKNOW; // 训练目标类型
int sportTag_ = 0; // 训练目标
- int totalHeartRate = 0;
- int countHeartRate = 0;
- int freq = 0; // 训练发送数据频率
+ int freq = 0; // 训练发送数据频率
bool Gettagstuats{false}; // 训练达标标志位
bool Startstate{false}; // 开始训练标志位
bool MomentumFlag{false}; // 训练量达标标志位
bool Openstate{false}; // 运动是否开始
+ std::vector<int> heartRateData; // 存储所有心率数据
+ std::vector<int> recentHeartRates; // 显示心率
+ std::unordered_map<int, int> delayed; // 延迟删除的心率值
+ std::priority_queue<int> maxHeap; // 最大堆,存储最大心率值
+ std::priority_queue<int, std::vector<int>, std::greater<int>> minHeap; // 最小堆,存储最小心率值
+ int totalHeartRate; // 总心率
+ int countHeartRate; // 心率计数
+ const int windowSize = 5; // 移动平均窗口大小
+
/*std::unique_ptr<SportData> sportdata;*/ // 使用 std::unique_ptr 管理 SportData 对象
};
}
#include <list>
#include "samgr_lite.h"
#include <vector>
+#include <queue>
+#include <numeric>
#include "traingrecord/include/TraingRecordModel.h"
#define MAX_FILE_PATH_LENGTH 128
{
return sportState_;
}
+ // 计算平均心率的函数
+ double CalculateAverageHeartRate(const std::vector<int> &heartRates)
+ {
+ if (heartRates.size() <= 2)
+ {
+ // 如果心率数据点少于等于2,无法去掉最高和最低值
+ return 0.0; // 或者返回心率的平均值
+ }
+
+ // 创建一个副本以避免修改原始数据
+ std::vector<int> sortedHeartRates = heartRates;
+
+ // 排序
+ std::sort(sortedHeartRates.begin(), sortedHeartRates.end());
+
+ // 去掉一个最高值和一个最低值
+ sortedHeartRates.erase(sortedHeartRates.begin()); // 去掉最低值
+ sortedHeartRates.pop_back(); // 去掉最高值
+
+ // 计算剩余心率的平均值
+ double sum = 0;
+ for (int rate : sortedHeartRates)
+ {
+ sum += rate;
+ }
+
+ return sum / sortedHeartRates.size(); // 返回平均值
+ }
/*分析数据*/
void TraingModel::AnalysisData(cywee_activity_result_t *cyweeInfo)
{
sportdata->std = cyweeInfo->step_length;
sportdata->pc = cyweeInfo->pace;
sportdata->distance = cyweeInfo->distance;
-
+ /*最慢配速*/
if (sportdata->spc < sportdata->pc)
{
sportdata->spc = sportdata->pc;
}
-
- sportdata->heart = cyweeInfo->hrs;
- SetIntensity(sportdata->heart); // 设置训练强度
- if (sportdata->heart > 50)
+ if (cyweeInfo->hrs > 50)
{
+ sportdata->heart = CalculateFilteredHeartRate(cyweeInfo->hrs); // 处理显示心率
sportdata->avgheart = CalculateAverageHeartRate(cyweeInfo->hrs); // 处理正常的平均心率
+ SetIntensity(sportdata->heart); // 设置训练强度
+ }
+ else
+ {
+ sportdata->heart = cyweeInfo->hrs;
}
// 达到最高心率进行心率提醒弹窗
if (sportdata->heart >= ConfigModel::GetInstance()->get_configData_int(ConfigModel::CONFIGMODEL_ITEM_TRAINING_HEART_MAX))
{
return sportdata->sportTagType;
}
- /*设置时间*/
+ /*重置训练配置*/
+ void TraingModel::ResetSharedTrainingData()
+ {
+ sportdata->Reset(); // 重置结构体
+ heartRateData.clear(); // 清空心率数据
+ recentHeartRates.clear();
+ delayed.clear(); // 重置 delayed 字典
+
+ while (!maxHeap.empty())
+ { // 清空最大堆
+ maxHeap.pop();
+ }
+ while (!minHeap.empty())
+ { // 清空最小堆
+ minHeap.pop();
+ }
+
+ totalHeartRate = 0;
+ countHeartRate = 0;
+
+ Gettagstuats = false; // 重置训练达标标志位
+ Openstate = true; // 开启运动开始标志位
+ }
+
+ /*设置运动开始与结束*/
void TraingModel::SetTimestamp()
{
uint32_t time;
WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Failed to get timestamp");
return;
}
+
ExerciseState currentState = GetSportState(); // 获取当前运动状态
- /*增加标志位互斥保障"开始""结束"的唯一性操作*/
- if (currentState == ExerciseState::Start && (!Startstate))
+
+ // 增加标志位互斥保障"开始"和"结束"的唯一性操作
+ if (currentState == ExerciseState::Start && !Startstate)
{
- sportdata->Reset(); // 重置结构体
+ ResetSharedTrainingData(); // 重置共享训练数据
- /*将Model的成员变量赋值到结构体里面*/
printf("SetTimestamp::time:%u \r\n", time);
sportdata->starttime = time;
sportdata->sportType = sportType_; // 训练类型
- Gettagstuats = false; // 重置训练达标标志位
- Openstate = true; // 开启运动开始标志位
- if (sportTag_) // 有值才设置[训练目标]
+
+ if (sportTag_) // 有值才设置[训练目标]
{
sportdata->sportTagType = sportTagType_;
sportdata->tag = sportTag_;
(Openingway == true) ? (printf("app发起运动\n")) : (printf("手表发起运动\n"));
- char *start_date = (char *)malloc(9 * sizeof(char)); // 分配内存给start_date
- if (uapi_get_YYMMDD_Time(start_date, '/') != ERRCODE_SUCC)
- {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Failed to get start date");
- free(start_date); // 释放内存
- return;
- }
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "start_date[%s]\r\n", start_date);
- sportdata->start_date = std::string(start_date);
- free(start_date); // 释放内存
-
- char *start_time = (char *)malloc(9 * sizeof(char)); // 分配内存给start_time
- if (uapi_get_HHMMSS_Time(start_time, ':', true) != ERRCODE_SUCC)
- {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Failed to get start time");
- free(start_time); // 释放内存
- return;
- }
- sportdata->start_time = std::string(start_time);
- free(start_time); // 释放内存
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "sportdata->start_time [%s]\r\n", (sportdata->start_time).c_str());
+ // 设置起始日期和时间
+ SetStartDateTime();
Startstate = true;
Endstate = false; // 确保"开始"和"结束"状态互斥
- printf("开始运动\r\n");
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "开始运动");
}
- else if (currentState == ExerciseState::End && (!Endstate))
+ else if (currentState == ExerciseState::End && !Endstate)
{
sportdata->endtime = time;
- char *end_time = (char *)malloc(9 * sizeof(char)); // 分配内存给end_time
- if (uapi_get_HHMMSS_Time(end_time, ':', true) != ERRCODE_SUCC)
- {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Failed to get end time");
- free(end_time); // 释放内存
- return;
- }
- // WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"end_time [%s]\r\n", end_time);
- sportdata->end_time = std::string(end_time);
+ SetEndTime();
+
sportState_ = ExerciseState::General;
Openstate = false; // 关闭运动标志位
- free(end_time); // 释放内存
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "sportdata->end_time [%s]\r\n", (sportdata->end_time).c_str());
+ // 记录运动数据
+ RecordSportData();
+
+ Startstate = false;
+ Endstate = true;
+
+ // 重置训练目标 [发生在训练前]
+ sportTag_ = 0;
+ sportTagType_ = ExerciseTag::UNKNOW;
+
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "结束运动");
+ }
+ }
+ /*设置开始时间*/
+ void TraingModel::SetStartDateTime()
+ {
+ std::string startDate, startTime;
+
+ if (!GetFormattedDate(startDate, "Failed to get start date"))
+ return;
+ if (!GetFormattedTime(startTime, "Failed to get start time"))
+ return;
+
+ sportdata->start_date = startDate;
+ sportdata->start_time = startTime;
+
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "sportdata->start_time [%s]\r\n", sportdata->start_time.c_str());
+ }
+ /*设置结束时间*/
+ void TraingModel::SetEndTime()
+ {
+ std::string endTime;
+
+ if (GetFormattedTime(endTime, "Failed to get end time"))
+ {
+ sportdata->end_time = endTime;
+ }
+
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "sportdata->end_time [%s]\r\n", sportdata->end_time.c_str());
+ }
+ /*获取日期字符串*/
+ bool TraingModel::GetFormattedDate(std::string &dateOutput, const char *errorMsg)
+ {
+ char *date = (char *)malloc(9 * sizeof(char)); // 分配内存给start_date
+ if (uapi_get_YYMMDD_Time(date, '/') != ERRCODE_SUCC)
+ {
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "%s", errorMsg);
+ free(date);
+ return false;
+ }
+ dateOutput = std::string(date);
+ free(date); // 释放内存
+ return true;
+ }
+ /*获取时间字符串*/
+ bool TraingModel::GetFormattedTime(std::string &timeOutput, const char *errorMsg)
+ {
+ char *time = (char *)malloc(9 * sizeof(char)); // 分配内存给start_time
+ if (uapi_get_HHMMSS_Time(time, ':', true) != ERRCODE_SUCC)
+ {
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "%s", errorMsg);
+ free(time);
+ return false;
+ }
+ timeOutput = std::string(time);
+ free(time); // 释放内存
+ return true;
+ }
+ /*保存数据*/
+ void TraingModel::RecordSportData()
+ {
#if READTEST
- if (SaveSportData() == false)
+ if (SaveSportData() == false)
+ {
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "SaveSportData error!");
+ }
+#else
+ if (MomentumFlag)
+ {
+ GetGoaldegree(); // 设置目标完成度
+ if (SaveSportData())
{
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "SaveSportData error!");
+ TraingRecordModel::GetInstance().SetJsonStatus(true);
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "SaveSportData ok!");
}
-#else
- /*存储正常数据[运动量达标]*/
- if (MomentumFlag)
+ else
{
- GetGoaldegree(); // 设置目标完成度
- if (SaveSportData())
- {
- TraingRecordModel::GetInstance().SetJsonStatus(true);
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "SaveSportData ok!");
- }
- else
- {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "SaveSportData error!");
- }
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "SaveSportData error!");
}
-#endif
- Startstate = false;
- Endstate = true;
-
- printf("结束运动\r\n");
}
+#endif
}
// 获取训练时长时间
std::string TraingModel::GetTrainingTime()
return ss.str();
}
- /*处理平均心率*/
int TraingModel::CalculateAverageHeartRate(int newHeartRate)
{
- totalHeartRate += newHeartRate; // 累加心率值
- countHeartRate++; // 记录心率值的个数
+ // 将新的心率添加到数据列表
+ heartRateData.push_back(newHeartRate);
+ totalHeartRate += newHeartRate;
+ countHeartRate++;
+
+ // 将新的心率插入到堆中
+ maxHeap.push(newHeartRate);
+ minHeap.push(newHeartRate);
+
+ // 如果超过窗口大小,移除最早的心率
+ if (heartRateData.size() > windowSize)
+ {
+ int oldestRate = heartRateData[0];
+ totalHeartRate -= oldestRate;
+ countHeartRate--;
+
+ // 将老旧值从列表中移除
+ heartRateData.erase(heartRateData.begin());
- int averageHeartRate = totalHeartRate / countHeartRate; // 计算平均心率
- return averageHeartRate;
+ // 标记老旧值为待删除
+ delayed[oldestRate]++;
+ }
+
+ // 清理堆中的老旧值
+ while (!maxHeap.empty() && delayed[maxHeap.top()] > 0)
+ {
+ delayed[maxHeap.top()]--;
+ maxHeap.pop();
+ }
+
+ while (!minHeap.empty() && delayed[minHeap.top()] > 0)
+ {
+ delayed[minHeap.top()]--;
+ minHeap.pop();
+ }
+
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "新心率: %d, 当前心率总和: %d, 心率计数: %d",
+ newHeartRate, totalHeartRate, countHeartRate);
+
+ // 如果心率数量少于 3,直接返回当前的平均值
+ if (countHeartRate < 3)
+ {
+ return totalHeartRate / countHeartRate; // 无法去除最大最小值
+ }
+
+ // 取出当前未被删除的最大和最小的心率
+ int maxRate = maxHeap.top();
+ int minRate = minHeap.top();
+
+ // 进行去极值后的平均计算
+ int average = (totalHeartRate - maxRate - minRate) / (countHeartRate - 2);
+
+ // 打印计算结果
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "去极值后的平均心率: %d (去掉最大值: %d, 去掉最小值: %d)",
+ average, maxRate, minRate);
+
+ return average;
}
- /*设置训练目标类型以及训练目标*/
+ // 显示心率
+ int TraingModel::CalculateFilteredHeartRate(int newHeartRate)
+ {
+ // 将新的心率添加到最近心率列表
+ recentHeartRates.push_back(newHeartRate);
+
+ // 如果超过窗口大小,移除最早的心率
+ if (recentHeartRates.size() > windowSize)
+ {
+ recentHeartRates.erase(recentHeartRates.begin());
+ }
+
+ // 计算当前窗口中的平均心率
+ int total = std::accumulate(recentHeartRates.begin(), recentHeartRates.end(), 0);
+
+ // 打印当前窗口的平均心率
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "过滤后当前窗口的平均心率: %d",
+ (total / recentHeartRates.size()));
+
+ return total / recentHeartRates.size(); // 返回计算后的平均值
+ }
+
+ // 设置训练目标类型以及训练目标
void TraingModel::SetSportTag(ExerciseTag tagtpye, int tag)
{
WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "tagtpye[%d] tag[%d]", tagtpye, tag);
*/
int age = ConfigModel::GetInstance()->GetUserAge();
int maxHeartRate = MAX_HEART_RATE - age;
- double intensityPercentage = (heart / (double)maxHeartRate) * 100;
+
+ // 确保最大心率为正值
+ if (maxHeartRate <= 0)
+ {
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "maxHeartRate %d is error", maxHeartRate);
+ return;
+ }
+
+ // 将 heart 转换为 double 以避免整数除法
+ double heartRateAsDouble = static_cast<double>(heart);
+ double intensityPercentage = (heartRateAsDouble / (double)maxHeartRate) * 100;
+
if (intensityPercentage < LOW_INTENSITY_THRESHOLD)
{
// 较低强度
}
int TraingModel::GetSportTagData()
{
- if (sportTag_)
+ if (sportdata->tag)
{
// 根据设置的训练目标类型去对应相对的数据
switch (sportdata->sportTagType)