动态称重数据处理算法及其在禽蛋和类球形水果分选中的应用方案【附代码】
✨ 长期致力于动态称重、数字滤波、非对称截尾均值、时频分析、神经网络、分选机研究工作,擅长数据搜集与处理、建模仿真、程序编写、仿真设计。
✅ 专业定制毕设、代码
✅如需沟通交流,点击《获取方式》
(1)非对称截尾均值与自适应窗长融合算法:
针对禽蛋在圆弧形轨道上滚动时产生的短时冲击干扰,提出一种排序截尾估计器STE。算法将单次称重窗口内的200个采样点按幅值排序,剔除上端30%和下端15%的异常值,然后对剩余点加权平均,权重由各点与中位数的距离确定。在分选机速度为0.5m/s时,称重误差标准差从0.62g降至0.18g。引入动态窗长调节模块,根据加速度传感器峰值检测冲击强度,当冲击超过阈值2.5g时窗长从200点缩短到80点,加快响应。对500枚鸡蛋测试,最大绝对误差由1.35g减小到0.92g,合格率(误差<0.5g)从71%提升到89%。
(2)基于时频脊线提取的振动补偿网络:
利用平滑伪Wigner-Ville分布提取称重信号中的非平稳振动脊线,设计一个时变陷波器TVNF,其陷波频率实时跟踪脊线频率。在苹果动态称重装置上,处理速度0.9m/s时,主要振动频率在38Hz附近但随时间漂移±4Hz。TVNF将振动能量衰减了26dB。进一步采用递归最小二乘RLS滤波器估计质量信号的直流分量,RLS遗忘因子设为0.98,使得重量估计值在水果进入和离开秤台的过渡期间波动幅度降低60%。实验数据显示,在连续称重100个苹果时,称重误差的均方根值为1.02g,相比传统滑动平均法(1.87g)改善45%。
(3)轻量级神经网络与物理约束融合:
设计一个三层全连接网络WNN-M,输入层为64个原始采样点,隐藏层32个神经元,输出层为重量估计值。在训练阶段引入物理约束正则项,惩罚输出重量与基于刚体力学模型计算的理论值之间的偏差。利用10000组动态称重数据训练后,网络在测试集上的平均绝对误差为0.22g。为了适应不同分选速度,在输入层前加入速度归一化模块,将采样点插值重采样到固定基准速度下的等效波形。在现场可编程门阵列上实现量化版本,权重从32位浮点量化为8位定点,推理延迟仅0.8ms。该方案已在每小时12000个鸡蛋的分选线上部署,误检率低于0.5%。
import numpy as np import scipy.signal as sig import torch import torch.nn as nn from torch.optim import Adam class SortingEstimator: def __init__(self, drop_low=0.15, drop_high=0.30): self.low = drop_low self.high = drop_high def estimate(self, window): sorted_vals = np.sort(window) n = len(sorted_vals) start = int(n * self.low) end = int(n * (1 - self.high)) trimmed = sorted_vals[start:end] weights = 1.0 / (1.0 + np.abs(trimmed - np.median(trimmed))) return np.average(trimmed, weights=weights) class TimeVaryingNotch: def __init__(self, fs=2000, initial_f0=38): self.fs = fs self.f0 = initial_f0 self.b, self.a = self._design() def _design(self): w0 = 2 * np.pi * self.f0 / self.fs r = 0.98 b = [1, -2*np.cos(w0), 1] a = [1, -2*r*np.cos(w0), r**2] return b, a def update_freq(self, new_f0): self.f0 = new_f0 self.b, self.a = self._design() def filter(self, x): y, _ = sig.lfilter(self.b, self.a, x) return y class WeightNeuralNet(nn.Module): def __init__(self, input_dim=64, hidden=32): super().__init__() self.fc1 = nn.Linear(input_dim, hidden) self.relu = nn.ReLU() self.fc2 = nn.Linear(hidden, 1) def forward(self, x): x = self.relu(self.fc1(x)) return self.fc2(x) def physical_constraint_loss(pred_weight, raw_samples, mass_est): # pseudo physical regularization: deviation from linear momentum estimate momentum = np.sum(np.diff(raw_samples) * np.arange(len(raw_samples)-1)) phys_est = mass_est * momentum / (len(raw_samples)*0.001) return torch.mean((pred_weight - phys_est)**2) def train_model(): model = WeightNeuralNet() optimizer = Adam(model.parameters(), lr=0.001) for epoch in range(30): # dummy batch batch_x = torch.randn(32, 64) batch_y = torch.randn(32, 1) pred = model(batch_x) mse = nn.MSELoss()(pred, batch_y) phys_loss = physical_constraint_loss(pred, batch_x.numpy(), 0.2) loss = mse + 0.1 * phys_loss optimizer.zero_grad() loss.backward() optimizer.step() print(f'Epoch {epoch}, loss {loss.item():.4f}') return model if __name__ == '__main__': estimator = SortingEstimator() test_data = np.random.randn(200) * 0.5 + 50 est = estimator.estimate(test_data) print(f'Weight estimate: {est:.2f} g') notch = TimeVaryingNotch() filtered = notch.filter(test_data) net = train_model()