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了吧 ...
随机推荐
- 剪贴板被占用导致应用使用剪贴板拷贝内容失败抛出 COMException 0x800401D0 错误
本文记录某些软件,例如 向日葵远程控制 软件占用剪贴板,导致 WPF 应用使用剪贴板拷贝内容和设置剪贴板时,抛出 System.Runtime.InteropServices.COMException ...
- ESP32 多线程入门实验
一.线程创建函数 函数 void xTaskCreate ( pdTASK_CODE pvTaskCode, const portCHAR * const pcNane, unsigned portS ...
- C++多态与虚拟:Objects 实例化(Objects Instantiation)探究
一.Objects的创建 依据已有的class CPoint ,我们可以产生一个或多个object(对象),或者说是产生一个instance(实体): CPoint aPoint(7.2); // a ...
- vue使用echart(地图,弹窗展示多条数据,option定义)
第二次用echart,第一次做地图, <template> <div class="echarts" style="background:#3bafde ...
- Kimi:文本解析利器,你相信光么?
缘起 第一次接触 kimi 是在微信群,开始以为是推广薅羊毛产品,后来在其他渠道也了解到 kimi,据说是"国产之光".我知道很多同学苦不能使用魔法久矣,索性就先踩踩这个" ...
- video2blog 视频转图文AI小工具正式开源啦
前言 最近对一些小细节做了很多处理,但是其实还是有非常多的问题,没办法时间毕竟时间有限.为什么在这个时候开源,因为主要功能可以全部跑通了,分支暂时没开发的功能也可以通过其他的工具来替代. 这个工具开发 ...
- Vue cli之单文件组件
组件有两种:脚本化组件.单文件组件 脚本化组件的缺点: html代码是作为js的字符串进行编写,所以组装和开发的时候不易理解,而且没有高亮效果. 脚本化组件用在小项目中非常合适,但是复杂的大项目中,如 ...
- C#实现的一个图片切割工具
效果如图: 工具代码: using System.Drawing; using System.Drawing.Imaging; class ImageCutterConfig { /// <su ...
- LLM 大模型学习必知必会系列(八):10分钟微调专属于自己的大模型
LLM 大模型学习必知必会系列(八):10分钟微调专属于自己的大模型 1.环境安装 # 设置pip全局镜像 (加速下载) pip config set global.index-url https:/ ...
- 【译】使用 .NET Aspire 和 Visual Studio 开发云原生应用
我们很高兴地向大家介绍 .NET Aspire,它旨在简化 .NET 云原生应用程序的构建和管理方式..NET Aspire 为像您这样的开发人员提供了一个改进的.有主见的框架,用于构建分布式应用程序 ...