常见的滤波算法有:
限幅滤波法,中位值滤波算法,算术平均滤波法,移动平均滤波算法(也叫递推平均滤波算法),中位值平均滤波算法等等。
服务器实时接收硬件传送过来的实时温度,实时浓度,实时电压,实时电流等实时数据时,通常会出现将异常的数据传送过来,比如电压,当实时接收硬件检测电动车电池电压时,会突然出现一些异常数据:比如正常电压数据值在1.5V-3.3V之间,突然电动车一刹车或者出现异常情况,电压一宿啊就变成3.3V以上或者1.5V以下,甚至出现了负数,这时,折线图现显示的实时电压数据图就会没有规律,不符合常识,也就是折现一下上一下下,这时有些题目就会要求对硬件传送过来的数据进行处理,并在图中展示出来。
当题目要求使用滤波算法时,这时需要注意的问题是:
1.展示折线图时需要用到两个折线图。一个用来展示数据未处理时的变化趋向,一个用来展示处理后的变化趋向。
2.当接受硬件传送过来的实时数据时,对于那些异常的数据,也要存入数据库中。
3.展示折线图时也可以用一个折线图,不过对于处理前的数据和处理后的数据可以用两种比较明显区分的颜色来代替。
接下来我将根据实时电压,来使用移动平均滤波算法,用一个折线图表示。具体如下:
(1)首先我使用的任然是前后端不分离,对于硬件传送过来的数据帧,我首先在后端写了一个方法来对数据帧进行处理,然后对接收的数据根据情况进行处理:
@Component
public class Method {
static double vs = 0;//定义一一个全局变量--用来表示前一个电压值
static double avgs = 2.0;//平均值定义一个-----参考值
static double value = 1;//设置电压的差值----1.5-2.5之间
static double before=0.0;//表示前一个电压值
public void addressMessage(String text) throws IOException, InterruptedException {
//这里表示处理从硬件那边发送过来的数据帧方法
if (text.startsWith("SDNData")) {
//数据帧格式--具体看硬件那边如何定义
//假如硬件那边发送过来的数据帧为:SDNData:V:2.3T
LocalDateTime localDateTime = LocalDateTime.now();
String time = localDateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
String currentv=text.substring(10,14);
V v = new V();//创建一个对象---与数据库相关
double v = Double.parseDouble(currentV); // 当前电压
// 根据电压范围进行处理
if (v >= 0 && v <= 3) {
// 当电压在0到3之间时
if (Math.abs(v - before) > 0.3) {
// 如果当前电压与前一个电压的差大于0.3,则进行滤波处理
double filteredV = AverageFilter(currentv, before2, 5);
before2 = filteredV; // 更新前一个值
v.setV(String.valueOf(currentv));//保留当前电压值
v.setP2(String.valueOf(filteredV));//过滤后的值
} else {
// 差小于等于0.3时,保留当前值
before = currentv; // 更新前一个值为当前值
v.setV(String.valueOf(currentv));
v.setP(String.valueOf(currentv));
}
} else {
// 当电压超出0到3的范围时,直接进行滤波处理
double filteredV =AverageFilter(v, before, 5);
before = filteredV; // 更新前一个值
v.setP(String.valueOf(filteredV));//过滤后的值
v.setV(String.valueOf(v));
}
v.setTime(time); // 设置时间
// 存入数据库
vMapper.insert(v);
}
public double AverageFilter(double currentValue, double previousAverage, int windowSize) {
// 实现移动平均滤波逻辑
// windowSize 是滑动窗口的大小,可以根据需求调整
//currentValue表示当前电压 previousAverage表示前一次的平均值 windowSize表示窗口的大小决定平均的范围
double alpha = 2.0 / (windowSize + 1); // 平滑因子,根据实际情况调整
return previousAverage + alpha * (currentValue - previousAverage);
}
}
注意:在我建立的数据库中,在为data的表中有v和p还有time这三个字段,v代表未被处理的原始数据,p代表经过滤波处理之后的数据,time表示接收每一条数据的时间。
(2)前端折线图展示
其中蓝色表示原始数据,红黄色表示过滤之后的数据
(3)前端代码如下所示
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>折线图</title>
<!-- 引入 ECharts -->
<script src="https://cdn.jsdelivr.net/npm/echarts/dist/echarts.min.js"></script>
<!-- 引入 Bootstrap 样式 -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.0/dist/css/bootstrap.min.css" rel="stylesheet">
<style>
.chart-container {
margin-bottom: 20px;
border: 1px solid #ddd;
padding: 10px;
}
</style>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-lg-6">
<div id="实时电压折线图" class="chart-container" style="height: 300px;"></div>
</div>
</div>
<script>
// 初始化图表
var myChart = echarts.init(document.getElementById('实时电压折线图'));
//涉及多个折线图可以将其放一块---还有导入导出
// 配置项
var option = {
title: {
text: '实时电压折线图'
},
xAxis: {
type: 'category',
},
yAxis: {
type: 'value',
min:-1.5,
max:3.5,
},
tooltip: {
trigger: 'axis', // 设置触发类型为坐标轴触发
axisPointer: {
type: 'cross' // 十字准星指示器,显示在坐标轴上
}
},
series: [
{
name: '电池电压',
data: [],
type: 'line',
color:'blue',
smooth:true
},
{
name: '有效电池电压',
data: [],
type: 'line',
color:'red'
}
]
};
// 使用配置项显示图表
myChart.setOption(option);
// 生成数据
function fetchData() {
fetch('http://localhost:8080/mysql/getAllHistory')
.then(response => response.json())
.then(data => {
// 只取最新的10条记录
// data = data.slice(-10);
var timeData = [];
var VData = [];
var PData = [];
data.forEach(item => {
timeData.push(item.time); // 时间
VData.push(item.v); //
PData.push(item.p); //
});
// 更新图表数据
myChart.setOption({
xAxis: {
data: timeData
},
series: [
{
name: '实时电池电压',
data: VData
},
{
name: '有效电池电压',
data: PData
}
]
});
})
.catch(error => console.error('Error fetching data:', error));
}
// 初次加载数据
fetchData();
// 定期获取数据
setInterval(fetchData, 1000); // 每隔5秒钟获取一次数据
}
</script>
</div>
</body>
</htm
(4)后端数据库代码如下:
1.controller层代码
@RestController
@CrossOrigin(origins = "http://localhost:63342")
@RequestMapping("/mysql")
public class VController {
@Autowired
private VService vService;
@Autowired
private VMapper vMapper;
@GetMapping("/getAllHistory")
public List<V> getAllHistory() {
List<V> allHistory = vService.getAllHistory();
V v= allHistory.get(0);
return vService.getAllHistory();
}
2.service层代码
public interface VService extends IService<V> {
List<V> getAllHistory();
}
3.service实现类代码
@Service
public class VServiceImpl extends ServiceImpl<VMapper, V>
implements VService{
@Autowired
private VMapper vMapper;
@Autowired
public VServiceImpl(VMapper vMapper) {
this.vMapper = vMapper
;
}
@Override
public List<V> getAllHistory() {
QueryWrapper wrapper=new QueryWrapper<>();
List<V> vs = vMapper.selectList(null);
return vs;
}
}
如运行上面代码有错误,可以在评论区指出错误或者私聊我
标签:数据,double,滤波,算法,电压,折线图,移动,data From: https://blog.csdn.net/m0_74809043/article/details/140965136