从数字输入中过滤掉二进制数组中的短暂波动。

huangapple go评论58阅读模式
英文:

Filtering out short fluctuations in binary array from digital input

问题

我有一个由0/1值表示的TTL信号数组。我想要平滑掉任何短暂的尖峰,即值在非常短的时间内发生变化(例如,少于4个样本),我知道这些是噪声。

例如,如果4是最小合法脉冲长度:

[0,0,0,0,0,0,1,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1,0,1,1,1,1,1,1] 

应该变成

[0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1] 

看起来很难找到一个确切的替换规则,尽管大多数情况在主观上是明显的。总的来说,这并不是非常重要,只要没有保留任何短暂的波动即可。

英文:

I have a ttl signal represented as an array of 0/1 values. I want to smooth out any short spikes where the value changes for a very short time (for instance, less than 4 samples), which I know are noise.

For instance, if 4 is the minimum legitimate pulse length:

[0,0,0,0,0,0,1,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1,0,1,1,1,1,1,1] 

should become

[0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1] 

It seems a little difficult to come up with an exact replacement rule, though most cases are obvious subjectively. In general, it's not super important, as long as none of the short fluctuations are preserved.

答案1

得分: 1

你可以简单地遍历输入数组,形成另一个只包含你想要的模式的数组。这可以通过一个相当简单的状态机来实现,它只是“缓冲”它经过的数组项,并剔除任何遇到的长度小于四个项的连续的1,将它们替换为0。

甚至可以使用正则表达式来处理输入数组,将短的连续的1替换为0。不过,这种方法可能效率较低。

以下是用PHP代码演示了一种实现上述状态机的方法,它并不严格优化速度或代码大小,而是以易读和易理解为目标:

define('SPIKE_LEN', 4);

$input  = [0,0,0,0,0,0,1,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1,0,1,1,1,1,1,1];
$output = [];

$count     = count($input);
$run_start = null;

for ($i = 0; $i < $count; ++$i) {
	$is_one = ($input[$i] == 1);
	$is_end = ($i == $count - 1);

	if ($is_one && is_null($run_start))
		$run_start = $i;

	elseif ($is_one && !is_null($run_start) && !$is_end)
		continue;

	elseif ((!$is_one && !is_null($run_start))
		|| ($is_one && $is_end)) {

		if ($i - $run_start > SPIKE_LEN)
			for ($j = $run_start; $j <= $i; ++$j)
				$output[$j] = $input[$j];
		else	// spike
			for ($j = $run_start; $j <= $i; ++$j)
				$output[$j] = 0;

		$run_start = null;
	}

	elseif (!$is_one && is_null($run_start))
		$output[$i] = $input[$i];

	else	// shouldn't be reached
		die("Internal error at position {$i} out of {$count}, value is {$input[$i]}\n");
}

echo('Input:  ' . join(' ', $input) . "\n");
echo('Output: ' . join(' ', $output) . "\n");

这里还有一些由这段代码产生的示例输出,针对两个不同的输入数组,第一个数组是来自问题的原始输入:

Input:  0 0 0 0 0 0 1 0 0 0 1 1 1 1 1 1 1 1 0 0 0 0 0 0 1 1 0 1 1 1 1 1 1 
Output: 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1
Input:  0 0 0 0 1 0 0 1 1 1 1 0 0 1 1 1 1 1 0 0 0 1 1 1 1 1 1 1 1 0 0 0 0 0 0 1 1 0 1 1 1 1 1 1 
Output: 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1

更新: 这段代码可以很容易地改进,记录并打印输入数组中的连续序列大小以及每个连续序列大小出现的次数。这些统计数据可以提供有关输入信号性质的有用信息。

英文:

You can simply traverse the input array, forming another array that contains only the patterns you want. It would be a rather simple state machine that just "buffers" the array items it goes through and weeds out any encountered runs of ones shorter than, say, four items, replacing them with zeros.

It could even be done with a regex that treats the input array as a string and replaces short runs of ones with zeros. Though, such an approach would perhaps be less efficient.

Here's PHP code that demonstrates one way to implement the above-mentioned state machine, in a form that isn't strictly optimized for speed or code size, but written to be easily readable and understandable:

define(&#39;SPIKE_LEN&#39;, 4);

$input  = [0,0,0,0,0,0,1,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1,0,1,1,1,1,1,1];
$output = [];

$count     = count($input);
$run_start = null;

for ($i = 0; $i &lt; $count; ++$i) {
	$is_one = ($input[$i] == 1);
	$is_end = ($i == $count - 1);

	if ($is_one &amp;&amp; is_null($run_start))
		$run_start = $i;

	elseif ($is_one &amp;&amp; !is_null($run_start) &amp;&amp; !$is_end)
		continue;

	elseif ((!$is_one &amp;&amp; !is_null($run_start))
		|| ($is_one &amp;&amp; $is_end)) {

		if ($i - $run_start &gt; SPIKE_LEN)
			for ($j = $run_start; $j &lt;= $i; ++$j)
				$output[$j] = $input[$j];
		else	// spike
			for ($j = $run_start; $j &lt;= $i; ++$j)
				$output[$j] = 0;

		$run_start = null;
	}

	elseif (!$is_one &amp;&amp; is_null($run_start))
		$output[$i] = $input[$i];

	else	// shouldn&#39;t be reached
		die(&quot;Internal error at position {$i} out of {$count}, value is {$input[$i]}\n&quot;);
}

echo(&#39;Input:  &#39; . join(&#39; &#39;, $input) . &quot;\n&quot;);
echo(&#39;Output: &#39; . join(&#39; &#39;, $output) . &quot;\n&quot;);

Here are also a couple of sample outputs produced by this code, for two different input arrays, the first of which is from the OP's question:

Input:  0 0 0 0 0 0 1 0 0 0 1 1 1 1 1 1 1 1 0 0 0 0 0 0 1 1 0 1 1 1 1 1 1 
Output: 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1
Input:  0 0 0 0 1 0 0 1 1 1 1 0 0 1 1 1 1 1 0 0 0 1 1 1 1 1 1 1 1 0 0 0 0 0 0 1 1 0 1 1 1 1 1 1 
Output: 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1

Update: This code could easily be improved to also record and print the run sizes in the input array and how many times each run size was found. Such stats could provide a useful insight into the nature of the input signal.

答案2

得分: 0

这是一种使用简单的滑动窗口(左填充第一个位和右填充最后一个位)和对窗口中的位进行多数投票的方法来平滑信号的方法:

signal   = [0,0,0,0,0,0,1,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1,0,1,1,1,1,1,1]
expected = [0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1]
def filter_noise(signal, window_dim):
left_pad = window_dim * [signal[0]]
right_pad = window_dim * [signal[-1]]
signal_padded = left_pad + signal + right_pad
signal_filtered = []
window_size = 2 * window_dim + 1
for i in range(len(signal)):
window = signal_padded[i:i+window_size]
bit = int(sum(window) > window_dim)
signal_filtered.append(bit)
return signal_filtered
print(filter_noise(signal, window_dim=1))

打印结果为

[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1]

在这个例子中,窗口大小为3恰好得到了期望的结果,即 filter_noise(signal, 1) == expected

英文:

Here's an approach that uses a simple sliding window (with left-padding of first bit and right-padding of last bit) and majority voting on the bits in the window as a way of smoothing the signal:

signal   = [0,0,0,0,0,0,1,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1,0,1,1,1,1,1,1]
expected = [0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1]
def filter_noise(signal, window_dim):
left_pad = window_dim * [signal[0]]
right_pad = window_dim * [signal[-1]]
signal_padded = left_pad + signal + right_pad
signal_filtered = []
window_size = 2 * window_dim + 1
for i in range(len(signal)):
window = signal_padded[i:i+window_size]
bit = int(sum(window) &gt; window_dim)
signal_filtered.append(bit)
return signal_filtered
print(filter_noise(signal, window_dim=1))

prints

[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1]

In this example, a window size of 3 happens to give the desired result, i.e. filter_noise(signal, 1) == expected.

huangapple
  • 本文由 发表于 2023年8月9日 09:55:17
  • 转载请务必保留本文链接:https://go.coder-hub.com/76864113.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定