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傅里叶变换的更多相关文章

  1. 基于傅里叶变换和PyQt4开发一个简单的频率计数器

    小学期的<信号与系统>课,要求写一个频率计数器,下面是我个人理解的频率计数 傅里叶变换的代码: # coding=utf-8 import numpy as np from scipy.i ...

  2. 数字信号处理--Z变换,傅里叶变换,拉普拉斯变换

    傅立叶变换.拉普拉斯变换.Z变换最全攻略 作者:时间:2015-07-19来源:网络       傅立叶变换.拉普拉斯变换.Z变换的联系?他们的本质和区别是什么?为什么要进行这些变换.研究的都是什么? ...

  3. OpenCV基于傅里叶变换进行文本的旋转校正

    傅里叶变换可以用于将图像从时域转换到频域,对于分行的文本,其频率谱上一定会有一定的特征,当图像旋转时,其频谱也会同步旋转,因此找出这个特征的倾角,就可以将图像旋转校正回去. 先来对原始图像进行一下傅里 ...

  4. 傅里叶变换库FFTW的安装配置(VS2010)

    FFTW是用来计算一维或者多维的离散傅里叶变换,输入可以为实数序列也可以为复数序列的C语言的子函数库,FFTW是免费软件,是作为fft函数库的各种应用的上佳选择. 1. 从网站http://www.f ...

  5. FFT教你做乘法(FFT傅里叶变换)

    题目来源:https://biancheng.love/contest/41/problem/C/index FFT教你做乘法 题目描述 给定两个8进制正整数A和B(A和B均小于10000位),请利用 ...

  6. 傅里叶变换:MP3、JPEG和Siri背后的数学

    九年前,当我还坐在学校的物理数学课的课堂里时,我的老师为我们讲授了一种新方法,给我留下了深刻映像.我认为,毫不夸张地说,这是对数学理论发现最广泛的应用.应用的领域包括:量子物理.射电天文学.MP3和J ...

  7. 完全搞懂傅里叶变换和小波(2)——三个中值定理<转载>

    书接上文,本文章是该系列的第二篇,按照总纲中给出的框架,本节介绍三个中值定理,包括它们的证明及几何意义.这三个中值定理是高等数学中非常基础的部分,如果读者对于高数的内容已经非常了解,大可跳过此部分.当 ...

  8. 完全搞懂傅里叶变换和小波(1)——总纲<转载>

    无论是学习信号处理,还是做图像.音视频处理方面的研究,你永远避不开的一个内容,就是傅里叶变换和小波.但是这两个东西其实并不容易弄懂,或者说其实是非常抽象和晦涩的! 完全搞懂傅里叶变换和小波,你至少需要 ...

  9. 【DWT笔记】傅里叶变换与小波变换

    [DWT笔记]傅里叶变换与小波变换 一.前言 我们经常接触到的信号,正弦信号,余弦信号,甚至是复杂的心电图.脑电图.地震波信号都是时域上的信号,我们也成为原始信号,但是通常情况下,我们在原始信号中得到 ...

  10. 【转】傅里叶变换 拉普拉斯变 z变换 DFT DCT意义

    傅里叶变换在物理学.数论.组合数学.信号处理.概率论.统计学.密码学.声学.光学.海洋学.结构动力学等领域都有着广泛的应用(例如在信号处理中,傅里叶变换的典型用途是将信号分解成幅值分量和频率分量). ...

随机推荐

  1. 一键关闭 Win11 系统广告「GitHub 热点速览」

    不知道读者中有多少人早已对 Windows 11 系统自带的广告感到厌烦,却又不知道如何关闭它们? 虽然网上有详细的关闭教程,但是都需要逐一手动操作,不是很方便.所以,今天「GitHub 热点速览」给 ...

  2. homebrew的安装和使用

    目录 背景 安装xcode 安装homebrew 有关报错解决 卸载脚本 homebrew软件搜索 brew 常用命令 brew redis安装 PhpWebStudy安装 安装php 背景 最近用b ...

  3. golang复用http.request.body

    golang复用http.request.body 问题及场景 业务当中有需要分发http.request.body的场景.比如微信回调消息只能指定一个地址,所以期望可以复制一份消息发给其他服务.由服 ...

  4. 使用.NET查询日出日落时间

    在WPF中,通过资源文件实现主题切换是个常见的功能,有不少文章介绍了如何实现手动切换主题.那如何实现自动切换主题呢?通常有两种机制:一是跟随系统明暗主题切换,二是像手机操作系统那样根据日出日落时间自动 ...

  5. 通过 OpenAPI 部署 Npcf_PolicyAuthorization-PostAppSessions API Service

    目录 文章目录 目录 OpenAPI 部署步骤 OpenAPI 官方网站:https://github.com/OAI/OpenAPI-Specification 支持通过标准的 yaml 文件来生成 ...

  6. mybaits-plus实现自定义字典转换

    需求:字典实现类似mybatis-plus中@EnumValue的功能,假设枚举类中应用使用code,数据库存储对应的value 思路:Mybatis支持对Executor.StatementHand ...

  7. .NET 中的表达式树

    .NET 中的表达式树(Expression Trees) 表达式树是什么? 表达式树(Expression Trees)是.NET框架中的一个强大功能,它将代码表示为一个由表达式节点组成的树形结构. ...

  8. 【C#】字符串按条件替换关键字

    private string MyReplace(string json, string keyWord, string newWord, Func<string, string, bool&g ...

  9. WPF加载GIF的五种方式(Storyboard / WpfAnimatedGif / ImageAnimator / PictureBox / MediaElement)

    部分内容参考博文WPF 如何显示gif 一.使用Storyboard 效果: (1)页面xaml: <Window x:Class="PlayGifDemo.StoryboardWin ...

  10. 前端使用 Konva 实现可视化设计器(12)- 连接线 - 直线

    这一章实现的连接线,目前仅支持直线连接,为了能够不影响原有的其它功能,尝试了2.3个实现思路,最终实测这个实现方式目前来说最为合适了. 请大家动动小手,给我一个免费的 Star 吧~ 大家如果发现了 ...