首页 > 解决方案 > 为 PYNQ 正确地将 float64 转换为 16 位定点

问题描述

我需要将 float64 值转换为固定点 <16,15> (16 位,小数部分为 15 位,整数部分为 1)。

我已经阅读了许多解决方案:

  1. 将浮点数转换为定点数
  2. C中的简单定点转换
  3. fxpmath库_

但是,在我的具体情况下,我还没有真正理解我需要的“类型”。

为了更好地解释这一点,我在 PYNQ(基于 Python 的 Xilinx 框架)中实现了一个生成简单正弦波的代码:

import numpy as np
###
fs = 44100  
n_samples = 1024 
f_sig = 130 #selected to get almost exactly a single frequency bin (43.066 * 3)
A = 1
seconds = 1

t = np.arange(0,seconds, step=1/fs)

#resolution of fft = fs/n_samples -> 44100/1024 = 43.066
data_in = A * np.sin(2*np.pi*f_sig*t)
data_in = data_in[:1024]
###

它会生成一个简单的正弦波,然后我选择前 1024 个样本。此选择的目标是将这些样本发送到 FFT logicore 块(FFT logicore 文档)。在我的具体情况下,FFT 已配置为接受实部和虚部的 16 位定点输入 <16,15>(您可以在第 18 页的文档中找到更多信息)并执行 1024 点 FFT。所以基本上我需要把这个正弦曲线float64ap_fixed<16,15>

但是,我不确定应该在转换中使用哪种 Python 数据类型。例如,在第二种方法中,它使用 auint16来存储转换后的数据。在第三种方法中,库返回一个对象。

当调用函数将输入复制到 DMA 缓冲区并计算 FFT 时,我有以下代码:

from pynq imort Overlay
from pynq import allocate

dma = overlay.axi_dma_0
buff_in = allocate(1024, 'uknown type') # which type should I use here? 
buff_in[:] = data_in[:]
np.copyto(buff_in, data_in, casting="unsafe")
dma.sendchannel.transfer(buff_in)

我理解基本算法应该是这样的:

import numpy as np
my_casting_int = int32(np.round(data_in * 2**15)))
my_casting_uint = uint32(np.round(data_in * 2**15)))

float64但同样,考虑到输入数据是带符号的正弦曲线,我不知道我是否需要有符号或无符号转换。

总结一切:

  1. 我的 FFT 期望每个输入样本有 2 个数组ap_fixed<16,15>,一个用于实部,一个用于虚部。作为一个真实的输入样本,我将有 16 位实部和 16 位,虚部基本上全为零。
  2. 我需要将我的正弦曲线从 Pythonfloat64转换为适合我的 FFT 核心的格式(即ap_fixed<16,15>)。
  3. 我不知道从float64.

标签: pythoncastingbit-manipulationfpgaxilinx

解决方案


我想 FFT 需要 ap_fixed<16,15>,其中 MSB 是符号位。在您的示例中,您已经签署了样本(因为正弦曲线介于 -1.0 和 1.0 之间),因此您的铸件必须是int(有符号整数)。但是,如果您需要有符号 int 的二补码表示,则使用uint. 在这两种情况下,使用 16 位强制转换就足够了。

np.round(data_in*2**15).astype(np.int16) # returns -16384
np.round(data_in*2**15).astype(np.uint16) # returns 49152

如果您使用float64并需要转换为 ap_fixed<16,15> (fxp-s16/15S1.15类型),请注意舍入和截断方法。

如果您使用fxpmath,则更清楚您在做什么转换。确实返回了一个对象,但是您可以按方法或按方法提取int(原始)值:rawuinturaw

from fxpmath import Fxp

#...

data_in_fxp = Fxp(data_in, dtype='fxp-s16/15') # or dtype='S1.15'

raw_data_int = data_in_fxp.raw()
raw_data_uint = data_in_fxp.uraw() # two-complement

这些方法返回一个 numpy 数组。如果你需要一个 pythonlistint,只需使用tolist方法,例如:data_in_fxp.raw().tolist()

可以修改舍入和溢出行为,有关更多信息,请访问fxpmath#behaviors


推荐阅读