def log2(x, name=None): """ Computes log_2(x) numpy compatibility: Equivalent to numpy.log2 """ with _tf.name_scope(name, op_util.resolve_op_name("Log2"), [x]): return log(x, 2)
def log(x, base, name=None): """ Computes log_{base}(x) """ with _tf.name_scope(name, op_util.resolve_op_name("Log"), [x, base]): n = _tf.log(x) base = _tf.convert_to_tensor(base, dtype=n.dtype) d = _tf.log(base) return n / d
def to_decibel(x, ref_val, name=None): """ Converts to decibel scale. :param x Tensor with values to convert to dB scale. :param ref_val Scalar representing reference value in bel scale :return: 10*log10(value/reference_value) """ with tf.name_scope(name, op_util.resolve_op_name("ToDecibel"), [x]): zero = tf.constant(0, dtype=ref_val.dtype) with tf.control_dependencies([ tf.assert_greater(ref_val, zero, data=[ref_val], message="reference value must be > 0") ]): return 10*math_ops.log10(x / ref_val)
def analytic_signal(input, dt=1, axis=None, name=None): """ Computes the analytic signal: x_a = x + j*h(x) Where x is the input signal, h(x) - the Hilbert transform of x. For more information see: https://en.wikipedia.org/wiki/Analytic_signal scipy compatibility Equivalent to scipy.signal.hilbert(input) """ with tf.name_scope(name, op_util.resolve_op_name("AnalyticSignal"), [input]): return input + 1j * tf.cast(hilbert(input, dt=dt, axis=axis), dtype=tf.complex64)
def clip_by_decibel(input, clip_value_min, clip_value_max, name=None): """ Converts to dB scale and limits dynamic range of input signal. :param range pair (min, max) of allowed dB values. Each output value will be limited to this range, i.e.: if result[i] > max => result[i] = max if result[i] < min => result[i] = min :return: input in dB scale, with values limited to given range """ with tf.name_scope(name, op_util.resolve_op_name("ClipByDecibel"), [input, clip_value_min, clip_value_max]): clip_value_max = tf.convert_to_tensor(clip_value_max, dtype=input.dtype) clip_value_min = tf.convert_to_tensor(clip_value_min, dtype=input.dtype) zero = tf.constant(0, dtype=input.dtype) with tf.control_dependencies([ tf.assert_greater_equal( clip_value_max, clip_value_min, data=[clip_value_min, clip_value_max], message="must be: clip_value_max >= clip_value_min"), tf.assert_greater_equal( clip_value_max, zero, data=[clip_value_max], message="clip value max must be >= 0 "), tf.assert_greater_equal(clip_value_min, zero, data=[clip_value_min], message="clip value min must be >= 0 ") ]): abs_input = tf.abs(input) ref_value = tf.reduce_max(abs_input) input_db = tf.cond( tf.equal(ref_value, zero), # We cannot use 0 as ref. value in dB scale. true_fn=lambda: abs_input, false_fn=lambda: wf.to_decibel(abs_input, ref_value)) # input_db has non-positive values return tf.clip_by_value(input_db, -1 * clip_value_max, -1 * clip_value_min)
def hilbert(input, dt=1, axis=None, name=None): """ Computes Hilbert transform of complex-valued signal. Computations will be done along given axis. Disclaimer: This function currently does not support tensors with undefined dimensions. scipy compatibility Equivalent to (-1)*scipy.fftpack.hilbert(input) :param input: tensor of tf.complex64 values :param dt: time step between consecutive samples :param axis input's dimension :return: tensor with values of type tf.complex64 """ with tf.name_scope(name, op_util.resolve_op_name("Hilbert"), [input]): input = tf.convert_to_tensor(value=input, name="input", dtype=tf.complex64) # TODO(pjarosik) axis parameter should be handled by tf.fft if axis is not None: rank = len(input.get_shape().as_list()) assert 0 <= axis < rank perm = [x for x in range(0, rank)] perm[axis] = rank - 1 perm[rank - 1] = axis input = tf.transpose(input, perm=perm) input_shape = tf.shape(input) input_rank = tf.rank(input) with tf.control_dependencies([ tf.assert_greater(input_rank, 0, data=[input], message="input can not be a scalar") ]): n = input_shape[input_rank - 1] y_f = tf.fft(input) f = tf.cast(fftfreq(n, d=dt), dtype=tf.complex64) output = tf.real(tf.ifft(-1j * tf.sign(f) * y_f)) if axis is not None: output = tf.transpose(output, perm=perm) return output
def fftfreq(n, d=1.0, name=None): """ Returns tf.fft sample frequencies. numpy compatibility Equivalent to np.fft.fftfreq :param n: 0-D tensor - number of samples of signal in time-domain :param d: value - sample spacing :return: 1-D tensor of length n with sample frequencies. """ with tf.name_scope(name, op_util.resolve_op_name("Fftfreq"), [n]): n = tf.cast(n, dtype=tf.float32) with tf.control_dependencies([ tf.assert_equal(tf.rank(n), 0, data=[n], message="n must be a scalar."), tf.assert_greater_equal(n, 2., data=[n], message="n must be > 2") ]): T = d * n dtype = tf.float32 non_negative_range = tf.cond( tf.equal(tf.mod(n, 2), 0), true_fn=lambda: tf.range(start=0, limit=n // 2, dtype=dtype), false_fn=lambda: tf.range( start=0, limit=((n - 1) // 2) + 1, dtype=dtype)) negative_range = tf.cond( tf.equal(tf.mod(n, 2), 0), true_fn=lambda: tf.range( start=-1 * (n // 2), limit=0, dtype=dtype), false_fn=lambda: tf.range( start=-1 * ((n - 1) // 2), limit=0, dtype=dtype)) return tf.concat( [tf.div(non_negative_range, T), tf.div(negative_range, T)], -1)