1. 代碼
這段代碼實現了一個一階低通濾波器(也稱為指數加權移動平均濾波器)。它適用于需要平滑數據、減少噪聲的場合。以下是一些常見的應用場景:
傳感器數據平滑:在嵌入式系統或物聯網設備中,傳感器(如溫度、濕度、加速度計、陀螺儀)的讀數可能含有高頻噪聲,通過一階低通濾波可以平滑數據,使其更穩定。
去抖動(Debouncing):在讀取機械開關或按鈕輸入時,可能會因為機械振動產生多次快速變化(抖動),使用濾波可以消除抖動,獲得穩定的狀態。
音頻處理:在音頻信號處理中,低通濾波可以用于去除高頻噪聲或實現簡單的音效。
控制系統:在控制系統中,濾波器可以用于平滑反饋信號,避免執行器因噪聲產生不必要的頻繁動作。
電池電壓監測:電池電壓可能會因為負載變化而波動,濾波可以得到一個更穩定的電壓值,用于準確估計電池電量。
運動控制:在機器人或無人機中,對姿態或位置數據進行濾波,可以使運動更加平穩。
經濟與金融:在股票價格或經濟指標分析中,使用移動平均來平滑短期波動,突出長期趨勢。
計算機視覺:對連續的視頻幀中的特征(如目標位置)進行濾波,以減少檢測誤差帶來的跳動。
注意:該濾波器的效果取決于ALPHA的取值。ALPHA越接近1,濾波器的響應越快(但平滑效果差),越接近0則平滑效果越好(但滯后越嚴重)。需要根據具體應用調整ALPHA的值。
另外,該代碼使用了全局變量lastResult來保存上一次的濾波結果,因此在多次調用中會保持狀態。需要注意的是,在多任務或中斷環境中使用全局變量可能需要防止競態條件(例如通過加鎖或使用原子操作)。
#define ALPHA 0.3 // 濾波系數(0<ALPHA<1)float lastResult = 0; // 上一次濾波結果
float firstOrderFilter(float currentVal) {float result = ALPHA * currentVal + (1 - ALPHA) * lastResult;lastResult = result; // 更新歷史值
return result;
}
2. html演示
這段代碼實現了一個一階低通濾波器(指數加權移動平均濾波器),常用于信號處理和傳感器數據平滑。下面我將創建一個可視化演示,展示這種濾波器在不同場景下的應用效果。
<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>一階低通濾波器應用</title><style>* {box-sizing: border-box;margin: 0;padding: 0;font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;}body {background: linear-gradient(135deg, #1a2a6c, #b21f1f, #fdbb2d);color: #fff;min-height: 100vh;padding: 20px;}.container {max-width: 1200px;margin: 0 auto;}header {text-align: center;margin-bottom: 30px;padding: 20px;background: rgba(0, 0, 0, 0.3);border-radius: 10px;}h1 {font-size: 2.5rem;margin-bottom: 10px;}.description {font-size: 1.1rem;max-width: 800px;margin: 0 auto;line-height: 1.6;}.applications {display: grid;grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));gap: 20px;margin-bottom: 30px;}.application-card {background: rgba(255, 255, 255, 0.1);backdrop-filter: blur(10px);border-radius: 10px;padding: 20px;box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);transition: transform 0.3s ease;}.application-card:hover {transform: translateY(-5px);}.application-card h3 {font-size: 1.5rem;margin-bottom: 15px;color: #ffcc00;}.application-card p {line-height: 1.5;margin-bottom: 10px;}.demo-container {background: rgba(255, 255, 255, 0.1);backdrop-filter: blur(10px);border-radius: 10px;padding: 20px;margin-top: 30px;box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);}.controls {display: flex;flex-wrap: wrap;gap: 15px;margin-bottom: 20px;align-items: center;}.control-group {display: flex;flex-direction: column;gap: 5px;}label {font-weight: bold;}input[type="range"] {width: 200px;}canvas {width: 100%;height: 300px;background: rgba(0, 0, 0, 0.2);border-radius: 5px;}.code-block {background: #2d2d2d;border-radius: 5px;padding: 15px;margin-top: 20px;overflow-x: auto;font-family: 'Consolas', monospace;}.highlight {color: #ffcc00;font-weight: bold;}@media (max-width: 768px) {.applications {grid-template-columns: 1fr;}.controls {flex-direction: column;align-items: flex-start;}}</style>
</head>
<body><div class="container"><header><h1>一階低通濾波器應用</h1><div class="description"><p>一階低通濾波器(指數加權移動平均)用于從信號中去除短期波動,保留長期發展趨勢。濾波系數ALPHA(α)決定平滑程度:α越小,平滑效果越強,但滯后越大。</p></div></header><div class="applications"><div class="application-card"><h3>傳感器數據處理</h3><p>用于平滑來自加速度計、陀螺儀、溫度傳感器等的數據,消除噪聲和瞬時干擾,提供更穩定的讀數。</p></div><div class="application-card"><h3>音頻信號處理</h3><p>在音頻應用中用于實現低通濾波效果,去除高頻噪聲,保留低頻成分,產生更柔和的音效。</p></div><div class="application-card"><h3>電池電壓監測</h3><p>平滑電池電壓讀數,避免因負載瞬時變化導致的電壓波動,提供更準確的電池電量估計。</p></div><div class="application-card"><h3>控制系統</h3><p>在反饋控制系統中過濾傳感器讀數,防止控制系統對噪聲過度反應,提高系統穩定性。</p></div><div class="application-card"><h3>經濟數據平滑</h3><p>應用于經濟指標和股票價格分析,消除短期波動,更好地展示長期趨勢。</p></div><div class="application-card"><h3>計算機視覺</h3><p>在對象跟蹤中平滑位置數據,減少檢測誤差導致的跳躍,提供更流暢的運動軌跡。</p></div></div><div class="demo-container"><h2>濾波器演示</h2><p>調整ALPHA值和噪聲水平,觀察原始信號與濾波后信號的差異:</p><div class="controls"><div class="control-group"><label for="alpha">ALPHA值: <span id="alpha-value">0.3</span></label><input type="range" id="alpha" min="0.01" max="0.99" step="0.01" value="0.3"></div><div class="control-group"><label for="noise">噪聲水平: <span id="noise-value">0.2</span></label><input type="range" id="noise" min="0.05" max="0.5" step="0.05" value="0.2"></div><div class="control-group"><label for="signal-type">信號類型:</label><select id="signal-type"><option value="sine">正弦波</option><option value="square">方波</option><option value="sawtooth">鋸齒波</option></select></div><button id="reset" style="padding: 8px 15px; border: none; border-radius: 5px; background: #ffcc00; color: #000; cursor: pointer;">重置圖表</button></div><canvas id="chart"></canvas><div class="code-block"><pre><code>#define ALPHA <span id="alpha-code">0.3</span> // 濾波系數(0<ALPHA<1)
float lastResult = 0; // 上一次濾波結果float firstOrderFilter(float currentVal) {float result = ALPHA * currentVal + (1 - ALPHA) * lastResult;lastResult = result; // 更新歷史值return result;
}</code></pre></div></div></div><script>// 獲取Canvas上下文const canvas = document.getElementById('chart');const ctx = canvas.getContext('2d');// 設置Canvas尺寸canvas.width = canvas.offsetWidth;canvas.height = canvas.offsetHeight;// 初始化變量let ALPHA = 0.3;let noiseLevel = 0.2;let signalType = 'sine';let lastResult = 0;let data = {raw: [],filtered: []};// 初始化圖表initializeChart();// 事件監聽document.getElementById('alpha').addEventListener('input', function() {ALPHA = parseFloat(this.value);document.getElementById('alpha-value').textContent = ALPHA.toFixed(2);document.getElementById('alpha-code').textContent = ALPHA.toFixed(2);updateChart();});document.getElementById('noise').addEventListener('input', function() {noiseLevel = parseFloat(this.value);document.getElementById('noise-value').textContent = noiseLevel.toFixed(2);updateChart();});document.getElementById('signal-type').addEventListener('change', function() {signalType = this.value;updateChart();});document.getElementById('reset').addEventListener('click', function() {initializeChart();});// 初始化圖表function initializeChart() {data = {raw: [],filtered: []};lastResult = 0;updateChart();}// 一階低通濾波器實現function firstOrderFilter(currentVal) {const result = ALPHA * currentVal + (1 - ALPHA) * lastResult;lastResult = result;return result;}// 生成信號function generateSignal(step, type) {const x = step / 20;switch(type) {case 'sine':return Math.sin(x);case 'square':return Math.sign(Math.sin(x));case 'sawtooth':return 2 * (x - Math.floor(x + 0.5));default:return Math.sin(x);}}// 更新圖表function updateChart() {// 清空數據data.raw = [];data.filtered = [];lastResult = 0;// 生成新數據for (let i = 0; i < 300; i++) {const signal = generateSignal(i, signalType);const noise = (Math.random() - 0.5) * noiseLevel;const rawValue = signal + noise;const filteredValue = firstOrderFilter(rawValue);data.raw.push(rawValue);data.filtered.push(filteredValue);}// 繪制圖表drawChart();}// 繪制圖表function drawChart() {// 清除畫布ctx.clearRect(0, 0, canvas.width, canvas.height);// 設置邊距const padding = 40;const width = canvas.width - padding * 2;const height = canvas.height - padding * 2;// 繪制網格ctx.strokeStyle = 'rgba(255, 255, 255, 0.1)';ctx.lineWidth = 1;// 水平網格線for (let i = 0; i <= 10; i++) {const y = padding + (i / 10) * height;ctx.beginPath();ctx.moveTo(padding, y);ctx.lineTo(canvas.width - padding, y);ctx.stroke();}// 垂直網格線for (let i = 0; i <= 10; i++) {const x = padding + (i / 10) * width;ctx.beginPath();ctx.moveTo(x, padding);ctx.lineTo(x, canvas.height - padding);ctx.stroke();}// 繪制坐標軸ctx.strokeStyle = '#ffffff';ctx.lineWidth = 2;// X軸ctx.beginPath();ctx.moveTo(padding, canvas.height - padding);ctx.lineTo(canvas.width - padding, canvas.height - padding);ctx.stroke();// Y軸ctx.beginPath();ctx.moveTo(padding, padding);ctx.lineTo(padding, canvas.height - padding);ctx.stroke();// 繪制原始信號(紅色)ctx.beginPath();ctx.strokeStyle = '#ff4444';ctx.lineWidth = 2;for (let i = 0; i < data.raw.length; i++) {const x = padding + (i / data.raw.length) * width;const y = canvas.height - padding - ((data.raw[i] + 1.5) / 3) * height;if (i === 0) {ctx.moveTo(x, y);} else {ctx.lineTo(x, y);}}ctx.stroke();// 繪制濾波后信號(黃色)ctx.beginPath();ctx.strokeStyle = '#ffcc00';ctx.lineWidth = 2;for (let i = 0; i < data.filtered.length; i++) {const x = padding + (i / data.filtered.length) * width;const y = canvas.height - padding - ((data.filtered[i] + 1.5) / 3) * height;if (i === 0) {ctx.moveTo(x, y);} else {ctx.lineTo(x, y);}}ctx.stroke();// 繪制圖例ctx.font = '14px sans-serif';ctx.fillStyle = '#ff4444';ctx.fillText('原始信號', canvas.width - 150, padding + 20);ctx.fillStyle = '#ffcc00';ctx.fillText('濾波后信號', canvas.width - 150, padding + 40);// 繪制標題ctx.fillStyle = '#ffffff';ctx.font = '16px sans-serif';ctx.fillText('一階低通濾波器效果演示', padding, padding - 10);// 繪制坐標標簽ctx.fillText('時間', canvas.width / 2, canvas.height - 10);ctx.save();ctx.translate(10, canvas.height / 2);ctx.rotate(-Math.PI / 2);ctx.fillText('振幅', 0, 0);ctx.restore();}// 窗口調整大小時重繪圖表window.addEventListener('resize', function() {canvas.width = canvas.offsetWidth;canvas.height = canvas.offsetHeight;drawChart();});</script>
</body>
</html>