news 2026/9/15 0:31:14

基于加速度传感器与MySQL状态机的睡眠阶段检测小程序

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于加速度传感器与MySQL状态机的睡眠阶段检测小程序

简介:这是一套面向计算机专业本科生的毕业设计级微信小程序实战项目,聚焦睡眠健康管理场景,提供从需求分析、前后端开发到部署上线的完整技术闭环。资源包含基于uniapp或原生小程序框架开发的前端代码、Java/PHP后端服务及MySQL 5.7+数据库设计,覆盖助眠音乐控制、睡眠数据可视化记录、睡眠知识问答与个人信息管理四大核心模块,并配套开题报告、设计文档与答辩PPT等学术材料。压缩包共110个文件,含53张界面截图(png)、14个逻辑脚本(js)、13个配置文件(json)、11个样式文件(wxss)及10个页面结构文件(wxml),辅以2份Word文档、2段教学视频(mp4)和1个动态加载动画(gif),整体大小14.63MB。目前已有169人学习下载,读者可直接导入HBuilder X或微信开发者工具运行调试,快速掌握小程序+MySQL全栈开发流程与毕业论文撰写规范。

1. 睡眠检测小程序不是健康数据看板,而是闭环行为干预系统

很多开发者拿到「睡眠检测小程序」这个标题,第一反应是做个带时间选择器和打卡按钮的静态页面,再连个 MySQL 存几条“23:05 入睡”“07:18 起床”。但真实场景里,用户凌晨两点点开小程序,看到“今日睡眠质量:差(深度睡眠仅1.2h)”,下一秒就切出微信刷短视频——数据没触发任何动作,检测就失去了意义。这个毕业设计源码包的价值,恰恰在于它用最小可行结构实现了「感知→反馈→引导」闭环:前端通过手机加速度传感器粗粒度识别体动频次(非医疗级,但符合学生项目边界),后端用 MySQL 建模睡眠阶段过渡规律(比如连续10分钟低频体动+心率区间匹配=浅睡期),再通过小程序模板消息推送轻量干预建议(“您昨晚浅睡偏多,今晚可尝试睡前1小时关闭蓝光屏幕”)。它面向的是能独立部署、理解数据流向、并能基于业务逻辑调整阈值参数的 IT 类毕业生,不是只懂拖拽生成器的零基础学员。


2. 用 wx.getAccelerometer 获取体动特征,而非调用未授权的健康平台API

小程序无法直接读取手机内置的睡眠监测芯片(如华为 TruSleep、苹果 HealthKit),但可通过wx.getAccelerometerAPI 以 50ms 频率采集加速度三轴原始数据。毕业设计源码中采用滑动窗口法处理该数据流,这是兼顾性能与有效性的常见做法。

2.1 加速度数据采集与本地降噪

小程序端在用户点击“开始检测”后启动监听:

// pages/sleep/start.js Page({ data: { isMonitoring: false, rawData: [] }, startMonitor() { const that = this; wx.startAccelerometer({ interval: 'game', // 最高采样频率,约50ms/次 success: () => { that.setData({ isMonitoring: true }); wx.onAccelerometerChange((res) => { // 只保留z轴(垂直方向)数据,人体平躺时z轴变化最敏感 const zValue = Math.abs(res.z); // 滑动窗口:保留最近200个点(约10秒),超长则截断 const newRaw = [...that.data.rawData.slice(-199), zValue]; that.setData({ rawData: newRaw }); }); } }); } });

提示:interval: 'game'是关键参数,'ui''normal'模式下采样间隔过长(200ms+),无法捕捉翻身等短时体动;但需注意wx.onAccelerometerChange在后台会被系统暂停,因此必须要求用户保持小程序前台运行。

2.2 服务端用 MySQL 计算体动活跃度指标

前端每30秒将rawData数组通过 POST 发送至/api/sleep/upload接口,后端(Node.js + Express)解析后存入 MySQL 表sleep_raw_data

CREATE TABLE `sleep_raw_data` ( `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, `user_id` VARCHAR(32) NOT NULL COMMENT '微信openid', `session_id` VARCHAR(64) NOT NULL COMMENT '本次检测会话唯一标识', `timestamp` DATETIME DEFAULT CURRENT_TIMESTAMP, `z_values` JSON NOT NULL COMMENT 'JSON数组,存储30秒内所有z轴绝对值', PRIMARY KEY (`id`), INDEX `idx_user_session` (`user_id`, `session_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

注意:z_values字段使用 JSON 类型,而非拆成多行记录,是因为学生项目需控制表数量与查询复杂度;实际生产环境应拆为子表并建时间分区。

服务端计算逻辑(简化版):

// routes/sleep.js app.post('/api/sleep/upload', async (req, res) => { const { userId, sessionId, zValues } = req.body; // 计算30秒内“显著体动次数”:z值 > 0.3g 的连续段数量(过滤微小抖动) const threshold = 0.3; let movementCount = 0; let inMovement = false; for (let i = 0; i < zValues.length; i++) { if (zValues[i] > threshold && !inMovement) { movementCount++; inMovement = true; } else if (zValues[i] <= threshold) { inMovement = false; } } // 插入汇总指标到 sleep_summary 表 await db.query( 'INSERT INTO sleep_summary (user_id, session_id, timestamp, movement_count) VALUES (?, ?, NOW(), ?)', [userId, sessionId, movementCount] ); res.json({ code: 0 }); });

movement_count就是后续判断“入睡潜伏期”“夜间觉醒次数”的核心输入。MySQL 中不进行实时复杂计算,只做轻量聚合,符合学生项目对数据库能力的合理预期。


3. MySQL 设计睡眠阶段状态机,用触发器自动标记阶段跃迁

单纯存储“每30秒体动次数”无法反映睡眠结构。毕业设计源码通过在 MySQL 中构建有限状态机(FSM),将连续时间段映射为“清醒→浅睡→深睡→REM”的粗略阶段,这是比纯前端判断更可靠的方案——状态持久化后,可回溯任意时刻状态,支撑“历史睡眠报告”功能。

3.1 状态定义与状态转移规则

sleep_stage_log表中定义四类状态及跃迁条件:

状态码名称触发条件(基于前3分钟 movement_count 均值)持续时间要求
0清醒> 8 次/分钟
1浅睡3~8 次/分钟≥ 5 分钟
2深睡≤ 2 次/分钟≥ 10 分钟
3REM体动频次回升但低于清醒阈值(4~6次/分钟)+ 心率区间匹配≥ 3 分钟

注意:心率数据在本项目中由用户手动录入(模拟),实际可接入微信运动接口(需用户授权),但毕业设计未强制依赖外部API,降低部署门槛。

3.2 用 MySQL 触发器实现状态自动更新

当新记录插入sleep_summary表时,触发器检查最近数据流并更新当前会话的最新状态:

DELIMITER $$ CREATE TRIGGER update_sleep_stage AFTER INSERT ON sleep_summary FOR EACH ROW BEGIN DECLARE avg_mov DECIMAL(5,2); DECLARE last_stage TINYINT; DECLARE current_time DATETIME; SET current_time = NEW.timestamp; -- 计算前3分钟平均体动次数(单位:次/分钟) SELECT IFNULL(AVG(movement_count) * 2, 0) INTO avg_mov FROM sleep_summary WHERE session_id = NEW.session_id AND timestamp BETWEEN DATE_SUB(current_time, INTERVAL 3 MINUTE) AND current_time; -- 获取当前会话最新状态 SELECT COALESCE(stage_code, 0) INTO last_stage FROM sleep_stage_log WHERE session_id = NEW.session_id ORDER BY timestamp DESC LIMIT 1; -- 状态跃迁逻辑(简化版) IF avg_mov > 8 THEN IF last_stage != 0 THEN INSERT INTO sleep_stage_log (session_id, stage_code, start_time, end_time) VALUES (NEW.session_id, 0, current_time, NULL); END IF; ELSEIF avg_mov BETWEEN 3 AND 8 THEN IF last_stage != 1 THEN -- 结束上一状态 UPDATE sleep_stage_log SET end_time = current_time WHERE session_id = NEW.session_id AND end_time IS NULL; -- 开启新状态 INSERT INTO sleep_stage_log (session_id, stage_code, start_time, end_time) VALUES (NEW.session_id, 1, current_time, NULL); END IF; END IF; END$$ DELIMITER ;

该触发器不处理深睡/REM 的完整判定(需结合心率),但已覆盖主要跃迁路径。学生可在此基础上扩展heart_rate字段和更精细条件,而无需改动应用层代码。

3.3 查询某次会话的完整睡眠阶段序列

前端请求/api/sleep/report?sessionId=xxx时,后端执行:

SELECT stage_code, TIME_FORMAT(TIMEDIFF(end_time, start_time), '%H:%i:%s') AS duration, COUNT(*) AS segment_count FROM sleep_stage_log WHERE session_id = 'xxx' AND end_time IS NOT NULL GROUP BY stage_code ORDER BY MIN(start_time);

返回结果直接用于绘制睡眠周期图(如 ECharts 柱状堆叠图),避免前端做状态拼接。


4. 前后端分离下的 token 安全传递与会话绑定策略

小程序用户身份由微信code换取openid后确立,但毕业设计源码中未使用 JWT 或 Redis Session,而是采用 MySQL 表user_session实现轻量会话管理——这既满足毕业设计对“可读性”和“无额外中间件依赖”的要求,又规避了wx.login过期导致的频繁重登问题。

4.1 登录流程:code 换 openid 后写入会话表

小程序端获取code后提交至后端:

// utils/login.js export async function login() { const { code } = await wx.login(); const res = await wx.request({ url: 'https://your-domain.com/api/auth/login', method: 'POST', data: { code } }); if (res.data.token) { wx.setStorageSync('auth_token', res.data.token); // 本地缓存 } }

后端(Node.js)处理:

// routes/auth.js app.post('/api/auth/login', async (req, res) => { const { code } = req.body; // 调用微信接口换取 openid(需配置 appid & secret) const wxRes = await axios.get( `https://api.weixin.qq.com/sns/jscode2session?appid=${APPID}&secret=${SECRET}&js_code=${code}&grant_type=authorization_code` ); const { openid, session_key } = wxRes.data; // 生成32位随机token(非JWT,无签名,仅作会话索引) const token = crypto.randomBytes(16).toString('hex'); // 写入 user_session 表,有效期24小时 await db.query( 'INSERT INTO user_session (token, openid, expires_at) VALUES (?, ?, DATE_ADD(NOW(), INTERVAL 24 HOUR))', [token, openid, null] ); res.json({ token }); });

对应 MySQL 表结构:

CREATE TABLE `user_session` ( `id` INT UNSIGNED NOT NULL AUTO_INCREMENT, `token` CHAR(32) NOT NULL UNIQUE, `openid` VARCHAR(64) NOT NULL, `expires_at` DATETIME NOT NULL, `created_at` DATETIME DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), INDEX `idx_openid_expire` (`openid`, `expires_at`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

4.2 接口鉴权:每次请求校验 token 有效性

所有受保护接口(如/api/sleep/upload)前置中间件:

function authMiddleware(req, res, next) { const token = req.headers.authorization?.replace('Bearer ', ''); if (!token) return res.status(401).json({ code: 401, msg: 'Missing token' }); db.query( 'SELECT openid FROM user_session WHERE token = ? AND expires_at > NOW()', [token], (err, results) => { if (err || results.length === 0) { return res.status(401).json({ code: 401, msg: 'Invalid or expired token' }); } req.userOpenid = results[0].openid; next(); } ); }

提示:此方案不依赖 Redis,所有状态落盘 MySQL,适合学生部署在单台 CentOS 7.9 服务器(如阿里云 ECS);但需注意user_session表定期清理,可在 crontab 中添加:

# 每日凌晨2点删除过期会话 0 2 * * * mysql -u root -p'password' your_db -e "DELETE FROM user_session WHERE expires_at < NOW();"

5. 说明文档(LW)不是操作手册,而是部署决策日志

毕业设计中的“说明文档(LW)”常被误解为功能列表或截图堆砌,但高质量的 LW 应记录每个技术选型背后的约束与权衡。源码包中的 LW 文档包含以下不可省略的章节,它们直接决定部署成功率。

5.1 MySQL 版本与字符集兼容性声明

明确标注测试环境为MySQL 5.7.32(非 8.0+),原因如下:

项目MySQL 5.7.32MySQL 8.0+选型理由
JSON 支持✅ 基础 JSON 函数(JSON_CONTAINS)✅ 更多函数(JSON_TABLE)项目仅需JSON_CONTAINS判断字段存在性
默认字符集latin1utf8mb4避免建表时因字符集不一致报错,学生可手动执行ALTER DATABASE your_db CHARACTER SET = utf8mb4
系统变量名max_allowed_packet同名但默认值更大上传大体积z_valuesJSON 时需确认该值 ≥ 64M

注意:若在 CentOS 7.9 上安装 MySQL,官方推荐使用mysql57-community-release-el7-11.noarch.rpm包,而非mysql80-community-release-el7-6.noarch.rpm,避免触发ONLY_FULL_GROUP_BY严格模式导致聚合查询失败。

5.2 小程序app.json中的关键配置项说明

LW 文档需逐条解释app.json中影响上线的字段,例如:

{ "permission": { "scope.userFuzzyLocation": { "desc": "用于获取用户模糊地理位置(非必需,本项目未使用)" }, "scope.record": { "desc": "【必须开启】用于调用 wx.startAccelerometer" } }, "requiredPrivateInfos": ["accelerometer"], "sitemapLocation": "sitemap.json" }
  • "requiredPrivateInfos"是微信 2023 年起强制要求的字段,漏填会导致真机调试时wx.startAccelerometer报错fail permission denied
  • "sitemap.json"必须存在且内容为{ "desc": "all" },否则小程序无法通过微信审核(即使只是毕业设计演示)。

5.3 部署时config.js的 3 个必改参数

后端config.js中以下参数必须人工修改,LW 文档用表格强调:

参数名示例值修改说明
DB_HOST127.0.0.1若 MySQL 与 Node.js 不在同一机器,需改为内网 IP(禁止填localhost
WX_APPIDwx1234567890abcdef微信公众平台申请的小程序 AppID,不是公众号 AppID
STATIC_URLhttps://your-domain.com小程序中图片/音频资源的 CDN 域名,若用本地路径(/static/xxx.png)需确保 Nginx 已配置静态文件路由

部署者只需按此表修改,即可跳过 80% 的“启动报错”问题。LW 的价值,正在于把“别人踩过的坑”变成“你抄作业的 checklist”。


验证 MySQL 是否正确加载睡眠阶段数据:执行SELECT * FROM sleep_stage_log WHERE session_id = 'test_001' ORDER BY start_time;,应返回至少 3 条不同stage_code的连续记录,且end_time字段非空。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/15 0:30:01

成考录取后要上课吗?学习形式与到校要求说明(2026 更新)

直接答案&#xff1a;要上课。录取后须按院校培养方案完成课程学习与考核&#xff0c;形式以线上为主&#xff0c;部分院校安排集中面授或线下考试&#xff0c;具体要求以院校当年规定为准。 录取不等于拿证。录取只是取得学籍&#xff0c;之后还有完整的培养过程&#xff1a;线…

作者头像 李华
网站建设 2026/9/15 0:28:02

上海土壤水文分组高精度栅格制作与SCS-CN径流模拟应用

简介&#xff1a;上海市土壤水文分组&#xff08;HSG&#xff09;高精度栅格数据&#xff0c;是基于USDA曲线数&#xff08;CN&#xff09;方法估算降雨径流的关键基础数据&#xff0c;适用于SWAT水文模型建模、城市排水规划及流域水文分析。数据源自HYSOGs250m与soilGrids250m…

作者头像 李华
网站建设 2026/9/15 0:26:31

成都网络营销推广公司避坑指南:5个实战问答帮你省钱

成都网络营销推广公司避坑指南:5个实战问答帮你省钱 网站上线半年,后台数据一片惨淡,除了几个误点进来的,连个咨询电话都没有。这是很多老板在找成都网络营销推广公司时最容易踩的坑。你以为花钱做了站、投了广告就能躺赢,结果钱花出去了,流量还是零。…

作者头像 李华
网站建设 2026/9/15 0:26:04

2026年金相显微镜选购指南:核心考量与品牌对比

1. 金相显微镜选购的核心考量因素金相显微镜作为材料科学实验室的核心设备&#xff0c;其成像质量直接关系到科研数据的可靠性。在2026年的市场环境下&#xff0c;选购一台称心如意的金相显微镜需要从光学性能、机械稳定性、软件功能和售后服务四个维度进行综合评估。光学系统是…

作者头像 李华
网站建设 2026/9/15 0:22:00

基于Matlab的动态手势识别算法实现与优化

1. 项目概述&#xff1a;动态手势识别的核心价值与应用场景动态手势识别作为人机交互领域的重要分支&#xff0c;正在智能家居、虚拟现实和工业控制等场景快速普及。与传统静态手势相比&#xff0c;连续手部动作的捕捉与分析对算法实时性和鲁棒性提出了更高要求。Matlab凭借其强…

作者头像 李华
网站建设 2026/9/15 0:21:29

成都网络营销推广公司揭秘:保姆级建站教程防黑挂马实战

成都网络营销推广公司揭秘:保姆级建站教程防黑挂马实战 昨天凌晨三点,我手机疯狂震动。客户哭着打电话过来,说公司官网首页突然变成了一堆乱码,点击进去全是博彩广告和木马下载链接。后台日志一片红,服务器CPU占用率飙到100%,SEO排名直接掉到了百度第10页之后。那一刻,客户的声音都在抖:“我们花了二十…

作者头像 李华