main.lua 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. -- LuaTools 需要 PROJECT 和 VERSION
  2. PROJECT = "fft_q15_test"
  3. VERSION = "1.0.0"
  4. _G.sys = require("sys")
  5. sys.taskInit(function()
  6. if not fft then
  7. while 1 do sys.wait(1000) log.info("bsp", "此BSP不支持fft库,请检查") end
  8. end
  9. -- FFT 参数配置
  10. local N = 2048 -- FFT 点数
  11. local fs = 2000 -- 采样频率 (Hz)
  12. local freq = 200 -- 测试信号频率 (Hz)
  13. log.info("fft", "q15 测试开始", "N=" .. N, "fs=" .. fs, "freq=" .. freq)
  14. -- 分配 zbuff:
  15. -- 整数缓冲(U12 以 16bit 承载,低12位有效)用于 q15 内核
  16. local real_i16 = zbuff.create(N * 2)
  17. local imag_i16 = zbuff.create(N * 2)
  18. -- 生成 U12 整数正弦写入 i16(避免浮点预处理干扰)
  19. for i = 0, N - 1 do
  20. local t = i / fs
  21. local x = math.sin(2 * math.pi * freq * t)
  22. local val = math.floor(2048 + 2047 * x + 0.5)
  23. if val < 0 then val = 0 end
  24. if val > 4095 then val = 4095 end
  25. real_i16:seek(i * 2, zbuff.SEEK_SET); real_i16:writeU16(val)
  26. imag_i16:seek(i * 2, zbuff.SEEK_SET); imag_i16:writeU16(0)
  27. end
  28. -- 生成 Q15 旋转因子到 zbuff(避免任何浮点旋转因子)
  29. local Wc_q15 = zbuff.create((N // 2) * 2)
  30. local Ws_q15 = zbuff.create((N // 2) * 2)
  31. fft.generate_twiddles_q15_to_zbuff(N, Wc_q15, Ws_q15)
  32. -- 执行 Q15 FFT(输入为 U12),显式传入 Q15 twiddle
  33. local t0 = mcu.ticks()
  34. fft.run(real_i16, imag_i16, N, Wc_q15, Ws_q15, { core = "q15", input_format = "u12" })
  35. local t1 = mcu.ticks()
  36. log.info("fft", "q15 FFT 完成", "耗时:" .. (t1 - t0) .. "ms")
  37. -- 扫描前半谱,寻找主峰
  38. local peak_k, peak_pow = 1, -1
  39. for k = 1, (N // 2) - 1 do
  40. real_i16:seek(k * 2, zbuff.SEEK_SET)
  41. imag_i16:seek(k * 2, zbuff.SEEK_SET)
  42. local rr = real_i16:readI16()
  43. local ii = imag_i16:readI16()
  44. local p = rr * rr + ii * ii
  45. if p > peak_pow then
  46. peak_pow = p
  47. peak_k = k
  48. end
  49. end
  50. local peak_freq = (peak_k) * fs / N
  51. log.info("fft", "主峰(Hz/bin)", string.format("%.2f", peak_freq), peak_k)
  52. -- 比较:使用 f32 内核处理相同输入(验证 q15 与 f32 结果一致性)
  53. -- 复制相同的 U12 输入到新的 zbuff
  54. local real_f32 = zbuff.create(N * 4) -- f32 需要 4 字节
  55. local imag_f32 = zbuff.create(N * 4)
  56. for i = 0, N - 1 do
  57. real_i16:seek(i * 2, zbuff.SEEK_SET)
  58. local val = real_i16:readU16()
  59. real_f32:seek(i * 4, zbuff.SEEK_SET)
  60. imag_f32:seek(i * 4, zbuff.SEEK_SET)
  61. real_f32:writeF32(val) -- 直接写入 U12 原始值
  62. imag_f32:writeF32(0.0)
  63. end
  64. -- 生成 f32 旋转因子
  65. local Wc, Ws = fft.generate_twiddles(N)
  66. -- 执行 f32 FFT(输入为 U12)
  67. local t2 = mcu.ticks()
  68. fft.run(real_f32, imag_f32, N, Wc, Ws, { input_format = "u12" })
  69. local t3 = mcu.ticks()
  70. local dt_f32 = (t3 - t2)
  71. log.info("fft", "f32 FFT 完成", "耗时:" .. dt_f32 .. "ms")
  72. -- 总结耗时对比
  73. log.info("fft", "对比(q15 vs f32, ms)", string.format("%d / %d", (t1 - t0), dt_f32))
  74. -- 注意:本测试刻意避免浮点旋转因子与f32路径,确保纯Q15链路
  75. end)
  76. sys.run()