使用 windows 固定采样时间的实时解决方法
Real Time Workaround using windows for fixed sampling time
我正在尝试从加速计传感器收集数据。我有一个 Arduino 对信号进行模数转换,并通过串行端口将其发送到 Windows.
上的 MATLAB
我每 5 毫秒通过串行端口从 Arduino 发送一个读数。我正在使用 MATLAB 在向量中的串行读取以及使用时钟方法读取数据的时间来保存该数据。
如果我要绘制我在读取的那一秒保存的向量列,我会得到一条曲线(非线性),当我查看一次读取和另一次读取之间的差异时,我看到它略有不同。
有什么方法可以让数据实时保存,采样时间固定?
注意:我使用的是250000波特率。
Matlab代码:
%%%%% Initialisation %%%%%
clear all
clc
format shortg
cnt = 1;%File name changer
sw = 1;%switch: 0 we add to current vector and 1 to start new vector
%%%%% Initialisation %%%%%
%%%%% Communication %%%%%
arduino=serial('COM7','BaudRate',250000);
fopen(arduino);
%%%%% Communication %%%%%
%%%%% Reading from Serial and Writing to .mat file%%%%%
while true,
if sw == 0,
if (length(Vib(:,1))==1000),% XXXX Samples in XX minutes
filename = sprintf('C:/Directory/%d_VibrationReading.mat',cnt);
save (filename,'Vib');
clear Vib
cnt= cnt+1;
sw = 1;
end
end
scan = fscanf(arduino,'%f');
if isfloat(scan) && length(scan(:,1))==6,% Change length for validation
vib = scan';
if sw == 1,
Vib = [vib clock];
sw = 0;
else
Vib = [Vib;vib clock];
end
end
end
%%%%% Reading from Serial and Writing to .mat file%%%%%
% Close Arduino Serial Port
fclose(arduino);
图1显示通过串口接收到的数据(每行对应1个串口读取)
图 2 显示随时钟保存的数据
图 1:
图2:
我知道我的回答不包含快速简便的解决方案。相反,它主要提供如何重新设计系统的建议。我在实时系统上工作了几年,看到它做错了太多次。可能只是 "fix",但使用您当前的通信模式会调整性能,但我相信您永远不会收到可靠的时间信息。
我将从一般系统设计的角度回答这个问题,而不是试图修复您的代码。我在哪里看到问题:
- 通常,在接收 PC 上附加时间信息不是一个好主意。只要传感器有能力并且有时钟,就将时间信息附加到传感器系统本身。这允许测量之间的准确相对定时。当传感器上的时钟设置不正确时,可能需要进行一些时钟调整,但这只是一个恒定的偏移量。
- 从 ASCII 编码数据切换到二进制数据。设置采样率和波特率后,每条消息只有 50 个字节。
- 编写一个健壮的接收器。只删除 "don't understand" 的消息不是一个好主意。每当缓冲区已满时,除非使用适当的终止符,否则您可能会收到多条消息。
- 使用预分配。您知道要写入的批次有多大。
一条消息的简单解决方案:
2 bytes - clock milliseconds
4 bytes - unix timestamp of measurement
For each sensor
2 bytes int32 sensor data
2 bytes - Terminator, constant value. Use a value which is outside the range for all previous integers, e.g. intmax
这种消息格式理论上应该允许您使用 21 个传感器。现在到接收部分:
要获得第一个版本 运行 良好的性能,请使用大批量数据(size
参数)调用 fread (serial)
并将所有读数转储到一个大元胞数组中。类似于:
C=cell(1000,1)
%seek until you hit a terminator
while not(terminator==fread(arduino,1));
for ix=1:numel(C)
C{ix}=fread(arduino,'int16',1000)
end
fclose(arduino);
读取数据后,将其附加到单个向量:C=[C{:}];
并尝试在 post-processing 中解析它。如果您管理性能,您稍后可能会 return 进行即时处理,但我建议以这种方式开始以建立系统。
我正在尝试从加速计传感器收集数据。我有一个 Arduino 对信号进行模数转换,并通过串行端口将其发送到 Windows.
上的 MATLAB我每 5 毫秒通过串行端口从 Arduino 发送一个读数。我正在使用 MATLAB 在向量中的串行读取以及使用时钟方法读取数据的时间来保存该数据。
如果我要绘制我在读取的那一秒保存的向量列,我会得到一条曲线(非线性),当我查看一次读取和另一次读取之间的差异时,我看到它略有不同。
有什么方法可以让数据实时保存,采样时间固定?
注意:我使用的是250000波特率。
Matlab代码:
%%%%% Initialisation %%%%%
clear all
clc
format shortg
cnt = 1;%File name changer
sw = 1;%switch: 0 we add to current vector and 1 to start new vector
%%%%% Initialisation %%%%%
%%%%% Communication %%%%%
arduino=serial('COM7','BaudRate',250000);
fopen(arduino);
%%%%% Communication %%%%%
%%%%% Reading from Serial and Writing to .mat file%%%%%
while true,
if sw == 0,
if (length(Vib(:,1))==1000),% XXXX Samples in XX minutes
filename = sprintf('C:/Directory/%d_VibrationReading.mat',cnt);
save (filename,'Vib');
clear Vib
cnt= cnt+1;
sw = 1;
end
end
scan = fscanf(arduino,'%f');
if isfloat(scan) && length(scan(:,1))==6,% Change length for validation
vib = scan';
if sw == 1,
Vib = [vib clock];
sw = 0;
else
Vib = [Vib;vib clock];
end
end
end
%%%%% Reading from Serial and Writing to .mat file%%%%%
% Close Arduino Serial Port
fclose(arduino);
图1显示通过串口接收到的数据(每行对应1个串口读取) 图 2 显示随时钟保存的数据
图 1:
图2:
我知道我的回答不包含快速简便的解决方案。相反,它主要提供如何重新设计系统的建议。我在实时系统上工作了几年,看到它做错了太多次。可能只是 "fix",但使用您当前的通信模式会调整性能,但我相信您永远不会收到可靠的时间信息。
我将从一般系统设计的角度回答这个问题,而不是试图修复您的代码。我在哪里看到问题:
- 通常,在接收 PC 上附加时间信息不是一个好主意。只要传感器有能力并且有时钟,就将时间信息附加到传感器系统本身。这允许测量之间的准确相对定时。当传感器上的时钟设置不正确时,可能需要进行一些时钟调整,但这只是一个恒定的偏移量。
- 从 ASCII 编码数据切换到二进制数据。设置采样率和波特率后,每条消息只有 50 个字节。
- 编写一个健壮的接收器。只删除 "don't understand" 的消息不是一个好主意。每当缓冲区已满时,除非使用适当的终止符,否则您可能会收到多条消息。
- 使用预分配。您知道要写入的批次有多大。
一条消息的简单解决方案:
2 bytes - clock milliseconds
4 bytes - unix timestamp of measurement
For each sensor
2 bytes int32 sensor data
2 bytes - Terminator, constant value. Use a value which is outside the range for all previous integers, e.g. intmax
这种消息格式理论上应该允许您使用 21 个传感器。现在到接收部分:
要获得第一个版本 运行 良好的性能,请使用大批量数据(size
参数)调用 fread (serial)
并将所有读数转储到一个大元胞数组中。类似于:
C=cell(1000,1)
%seek until you hit a terminator
while not(terminator==fread(arduino,1));
for ix=1:numel(C)
C{ix}=fread(arduino,'int16',1000)
end
fclose(arduino);
读取数据后,将其附加到单个向量:C=[C{:}];
并尝试在 post-processing 中解析它。如果您管理性能,您稍后可能会 return 进行即时处理,但我建议以这种方式开始以建立系统。