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

 

posted @ 2024-06-24 17:17  Karl_Albright  阅读(108)  评论(0编辑  收藏  举报