我在这里看到了下面的代码,但是如果将其绘制并缩放,则频率峰值并不完全在50Hz和80Hz上;他们有点偏离。有人知道为什么会这样吗?如何使峰值恰好在50Hz和80Hz?
struct PurchaseTotals: Codable {
var sumTotal: Double?
var animal: String?
var name: String?
lazy var formattedsumTotal: String? = {
if let sumTotal = sumTotal {
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
let str = formatter.string(from: NSNumber(value: sumTotal))
return str
}
return nil
}()
}
class TableViewController: UITableViewController {
var structure = [PurchaseTotals]() {
didSet {
dataSource = structure.filter({ $0.sumTotal == nil })
self.tableView.reloadData()
}
}
var dataSource = [PurchaseTotals]()
override func viewDidLoad() {
super.viewDidLoad()
let str = """
[{"name":"Jake","animal":"dog"},{"name":"Mary","animal":"cat"},{"sumTotal":100}]
"""
if let data = str.data(using: .utf8) {
do {
structure = try JSONDecoder().decode([PurchaseTotals].self, from: data)
} catch {
print(error)
}
}
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return dataSource.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = dataSource[indexPath.row].name
return cell
}
}
答案 0 :(得分:2)
这是一个简单的近似误差,原因是xf
不采用值50
和/或80
。如果您更改了N
和/或linspace()
参数,则可以使xf
精确地在50
和80
处采样,那里没有峰位移:
import numpy as np
import matplotlib.pyplot as plt
import scipy.fftpack
# Number of samplepoints
N = 80
# sample spacing
T = 1.0 / 800.0
x = np.linspace(0.0, N*T, N)
y = np.sin(50.0 * 2.0*np.pi*x) + 0.5*np.sin(80.0 * 2.0*np.pi*x)
yf = scipy.fftpack.fft(y)
xf = np.linspace(0.0, 1.0/(2.0*T), N//2 + 1)
fig, ax = plt.subplots(figsize=(10, 10))
ax.plot(xf, 2.0/N * np.abs(yf[:N//2 + 1]))
ax.plot([50, 50], [0, 1])
ax.plot([80, 80], [0, 1])
plt.show()
与xf
:
[ 0. 10. 20. 30. 40. 50. 60. 70. 80. 90. 100. 110. 120. 130.
140. 150. 160. 170. 180. 190. 200. 210. 220. 230. 240. 250. 260. 270.
280. 290. 300. 310. 320. 330. 340. 350. 360. 370. 380. 390. 400.]
答案 1 :(得分:0)
如果正弦波在FFT长度内正好是整数周期,则纯的未调制正弦波的频率仅显示为单个FFT bin峰结果。
否则,如果频率甚至与FFT的周期基矢量稍有不同,则将出现开窗伪像,有时称为“泄漏”。
如果您希望非插值FFT峰值幅度恰好位于信号频率上,则必须将FFT的长度更改为信号周期的精确整数倍(或更改您的信号周期信号频率)。
答案 2 :(得分:0)
尽管事实已经有例外的答案:
如果需要知道峰值的精确频率,可以使用简单的方法来尝试不降低采样率。如果您不知道要测量的频率,该怎么办。因此,这不是显示问题的答案,而是“现实生活”检测问题的答案。假设其他峰“相距较远”,则有一种使用高斯窗的简单方法。在对数刻度上,峰将呈抛物线形状,因此三个最高点仅提供最大值的真实位置。这可以在一个仅求解一个线性方程的简单程序中进行转换。这是我用于分析光谱的课程的一部分:
def get_base_frequency( self ):
"""
uses the fact that the fourier of a gaussion is a gaussian.
folding the virtual deltapeak of a frequency results in a gaussian.
taking the log and looking at two consecutive bins, preferably near the maximum,
allows to calculate the position of the maximum, i.e. the frequency
(square terms of the gaussians cancel and a linear equation is solved)
"""
sigma = self.wavePoints / 8.0 ##my choice ... seems to work well
tau = self.wavePoints / ( 2.0 * np.pi * sigma )
pf, ps = self.spectrum_single_sided( windowType=[ 'Gaussian', sigma ] )
### fft providing freqency and spectral data
n = np.argmax( ps ) - 1
slg = tau**2 * np.log( ps[ n + 1 ] / ps[ n ] )
better = slg + n + 0.5
return better * self.sampleRate / self.wavePoints
就是这样。
如果需要峰值高度,我建议使用平顶窗进行第二次英尺测量。