Select Git revision
spectra.cs 6.29 KiB
using System;
using System.Runtime.InteropServices;
namespace Kiss
{
/// <summary>
/// This Class holds an impedance spectra and provides various transformations that are required to get the values into a form expected by kiss networks
/// </summary>
public class Spectra
{
/// <summary>
/// The real part of the spectra
/// </summary>
public float[] Real;
/// <summary>
/// The imaginary part of the spectra
/// </summary>
public float[] Imaginary;
/// <summary>
/// The frequencys of the datapoints of the spectra
/// </summary>
public float[] Omega;
/// <summary>
/// This constructor constructs a spectra from a series of arrays
/// </summary>
/// <param name="Real">
/// The real part of the spectra
/// </param>
/// <param name="Imaginary">
/// The imaginary part of the spectra, its length must be the same as <paramref name="Real"/>
/// </param>
/// <param name="Omega">
/// The frequency values in rad/s of eatch datapoint, its lenght must be the same as <paramref name="Real"/>
/// </param>
/// <exception cref="Kiss.EnviromentException">
/// Thrown if the enviroment is unacceptable for the operation of this libaray
/// </exception>
public Spectra(float[] Real, float[] Imaginary, float[] Omega)
{
Utils.CheckEnvThrow();
if(Real.Length != Imaginary.Length || Real.Length != Omega.Length)
throw new ArgumentException("the real, imaginary and omega parts of the spectra have to be of the same size");
this.Real = Real;
this.Imaginary = Imaginary;
this.Omega = Omega;
}
/// <summary>
/// This constructor constructs a spectra from a series of arrays
/// </summary>
/// <param name="Real">
/// The real part of the spectra
/// </param>
/// <param name="Imaginary">
/// The imaginary part of the spectra, its length must be the same as <paramref name="Real"/>
/// </param>
/// <param name="Omega">
/// The frequency values in rad/s of eatch datapoint, its lenght must be the same as <paramref name="Real"/>
/// </param>
public Spectra(double[] Real, double[] Imaginary, double[] Omega)
{
if(Real.Length != Imaginary.Length || Real.Length != Omega.Length)
throw new ArgumentException("the real, imaginary and omega parts of the spectra have to be of the same size");
this.Real = DoubleToFloat(Real);
this.Imaginary = DoubleToFloat(Imaginary);
this.Omega = DoubleToFloat(Omega);
}
/// <summary>
/// This method normalizes the data into the range [0, 1]
/// </summary>
public void Normalize()
{
Capi.kiss_normalize_spectra(Real, Imaginary, (UIntPtr)Real.Length);
}
/// <summary>
/// This method resamples the spectra to the size given in newSize.
/// Upsampling is achived via linear interpolation, downsampling is achived via the nearest-neighbor method.
/// </summary>
/// <param name="newSize">
/// The size to resample the spectra to
/// </param>
public void Resample(int newSize)
{
var ret_ptr_real = new IntPtr();
var ret_ptr_imag = new IntPtr();
Capi.kiss_resample_spectra(Real, Imaginary, (UIntPtr)Real.Length, ref ret_ptr_real, ref ret_ptr_imag, (UIntPtr)newSize);
Real = new float[newSize];
Imaginary = new float[newSize];
Marshal.Copy(ret_ptr_real, Real, 0, newSize);
Marshal.Copy(ret_ptr_imag, Imaginary, 0, newSize);
Capi.free(ret_ptr_real);
Capi.free(ret_ptr_imag);
}
/// <summary>
/// Approximate the element wise absolute gradient at the given point of the sepctra in the place given
/// </summary>
/// <param name="index">
/// The index at which to aproxmiate the gradiant
/// </param>
/// <returns>
/// The element wise absolute of the gradiant as a tuple of floats
/// </returns>
public Tuple<float, float> Absgrad(int index)
{
var resultArray = new float[2];
IntPtr ptr = Capi.kiss_absgrad(Real, Imaginary, Omega, (UIntPtr)Real.Length, (UIntPtr)index);
Marshal.Copy(ptr, resultArray, 0, 2);
Capi.free(ptr);
return new Tuple<float, float>(resultArray[0], resultArray[1]);
}
/// <summary>
/// Applies the same series of filteres used by kiss networks (applied by TorchKissAnn) during training.
///
/// In almost all cases this function should be called before a sepctra is given to a kiss network.
/// </summary>
/// <param name="outputSize">
/// the length the spectra should have after filtering
/// </param>
/// <returns>
/// True if sucessfull, false otherwise
/// </returns>
public bool Filter(int outputSize)
{
var ret_ptr_real = new IntPtr();
var ret_ptr_imag = new IntPtr();
byte ret = Capi.kiss_filter_spectra(Real, Imaginary, Omega, (UIntPtr)Real.Length, ref ret_ptr_real, ref ret_ptr_imag, (UIntPtr)outputSize);
if(ret == 1)
{
Real = new float[(int)outputSize];
Imaginary = new float[(int)outputSize];
Marshal.Copy(ret_ptr_real, Real, 0, (int)outputSize);
Marshal.Copy(ret_ptr_imag, Imaginary, 0, (int)outputSize);
Capi.free(ret_ptr_real);
Capi.free(ret_ptr_imag);
}
return Convert.ToBoolean(ret);
}
/// <summary>
/// Applies the same series of filteres used by kiss networks (applied by TorchKissAnn) during training.
///
/// In almost all cases this function should be called before a sepctra is given to a kiss network.
/// </summary>
/// <param name="outputSize">
/// the length the spectra should have after filtering
/// </param>
/// <returns>
/// True if sucessfull, false otherwise
/// </returns>
public bool Reduce(float threshFactor, bool useSecondDeriv)
{
var ret_ptr_real = new IntPtr();
var ret_ptr_imag = new IntPtr();
var lengthPtr = new UIntPtr();
byte ret = Capi.kiss_reduce_spectra(Real, Imaginary, Omega, (UIntPtr)Real.Length, threshFactor, Convert.ToByte(useSecondDeriv), ref ret_ptr_real, ref ret_ptr_imag, ref lengthPtr);
if(ret == 1)
{
Real = new float[(int)lengthPtr];
Imaginary = new float[(int)lengthPtr];
Marshal.Copy(ret_ptr_real, Real, 0, (int)lengthPtr);
Marshal.Copy(ret_ptr_imag, Imaginary, 0, (int)lengthPtr);
Capi.free(ret_ptr_real);
Capi.free(ret_ptr_imag);
}
return Convert.ToBoolean(ret);
}
/// <summary>
/// Converts an array of doubles to an array of floats.
/// </summary>
/// <param name="input">
/// The input array.
/// </param>
/// <returns>
/// An array with the same values as the input truncated to floats.
/// </returns>
private static float[] DoubleToFloat(double[] input)
{
var res = new float[input.Length];
for(int i = 0; i < input.Length; ++i)
res[i] = (float)input[i];
return res;
}
}
}