0%

数据如何分段

  • The recorded signals were divided into 4 s long segments, which can be regarded as semi-isometric contraction, with 50 % overlapping and concatenated the segments from the five trials at a same timing.
  • 怎么匹配不同区间上的mu?通过重叠部分。如果匹配程度>90那么就说明是同一个mu
  • 如何获取整个区间上的波形?通过插值来获取这个MUAP的动态变化,获得更高的分辨率

1. Qt上位机

分为两个线程,分别是采集线程和绘制线程。

1.1 采集线程

采集线程面向过程,从buffer(C风格数组)中读取数据,并写入txt文本文件中。数据采集卡需要读取三个通道,分别代表编码器的 A 相,编码器的 B 相,以及同步信号。缓冲区的数据是同一时刻三个通道的数据是相邻的。然后通过 A 相和 B 相的脉冲数计算转过的角度,A 相在 B 相前角度就是正,A 相在 B 相后角度就是负。记录当前时间与开始时间的差值,作为绘制的 x 坐标,记录当前的角度,作为 y 坐标。这个 x 坐标和 y 坐标是 samplingForce 这个对象的成员变量。

ui 线程通过访问这个 samplingForce 的类成员来获取绘制的点。这中间涉及到线程安全问题以及面向对象的问题。

Read more »

1. Shared_ptr 的底层原理

std::shared_ptr 是 C++ 标准库中的一个智能指针,用于自动管理对象的生命周期。它通过引用计数来跟踪有多少个 shared_ptr 指向同一个对象。当最后一个 shared_ptr 被销毁或重置时,对象也会被删除。

内部结构

std::shared_ptr 的底层实现通常包括以下几个关键组件:

  1. 控制块(Control Block)
    • 控制块通常是一个独立的对象,它负责管理对象的引用计数和弱引用计数。
    • 引用计数(use_count)记录了多少个 shared_ptr 指向同一个对象。
    • 弱引用计数(weak_count)记录了多少个 std::weak_ptr 持有对该对象的引用。
  2. 存储机制
    • std::shared_ptr 包含一个指向控制块的指针。
    • 控制块包含一个指向实际对象的指针。
    • 控制块还包含一个指向删除器函数的指针(可选)。
Read more »

1. Main函数初始化

ChatServer 同时兼具两种服务器的功能,一种是 TCP 服务器,用于聊天,一种是 gRPC 服务器,用于消息的转发。

所以初始化的时候就需要两种初始化,分别跑在不同的线程里。之前是让 ioc.run() 单独跑在一个线程里的,这次让 gRPC 的监听单独跑在一个线程里:

1
2
3
4
5
6
7
8
9
10
11
ChatServiceImpl service;
grpc::ServiceBuilder builder;
// 监听端口和添加服务
builder.AddListeningPort(server_address);
builder.RegisterService(service);
// 构建并启动gRPC服务器
unique_ptr<grpc::Server> server(builder.BuildAndStart());
// 单独启动一个线程处理grpc服务
std::thread grpc_server_thread([&server](){
server.Wait();
});
Read more »

1. Main函数的初始化

StatusServer 主要用作 GateServer 的 gRPC 服务器以及 ChatServer 的 gRPC 的客户端。

主函数是如何初始化 gRPC 服务器的?

在主函数里面,只需要启动 gRPC 的服务端就可以了。作为服务端,肯定是要一直处于监听状态,那么就需要一个上下文和一个监听端点:

  • 这里的端点就是服务器自己设定的端口号,在 init 文件初始化的 50052,而 IP 是所有地址的 IP 都可以监听,所以是 0.0.0.0,这样 IP 和 Port 组成了一个地址(端点)传给这个 builder。

  • 这里的上下文和客户端的 ClientContext 有区别,用的是 builder 来开始和监听服务的。而服务的具体实现需要通过一个类来实例化,这个实例包含了 proto 文件中定义的 rpc 接口。

首先来看如何实现这个服务接口的。StatusServer 定义了两个 gRPC 接口:

  • GetChatServer
  • Login
Read more »

1. Main函数的初始化

GateServer 既作为服务器,又作为客户端:

  • 作为聊天客户端的网关服务器
  • 作为gRPC的客户端,gRPC的客户端比较简单,不需要在 Main 函数中进行初始化
    • 邮箱验证服务
    • 状态查询服务
  • 作为验证服务的客户端

Main 函数中需要连接 Reids 服务器和 MySQL 服务器:

1
2
MysqlMgr::GetInstance();
RedisMgr::GetInstance();
Read more »

肌肉接口通常只有在截肢后有相关残余肌肉组织可用时才可能。截肢程度越高,对控制信号的需求就越大,可用于进行直观控制的肌肉就越少。尽管如此,肌肉可以被用来将神经代码传递到缺失肢体的神经去神经化和再神经化。这种手术被称为靶向肌肉再支配(TMR),它是假肢的一个突破。

增加激活水平的两种生理机制:额外运动神经元的募集和活动运动神经元放电频率的调节。运动神经元放电时序已被汇集以获得所有运动神经元的放电时序的集合,作为神经驱动的估计。

尽管平均校正值(ARV)和均方根值(RMS)随着募集的运动单元(MU)的数量及其发射率单调增加。它们不区分这些激活模式和运动单元动作电位(MUAP)的影响。这在动态肌肉收缩中变得有问题,因为肌肉的几何变化会导致 MUAP 形状的变化。因此,在 RMS 和 ARV 指标中,MUAP 的变化很容易被误认为是肌肉兴奋模式的变化。据我们所知,MUAP 变化对 ARV 或 RMS 指标的影响尚未系统量化。

更先进的肌肉兴奋技术建立在通过分解 hdEMG 信号直接识别 MU 发放序列的基础上。这些技术将 MUAP 与兴奋模式完全分离,但在很大程度上仅在等长肌肉收缩上进行了测试。没有详细研究动态条件,主要是由于缺乏可靠的动态 hdEMG 分解技术。

我们量化了 MUAP 对基于 RMS 的 hdEMG 肌肉兴奋估计的负面影响。RMS 度量在等距和动态条件下均产生14%的NRMSE(图1和图2)。即使只有5个已识别的 MU,基于 CKC 的 CST 也显著优于 RMS 度量。NRMSE 随着识别的 MU 的数量而进一步降低。

总结就是:先选一段信号区间用于估计初始参数,然后再在各个区间上改进参数。

提出了一种新的动态hdEMG卷积数据模型,以及用于评估MU识别准确性和分析动态肌肉收缩中MU动作电位(MUAP)变化对MU识别的影响的脉压比(PNR)指标。我们在不同的动态收缩速度下,对来自肱二头肌、股外侧肌和股直肌的信号测试了所提出的方法。

当考虑MU发射时间的预先存在的知识时,可以显著提高尖峰分割方法的鲁棒性。例如,在处于相对恒定收缩水平的健康人体肌肉中,MU发射频率相对恒定。棘间距的标准偏差在平均棘间距的10%到30%之间[5]。不幸的是,这不适用于病理情况或快速肌肉收缩的情况,在这些情况下,这种额外知识的实施会大大降低MU尖峰分割的准确性。

Read more »