"""
Module for producing testing data for resistics
This includes testing data for:
- Record
- History
- TimeMetadata
- TimeData
- DecimatedData
- SpectraData
"""
from typing import List, Dict, Optional, Type, Union
import numpy as np
import pandas as pd
from resistics.common import Record, History, get_record
from resistics.time import get_time_metadata, TimeMetadata, TimeData
from resistics.decimate import DecimatedMetadata, DecimatedData
from resistics.spectra import SpectraLevelMetadata, SpectraMetadata, SpectraData
from resistics.gather import SiteCombinedMetadata
from resistics.transfunc import Component, ImpedanceTensor
from resistics.regression import RegressionInputMetadata, Solution
DEFAULT_TIME_DATA_DTYPE = np.float32
[docs]def record_example1() -> Record:
"""Get an example Record"""
from resistics.common import get_record
return get_record(
creator={"name": "example1", "a": 5, "b": -7.0},
messages=["Message 1", "Message 2"],
)
[docs]def record_example2() -> Record:
"""Get an example Record"""
from resistics.common import get_record
return get_record(
creator={"name": "example2", "a": "parzen", "b": -21},
messages=["Message 5", "Message 6"],
)
[docs]def history_example() -> History:
"""Get a History example"""
from resistics.common import History
return History(records=[record_example1(), record_example2()])
[docs]def time_data_ones(
fs: float = 10,
first_time: str = "2020-01-01 00:00:00",
n_samples: int = 10,
dtype: Optional[Type] = None,
) -> TimeData:
"""
TimeData with all ones
Parameters
----------
fs : float, optional
The sampling frequency, by default 10
first_time : str, optional
The time of the first sample, by default "2020-01-01 00:00:00"
n_samples : int, optional
The number of samples, by default 10
dtype : Optional[Type], optional
The data type for the values, by default None
Returns
-------
TimeData
The TimeData
"""
if dtype is None:
dtype = DEFAULT_TIME_DATA_DTYPE
metadata = time_metadata_mt(fs, first_time, n_samples)
data = np.ones(shape=(len(metadata.chans), n_samples), dtype=dtype)
creator = {
"name": "time_data_ones",
"fs": fs,
"first_time": first_time,
"n_samples": n_samples,
}
messages = ["Generated time data with fixed values"]
record = get_record(creator, messages)
metadata.history.add_record(record)
return TimeData(metadata, data)
[docs]def time_data_simple(
fs: float = 10,
first_time: str = "2020-01-01 00:00:00",
dtype: Optional[Type] = None,
) -> TimeData:
"""
Time data with 16 samples
Parameters
----------
fs : float, optional
The sampling frequency, by default 10
first_time : str, optional
The time of the first sample, by default "2020-01-01 00:00:00"
dtype : Optional[Type], optional
The data type for the values, by default None
Returns
-------
TimeData
The TimeData
"""
if dtype is None:
dtype = DEFAULT_TIME_DATA_DTYPE
data = np.array(
[
[1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1],
[1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4, 5, 6, 7],
[1, 2, 3, 5, 1, 2, 3, 4, 2, 6, 7, 6, 5, 4, 3, 2],
[2, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 1, 3, 3, 3, 3],
],
dtype=dtype,
)
n_samples = data.shape[1]
metadata = time_metadata_mt(fs, first_time, n_samples)
creator = {"name": "time_data_simple", "fs": fs, "first_time": first_time}
messages = ["Generated time data with simple values"]
record = get_record(creator, messages)
metadata.history.add_record(record)
return TimeData(metadata, data)
[docs]def time_data_with_nans(
fs: float = 10,
first_time: str = "2020-01-01 00:00:00",
dtype: Optional[Type] = None,
) -> TimeData:
"""
TimeData with 16 samples and some nan values
Parameters
----------
fs : float, optional
Sampling frequency, by default 10
first_time : str, optional
The time of the first sample, by default "2020-01-01 00:00:00"
dtype : Optional[Type], optional
The data type for the values, by default None
Returns
-------
TimeData
The TimeData
"""
if dtype is None:
dtype = DEFAULT_TIME_DATA_DTYPE
data = np.array(
[
[1, 1, 1, 0, np.nan, 0, 1, 1, 1, np.nan, 0, 0, 0, 0, 1, 1],
[1, 2, np.nan, np.nan, 5, 6, np.nan, 8, 9, 1, 2, 3, 4, 5, 6, 7],
[np.nan, 2, 3, 5, 1, 2, 3, 4, 2, 6, 7, np.nan, np.nan, 4, 3, 2],
[2, 0, 0, 1, 2, 3, np.nan, np.nan, np.nan, 0, 0, 1, 3, 3, 3, 3],
],
dtype=dtype,
)
n_samples = data.shape[1]
metadata = time_metadata_mt(fs, first_time, n_samples)
creator = {"name": "time_data_with_nans", "fs": fs, "first_time": first_time}
messages = ["Generated time data with some nan values"]
record = get_record(creator, messages)
metadata.history.add_record(record)
return TimeData(metadata, data)
[docs]def time_data_linear(
fs: float = 10,
first_time: str = "2020-01-01 00:00:00",
n_samples: int = 10,
dtype: Optional[Type] = None,
) -> TimeData:
"""
Get TimeData with linear data
Parameters
----------
fs : float, optional
The sampling frequency, by default 10
first_time : str, optional
Time of first sample, by default "2020-01-01 00:00:00"
n_samples : int, optional
The number of samples, by default 10
dtype : Optional[Type], optional
The data type for the values, by default None
Returns
-------
TimeData
TimeData with linear values
"""
if dtype is None:
dtype = DEFAULT_TIME_DATA_DTYPE
metadata = time_metadata_mt(fs, first_time, n_samples)
data = np.empty(shape=(metadata.n_chans, n_samples), dtype=dtype)
for idx in range(metadata.n_chans):
data[idx, :] = np.arange(n_samples)
creator = {
"name": "time_data_linear",
"fs": fs,
"first_time": first_time,
"n_samples": n_samples,
}
messages = ["Generated time data with linear values"]
record = get_record(creator, messages)
metadata.history.add_record(record)
return TimeData(metadata, data)
[docs]def time_data_random(
fs: float = 10,
first_time: str = "2020-01-01 00:00:00",
n_samples: int = 10,
dtype: Optional[Type] = None,
) -> TimeData:
"""
TimeData with random values and specifiable number of samples
Parameters
----------
fs : float, optional
The sampling frequency, by default 10
first_time : str, optional
Time of first sample, by default "2020-01-01 00:00:00"
n_samples : int, optional
The number of samples, by default 10
dtype : Optional[Type], optional
The data type for the values, by default None
Returns
-------
TimeData
The TimeData
"""
if dtype is None:
dtype = DEFAULT_TIME_DATA_DTYPE
metadata = time_metadata_mt(fs, first_time, n_samples)
data = np.random.normal(0, 3, size=(metadata.n_chans, n_samples)).astype(dtype)
creator = {
"name": "time_data_random",
"fs": fs,
"first_time": first_time,
"n_samples": n_samples,
}
messages = ["Generated time data with random values"]
record = get_record(creator, messages)
metadata.history.add_record(record)
return TimeData(metadata, data)
[docs]def time_data_periodic(
frequencies: List[float],
fs: float = 50,
first_time: str = "2020-01-01 00:00:00",
n_samples: int = 100,
dtype: Optional[Type] = None,
) -> TimeData:
"""
Get period TimeData
Parameters
----------
frequencies : List[float]
Frequencies to include
fs : float, optional
Sampling frequency, by default 50
first_time : str, optional
The first time, by default "2020-01-01 00:00:00"
n_samples : int, optional
The number of samples, by default 100
dtype : Optional[Type], optional
The data type for the values, by default None
Returns
-------
TimeData
Periodic TimeData
"""
if dtype is None:
dtype = DEFAULT_TIME_DATA_DTYPE
metadata = time_metadata_1chan(fs, first_time, n_samples)
times = np.arange(0, n_samples) * (1 / fs)
data = np.zeros(shape=(1, n_samples), dtype=dtype)
for freq in frequencies:
data += np.sin(times * 2 * np.pi * freq)
creator = {
"name": "time_data_periodic",
"frequencies": frequencies,
"fs": fs,
"first_time": first_time,
"n_samples": n_samples,
}
messages = ["Generated time data with periodic values"]
record = get_record(creator, messages)
metadata.history.add_record(record)
return TimeData(metadata, data)
[docs]def time_data_with_offset(
offset=0.05,
fs: float = 10,
first_time: str = "2020-01-01 00:00:00",
n_samples: int = 11,
dtype: Optional[Type] = None,
) -> TimeData:
"""
Get TimeData with an offset on the sampling
Parameters
----------
offset : float, optional
The offset on the sampling in seconds, by default 0.05
fs : float, optional
The sampling frequency, by default 10
first_time : str, optional
The first time of the TimeData, by default "2020-01-01 00:00:00"
n_samples : int, optional
The number of samples, by default 11
dtype : Optional[Type], optional
The data type for the values, by default None
Returns
-------
TimeData
The TimeData
"""
if dtype is None:
dtype = DEFAULT_TIME_DATA_DTYPE
first_time = (pd.to_datetime(first_time) + pd.Timedelta(offset, "s")).isoformat()
metadata = time_metadata_1chan(fs, first_time, n_samples)
data = np.arange(0, n_samples).reshape(1, n_samples)
creator = {
"name": "time_data_with_offset",
"offset": offset,
"fs": fs,
"first_time": first_time,
"n_samples": n_samples,
}
messages = ["Generated time data with an offset"]
record = get_record(creator, messages)
metadata.history.add_record(record)
return TimeData(metadata, data)
[docs]def decimated_data_random(
fs: float = 0.25,
first_time: str = "2021-01-01 00:00:00",
n_samples: int = 1024,
n_levels: int = 3,
factor: int = 4,
) -> DecimatedData:
"""
Get random decimated data
Parameters
----------
fs : float, optional
Sampling frequency, by default 10
first_time : str, optional
The time of the first sample, by default "2021-01-01 00:00:00"
n_samples : int, optional
The number of samples, by default 1024
n_levels : int, optional
The number of levels, by default 3
factor : int, optional
The decimation factor for each level, by default 4
Returns
-------
DecimatedData
The decimated data
"""
metadata = decimated_metadata(
fs, first_time, n_samples=n_samples, n_levels=n_levels, factor=factor
)
data = {}
for ilevel in range(metadata.n_levels):
level_samples = metadata.levels_metadata[ilevel].n_samples
data[ilevel] = np.random.normal(0, 3, size=(metadata.n_chans, level_samples))
creator = {
"name": "decimated_data_random",
"fs": fs,
"first_time": first_time,
"n_levels": n_levels,
}
record = get_record(creator, "Generated random decimated data")
metadata.history.add_record(record)
return DecimatedData(metadata, data)
[docs]def decimated_data_linear(
fs: float = 0.25,
first_time: str = "2021-01-01 00:00:00",
n_samples: int = 1024,
n_levels: int = 3,
factor: int = 4,
):
"""
Get linear decimated data
Parameters
----------
fs : float, optional
Sampling frequency, by default 10
first_time : str, optional
The time of the first sample, by default "2021-01-01 00:00:00"
n_samples : int, optional
The number of samples, by default 1024
n_levels : int, optional
The number of levels, by default 3
factor : int, optional
The decimation factor for each level, by default 4
Returns
-------
DecimatedData
The decimated data
"""
metadata = decimated_metadata(
fs, first_time, n_samples=n_samples, n_levels=n_levels, factor=factor
)
data = {}
for ilevel in range(metadata.n_levels):
level_samples = metadata.levels_metadata[ilevel].n_samples
level_data = np.array([np.arange(level_samples), -1 * np.arange(level_samples)])
data[ilevel] = level_data
creator = {
"name": "decimated_data_linear",
"fs": fs,
"first_time": first_time,
"n_levels": n_levels,
}
record = get_record(creator, "Generated linear decimated data")
metadata.history.add_record(record)
return DecimatedData(metadata, data)
[docs]def decimated_data_periodic(
frequencies: Dict[str, List[float]],
fs: float = 0.25,
first_time: str = "2021-01-01 00:00:00",
n_samples: int = 1024,
n_levels: int = 3,
factor: int = 4,
):
"""
Get periodic decimated data
Parameters
----------
frequencies : Dict[str, List[float]]
Mapping from channel to list of frequencies to add
fs : float, optional
Sampling frequency, by default 10
first_time : str, optional
The time of the first sample, by default "2021-01-01 00:00:00"
n_samples : int, optional
The number of samples, by default 1024
n_levels : int, optional
The number of levels, by default 3
factor : int, optional
The decimation factor for each level, by default 4
Returns
-------
DecimatedData
The decimated data
"""
metadata = decimated_metadata(
fs, first_time, n_samples=n_samples, n_levels=n_levels, factor=factor
)
data = {}
for ilevel in range(metadata.n_levels):
level_samples = metadata.levels_metadata[ilevel].n_samples
level_fs = metadata.levels_metadata[ilevel].fs
times = np.arange(0, level_samples) * (1 / level_fs)
level_data = []
for chan in metadata.chans:
chan_data = np.zeros(shape=(level_samples))
for freq in frequencies[chan]:
if freq > level_fs / 2:
continue
chan_data += np.sin(times * 2 * np.pi * freq)
level_data.append(chan_data)
data[ilevel] = np.array(level_data)
creator = {
"name": "decimated_data_periodic",
"fs": fs,
"first_time": first_time,
"n_levels": n_levels,
}
record = get_record(creator, "Generated periodic decimated data")
metadata.history.add_record(record)
return DecimatedData(metadata, data)
[docs]def spectra_data_basic() -> SpectraData:
"""
Spectra data with a single decimation level
Returns
-------
SpectraData
Spectra data with a single level, a single channel and two windows
"""
data = {}
# fmt:off
data[0] = np.array(
[
[[0 + 0j, 1 + 1j, 2 + 2j, 3 + 3j, 4 + 4j, 5 + 5j, 6 + 6j, 7 + 7j, 8 + 8j, 9 + 9j]],
[[-1 + 1j, 0 + 2j, 1 + 3j, 2 + 4j, 3 + 5j, 4 + 6j, 5 + 7j, 6 + 8j, 7 + 9j, 8 + 10j]],
]
)
# fmt:on
freqs = [0, 10, 20, 30, 40, 50, 60, 70, 80, 90]
level_metadata = SpectraLevelMetadata(
fs=180,
n_wins=2,
win_size=20,
olap_size=5,
index_offset=0,
n_freqs=10,
freqs=freqs,
)
metadata_dict = time_metadata_1chan().dict()
metadata_dict["fs"] = [180]
metadata_dict["n_levels"] = 1
metadata_dict["levels_metadata"] = [level_metadata]
metadata_dict["ref_time"] = metadata_dict["first_time"]
metadata = SpectraMetadata(**metadata_dict)
creator = {
"name": "spec_data_basic",
}
record = get_record(creator, "Generated spectra data with 1 channel and 1 level")
metadata.history.add_record(record)
return SpectraData(metadata, data)
[docs]def components_mt() -> Dict[str, Component]:
"""
Get example components for the Impedance Tensor
Returns
-------
Dict[str, Component]
Dictionary of component values (ExHx, ExHy, EyHx, EyHy)
"""
components = {
"ExHx": Component(real=[1, 1, 2, 2, 3], imag=[5, 5, 4, 4, 3]),
"ExHy": Component(real=[1, 2, 3, 4, 5], imag=[-5, -4, -3, -2, -1]),
"EyHx": Component(real=[-1, -2, -3, -4, -5], imag=[5, 4, 3, 2, 1]),
"EyHy": Component(real=[-1, -1, -2, -2, -3], imag=[-5, -5, -4, -4, -3]),
}
return components
[docs]def solution_mt() -> Solution:
"""
Get an example impedance tensor solution
Returns
-------
Solution
The solution
"""
tf = ImpedanceTensor()
fs = 128
freqs = [10.0, 20.0, 30.0, 40.0, 50.0]
components = components_mt()
metadata = regression_input_metadata_mt(fs, freqs)
return Solution(
tf=tf,
freqs=freqs,
components=components,
history=History(),
contributors=metadata.contributors,
)