【问题标题】:Compressing a sinewave table压缩正弦波表
【发布时间】:2011-08-06 03:35:51
【问题描述】:

我有一个包含 1024 个条目的大型数组,在 range(14, 86) 中有 7 位值

这意味着有多个索引范围具有相同的值。

例如,

consider the index range 741 to 795. It maps to 14
consider the index range 721 to 740. It maps to 15
consider the index range 796 to 815. It maps to 15

我想将此地图提供给 Python 程序,该程序会输出以下内容:

if((index >= 741) and (index <= 795)) return 14;
if((index >= 721) and (index <= 740)) return 15;
if((index >= 796) and (index <= 815)) return 15;

groupby 映射值的一些代码已准备好,但我无法使用 pairwise 编写表达式。

有人做过类似的事情吗?

我以两种形式上传了数据集:

通常,ordered by index

Grouped by mapped value.

【问题讨论】:

  • 这将适用于 8 位 8051 内核。
  • 我必须说是一次非常糟糕的表压缩尝试。如果有人可以提出一种更好的方法(RLE 和 delta 编码的混合?)来压缩数据集并具有与数组查找相当的性能,我们将不胜感激!
  • RLE 编码可以在 g(n)=36 上为 228..255、35 为 208..227、34 为 195..207、33 为 183..194、32 提供进一步的压缩对于 173..182,对于 164..172,对于 31,对于 156..163,对于 30。取决于您在表大小和代码大小之间的权衡。在极端情况下,您可以使用压缩表实现完整的二进制搜索。
  • CORDIC 将在周期性 fns 上工作,他说他还添加了模拟噪声。单独列出 fn 和噪声可能会更紧凑。他需要show us teh dataz 才能告诉我们 ;-)
  • 我添加了仅存储表格四分之一的算法。

标签: python compression trigonometry run-length-encoding


【解决方案1】:

如果您不介意由于四舍五入而略有不同的值,我可以为您很好地真正压缩该值。

from math import pi, sin
interval=2*pi/1024
sinval=lambda i:int(round(sin(i*interval)*36))+50

这是实际执行您想要的操作的代码;它适用于

vals = sorted((sinval(i), i) for i in range(1024))

作为测试数据。如果您在第一列中有索引,则需要在此处切换for 循环中valindex 的顺序。

ranges, oldval, oldidx = [[0, 0]], 0, 0
for val, index in vals:
    if not (val == oldval and index == oldidx + 1):
        ranges[-1].append(oldidx)
        ranges.append([val, index])
    oldval, oldidx = val, index
ranges[-1].append(oldidx)
ranges.pop(0)
ifs = ('if((index >= {1}) and (index <= {2})) return {0};\n'.format(val, start, end)
            for val, start, end in ranges)
print ''.join(ifs)

编辑:哎呀,我错过了一行。固定的。另外,你的乘数实际上是 36 而不是 35,我脑子里肯定是 (14, 86) 到 (15, 85)。

编辑 2:向您展示如何仅存储表格的四分之一。

from math import pi, sin

full = 1024
half = 512
quarter = 256
mag = 72
offset = 50

interval = 2 * pi / full

def sinval(i):
    return int(round(sin(i * interval) * (mag // 2))) + offset

vals = [sinval(i) for i in range(quarter)]

def sintable(i):
    if  i >= half + quarter:
        return 2 * offset - vals[full - i - 1]
    elif  i >= half:
        return 2 * offset - vals[i - half]
    elif i >= quarter:
        return vals[half - i - 1]
    else:
        return vals[i]

for i in range(full):
    assert -1 <= sinval(i) - sintable(i) <= 1

如果您从表中减去偏移量,只需将前两个 -vals[...] 改为。

此外,底部的比较是模糊的,因为我得到了 72 个错误。这仅仅是因为您的值被四舍五入为整数;它们都是介于两个值之间的位置,因此准确度几乎没有下降。

【讨论】:

  • 这将在 8 位 8051 内核上运行。不过,我想知道你是如何推导出常数的!
  • (85 - 15) / 2 = 35,桌子从 50 开始和结束......我会看看并在几秒钟内真正回答你的问题。
  • 我很感激!得到答案后,将上面公式的输出与我上传的表格进行比较:值会有一些变化。因此,我建议您使用我上传的表格进行测试。
  • 很好的答案。另一方面,这看起来不像是现在“压缩”波表的好方法,是吗:-(
  • 这里是如何只存储表格的四分之一。
【解决方案2】:

关闭后,我才发现这个解决方案"What's the most Pythonic way to identify consecutive duplicates in a list?"


NB:使用像 sine 这样的周期性 fn,您可以通过仅存储四分之一(即 256 个值)或一半的表格来解决问题,然后在查找时的索引。正如我所评论的,如果您进一步不存储 +50 的偏移量,则需要少一点,代价是在查找时间后增加一个整数。因此,79% 的压缩率很容易实现。 RLE 会给你更多。即使 fn 有噪声,您仍然可以通过这种通用方法获得不错的压缩效果。

正如 agf 指出的那样,你的 f(n) = 50 + 36*sin(72*pi*n/1024) = 50 + g(n)

因此,将g(n) = 36*sin(72*pi*n/1024) 的 256 个值制成表格,仅适用于 n=0..255 范围

那么 f(n) 很容易通过以下方式计算:

if 0 <= n < 256, f(n) = 50 + g(n)
if 256 <= n < 512, f(n) = 50 + g(511-n)
if 512 <= n < 768, f(n) = 50 - g(n-512)
if 768 <= n < 1024, f(n) = 50 - g(1023-n)

无论如何,这是一个通用的表格压缩器解决方案,它将生成 (istart,iend,value) 三元组。

我不知道如何使用列表推导和 itertools.takewhile() 以 Python 方式执行此操作;需要打磨。

#import itertools

table_="""
    0       50
    1       50
    ...
    1021    49
    1022    50
    1023    50""".split()

# Convert values to int. Throw away the indices - will recover them with enumerate()
table = [int(x) for x in table_[1::2]]

compressed_table = []
istart = 0
for i,v in enumerate(table):
    if v != table[i-1]:
        iend = i-1
        compressed_table.append((istart,iend,table[i-1]))
        istart = i
    else:
        continue # skip identical values
# Slightly ugly: append the last value, when the iterator was exhausted
compressed_table.append((istart,i,table[i]))

(注意,在 agf 改变他的方法之前,我开始使用表压缩器方法......试图获得一个 itertools 或列表理解解决方案)

【讨论】:

  • 干得好。您的解决方案在功能上是相同的。我知道利用波对称性的方法,但也可以制作表格来保存一些不对称样本,包括模拟噪声。然而,对之间的偏差不会移动超过 3 - 4 位 LSB。否则,如果我只对正弦感兴趣,带有一点 LUT 的多项式插值会起作用。
  • @PoorLuzer,然后可能将高位和低位分别制表。向我们展示一些实际的样本噪声数据?您想要数据紧凑性与代码之间的什么权衡?
  • 举个例子让人想到细节,但考虑一下DTMF波表。不要认为音调的细节是两个正弦的总和,而是在抽象层次上考虑一个数字= 1 个独特的波形。对于噪音,请考虑声音“hi”的 wav 编码。
  • 您在 256-511 和 768-1023 中落后一位。
猜你喜欢
  • 1970-01-01
  • 2011-01-15
  • 1970-01-01
  • 1970-01-01
  • 2013-08-07
  • 2012-07-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多