C# pythonnet(2)_傅里叶变换(FFT)
Python代码如下
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt # 读取数据
data = pd.read_csv('clean_data_row.csv')
# 进行傅里叶变换
fft_result = np.fft.fft(data)
frequencies = np.fft.fftfreq(len(data)) # 计算功率谱密度
power_spectrum = np.abs(fft_result)**2 / len(data)
print(len(power_spectrum))
frequencies_positive = frequencies[:len(frequencies)//2] # 绘制频谱图和功率谱密度图
# 频谱图
plt.figure(figsize=(12, 6))
plt.subplot(1, 2, 1)
plt.plot(frequencies, np.abs(fft_result))
plt.xlabel('Frequency (Hz)')
plt.ylabel('Amplitude')
plt.title('Frequency Spectrum')
# 功率谱密度图
plt.subplot(1, 2, 2)
plt.plot(frequencies_positive, power_spectrum[:len(power_spectrum)//2])
plt.xlabel('Frequency (Hz)')
plt.ylabel('Power')
plt.title('Power Spectrum Density') plt.tight_layout()
plt.show()
下面我们修改成C#代码
创建控制台程序,Nuget安装 CsvHelper 和 pythonnet

public class Program
{
const string PathToPythonDir = "D:\\Python311";
const string DllOfPython = "python311.dll"; static void Main(string[] args)
{
// 傅里叶变换
FFT();
}
/// <summary>
/// 傅里叶变换
/// </summary>
static void FFT()
{
try
{
Runtime.PythonDLL = Path.Combine(PathToPythonDir, DllOfPython);
PythonEngine.Initialize();
using (Py.GIL())
{
dynamic pd = Py.Import("pandas");
dynamic np = Py.Import("numpy");
dynamic plt = Py.Import("matplotlib.pyplot");
dynamic fft = Py.Import("scipy.fftpack"); using dynamic scope = Py.CreateScope();
scope.Exec(@"def get_slice(net_array): return net_array[:len(net_array)//2]"); // 读取数据
var data = pd.read_csv("clean_data_row.csv");
int listLength = data.__len__();
Console.WriteLine("读取长度:" + listLength); // 进行傅里叶变换
var fft_result = fft.fft(data); // 对数据进行傅里叶变换
var frequencies = fft.fftfreq(listLength); // 计算功率谱密度
var power_spectrum = np.square(np.abs(fft_result)) / listLength;
var frequencies_positive = scope.get_slice(frequencies); /*
// 如果是api接口,直接返回x轴和y轴数据
double[] xAxis = frequencies.As<double[]>();
PyObject yAxisDatas = np.abs(fft_result);
double[][] yAxis = yAxisDatas.As<dynamic[]>()
.Select(s => (double[])s.As<double[]>())
.ToArray(); double[] xAxis2 = xAxis.Take(listLength / 2).ToArray();
PyObject yAxisDatas2 = power_spectrum;
double[][] yAxis2 = yAxisDatas2.As<dynamic[]>()
.Select(s => (double[])s.As<double[]>())
.Take(listLength / 2)
.ToArray();
*/ // 绘制频谱图和功率谱密度图
plt.figure(figsize: new dynamic[] { 12, 6 }); // 频谱图
plt.subplot(1, 2, 1);
plt.plot(frequencies, np.abs(fft_result));
plt.xlabel("Frequency (Hz)");
plt.ylabel("Amplitude");
plt.title("Frequency Spectrum"); // 功率谱密度图
plt.subplot(1, 2, 2);
plt.plot(frequencies_positive, scope.get_slice(power_spectrum));
plt.xlabel("Frequency (Hz)");
plt.ylabel("Power");
plt.title("Power Spectrum Density"); // 布局调整,防止重叠
plt.tight_layout();
// 显示图表
plt.show();
}
}
catch (Exception e)
{
Console.WriteLine("报错了:" + e.Message + "\r\n" + e.StackTrace);
}
} /// <summary>
/// 读取CSV数据
/// </summary>
/// <param name="filePath">文件路径</param>
/// <returns>文件中数据集合,都是double类型</returns>
static List<double[]> ReadCsvWithCsvHelper(string filePath)
{
using (var reader = new StreamReader(filePath))
using (var csv = new CsvReader(reader, CultureInfo.InvariantCulture))
{
var result = new List<double[]>();
// 如果你的CSV文件有标题行,可以调用ReadHeader来读取它们
csv.Read();
csv.ReadHeader();
while (csv.Read())
{
result.Add(new double[] {
csv.GetField<double>(0),
csv.GetField<double>(1),
csv.GetField<double>(2),
});
}
return result;
}
}
}
以下是运行后结果,

源代码:https://gitee.com/Karl_Albright/csharp-demo/tree/master/PythonnetDemo/PythonnetFFT
这里有人会问,为什么不用 MathNet.Numerics 直接计算,因为计算结果和Python的结果差别太大了,希望有知道为什么的大佬留言,这里我也记录以下实现步骤
创建Windows 窗体应用(WinForm),Nuget安装 CsvHelper、MathNet.Numerics、OxyPlot.Core、OxyPlot.WindowsForms

public partial class Form1 : Form
{
double[] xAxis = new double[0];
double[][] yAxis = new double[0][];
double[] xAxis2 = new double[0];
double[][] yAxis2 = new double[0][];
public Form1()
{
InitializeComponent(); var datas = ReadCsvWithCsvHelper("clean_data_row.csv");
CalcFFT(datas);
DrawPlot();
}
OxyColor[] colors =
[
OxyColors.Blue,
OxyColors.Yellow,
OxyColors.Red,
OxyColors.Green,
OxyColors.Pink,
OxyColors.Black,
OxyColors.Orange,
];
public List<double[]> ReadCsvWithCsvHelper(string filePath)
{
using (var reader = new StreamReader(filePath))
using (var csv = new CsvReader(reader, CultureInfo.InvariantCulture))
{
var result = new List<double[]>();
// 如果你的CSV文件有标题行,可以调用ReadHeader来读取它们
csv.Read();
csv.ReadHeader();
while (csv.Read())
{
result.Add([
csv.GetField<double>(0),
csv.GetField<double>(1),
csv.GetField<double>(2),
]);
}
return result;
}
} public void CalcFFT(List<double[]> datas)
{
var first = datas.First();
yAxis = new double[first.Length][];
yAxis2 = new double[first.Length][];
for (int i = 0; i < first.Length; i++)
{
// 将数据转换为Complex32数组以便进行傅里叶变换
Complex32[] dataComplex = datas.Select(item => new Complex32((float)item[i], 0)).ToArray(); // 进行傅里叶变换
Fourier.Forward(dataComplex, FourierOptions.AsymmetricScaling); var len = dataComplex.Length;
// 计算频率
double[] frequencies = Fourier.FrequencyScale(len, 1); xAxis = frequencies;
yAxis[i] = dataComplex.Select(x => Math.Abs(Math.Round(x.Magnitude, 7))).ToArray(); xAxis2 = frequencies.Take(len / 2).ToArray();
yAxis2[i] = dataComplex.Select(x => Math.Abs(Math.Round((x.Magnitude * x.Magnitude / len), 7))).Take(len / 2).ToArray();
} } public void DrawPlot()
{
// 绘制频谱图和功率谱密度图(这里使用OxyPlot库)
var plotModel = new PlotModel { Title = "Spectrum Analysis" }; // 频谱图
int xAxisLength = xAxis.Length;
int yAxisLength = yAxis.Length; for (int i = 0; i < yAxisLength; i++)
{
var frequencySeries = new LineSeries
{
Title = "Item" + (i + 1),
MarkerType = MarkerType.None,
Color = colors[i]
};
for (int j = 0; j < xAxisLength; j++)
{
frequencySeries.Points.Add(new DataPoint(xAxis[j], yAxis[i][j]));
}
plotModel.Series.Add(frequencySeries);
}
plotModel.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Title = "Frequency (Hz)" });
plotModel.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Title = "Amplitude" });
this.plotView1.Model = plotModel; var plotModel2 = new PlotModel { Title = "Power Spectrum Density" };
// 功率谱密度图
int xAxis2Length = xAxis2.Length;
int yAxis2Length = yAxis2.Length; for (int i = 0; i < yAxis2Length; i++)
{
var powerSeries = new LineSeries
{
Title = "Item" + (i + 1),
MarkerType = MarkerType.None,
Color = colors[i]
};
for (int j = 0; j < xAxis2Length; j++)
{
powerSeries.Points.Add(new DataPoint(xAxis2[j], yAxis2[i][j]));
}
plotModel2.Series.Add(powerSeries);
} plotModel2.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Title = "Frequency (Hz)" });
plotModel2.Axes.Add(new LinearAxis { Position = AxisPosition.Right, Title = "Power" });
this.plotView2.Model = plotModel2;
}
}

源代码:https://gitee.com/Karl_Albright/csharp-demo/tree/master/PythonnetDemo/PythonnetFFTWinFormsApp
C# pythonnet(2)_傅里叶变换(FFT)的更多相关文章
- 快速傅里叶变换(FFT)_转载
FFTFFT·Fast Fourier TransformationFast Fourier Transformation快速傅立叶变换 P3803 [模板]多项式乘法(FFT) 参考上文 首 ...
- 快速傅里叶变换FFT
多项式乘法 #include <cstdio> #include <cmath> #include <algorithm> #include <cstdlib ...
- [学习笔记] 多项式与快速傅里叶变换(FFT)基础
引入 可能有不少OIer都知道FFT这个神奇的算法, 通过一系列玄学的变化就可以在 $O(nlog(n))$ 的总时间复杂度内计算出两个向量的卷积, 而代码量却非常小. 博主一年半前曾经因COGS的一 ...
- 快速傅里叶变换FFT& 数论变换NTT
相关知识 时间域上的函数f(t)经过傅里叶变换(Fourier Transform)变成频率域上的F(w),也就是用一些不同频率正弦曲线的加 权叠加得到时间域上的信号. \[ F(\omega)=\m ...
- 浅谈范德蒙德(Vandermonde)方阵的逆矩阵的求法以及快速傅里叶变换(FFT)中IDFT的原理
浅谈范德蒙德(Vandermonde)方阵的逆矩阵与拉格朗日(Lagrange)插值的关系以及快速傅里叶变换(FFT)中IDFT的原理 标签: 行列式 矩阵 线性代数 FFT 拉格朗日插值 只要稍微看 ...
- 快速傅里叶变换(FFT)学习笔记
定义 多项式 系数表示法 设\(A(x)\)表示一个\(n-1\)次多项式,则所有项的系数组成的\(n\)维向量\((a_0,a_1,a_2,\dots,a_{n-1})\)唯一确定了这个多项式. 即 ...
- Algorithm: 多项式乘法 Polynomial Multiplication: 快速傅里叶变换 FFT / 快速数论变换 NTT
Intro: 本篇博客将会从朴素乘法讲起,经过分治乘法,到达FFT和NTT 旨在能够让读者(也让自己)充分理解其思想 模板题入口:洛谷 P3803 [模板]多项式乘法(FFT) 朴素乘法 约定:两个多 ...
- 再探快速傅里叶变换(FFT)学习笔记(其三)(循环卷积的Bluestein算法+分治FFT+FFT的优化+任意模数NTT)
再探快速傅里叶变换(FFT)学习笔记(其三)(循环卷积的Bluestein算法+分治FFT+FFT的优化+任意模数NTT) 目录 再探快速傅里叶变换(FFT)学习笔记(其三)(循环卷积的Blueste ...
- 多项式 之 快速傅里叶变换(FFT)/数论变换(NTT)/常用套路【入门】
原文链接https://www.cnblogs.com/zhouzhendong/p/Fast-Fourier-Transform.html 多项式 之 快速傅里叶变换(FFT)/数论变换(NTT)/ ...
- 快速傅里叶变换(FFT)
扯 去北京学习的时候才系统的学习了一下卷积,当时整理了这个笔记的大部分.后来就一直放着忘了写完.直到今天都腊月二十八了,才想起来还有个FFT的笔记没整完呢.整理完这个我就假装今年的任务全都over了吧 ...
随机推荐
- Pinpoint对k8s关键业务模块进行全链路监控(17)
一.全链路监控概述 1.1 什么是全链路监控 在分布式微服务架构中,系统为了接收并处理一个前端用户请求,需要让多个微服务应用协同工作,其中 的每一个微服务应用都可以用不同的编程语言构建,由不同的团队开 ...
- 云原生最佳实践系列 6:MSE 云原生网关使用 JWT 进行认证鉴权
01 方案概述 MSE 网关可以为后端服务提供转发路由能力,在此基础上,一些敏感的后端服务需要特定认证授权的用户才能够访问.MSE 云原生网关致力于提供给云上用户体系化的安全解决方案,其中 JWT 认 ...
- 函数编程:强大的 Stream API
函数编程:强大的 Stream API 每博一文案 只要有人的地方,世界就不会是冰冷的,我们可以平凡,但绝对不可以平庸. ------ <平凡的世界> 人活着,就得随时准备经受磨难.他已经 ...
- C#.NET体系图文概述—2024最全总结
C# 是一种简单.现代.面向对象和类型安全的编程语言.. .NET 是由 Microsoft 创建的开发平台,平台包含了语言规范.工具.运行,支持开发各种应用,如Web.移动.桌面等..NET框架有多 ...
- 04. rails入门学习 创建控制器
学习视频 https://www.bilibili.com/video/BV1RJ411W7N3?t=49&p=7 一. 启动rails 启动 cd circles/ #到circles的项目 ...
- WordPress对url做重定向处理
在一个网站进行改版滞后,可能会产生大量的错误的urls,我们想让这些urls还是存在的,并跳转到新的url,此时就要做301重定向. 针对wordpress做重定向,一般推荐使用redirection ...
- DB2 关联更新
update GIS_TER_ADDRESS_MSG set (POS_X,POS_Y)=(select LAT,LON from TEMP_ATM where GIS_TER_ADDRESS_MSG ...
- 鸿蒙stage模型
app.json5全局的配置文件 icon和label是应用列表的 module.json5模块配置文件 中有一个abilities其中的icon和label才是桌面的图标和名称 日志的话就是hail ...
- 第二届黄河流域网络安全技能挑战赛Web_wirteup
前言 好久没写过比赛的wp了,黄河流域的web出的不错,挺有意思了,花了点时间,也是成功的ak了 myfavorPython 注册登录,一个base64输入框,猜测pickle反序列化,简单测试下,返 ...
- C语言:Hello Word(梦开始的地方)
#include <stdio.h>//标准输入输出头文件,下面的printf打印的函数包含在这个头文件里面 int main() { printf("Hello Word!&q ...