-
Notifications
You must be signed in to change notification settings - Fork 13
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Frequency domain sweep synthesis #199
Changes from 4 commits
7a35a41
3eb99d3
4a9f22a
b39f15a
7a4647e
8fdaf40
b048bb8
89573c6
e719946
61dcac9
299acc6
c0d6fba
9e49d03
0fd92bd
e51f2b2
8685649
382cf14
3eec2c0
f2b9b6d
7d7a73e
be43e4e
c6cd558
24bcd74
f239137
717cafd
e5d7c2e
d7a5fb6
f0fb9e9
67e6403
7880500
ab5bcf8
1f4f974
b46bd7d
edf1da8
4f2e289
89e4bbb
0f3693c
8276679
876ceb1
6cc1af2
1b90fc1
c954e59
e1d3bff
c07e9d4
9916ec8
68669ca
be1b624
13f12b7
fb4d817
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -158,6 +158,14 @@ def linear_sweep_time(n_samples, frequency_range, n_fade_out=90, amplitude=1, | |
seconds, and the frequency limits :math:`f_\\mathrm{low}` and | ||
:math:`f_\\mathrm{high}`. | ||
|
||
.. note:: | ||
The linear sweep can also be generated in the frequency domain | ||
(see :py:func:`~general_sweep_synthesis`). Time domain synthesis | ||
exhibits a constant temporal envelope in trade of slight ripples in the | ||
magnitude response. Frequency domain synthesis exhibits smooth | ||
magnitude spectra and in trade of a slightly irregular temporal | ||
envelope. | ||
|
||
Parameters | ||
---------- | ||
n_samples : int | ||
|
@@ -196,6 +204,17 @@ def linear_sweep_time(n_samples, frequency_range, n_fade_out=90, amplitude=1, | |
return signal | ||
|
||
|
||
def linear_sweep_freq( | ||
n_samples, start_margin=None, stop_margin=None, frequency_range=None, | ||
butterworth_order=8, double=True, sampling_rate=44100): | ||
|
||
signal, group_delay = _sweep_synthesis_freq( | ||
n_samples, "linear", start_margin, stop_margin, | ||
frequency_range, butterworth_order, double, sampling_rate) | ||
|
||
return signal, group_delay | ||
|
||
|
||
def exponential_sweep(n_samples, frequency_range, n_fade_out=90, | ||
amplitude=1, sweep_rate=None, sampling_rate=44100): | ||
""" | ||
|
@@ -229,6 +248,14 @@ def exponential_sweep_time(n_samples, frequency_range, n_fade_out=90, | |
seconds, and the frequency limits :math:`f_\\mathrm{low}` and | ||
:math:`f_\\mathrm{high}`. | ||
|
||
.. note:: | ||
The exponential sweep can also be generated in the frequency domain | ||
(see :py:func:`~general_sweep_synthesis`). Time domain synthesis | ||
exhibits a constant temporal envelope in trade of slight ripples in the | ||
magnitude response. Frequency domain synthesis exhibits smooth | ||
magnitude spectra and in trade of a slightly irregular temporal | ||
envelope. | ||
|
||
Parameters | ||
---------- | ||
n_samples : int | ||
|
@@ -271,6 +298,155 @@ def exponential_sweep_time(n_samples, frequency_range, n_fade_out=90, | |
return signal | ||
|
||
|
||
def exponential_sweep_freq( | ||
n_samples, start_margin=None, stop_margin=None, frequency_range=None, | ||
butterworth_order=8, double=True, sampling_rate=44100): | ||
|
||
signal, group_delay = _sweep_synthesis_freq( | ||
n_samples, "exponential", start_margin, stop_margin, | ||
frequency_range, butterworth_order, double, sampling_rate) | ||
|
||
return signal, group_delay | ||
|
||
|
||
def magnitude_weighted_sweep( | ||
n_samples, magnitude, start_margin=None, stop_margin=None, | ||
double=True, sampling_rate=44100): | ||
|
||
signal, group_delay = _sweep_synthesis_freq( | ||
n_samples, magnitude, start_margin, stop_margin, | ||
None, None, double, sampling_rate) | ||
|
||
return signal, group_delay | ||
|
||
|
||
def perfect_sweep( | ||
f-brinkmann marked this conversation as resolved.
Show resolved
Hide resolved
|
||
n_samples, sampling_rate=44100): | ||
|
||
signal, group_delay = _sweep_synthesis_freq( | ||
n_samples, "perfect", None, None, None, None, False, sampling_rate) | ||
|
||
return signal, group_delay | ||
|
||
|
||
def _sweep_synthesis_freq( | ||
n_samples, magnitude, start_margin=None, stop_margin=None, | ||
frequency_range=None, buterworth_order=8, double=True, | ||
sampling_rate=44100): | ||
""" | ||
Frequency domain sweep synthesis with arbitrary magnitude response. | ||
|
||
TODO Link to fractional octave smoothing in Notes | ||
|
||
TODO Implement calculation of group delay of impulse responses | ||
|
||
TODO Examples | ||
|
||
Sweep sweep synthesis according to [#]_ | ||
|
||
.. note:: | ||
The linear and exponential sweep can also be generated in the time | ||
domain (see :py:func:`~linear_sweep`, :py:func:`~exponential_sweep`). | ||
Frequency domain synthesis exhibits smooth magnitude spectra and in | ||
trade of a slightly irregular temporal envelope. Time domain synthesis | ||
exhibits a constant temporal envelope in trade of slight ripples in the | ||
magnitude response. | ||
|
||
Parameters | ||
---------- | ||
n_samples : int | ||
The length of the sweep in samples. | ||
magnitude : Signal, string | ||
Specify the magnitude response of the sweep. | ||
|
||
signal | ||
The magnitude response as :py:class:`~pyfar.classes.audio.Signal` | ||
object. If ``signal.n_samples`` is smaller than `n_samples`, zeros | ||
are padded to the end of `signal`. Note that `frequency_range` is | ||
not required in this case. | ||
``'linear'`` | ||
Design a sweep with linearly increasing frequency and a constant | ||
magnitude spectrum. | ||
``'exponential'`` | ||
Design a sweep with exponentially increasing frequency. The | ||
magnitude decreases by 3 dB per frequency doubling and has constant | ||
energy in fiters of relative constant bandwidth (e.g. octaves). | ||
``'perfect'`` | ||
Perfect sweep according to [#]_. Note that the parameters | ||
`start_margin`, `stop_margin`, `frequency_range` and `double` are | ||
not required in this case. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Calling this magnitude is a bit misleading. The effect on the magnitude is only a secondary effect. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Renamed it to |
||
|
||
start_margin : int, optional | ||
The time in samples, at which the sweep starts. The start margin is | ||
required because the frequency domain sweep synthesis has pre-ringing | ||
in the time domain. Not required if `spectrum` is ``'perfect'``. | ||
stop_margin : int, optional | ||
Time in samples, at which the sweep stops. This is relative to | ||
`n_samples`, e.g., a stop margin of 100 samples means that the sweep | ||
ends at sample ``n_samples-10``. This is required, because the | ||
frequency domain sweep synthesis has post-ringing in the time domain. | ||
Not required if `spectrum` is ``'perfect'``. | ||
frequency_range : array like, optional | ||
Frequency range of the sweep given by the lower and upper cut-off | ||
frequency in Hz. The restriction of the frequency range is realized | ||
by appling a Butterworth band-pass with the specified frequencies. | ||
Not required if `spectrum` is ``'perfect'`` or `signal`. | ||
butterworth_order : int, optional | ||
The order of the Butterworth filters that are applied to limit the | ||
frequency range. The default is ``8``. | ||
double : bool, optional | ||
Double `n_samples` during the sweep calculation (recommended). The | ||
default is ``True``. Not required if `spectrum` is ``'perfect'``. | ||
sampling_rate : int, optional | ||
The sampling rate in Hz. The default is ``44100``. | ||
|
||
Returns | ||
------- | ||
sweep : Signal | ||
The sweep signal. The Signal is in the time domain and has the ``none`` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. RMS :) |
||
FFT normalization (see :py:func:`~pyfar.dsp.fft.normalization`). The | ||
sweep parameters are written to `comment`. | ||
group_delay_sweep : FrequencyData | ||
The group delay of the sweep as a single sided spectrum between 0 Hz | ||
and ``sampling_rate/2``. | ||
|
||
TODO add this after implementation is complete: | ||
|
||
This can be used to calculate the group delay of the impulse responses | ||
of linear and harmonic distortion products after deconvoloution (see | ||
:py:func:`~pyfar.dsp...`). | ||
|
||
Notes | ||
----- | ||
The envelope of the sweep time signal should be constant, appart from | ||
slight overshoots at the beginning and end. If this is not the case, try to | ||
provide a smoother spectrum (if `spectrum` is `signal`) or increase | ||
`n_samples`. | ||
|
||
References | ||
---------- | ||
.. [#] S. Müller, P. Massarani. 'Transfer Function Measurement with Sweeps. | ||
Directors Cut Including Previously Unreleased Material and some | ||
Corrections. J. Audio Eng. Soc. 2001, 49 (6), 443–471. | ||
.. [#] C. Antweiler, A. Telle, P. Vary, G. Enzner. 'Perfect-Sweep NLMS for | ||
Time-Variant Acoustic System Identification,' IEEE Int. Conf. | ||
Acoustics, Speech and Signal Processing (ICASSP), | ||
Prague, Czech Republic, 2011. doi: 10.1109/ICASSP.2012.6287930. | ||
|
||
Examples | ||
-------- | ||
TODO Example with spectrum=singal | ||
(e.g., Bass emphasis by means of low shelve filter) | ||
|
||
TODO Examples with spectrum="linear" | ||
|
||
TODO Examples with spectrum="exponential" | ||
|
||
TODO Examples with spectrum="perfect" | ||
""" | ||
pass | ||
|
||
|
||
def _time_domain_sweep(n_samples, frequency_range, n_fade_out, amplitude, | ||
sampling_rate, sweep_type, sweep_rate=None): | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The more I think about this, I'd prefer magnitude_spectrum_weighted_sweep:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes - changed :)