//line = N/2.56 /// <summary> /// range of f : -Line*df ~ Line*df where df = Fs/length /// </summary> /// <param name="f">frequency 배열. length: 2*line + 1</param> /// <param name="y">스펙트럼값 배열. length: 2*line + 1</param> /// <param name="Fs"></param> public static void FullSpectrum_RMS(data_type[] x1, data_type[] x2, double[] f, double[] y, double Fs, Unit2Type Unit2Type, WindowFunction windowFunc)//length = 2^m, the length of h and x = length, the length of f and y = length/2 { int length = x1.Length; int i; double sum, rms; int k1, k2, N, half_length; var XH = new Complex[65536]; double scale_rms_vec; int line, count; var h = GetWindow(windowFunc, length); line = (int)Math.Round((double)length / 2.56); if (length != length_saved) { df = Fs / ((double)length); scale = 0.0; for (i = 0; i < length; i++) { scale = scale + h[i] * h[i]; } scale = ((double)length) * scale; scale = 1.0 / scale; length_saved = length; } // k1 = floor(f1/df) - 1; // k2 = ceil(f2/df) + 1; half_length = length >> 1; // if(k1 < 0) // k1 = 0; // else if(k1 > half_length) // k1 = half_length; // // if(k2 < 0) // k2 = 0; // else if(k2 > half_length) // k2 = half_length; for (i = 0; i < length; i++) { XH[i].Real = (data_type)(h[i] * x1[i]); XH[i].Imag = (data_type)(h[i] * x2[i]); } N = (int)Math.Round(Math.Log10((double)length) / Math.Log10(2.0)); FFT(XH, N); //RMS scalar generation // sum = 0.0; // for(i = k1; i <= k2; i++) // { // sum = sum + XH[i].real*XH[i].real + XH[i].imag*XH[i].imag; // } // // rms = sqrt(scale*2.0*sum); //RMS vector generation scale = 0.0; for (i = 0; i < length; i++) { scale = scale + h[i]; } scale = 1.0 / 1.414214 / (scale); switch (Unit2Type) { case Unit2Type.pk: scale = scale * 1.414213; break; case Unit2Type.pp: scale = scale * 2.828427; break; default: break; } count = 0; for (i = -line; i <= line; i++) { f[count] = df * ((double)i); count++; } count = 0; for (i = length - line; i <= length - 1; i++) { y[count] = scale * Math.Sqrt(XH[i].Real * XH[i].Real + XH[i].Imag * XH[i].Imag); count++; } for (i = 0; i <= line; i++) { y[count] = scale * Math.Sqrt(XH[i].Real * XH[i].Real + XH[i].Imag * XH[i].Imag); count++; } }
internal static double GetBandpass(float[] timeData, double maxFrequency, WindowFunction windowType, Unit2Type unitType /*무시*/, double bandLow, double bandHigh, RobinIntegralType integralType) { double result = 0.0f; int dataSize = timeData.Length; // Sampling Rate와 데이터 개수 계산 float maxFreq = (float)maxFrequency; float srate = (float)(maxFreq * 2.56); int _size = dataSize; // Time 데이터 버퍼 var fftdata = new double[_size]; for (int index = 0; index < _size; index++) { fftdata[index] = timeData[index]; } // FFT 결과 데이터 버퍼 var fftresult = new double[_size]; double deltaf = srate / _size; // DSP의 autospectrum_d 함수 호출 #if false // nadamath 알고리즘 result = nadaMath.autospectrum_d(ref fftdata[0], (int)(Math.Log(_size, 2)), ref fftresult[0], (int)(windowType), (int)Unit2Type.rms, // (int)unitType, rms가 default임 bandLow, bandHigh, deltaf, 0, 0); #else //CXII 알고리즘 //result = CmsMath.autospectrum_d(fftdata, // (int)(Math.Log(_size, 2)), // fftresult, // windowType, // Unit2Type.rms, // (int)unitType, rms가 default임 // bandLow, // bandHigh, // deltaf, // 0, // 0); result = CmsMath.autospectrum_cxii(fftdata, (int)(Math.Log(_size, 2)), fftresult, (int)(windowType), (int)Unit2Type.rms, // (int)unitType, rms가 default임 bandLow, bandHigh, deltaf, 0, 0, srate); #endif if (integralType != RobinIntegralType.None) { double[] window = new double[_size]; double factor = 8.0 * Math.Atan(1.0) / (_size - 1); for (int i = 0; i < _size; i++) { window[i] = 0.5 - 0.5 * Math.Cos(factor * i); } double WinScale = 0; for (int i = 0; i < _size; i++) { WinScale += window[i]; } double WinScale2 = 0; for (int i = 0; i < _size; i++) { WinScale2 += (window[i] * window[i]); } double rms = 0.0; int length = (int)(_size / 2.56); double freq, omega, tempResult; for (int i = 0; i < length; i++) { freq = i * deltaf; omega = 2 * 4 * Math.Atan(1) * freq; if (0 == i) { fftresult[i] = 0; } else { fftresult[i] = (float)(fftresult[i] * 9.80665f * 1000.0f / omega); } if (integralType == RobinIntegralType.Double) { if (0 == i) { fftresult[i] = 0; } else { fftresult[i] = (float)(fftresult[i] * 1000.0f / omega); /// [김보근] /// 변위인 경우 rms --> peak --> peak to peak로 변환하기 위해서 fft 결과 데이터에 루트 2로 나누고 2를 곱해줌 /// fftresult[i] = fftresult[i] / sqrt(2.0) * 2.0 fftresult[i] = (float)(fftresult[i] / Math.Sqrt(2.0) * 2.0); //////////////////////////////////////////////////////////////////////////////////////////////////////////// } } if ((bandLow <= freq) && (freq <= bandHigh)) { tempResult = fftresult[i] * fftresult[i]; tempResult *= (WinScale * WinScale) / (_size * WinScale2); rms += tempResult; } } result = Math.Sqrt(rms); } return(result); }
//static UnmanagedLibrary vibecDll; //[UnmanagedFunctionPointer(CallingConvention.Winapi)] //delegate Real BPF_RMSFunc(Real[] asyncData, int length, Real[] f, Real[] y, Real f1, Real f2, Real fs); //static BPF_RMSFunc pfBPF_RMS; //public static double BPF_RMS(data_type[] x, double[] f, double[] y, double f1, double f2, double Fs)//length = 2^m, the length of h and x = length, the length of f and y = length/2 //{ // if (vibecDll == null) // { // vibecDll = new UnmanagedLibrary("VibeC.dll"); // pfBPF_RMS = vibecDll.GetUnmanagedFunction<BPF_RMSFunc>("BPF_RMS"); // } // var tempf = new data_type[f.Length]; // var tempy = new data_type[y.Length]; // var result = pfBPF_RMS(x, x.Length, tempf, tempy, (data_type)f1, (data_type)f2, (data_type)Fs); // for (int i = 0; i < f.Length; i++) // { // f[i] = tempf[i]; // y[i] = tempy[i]; // } // return result; //} // //x:async데이타 , f:주파수 length/2개 얻음, y 주파수별 rms, f1: band low 주파수 시작점(Hz), f2: band high주파수 시작점(Hz), Fs: 보드 샘플링 레이트 ////plot f, y 하면 바로 스펙트럼 public static double BPF_RMS(data_type[] x, double[] f, double[] y, double f1, double f2, double Fs, Unit2Type Unit2Type, WindowFunction windowFunc)//length = 2^m, the length of h and x = length, the length of f and y = length/2 { int length = x.Length; int i; double df, sum, rms; int k1, k2, N, half_length; var XH = new Complex[65536]; double scale; //var h = Hann(x.Length); var h = GetWindow(windowFunc, x.Length); df = Fs / ((double)length); k1 = (int)Math.Floor(f1 / df) - 1; k2 = (int)Math.Ceiling(f2 / df) + 1; half_length = length >> 1; scale = 0.0; for (i = 0; i < length; i++) { scale = scale + h[i] * h[i]; } scale = ((double)length) * scale; scale = 1.0 / scale; if (k1 < 0) { k1 = 0; } else if (k1 > half_length) { k1 = half_length; } if (k2 < 0) { k2 = 0; } else if (k2 > half_length) { k2 = half_length; } for (i = 0; i < length; i++) { XH[i].Real = (data_type)(h[i] * x[i]); XH[i].Imag = 0.0f; } N = (int)Math.Round(Math.Log10((double)length) / Math.Log10(2.0)); FFT(XH, N); //RMS scalar generation sum = 0.0; for (i = k1; i <= k2; i++) { sum = sum + XH[i].Real * XH[i].Real + XH[i].Imag * XH[i].Imag; } rms = Math.Sqrt(scale * 2.0 * sum); //RMS vector generation scale = 0.0; for (i = 0; i < length; i++) { scale = scale + h[i]; } scale = 1.414214 / scale; //*((double)length); switch (Unit2Type) { case Unit2Type.pk: scale = scale * 1.414213; break; case Unit2Type.pp: scale = scale * 2.828427; break; default: break; } for (i = 0; i < half_length; i++) { f[i] = df * ((double)i); y[i] = scale * Math.Sqrt(XH[i].Real * XH[i].Real + XH[i].Imag * XH[i].Imag); } RMS = rms; return(rms); }