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傅里叶变换的更多相关文章
- 基于傅里叶变换和PyQt4开发一个简单的频率计数器
小学期的<信号与系统>课,要求写一个频率计数器,下面是我个人理解的频率计数 傅里叶变换的代码: # coding=utf-8 import numpy as np from scipy.i ...
- 数字信号处理--Z变换,傅里叶变换,拉普拉斯变换
傅立叶变换.拉普拉斯变换.Z变换最全攻略 作者:时间:2015-07-19来源:网络 傅立叶变换.拉普拉斯变换.Z变换的联系?他们的本质和区别是什么?为什么要进行这些变换.研究的都是什么? ...
- OpenCV基于傅里叶变换进行文本的旋转校正
傅里叶变换可以用于将图像从时域转换到频域,对于分行的文本,其频率谱上一定会有一定的特征,当图像旋转时,其频谱也会同步旋转,因此找出这个特征的倾角,就可以将图像旋转校正回去. 先来对原始图像进行一下傅里 ...
- 傅里叶变换库FFTW的安装配置(VS2010)
FFTW是用来计算一维或者多维的离散傅里叶变换,输入可以为实数序列也可以为复数序列的C语言的子函数库,FFTW是免费软件,是作为fft函数库的各种应用的上佳选择. 1. 从网站http://www.f ...
- FFT教你做乘法(FFT傅里叶变换)
题目来源:https://biancheng.love/contest/41/problem/C/index FFT教你做乘法 题目描述 给定两个8进制正整数A和B(A和B均小于10000位),请利用 ...
- 傅里叶变换:MP3、JPEG和Siri背后的数学
九年前,当我还坐在学校的物理数学课的课堂里时,我的老师为我们讲授了一种新方法,给我留下了深刻映像.我认为,毫不夸张地说,这是对数学理论发现最广泛的应用.应用的领域包括:量子物理.射电天文学.MP3和J ...
- 完全搞懂傅里叶变换和小波(2)——三个中值定理<转载>
书接上文,本文章是该系列的第二篇,按照总纲中给出的框架,本节介绍三个中值定理,包括它们的证明及几何意义.这三个中值定理是高等数学中非常基础的部分,如果读者对于高数的内容已经非常了解,大可跳过此部分.当 ...
- 完全搞懂傅里叶变换和小波(1)——总纲<转载>
无论是学习信号处理,还是做图像.音视频处理方面的研究,你永远避不开的一个内容,就是傅里叶变换和小波.但是这两个东西其实并不容易弄懂,或者说其实是非常抽象和晦涩的! 完全搞懂傅里叶变换和小波,你至少需要 ...
- 【DWT笔记】傅里叶变换与小波变换
[DWT笔记]傅里叶变换与小波变换 一.前言 我们经常接触到的信号,正弦信号,余弦信号,甚至是复杂的心电图.脑电图.地震波信号都是时域上的信号,我们也成为原始信号,但是通常情况下,我们在原始信号中得到 ...
- 【转】傅里叶变换 拉普拉斯变 z变换 DFT DCT意义
傅里叶变换在物理学.数论.组合数学.信号处理.概率论.统计学.密码学.声学.光学.海洋学.结构动力学等领域都有着广泛的应用(例如在信号处理中,傅里叶变换的典型用途是将信号分解成幅值分量和频率分量). ...
随机推荐
- 对象存储服务的Lambda特性
AWS S3提供了Lambda服务,详见Amazon S3 Object Lambda. 技术方案 作为兼容AWS S3能力的对象存储服务,交付Lambda特性时,关注点有: 实现方式 SDK 独立进 ...
- postman使用中问题汇总
当用postman来通过接口造数据时,读取参数化文件中身份证字段的值读取错误. 参数文件如下 选择参数文件后预览的数据如下 身份证号码全部变成了0000结尾的 解决方案: 需要将身份证号码用引号引起来 ...
- java引入jep实现四则运算包含负数且规范两位小数
1.在pom中引入依赖 <!--四则运算--> <dependency> <groupId>jep</groupId> <artifactId&g ...
- pde复习笔记 第一章 波动方程 第三节 分离变量法
教材 谷超豪<数学物理方程>第四版,虽然我们老师用的第三版,但是除了页码对不上,习题多了一点,也似乎没有多少区别. 打算开个新栏专门总结一下pde的各种计算问题,在图书馆算的手麻了,但是习 ...
- 【web安全】修改和配置tomcat版本信息
场景 目前网络安全的越来越受重视,tomcat作为重要的web容器被广泛应用,如何隐藏信息保证.在开放网络世界中,不易被攻击. 操作思路 1.进入Tomcat文件中的lib文件夹,将catalina. ...
- 案例-java贪吃蛇(附源码)
创建屏幕 开始游戏的窗口,首先引入窗口,然后在窗口画布上进行添加各类动画. JFrame frame=new JFrame("My SnakeGame"); Jframe 是个类, ...
- C语言:将txt文件的单词导入链表&&删除链表重复单词
文章目录 前言 主要分为两个实现部分,按个人需求浏览 首先明确几个任务 先过一遍如何操作的流程. ①全局变量和结构体代码部分 ②实现:将文件单词导入链表 a: 寻找txt文件中最长单词的函数 b: 导 ...
- IDEA 2020 版配置VUE
找到IDE工具栏,就是启动项目的run那里 点击下拉框,找到Eidt Confiuration,选择 选择小加号 选取npm 设置npm页,完成后,点击apply run npm ,如图选择run或者 ...
- 5GC 关键技术之 SBA(基于服务的软件架构)
目录 文章目录 目录 前文列表 5GC 的关键技术 SBA(基于服务的软件架构) 微服务架构 NF 的模块化 NF Service 的服务化 前文列表 <简述移动通信网络的演进之路> &l ...
- 4G EPS 中的随机接入
目录 文章目录 目录 前文列表 UE 的随机接入 基于竞争的随机接入流程 基于非竞争的随机接入流程 PRACH(物理随机接入信道) 上行 TA(时间提前量) 前文列表 <4G EPS 中的小区搜 ...