2

我想组装一个 SDR 系统,该系统最初调谐 AM,后来调谐 FM 等。我计划用来执行此操作的系统将有一个用于直接数字合成 (DDS) 的正弦查找表。为了正确调谐,我希望能够精确控制馈送到混频器(在这种情况下为乘数)的正弦波的频率。我希望线性插值会很接近,但认为非线性方法会提供更好的结果。

什么是用于正弦表的良好且快速的插值方法。目标系统上的乘法和加法很便宜;分裂代价高昂。

编辑:我计划用乘法/移位函数实现常量,以将常量标准化为缩放整数。中间值将使用宽加,乘法将使用 18 或 17 位。可以使用浮点“预计算”,但不能在目标平台上使用。当我说“除法代价高昂”时,我的意思是它必须使用乘数和大量代码来实现。这不是不可想象的,但应该避免。然而,真正的浮点 IEEE 方法将在该平台上占用大量资源,以及自定义实现。

任何 SDR 经验都会有所帮助。

4

6 回答 6

8

如果线性插值没有得到很好的结果,可以尝试三角关系。

和差公式

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
于 2009-07-22T11:30:01.737 回答
4

为什么是桌子?当信号为 -20db 时,这个非常快速的函数在 -90db 处具有最差的噪声峰值。这真是太好了。

对于音频的重采样,我总是使用 Elephant 论文中的一种插值器。这在之前的 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

所以我们要看看 sin(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 个字节,并且您在 16 位分辨率中仅在 180+90*9 字节中编码到十分之一度。您可以根据需要进行扩展(可能达到 32 位角度和 16 位补间角度)并在两者之间快速线性插值。为了最大限度地减少存储空间,您正在利用连续值彼此接近的事实。


编辑 2:在表格中编码中间角度的更好方法

我只记得当我这样做时,我最终非常紧凑地表达了根据线性插值的期望值与实际值之间的差异。这个错误总是在同一个方向。

我首先计算了该范围内的最大误差,然后以此为基础。

工作得很好。我觉得我应该在博客条目中编写代码来说明。:-)

于 2009-07-24T17:21:10.850 回答
4

平滑函数的表插值 = ick hurl bleah。恕我直言,我只会在一些非常奇怪的函数上使用表插值,或者在绝对需要确保避免不连续的地方(请注意,插值表的导数是不连续的)。当您完成表查找和所需的插值代码时,您可能已经评估了一两个多项式,至少如果乘法不会导致您过多的胃灼热。

恕我直言,您最好对正弦波形的每个段(例如 -90 到 +90 度,或 -45 到 +45 度,然后是相同宽度的其他段)使用切比雪夫近似,并选择最小度多项式将您的错误减少到所需的值。如果段足够小,您可以使用二次甚至线性多项式;在准确性、段数和多项式次数之间存在权衡。

请参阅我在另一个问题中的帖子,它会为您省去计算系数的麻烦(至少如果您相信我的数学)。

(编辑:如果不清楚,您可以在设计时在您最喜欢的高性能 PC 上进行 Chebyshev 近似,以便在运行时您可以使用脏包微控制器或 FPGA 或任何具有简单多项式的东西1-4.除非你知道自己在做什么,否则不要超过4级,3或以下会更好。)

于 2009-07-23T15:49:21.237 回答
3

正弦表中的插值实际上是重新采样。显然,您可以通过一次调用来获得完美的结果sin,因此无论您的解决方案是什么,它都需要超越它。对于固定滤波器重采样,您仍然只有一组固定的可用点(3:1 上采样器意味着您在表中的每个点之间将有 2 个新点可用)。目标系统上的内存有多贵?我的主要建议是简单地提高表格分辨率并使用线性插值。您将获得与更小的表和简单的上采样相同的结果,但计算开销更少。

于 2009-07-22T11:01:53.917 回答
1

您是否考虑过将泰勒级数用于三角函数(在此处找到)?这涉及乘法和除法,但取决于您的数字的表示方式,您可以将除法转换为乘法(如果您非常幸运,也可以转换为位移)。您可以根据需要计算该系列的任意数量的项,并以这种方式获得您的精度。

或者,如果这个正弦波在某个时候将成为模拟信号,那么您可以使用查找表方法并使用模拟滤波器从生成的波形中去除采样频率。如果您的采样频率是正弦频率的 100 倍,则很容易去除。您需要一个可变过滤器来执行此操作。我从来没有做过这样的事情,但我知道有数字电位器可以采用二进制数并改变它们的电阻。这可能是可变 RC 滤波器的基础——可能带有一些用于增益的运算放大器等。

祝你好运!

于 2009-07-24T17:16:55.647 回答
0

人们已经编写了一些非常聪明的代码,用于在内存很小的系统上快速计算 sin(),这些系统甚至没有硬件乘法指令,更不用说除法指令了。

按照复杂度递增的顺序:

  • 使用方波。许多 AM 收音机在其环形解调器中使用方波,我不明白为什么您的 AM 解调器需要更复杂的东西。

  • 通过在每个四分之一周期 256 个值的原始表中查找“最接近的值”来近似 sin()。是的,您会看到看起来很可怕的楼梯,但是(通过一点模拟过滤)这通常效果很好。(事实上​​,这通常是多余的,一张短得多的桌子就足够了)。

  • 通过在原始表中查找 2 个最接近的值并在它们之间进行线性插值来近似 sin()。

  • 对于 sin(x),每四分之一周期具有 16 个短的、等间距的 x 三次样条曲线的近似 sin()“提供优于 16 位精度”。

Wikibooks: Fixed-Point Numbers链接到最后 3 个的一些巧妙实现。

于 2013-05-01T19:04:52.347 回答