我想整理一个SDR系统,该系统最初调谐AM,后来调制FM等。 我计划用来执行此操作的系统将具有用于直接数字合成(DDS)的正弦查找表。 为了正确调谐,我希望能够精确控制馈送到混频器的正弦波频率(在这种情况下为乘法器)。我希望线性插值很接近,但认为非线性方法会提供更好的结果。
什么是用于正弦表的良好且快速的插值方法。乘法和加法在目标系统上很便宜;分工是昂贵的。
编辑: 我计划使用乘法/移位函数实现常量,以将常量标准化为缩放整数。中间值将使用宽增加,乘法将使用18或17位。可以使用浮点“预计算”,但不能在目标平台上使用。当我说“划分成本很高”时,我的意思是它必须使用乘法器和大量代码来实现。这不是不可想象的,但应该避免。但是,真正的浮点IEEE方法将在此平台上占用大量资源,以及自定义实现。
任何SDR经验都会有所帮助。
答案 0 :(得分:7)
如果使用线性插值得不到很好的结果,可以尝试三角关系。
总和和差分公式
sin(A+B)=sinA*cosB + cosA*sinB
sin(A-B)=sinA*cosB - cosA*sinB
cos(A+B)=cosA*cosB - sinA*sinB
cos(A-B)=cosA*cosB + sinA*sinB
你可以预先计算A,B范围的sin和cos值,即
A range: 0, 10, 20, ... 90
B range: 0.01 ... 0.99
答案 1 :(得分:4)
平滑函数的表插值= ick hurl bleah。恕我直言我只会在一些非常奇怪的函数上使用表插值,或者你绝对需要确保避免不连续的地方(注意插值表的导数虽然是不连续的)。当你完成表查找和所需的插值代码时,你可能已经计算了一两个多项式,至少如果乘法不会导致你太多的胃灼热。
恕我直言,对于正弦波形的每个段(例如-90到+90度,或-45到+45度,然后是相同宽度的其他段),使用Chebyshev approximation会更好并选择将误差降低到所需值的最小度多项式。如果该段足够小,您可以使用二次或甚至线性多项式;在准确度,段数和多项式程度之间存在权衡。
参见my post in this other question,它可以省去计算系数的麻烦(至少如果你相信我的数学计算)。
(编辑:如果不清楚,你可以在你最喜欢的高性能PC上进行Chebyshev近似设计,这样在运行时你可以使用一个杂物袋微控制器或FPGA或其他任何一个简单的学位为1-4的多项式。除非你知道你在做什么,否则不要超过4级.3或以下会更好。)
答案 2 :(得分:4)
为什么要一张桌子?当信号为-20db时,This very fast function的最差噪声峰值为-90db。那太好了。
对于重新采样音频,我总是使用象纸中的一个插值器。这在previous SO question中进行了讨论。
如果你的处理器没有fp,你仍然可以做这些事情,但它们更难。我去过那儿。我感觉到你的痛苦。祝好运!我曾经为fp转换为整数以获得乐趣,但现在你必须付钱给我。 : - )
适用于您的问题的酷在线参考:
http://www.audiomulch.com/~rossb/code/sinusoids/
http://www.dattalo.com/technical/theory/sinewave.html
修改:根据您的评论添加其他想法
由于你正在处理一个棘手的处理器,也许你应该研究如何使你的正弦表有更多的角度来查找,但仍然保持小。
假设你将一个象限分成了90个(实际上,你可能会使用256个,但是为了熟悉和清晰,让它保持90个)。将它们编码为16位。到目前为止,这是180字节的表。
现在,对于这些学位中的每一个,我们将有9个(实际上可能是8或16个)中间点。
我们以3度到4度之间的范围为例。
sin(3)=0.052335956 //this will be in your table as a 16-bit number
sin(4)=0.069756474 //this will be in your table as a 16-bit number
所以我们要看罪(3.1)
sin(3.1)=0.054978813 //we're going to be tricky and store the result
// in 8 bits as a percentage of the distance between
// sin(3) and sin(4)
你想要做的是弄清楚sin(3.1)如何适应sin(3)和sin(4)之间的关系。如果它介于中间,则代码为128的字节。如果它是中间的四分之一,代码为64。
这是一个额外的90个字节,你只需要在180 + 90 * 9字节的16位资源中编码到十分之一度。您可以根据需要进行扩展(可能会达到32位角度和16位补间角度)并在两者之间进行线性插值。为了最大限度地减少存储空间,您可以利用连续值彼此接近的事实。
编辑2:在表格中编码中间角度的更好方法
我记得当我这样做时,我最终非常紧凑地表达了根据线性插值的期望值和实际值之间的差值。这个错误总是在同一个方向。
我首先计算了范围内的最大误差,然后根据该范围计算了尺度。
工作得很好。我觉得我应该在博客条目中做代码来说明。 : - )
答案 3 :(得分:3)
正弦表中的插值有效地重新采样。显然,只需一次调用sin
即可获得完美的结果,因此无论您的解决方案是什么,它都需要超越它。对于固定滤波器重采样,您仍然只有一组固定的可用点(3:1上采样器意味着您将在表中的每个点之间有2个新点)。目标系统上的内存有多贵?我的主要建议是简单地提高表格分辨率并使用线性插值。您将获得与较小的表和简单上采样相同的结果,但计算开销较少。
答案 4 :(得分:1)
您是否考虑过将Taylor系列用于trig函数(找到here)?这涉及乘法和除法,但取决于你的数字如何表示,你可能能够将除法变成乘法(或者如果你很幸运则换位)。您可以根据需要计算系列的任意数量,并以此方式获得精度。
或者,如果此正弦波在某个时刻成为模拟信号,那么您可以使用查找表方法并使用模拟滤波器从结果波形中移除采样频率。如果您的采样频率是正弦频率的100倍,则很容易将其移除。你需要一个可变过滤器才能做到这一点。我从来没有做过这样的事情,但我知道有数字电位器采用二进制数并改变它们的电阻。这可能是可变RC滤波器的基础 - 可能有一些运算放大器用于增益等。
祝你好运!答案 5 :(得分:0)
人们已经编写了一些非常聪明的代码,用于在具有少量内存的系统上快速计算sin(),这些内存甚至没有硬件乘法指令,更不用说除法指令了。
为了增加复杂性:
使用方波。许多AM无线电在其ring demodulator中使用方波,我不明白为什么你的AM解调器需要更复杂的东西。
通过查找每季度周期256个值的原始表中的“最接近的值”来近似sin()。是的,你看到看起来很可怕的阶梯,但是(通过一些模拟过滤)这通常很有效。 (事实上,这通常是矫枉过正的,而且更短的表就足够了。)
通过查找原始表中最近的2个值并在它们之间进行线性插值来近似sin()。
对于sin(x),每四分之一周期使用16个短的,等间距x的三次样条的近似sin()“给出了比16位精度更好的”。
Wikibooks: Fixed-Point Numbers链接到最后3个的一些聪明的实现。