def test_manually_generated_spectrograms(): """Tests the concatenation behavior with manually generated spectrograms.""" spectrogram1 = sumpf.Spectrogram(channels=numpy.array([ ([1.11, 1.12, 1.13], [1.21j, 1.22j, 1.23j], [1.31, 1.32, 1.33]) ]), resolution=1.0, sampling_rate=2.0, offset=1, labels=("s1c1", )) spectrogram2 = sumpf.Spectrogram(channels=numpy.array([ ([2.11, 2.12, 2.13, 2.14], [2.21j, 2.22j, 2.23j, 2.24j]), ([3.11, 3.12, 3.13, 3.14], [3.21j, 3.22j, 3.23j, 3.24j]) ]), resolution=3.0, sampling_rate=4.0, offset=-4, labels=("s2c1", "s2c2")) spectrogram12 = sumpf.Spectrogram(channels=numpy.array([ ([2.11, 3.23, 3.25, 3.27], [2.21j, 3.43j, 3.45j, 3.47j], [0.0, 1.31, 1.32, 1.33]), ([3.11, 3.12, 3.13, 3.14], [3.21j, 3.22j, 3.23j, 3.24j], [0.0, 0.0, 0.0, 0.0]) ]), resolution=1.0, sampling_rate=2.0, offset=0, labels=("Concatenation 1", "Concatenation 2")) spectrogram21 = sumpf.Spectrogram(channels=numpy.array([ ([2.11, 2.12, 2.13, 2.14, 0.0, 1.11, 1.12, 1.13], [2.21j, 2.22j, 2.23j, 2.24j, 0.0j, 1.21j, 1.22j, 1.23j], [0.0, 0.0, 0.0, 0.0, 0.0, 1.31, 1.32, 1.33]), ([3.11, 3.12, 3.13, 3.14, 0.0, 0.0, 0.0, 0.0], [3.21j, 3.22j, 3.23j, 3.24j, 0.0j, 0.0j, 0.0j, 0.0j], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]) ]), resolution=3.0, sampling_rate=4.0, offset=-4, labels=("Concatenation 1", "Concatenation 2")) assert tests.compare_spectrograms_approx( _concatenate_spectrograms([spectrogram1, spectrogram2]), spectrogram12) assert tests.compare_spectrograms_approx( _concatenate_spectrograms([spectrogram2, spectrogram1]), spectrogram21) assert tests.compare_spectrograms_approx( sumpf.Concatenate([spectrogram1, spectrogram2]).output(), spectrogram12) assert tests.compare_spectrograms_approx( sumpf.Concatenate([spectrogram2, spectrogram1]).output(), spectrogram21)
def _sanitize_offsets(data): """makes sure, that the offsets of the signals and spectrograms are not so large, that the concatenation requires excessive amounts of memory.""" r = random.Random() r.seed(data[0].offset()) # the first data set is returned with its original offset result = [data[0]] # the other data sets offset must not exceed their length, so the concatenation is at maximum twice as long as the original data sets combined for s in data[1:]: if abs(s.offset()) < s.length(): result.append(s) else: if isinstance(s, sumpf.Signal): result.append( sumpf.Signal(channels=s.channels(), sampling_rate=s.sampling_rate(), offset=random.randint(-s.length(), s.length()), labels=s.labels())) else: result.append( sumpf.Spectrogram(channels=s.channels(), resolution=s.resolution(), sampling_rate=s.sampling_rate(), offset=random.randint( -s.length(), s.length()), labels=s.labels())) return result
def _compare_merge_spectrograms_first_channel_first(spectrograms, merged): """test if the merged spectrogram's channels are ordered in a way that the first channels of all input spectrogram come first""" resolution = spectrograms[0].resolution() sampling_rate = spectrograms[0].sampling_rate() spectrograms = list(spectrograms) c = 0 d = 0 while spectrograms: to_remove = [] for s in spectrograms: if d < len(s): spectrogram = sumpf.Spectrogram(channels=s[d].channels(), resolution=resolution, # take the resolution from the first spectrogram sampling_rate=sampling_rate, # take the sampling rate from the first spectrogram offset=s[d].offset(), labels=s[d].labels()) # the merged spectrogram has a label for each channel, which could be empty start = spectrogram.offset() - merged.offset() stop = start + spectrogram.length() max_f = spectrogram.number_of_frequencies() assert merged[c, 0:max_f, start:stop] == spectrogram c += 1 else: to_remove.append(s) for s in to_remove: spectrograms.remove(s) d += 1 assert c == len(merged)
def _sanitize_offsets(data): """makes sure, that the offsets of the signals and spectrograms are not so large, that the merged signal requires excessive amounts of memory.""" first_offset = data[0].offset() r = random.Random() r.seed(first_offset) # the first signal is returned with its original offset result = [data[0]] # the other signal's offset must not differ from the first signal's offset by more than their length for s in data[1:]: if abs(first_offset - s.offset()) < s.length(): result.append(s) else: if isinstance(s, sumpf.Signal): result.append(sumpf.Signal(channels=s.channels(), sampling_rate=s.sampling_rate(), offset=random.randint(first_offset - s.length(), first_offset + s.length()), labels=s.labels())) else: # s must be a spectrogram result.append(sumpf.Spectrogram(channels=s.channels(), resolution=s.resolution(), sampling_rate=s.sampling_rate(), offset=random.randint(first_offset - s.length(), first_offset + s.length()), labels=s.labels())) return result
def _concatenate_spectrograms(spectrograms): """A simple but inefficient implementation, that concatenates signals by adding them.""" # test for the corner cases of zero or one signal if not spectrograms: raise RuntimeError("Nothing to concatenate") if len(spectrograms) == 1: return spectrograms[0] # add the signals sum_ = spectrograms[0] index = spectrograms[0].length() + spectrograms[0].offset() for s in spectrograms[1:]: # fill missing channels with zeros if len(s) < len(sum_): new_channels = numpy.zeros(shape=(len(sum_), s.number_of_frequencies(), s.length()), dtype=numpy.complex128) new_channels[0:len(s)] = s.channels() s = sumpf.Spectrogram(channels=new_channels, offset=s.offset()) elif len(sum_) < len(s): new_channels = numpy.zeros(shape=(len(s), sum_.number_of_frequencies(), sum_.length()), dtype=numpy.complex128) new_channels[0:len(sum_)] = sum_.channels() sum_ = sumpf.Spectrogram(channels=new_channels, offset=sum_.offset()) sum_ += s.shift(index) index += s.length() + s.offset() # return a signal with the correct labels return sumpf.Spectrogram(channels=sum_.channels(), resolution=spectrograms[0].resolution(), sampling_rate=spectrograms[0].sampling_rate(), offset=sum_.offset(), labels=tuple( tuple(f"Concatenation {i}" for i in range(1, len(sum_) + 1))))
def _compare_merge_first_spectrogram_first(spectrograms, merged): """tests if the merged spectrogram's channels are ordered like the input spectrograms""" c = 0 resolution = spectrograms[0].resolution() sampling_rate = spectrograms[0].sampling_rate() for s in spectrograms: spectrogram = sumpf.Spectrogram(channels=s.channels(), resolution=resolution, # take the resolution from the first spectrogram sampling_rate=sampling_rate, # take the sampling rate from the first spectrogram offset=s.offset(), labels=s.labels()) # the merged spectrogram has a label for each channel, which could be empty start = spectrogram.offset() - merged.offset() stop = start + spectrogram.length() max_f = s.number_of_frequencies() assert merged[c:c + len(spectrogram), 0:max_f, start:stop] == spectrogram c += len(spectrogram) assert c == len(merged)
from lad_harmonics import lad_training_harmonics from lad import lad_training from lad import lad_testing import numpy as np import sumpf import sumpf_staging import utilities import matplotlib.pyplot as plt signal = sumpf.SineWave(frequency=200.0, sampling_rate=2048, length=16384) #for i in range(2, 2049, 2): #signal = signal + sumpf.SineWave(frequency=i, sampling_rate=2048, length=16384) spectrogram = signal.short_time_fourier_transform() #lad_training_harmonics(spectrogram.magnitude()) lad_training(spectrogram.magnitude()) spectrogram2 = lad_testing(spectrogram.magnitude()) result_spectrogram = sumpf.Spectrogram(channels=spectrogram2) plot = utilities.plot(spectrogram, log_frequency=False, log_magnitude=True) plot = plot.plot(result_spectrogram) #plot = plot.plot(added_signals) #plot = plot.plot(spectrogram) #plot[0].set_xlim(0, 5) #plot[1].set_xlim(0, 5) plot.show()
import sumpf import sumpf_staging import utilities import matplotlib.pyplot as plt import matplotlib.patches as mpatches result = [] resultFormula = [] #resultMLS = [0.53, 0.56, 0.56] #inputMLS = [2, 3, 4] inputs = [] input_wave = np.zeros((1, 9, 10000)) for c in range(2, 1000): for i in range(0, 10000, c): input_wave[0, 0:9, i] = 1 spectrogram = sumpf.Spectrogram(channels=input_wave) res = lad_training(spectrogram.magnitude()) result.append(res) resultFormula.append(pow(c - 1, 2) / (pow(c, 2) + 1)) input_wave = np.zeros((1, 9, 10000)) inputs.append(c) yellow_patch = mpatches.Patch(color='yellow', label='LAD') black_patch = mpatches.Patch(color='black', label='Formula') red_patch = mpatches.Patch(color='red', label='MLS') plt.plot(inputs, result, 'yo', inputs, resultFormula, 'k') plt.title('Change in Time-Right Weight According to Consecutivity') plt.ylabel('Time-Right Weight') plt.xlabel('Consecutivity') plt.legend(handles=[yellow_patch, black_patch]) plt.show()
def output( self ): # noqa: C901; it's either a complex method or a lot of duplicated code # pylint: disable=too-many-branches,too-many-statements; """Computes the concatenated signal and returns it :returns: a Signal instance """ if not self.__data: raise RuntimeError("Nothing to concatenate") if len(self.__data) == 1: return next(iter(self.__data.values()) ) # simply return the first and only data set else: first = next(iter(self.__data.values())) # find the start and stop samples of the data sets index = 0 indices = [] number_of_channels = 0 for s in self.__data.values(): start = index + s.offset() index = start + s.length() indices.append((start, index, s.channels())) number_of_channels = max(number_of_channels, len(s)) indices.sort(key=lambda t: (t[0], t[1])) # allocate an array for the concatenated channels and copy the first data set offset = min(i[0] for i in indices) length = max(i[1] for i in indices) - offset start, stop, dataset_channels = indices[0] start -= offset stop -= offset if len(dataset_channels.shape) == 2: signal = True channels = sumpf_internal.allocate_array( shape=(number_of_channels, length), dtype=dataset_channels.dtype) channels[0:len(dataset_channels), start:stop] = dataset_channels if len(dataset_channels) < number_of_channels: channels[len(dataset_channels):, start:stop] = 0.0 else: signal = False number_of_frequencies = max(i[2].shape[1] for i in indices) channels = sumpf_internal.allocate_array( shape=(number_of_channels, number_of_frequencies, length), dtype=dataset_channels.dtype) l, f = dataset_channels.shape[0:2] channels[0:l, 0:f, start:stop] = dataset_channels if f < number_of_frequencies: channels[0:l, f:, start:stop] = 0.0 if l < number_of_channels: channels[l:, :, start:stop] = 0.0 # copy the other data sets last_index = 0 # the maximum sample index, at which there is already data in the channels array for index, previous in zip(indices[1:], indices[0:-1]): start, stop, dataset_channels = index start -= offset stop -= offset l, f = dataset_channels.shape[0:2] last_index = max(last_index, previous[1] - offset) if start < last_index: # the current data set overlaps with the previous one, add the samples in the overlapping region if last_index >= stop: # pylint: disable=no-else-continue stop = start + dataset_channels.shape[-1] if signal: channels[0:l, start:stop] += dataset_channels else: channels[0:l, 0:f, start:stop] += dataset_channels continue else: if signal: channels[ 0:l, start: last_index] += dataset_channels[:, 0:last_index - start] dataset_channels = dataset_channels[:, last_index - start:] else: channels[ 0:l, 0:f, start: last_index] += dataset_channels[:, :, 0:last_index - start] dataset_channels = dataset_channels[:, :, last_index - start:] start = last_index elif start > last_index: # a gap between the current data set and the previous one, fill it with zeros if signal: channels[:, last_index:start] = 0.0 else: channels[:, :, last_index:start] = 0.0 if signal: channels[0:l, start:stop] = dataset_channels if len( dataset_channels ) < number_of_channels: # if the current signal has less channels than the other, fill the missing channels with zeros channels[l:, start:stop] = 0.0 else: channels[0:l, 0:f, start:stop] = dataset_channels if f < number_of_frequencies: channels[0:l, f:, start:stop] = 0.0 if len( dataset_channels ) < number_of_channels: # if the current signal has less channels than the other, fill the missing channels with zeros channels[l:, :, start:stop] = 0.0 # create and return the result if signal: return sumpf.Signal( channels=channels, sampling_rate=first.sampling_rate(), offset=offset, labels=tuple(f"Concatenation {i}" for i in range(1, number_of_channels + 1))) else: return sumpf.Spectrogram( channels=channels, resolution=first.resolution(), sampling_rate=first.sampling_rate(), offset=offset, labels=tuple(f"Concatenation {i}" for i in range(1, number_of_channels + 1)))
from lad import lad_training from lad import lad_testing import numpy as np import sumpf import sumpf_staging import utilities signal = sumpf.LinearSweep(length=2**18) spectrogram = signal.short_time_fourier_transform() lad_training(spectrogram.magnitude()) result = lad_testing(spectrogram.magnitude()) result_spectrogram = sumpf.Spectrogram( channels=result, resolution=spectrogram.resolution(), sampling_rate=spectrogram.sampling_rate()) plot = utilities.plot(result_spectrogram, log_frequency=False, log_magnitude=False) plot = plot.plot(spectrogram) plot.show()
def test_merge_spectrograms_manually(): """Tests the merging behavior with manually generated spectrograms.""" spectrogram1 = sumpf.Spectrogram(channels=numpy.array([([1.11j, 1.12, 1.13j], [1.21j, 1.22, 1.23j], [1.31j, 1.32, 1.33j])]), resolution=1.0, sampling_rate=2.0, offset=1, labels=("s1c1",)) spectrogram2 = sumpf.Spectrogram(channels=numpy.array([([2.11, 2.12j, 2.13, 2.14j], [2.21, 2.22j, 2.23, 2.24j]), ([3.11, 3.12j, 3.13, 3.14j], [3.21, 3.22j, 3.23, 3.24j])]), resolution=2.0, sampling_rate=3.0, offset=-4, labels=("s2c1", "s2c2")) spectrogram12 = sumpf.Spectrogram(channels=numpy.array([([0.0, 0.0, 0.0, 0.0, 0.0, 1.11j, 1.12, 1.13j], [0.0, 0.0, 0.0, 0.0, 0.0, 1.21j, 1.22, 1.23j], [0.0, 0.0, 0.0, 0.0, 0.0, 1.31j, 1.32, 1.33j]), ([2.11, 2.12j, 2.13, 2.14j, 0.0, 0.0, 0.0, 0.0], [2.21, 2.22j, 2.23, 2.24j, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]), ([3.11, 3.12j, 3.13, 3.14j, 0.0, 0.0, 0.0, 0.0], [3.21, 3.22j, 3.23, 3.24j, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0])]), resolution=1.0, sampling_rate=2.0, offset=-4, labels=("s1c1", "s2c1", "s2c2")) spectrogram21 = sumpf.Spectrogram(channels=numpy.array([([2.11, 2.12j, 2.13, 2.14j, 0.0, 0.0, 0.0, 0.0], [2.21, 2.22j, 2.23, 2.24j, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]), ([3.11, 3.12j, 3.13, 3.14j, 0.0, 0.0, 0.0, 0.0], [3.21, 3.22j, 3.23, 3.24j, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]), ([0.0, 0.0, 0.0, 0.0, 0.0, 1.11j, 1.12, 1.13j], [0.0, 0.0, 0.0, 0.0, 0.0, 1.21j, 1.22, 1.23j], [0.0, 0.0, 0.0, 0.0, 0.0, 1.31j, 1.32, 1.33j])]), resolution=2.0, sampling_rate=3.0, offset=-4, labels=("s2c1", "s2c2", "s1c1")) spectrogram21c = sumpf.Spectrogram(channels=numpy.array([([2.11, 2.12j, 2.13, 2.14j, 0.0, 0.0, 0.0, 0.0], [2.21, 2.22j, 2.23, 2.24j, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]), ([0.0, 0.0, 0.0, 0.0, 0.0, 1.11j, 1.12, 1.13j], [0.0, 0.0, 0.0, 0.0, 0.0, 1.21j, 1.22, 1.23j], [0.0, 0.0, 0.0, 0.0, 0.0, 1.31j, 1.32, 1.33j]), ([3.11, 3.12j, 3.13, 3.14j, 0.0, 0.0, 0.0, 0.0], [3.21, 3.22j, 3.23, 3.24j, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0])]), resolution=2.0, sampling_rate=3.0, offset=-4, labels=("s2c1", "s1c1", "s2c2")) FIRST_CHANNELS_FIRST = sumpf.Merge.modes.FIRST_CHANNELS_FIRST assert sumpf.Merge([spectrogram1, spectrogram2]).output() == spectrogram12 assert sumpf.Merge([spectrogram2, spectrogram1]).output() == spectrogram21 assert sumpf.Merge([spectrogram1, spectrogram2], mode=FIRST_CHANNELS_FIRST).output() == spectrogram12 assert sumpf.Merge([spectrogram2, spectrogram1], mode=FIRST_CHANNELS_FIRST).output() == spectrogram21c
def output(self): """Computes the merged data set and returns it. :returns: a data set, that contains all channels of the added data sets. """ if not self.__data: raise RuntimeError("Nothing to merge") if len(self.__data) == 1: return next(iter(self.__data.values()) ) # simply return the first and only data set else: first = next(iter(self.__data.values())) number_of_channels = sum(len(s) for s in self.__data.values()) labels = [""] * number_of_channels if isinstance(first, sumpf.Signal): merged_offset = min(s.offset() for s in self.__data.values()) length = max(s.offset() + s.length() for s in self.__data.values()) - merged_offset channels = sumpf_internal.allocate_array( shape=(number_of_channels, length)) for index, channel, offset, label in zip( self.__indices(), (c for d in self.__data.values() for c in d.channels()), (d.offset() for d in self.__data.values() for l in d.channels()), # pylint: disable=line-too-long (l for d in self.__data.values() for l in d.labels())): start = offset - merged_offset stop = start + len(channel) channels[index, 0:start] = 0.0 channels[index, start:stop] = channel channels[index, stop:] = 0.0 labels[index] = label return sumpf.Signal(channels=channels, sampling_rate=first.sampling_rate(), offset=merged_offset, labels=labels) elif isinstance(first, sumpf.Spectrum): length = max(s.length() for s in self.__data.values()) channels = sumpf_internal.allocate_array( shape=(number_of_channels, length), dtype=numpy.complex128) for index, channel, label in zip( self.__indices(), (c for d in self.__data.values() for c in d.channels()), (l for d in self.__data.values() for l in d.labels())): channels[index, 0:len(channel)] = channel channels[index, len(channel):] = 0.0 labels[index] = label return sumpf.Spectrum(channels=channels, resolution=first.resolution(), labels=labels) elif isinstance(first, sumpf.Spectrogram): merged_offset = min(s.offset() for s in self.__data.values()) length = max(s.offset() + s.length() for s in self.__data.values()) - merged_offset number_of_frequencies = max(s.number_of_frequencies() for s in self.__data.values()) channels = sumpf_internal.allocate_array( shape=(number_of_channels, number_of_frequencies, length), dtype=numpy.complex128) channels[:] = 0.0 for index, channel, offset, label in zip( self.__indices(), (c for d in self.__data.values() for c in d.channels()), (d.offset() for d in self.__data.values() for l in d.channels()), # pylint: disable=line-too-long (l for d in self.__data.values() for l in d.labels())): channel_frequencies, channel_length = channel.shape start = offset - merged_offset stop = start + channel_length channels[index, 0:channel_frequencies, start:stop] = channel labels[index] = label return sumpf.Spectrogram(channels=channels, resolution=first.resolution(), sampling_rate=first.sampling_rate(), offset=merged_offset, labels=labels) elif isinstance(first, sumpf.Filter): transfer_functions = [None] * number_of_channels for index, transfer_function, label in zip( self.__indices(), (tf for d in self.__data.values() for tf in d.transfer_functions()), # pylint: disable=line-too-long (l for d in self.__data.values() for l in d.labels())): transfer_functions[index] = transfer_function labels[index] = label return sumpf.Filter(transfer_functions=transfer_functions, labels=labels) else: raise ValueError( f"Cannot merge data sets of type {type(first)}")