Source code for reda.eis.convert

import numpy as np
"""
Convert between different representations for complex resistivity spectra

Basically we always have two parameters for each frequency. These two
parameters can be representated in various forms: conductivity/resistivity;
magnitude-phase/real-imaginary part.

Note that in this context it doesn't matter if we deal with conductivities or
conductances (same for resitivity and resistance).
"""


[docs] def split_data(data, squeeze=False): """ Split 1D or 2D into two parts, using the last axis Parameters ---------- data: squeeze : squeeze results to remove unnecessary dimensions """ vdata = np.atleast_2d(data) nr_freqs = int(vdata.shape[1] / 2) part1 = vdata[:, 0:nr_freqs] part2 = vdata[:, nr_freqs:] if(squeeze): part1 = part1.squeeze() part2 = part2.squeeze() return part1, part2
[docs] def to_complex(mag, pha): complex_nr = mag * np.exp(1j / 1000 * pha.astype(np.float32)) return complex_nr
[docs] def generic_magpha_to_reim(mag, pha): """ Generically convert magnitude and phase to real and imaginary part using the formula :math:`mag \cdot exp(1j / 1000 * pha)` Thus it is suitable for resistivities, multiply conductivity phases with -1 """ complex_nr = to_complex(mag, pha) real_part = np.real(complex_nr) imag_part = np.imag(complex_nr) return real_part, imag_part
#################### # # from converter ## ####################
[docs] def from_ccomplex(data): cre = np.real(data) cim = np.imag(data) return cre, cim
[docs] def from_rcomplex(data): # rre = np.real(data) Y = 1.0 / data cre = np.real(Y) cim = np.imag(Y) return cre, cim
[docs] def from_cre_cim(data): cre, cim = split_data(data) return cre, cim
[docs] def from_cre_cmim(data): cre, cmim = split_data(data) return cre, -cmim
[docs] def from_cmag_cpha(data): cmag, cpha = split_data(data) cre, cim = generic_magpha_to_reim(cmag, cpha) return cre, cim
[docs] def from_log10rmag_rpha(data): rlog10mag, rpha = split_data(data) Z = to_complex(10 ** rlog10mag, rpha) Y = 1 / Z real_part = np.real(Y) imag_part = np.imag(Y) return real_part, imag_part
[docs] def from_lnrmag_rpha(data): rlnmag, rpha = split_data(data) Z = to_complex(np.exp(rlnmag), rpha) Y = 1 / Z real_part = np.real(Y) imag_part = np.imag(Y) return real_part, imag_part
[docs] def from_rmag_rpha(data): rmag, rpha = split_data(data) Z = to_complex(rmag, rpha) Y = 1 / Z real_part = np.real(Y) imag_part = np.imag(Y) return real_part, imag_part
[docs] def from_rre_rmim(data): rre, rmim = split_data(data) Z = rre - 1j * rmim Y = 1 / Z real_part = np.real(Y) imag_part = np.imag(Y) return real_part, imag_part
[docs] def from_rre_rim(data): rre, rim = split_data(data) Z = rre + 1j * rim Y = 1 / Z real_part = np.real(Y) imag_part = np.imag(Y) return real_part, imag_part
################## # # to converter ## ################## # converts from conductiviy re/im to various formats
[docs] def to_cre_cim(cre, cim): data = np.hstack((cre, cim)) return data
[docs] def to_cre_cmim(cre, cim): cmim = -np.array(cim) data = np.hstack((cre, cmim)) return data
[docs] def to_cmag_cpha(cre, cim): Y = cre + 1j * cim cmag = np.abs(Y) cpha = np.arctan2(cim, cre) * 1000 return np.hstack((cmag, cpha))
[docs] def to_rre_rim(cre, cim): Y = cre + 1j * cim Z = 1 / Y real_p = np.real(Z) imag_p = np.imag(Z) return np.hstack((real_p, imag_p))
[docs] def to_rre_rmim(cre, cim): Y = cre + 1j * cim Z = 1 / Y real_p = np.real(Z) mimag_p = -np.imag(Z) return np.hstack((real_p, mimag_p))
[docs] def to_rmag_rpha(cre, cim): Y = cre + 1j * cim Z = 1 / Y real_p = np.real(Z) imag_p = np.imag(Z) mag = np.abs(Z) pha = np.arctan2(imag_p, real_p) * 1000 return np.hstack((mag, pha))
[docs] def to_log10rmag_rpha(cre, cim): rmag_rpha = to_rmag_rpha(cre, cim) mag_slice = slice(0, int(rmag_rpha.shape[1] / 2)) log10rmag_rpha = rmag_rpha log10rmag_rpha[:, mag_slice] = np.log10(rmag_rpha[:, mag_slice]) return log10rmag_rpha
[docs] def to_lnrmag_rpha(cre, cim): rmag_rpha = to_rmag_rpha(cre, cim) mag_slice = slice(0, int(rmag_rpha.shape[1] / 2)) lnrmag_rpha = rmag_rpha lnrmag_rpha[:, mag_slice] = np.log(rmag_rpha[:, mag_slice]) return lnrmag_rpha
[docs] def to_ccomplex(cre, cim): return cre + 1j * cim
[docs] def to_rcomplex(cre, cim): Y = cre + 1j * cim Z = 1.0 / Y return Z
# store the converter functions in dicts from_converters = { 'lnrmag_rpha': from_lnrmag_rpha, 'log10rmag_rpha': from_log10rmag_rpha, 'rmag_rpha': from_rmag_rpha, 'rre_rim': from_rre_rim, 'rre_rmim': from_rre_rmim, 'cmag_cpha': from_cmag_cpha, 'cre_cim': from_cre_cim, 'cre_cmim': from_cre_cmim, 'ccomplex': from_ccomplex, 'rcomplex': from_rcomplex, } to_converters = { 'lnrmag_rpha': to_lnrmag_rpha, 'log10rmag_rpha': to_log10rmag_rpha, 'rmag_rpha': to_rmag_rpha, 'rre_rim': to_rre_rim, 'rre_rmim': to_rre_rmim, 'cmag_cpha': to_cmag_cpha, 'cre_cim': to_cre_cim, 'cre_cmim': to_cre_cmim, 'ccomplex': to_ccomplex, 'rcomplex': to_rcomplex, }
[docs] def convert(input_format, output_format, data, one_spectrum=False): """ Convert from the given format to the requested format Parameters ---------- input_format : format of input data (parameter 'data') output_format : format of output data data : numpy array containing data in specified input format one_spectrum : True|False, the input data comprises one spectrum. This allows for an additional format of the data array. Possible input/output formats: ------------------------------ 'lnrmag_rpha' 'log10rmag_rpha' 'rmag_rpha' 'rre_rim' 'rre_rmim' 'cmag_cpha' 'cre_cim' 'cre_cmim' 'ccomplex' 'rcomplex' Array format ------------ data is either 1D or 2D. A 1D array correspond to one spectrum, with double the size of the frequencies (which are not needed for the conversion). Thus, the first halt either comprises a magnitude data, and the second one phase data, or the parts comprise real and imaginary parts. For the 2D case there exist two possibilities: First, if one_spectrum is False, then the first axis denotes the spectrum number, and each spectrum is stored on the second axis as described for the 1D case. Second, if one_spectrum is True, and the first axis has the size two, then the axis denotes either magnitude (index 0) and phase (index 1), or real (index 0) and imaginary (index 1) parts. The second axis has the same size as there are frequencies. Internally we always convert to real part and imaginary part of conductivity, and then convert back to the output format. Return values are of the same dimensions as input variables. """ if input_format == output_format: return data if input_format not in from_converters: raise KeyError('Input format {0} not known!'.format(input_format)) if output_format not in to_converters: raise KeyError('Output format {0} not known!'.format(output_format)) # internally we always work with the second axis of double the frequency # size if len(data.shape) == 2 and data.shape[0] == 2 and one_spectrum: work_data = np.hstack((data[0, :], data[1, :])) one_spec_2d = True else: work_data = data one_spec_2d = False cre, cim = from_converters[input_format](work_data) converted_data = to_converters[output_format](cre, cim) if one_spec_2d: part1, part2 = split_data(converted_data, True) converted_data = np.vstack((part1, part2)) # reshape to input size (this should only be necessary for 1D data) if len(data.shape) == 1: converted_data = np.squeeze(converted_data) return converted_data