# The `audiomath.Signal` sub-module¶

This semi-independent submodule provides various basic signal-processing tools that can be used with or without the `audiomath.Sound` container.

`audiomath.Signal.``UnwrapDiff`(x, base=6.283185307179586, axis=None, startval=None, dtype=None)

Assume `X` is a wrapped version of an underlying value `Y` we’re interested in. For example, it’s a 16-bit value that wraps around at 65536, or it’s an angle which wraps back to 0 at 2*pi.

`base` is the value (65536 or 2*pi in the above examples) such that `X = Y % base`. The default value of `base` is 2*pi.

Let `dY` be the numeric diff of `Y` in dimension `axis`, computed from `X` by unwrapping in order to avoid jumps larger than `base/2`. Thus, with `base=65536`, a jump from 65535 to 1 is considered as a step of +2. With `base=360`, a jump from 10 to 350 is considered as a step of -20.

`Y` is then reconstructed based on `dY` and `startval` (which defaults to the actual initial value(s) of `X`).

Return value is `(dY,Y)`.

`audiomath.Signal.``msec2samples`(msec, samplingfreq_hz)

Converts milliseconds to the nearest integer number of samples given the specified sampling frequency.

`audiomath.Signal.``samples2msec`(samples, samplingfreq_hz)

Converts samples to milliseconds given the specified sampling frequency.

`audiomath.Signal.``ApplyWindow`(s, func=<function Hann>, axis=0, **kwargs)

If `s` is a `numpy.ndarray`, return a windowed copy of the array. If `s` is an `audiomath.Sound` object (for example, if this is being used a method of that class), then its internal array `s.y` will be replaced by a windowed copy.

Windowing means multiplication by the specified window function, along the specified time `axis`.

`func` should take a single positional argument: length in samples. Additional `**kwargs`, if any, are passed through. Suitable examples include `numpy.blackman`, `numpy.kaiser`, and friends.

`audiomath.Signal.``ModulateAmplitude`(s, freq_hz=1.0, phase_rad=None, phase_deg=None, amplitude=0.5, dc=0.5, samplingfreq_hz=None, duration_msec=None, duration_samples=None, axis=None, waveform=None, **kwargs)

If `s` is a `numpy.ndarray`, return a modulated copy of the array. If `s` is an `audiomath.Sound` object (for example, if this is being used a method of that class), then its internal array `s.y` will be replaced by a modulated copy.

Modulation means multiplication by the specified `waveform`, along the specified time `axis`.

Default phase is such that amplitude is 0 at time 0, which corresponds to phase_deg=-90 if `waveform` follows sine phase (remember: by default the modulator is a raised waveform, because `dc=0.5` by default). To change phase, specify either `phase_rad` or `phase_deg`.

`audiomath.Signal.``GenerateWaveform`(container=None, freq_hz=1.0, phase_rad=None, phase_deg=None, amplitude=1.0, dc=0.0, samplingfreq_hz=None, duration_msec=None, duration_samples=None, axis=None, waveform=None, waveform_domain='auto', **kwargs)

Create a signal (or multiple signals, if the input arguments are arrays) which is a function of time (time being defined along the specified `axis`).

If this is being used as a method of an `audiomath.Sound` instance, then the `container` argument is automatically set to that instance. Otherwise (if used as a global function), the `container` argument is optional—if supplied, it should be a `audiomath.Sound` object. With a `container`, the `axis` argument is set to 0, and the container object’s sampling frequency number of channels and duration (if non-zero) are used as fallback values in case these are not specified elsewhere. The resulting signal is put into `container.y` and a reference to the `container` is returned.

Default phase is 0, but may be changed by either `phase_deg` or `phase_rad` (or both, as long as the values are consistent).

Default duration is 1000 msec, but may be changed by either `duration_samples` or `duration_msec` (or both, as long as the values are consistent).

If `duration_samples` is specified and `samplingfreq_hz` is not, then the sampling frequency is chosen such that the duration is 1 second—so then `freq_hz` can be interpreted as cycles per signal.

The default `waveform` function is `numpy.cos` which means that amplitude, phase and frequency arguments can be taken straight from the kind of dictionary returned by `fft2ap()` for an accurate reconstruction. A `waveform` function is assumed by default to take an input expressed in radians, unless the first argument in its signature is named `cycles`, `samples`, `seconds` or `milliseconds`, in which case the input argument is adjusted accordingly to achieve the named units. (To specify the units explicitly as one of these options, pass one of these words as the `waveform_domain` argument.)

In this module, `SineWave()`, `SquareWave()`, `TriangleWave()` and `SawtoothWave()` are all functions of cycles (i.e. the product of time and frequency), whereas `Click()` is a function of milliseconds. Any of these can be passed as the `waveform` argument.

`audiomath.Signal.``Click`(milliseconds, positivePulseWidth=0.5, negativePulseWidth='symmetric')

A signal function that can be passed as the `waveform` argument to `GenerateWaveform`, to generate periodic clicks. Each click is a positive pulse optionally followed by a negative pulse. If `negativePulseWidth` is `None` or the string `'symmetric'`, then the width of the negative pulse is made the same as `positivePulseWidth`. Otherwise, input arguments are all expressed in milliseconds.

`audiomath.Signal.``SineWave`(cycles, phase_deg=0, maxharm=None, rescale=False)

A sine wave, but with the input expressed in cycles (0 to 1) instead of radians (0 to 2*pi). Otherwise no different from `numpy.sin`, except that the function signature has `maxharm` and `rescale` arguments (which are ignored) for compatibility with `SquareWave()`, `TriangleWave()` and `SawtoothWave()`.

This function can be passed as the `waveform` argument to `GenerateWaveform`.

`audiomath.Signal.``SquareWave`(cycles, phase_deg=0, maxharm=None, rescale=False, duty=0.5, ramp=0, tol=1e-08)

A square wave with its peaks and troughs in sine phase. If `maxharm` is an integer, then an anti-aliased approximation to the square wave (containing no components of higher frequency than `maxharm` times the fundamental) is returned instead. In this case, the `rescale` flag can be set to ensure that the sampled waveform does not exceed +/- 1.0

This function can be passed as the `waveform` argument to `GenerateWaveform`.

`audiomath.Signal.``TriangleWave`(cycles, phase_deg=0, maxharm=None, rescale=False)

A triangle wave with its peaks and troughs in sine phase. If `maxharm` is an integer, then an anti-aliased approximation to the triangle wave (containing no components of higher frequency than `maxharm` times the fundamental) is returned instead. The `rescale` flag, included for compatibility with `SawtoothWave()` and `SquareWave()`, has no effect.

This function can be passed as the `waveform` argument to `GenerateWaveform`.

`audiomath.Signal.``SawtoothWave`(cycles, phase_deg=0, maxharm=None, rescale=False)

A sawtooth wave with its polarity and zero-crossings in sine phase. If `maxharm` is an integer, then an anti-aliased approximation to the sawtooth wave (containing no components of higher frequency than `maxharm` times the fundamental) is returned instead. In this case, the `rescale` flag can be set to ensure that the waveform does not exceed +/- 1.0

This function can be passed as the `waveform` argument to `GenerateWaveform`.

`audiomath.Signal.``Noise`(cycles, distribution='uniform', **kwargs)

This function can be passed as the `waveform` argument to `GenerateWaveform`. The `distribution` argument should be a function, or the name of a function within `numpy.random`, that takes a `size` keyword argument dictating the shape of its output array. Additional `**kwargs` are passed through to the function.

If the function is `numpy.random.uniform`, then the `low` argument is set to -1.0 by default instead of the usual 0.0.

If the function is `numpy.random.normal`, then the `scale` argument is set to 0.2 by default instead of the usual 1.0.

`audiomath.Signal.``fftfreqs`(nSamples, samplingfreq_hz=1.0)

Return a 1-D numpy.array of length `nSamples` containing the positive and negative frequency values corresponding to the elements of an `nSamples`-point FFT. If `samplingfreq_hz` is not supplied, 1.0 is assumed, so the result has 0.5 as its Nyquist frequency.

`audiomath.Signal.``fft2ap`(X, samplingfreq_hz=2.0, axis=0)

Given discrete Fourier transform(s) `X` (with frequency along the specified `axis`), return a dict containing a properly scaled amplitude spectrum, a phase spectrum in degrees and in radians, and a frequency axis (coping with all the fiddly edge conditions).

The inverse of `d = fft2ap(X)` is `X = ap2fft(**d)`

`audiomath.Signal.``ap2fft`(amplitude, phase_rad=None, phase_deg=None, samplingfreq_hz=2.0, axis=0, freq_hz=None, fullfreq_hz=None, nSamples=None)

Keyword arguments match the fields of the `dict` output by `fft2ap()`.

The inverse of `d = fft2ap(X)` is `X = ap2fft(**d)`

`audiomath.Signal.``Reconstruct`(ap, **kwargs)

Check the accuracy of `fft2ap()` and `GenerateWaveform()` by reconstructing a signal as the sum of cosine waves with amplitudes and phases specified in dict `ap`, which is of the form output by `fft2ap()`.

`audiomath.Signal.``Toy`(nSamples=11, nCycles=None, amplitude=(1.0, 0.1), phase_deg=0)

Toy sinusoidal signals for testing `fft2ap()` and `ap2fft()`. Check both odd and even `nSamples`.

`audiomath.Signal.``Shoulder`(x, s, complement=False)

Return a (possibly asymmetric) Tukey window function of `x`. `s` may have 1, 2, 3 or 4 elements:

1. raised cosine between `x=s-0.5` and `x=s+0.5`
2. raised cosine between `x=s` and `x=s`
3. raised cosine rise from `s` to `s`, and fall from `s` to `s`
4. raised cosine rise from `s` to `s`, plateau from `s` to `s`, and fall from `s` to `s`
`audiomath.Signal.``Hilbert`(x, N=None, axis=0, band=(), samplingfreq_hz=None, return_dict=False)

Compute the analytic signal, just like `scipy.signal.hilbert` but with the differences that (a) the computation can be performed along any axis and (b) a limited band of the signal may be considered. The `band` argument can be a two-, three- or four-element tuple suitable for passing to `Shoulder()`, specifying the edges of the passband (expressed in Hz if `samplingfreq_hz` is explicitly supplied, or relative to Nyquist if not).

If `return_dict` is True, do not return just the complex analytic signal but rather a dict containing its amplitude, phase, and unwrapped phase difference.

`audiomath.Signal.``Spectrum`(x, samplingfreq_hz=None, axis=None)

Runs `fft` on a signal followed by `fft2ap`, to return spectral information in “human-readable” format with the annoying corner cases handled.

The inverse operation is `InverseSpectrum()`.

`audiomath.Signal.``InverseSpectrum`(ap, real=True)

Inverse of `Spectrum()`. Takes the `dict` output of `Spectrum()` (or of the underlying `fft2ap()`) and runs `ap2fft()` followed by `ifft()` on it to return a signal. If `real` is true, which it is by default, discard the imaginary part of the result.

`audiomath.Signal.``ReweightSpectrum`(s, func, *pargs, **kwargs)

Brutally filter the sound `s` by transforming into the Fourier domain, weighting the amplitude spectrum, and transforming back. The filtering is non-causal and (TODO) will have wrap-around artifacts whereby the two ends of the signal may bleed into each other, so use with caution—it is most suitable for noise or for periodic signals. No group delay is introduced.

Args:
s (numpy.ndarray or audiomath.Sound):
The input sound data. If `s` is an array, a new array will be returned. If it is a `Sound` instance, `s` will get changed in-place (the array `s.y` will be replaced by a new array) and returned.
func (callable):
A function that takes a numeric array of frequencies, in Hz, as its first (and only required) argument, and outputs a corresponding array of weights.
samplingfreq_hz (float):
Sampling frequencym in Hz. Not needed if `s` is a `Sound` instance.
axis (int):
Axis along which time runs. Not needed if `s` is a `Sound` instance.

Additional `*pargs` and `**kwargs` are passed straight through to `func()`.

`audiomath.Signal.``Timebase`(x, samplingfreq_hz=None, axis=None)

Return a discrete time axis in seconds, against which signal `x` can be plotted. `x` may be an `audiomath.Sound` instance, or you may supply `samplingfreq_hz` explicitly.

`audiomath.Signal.``PlotSignal`(x, samplingfreq_hz=None, axis=None, **kwargs)

Plot `x` (an array with time running along the specified `axis`, or an `audiomath.Sound` instance) against the appropriate `Timebase()`.

`audiomath.Signal.``PlotSpectrum`(x, samplingfreq_hz=None, axis=None, dB=False, baseValue=None, **kwargs)

Input argument `x` may be a `numpy.array` or `audiomath.Sound`, in which case `Spectrum()` will be called on it. Or it may be the `dict` output of a previous `Spectrum()` or `fft2ap()` call.