Skip to content
5.767348 -125.99
6.117197 -125.73
6.491126 -125.41
6.890947 -125.15
7.315032 -124.90
7.764832 -124.64
8.239069 -124.44
8.738852 -120.26
9.240211 -117.82
9.740038 -117.59
10.287374 -117.03
10.887133 -116.79
11.511741 -116.68
12.161496 -116.44
12.882118 -115.79
13.681756 -115.53
14.552726 -111.48
15.502251 -108.58
16.455202 -108.84
17.404829 -108.60
18.403366 -108.41
19.452963 -108.17
20.574747 -100.82
21.774265 -98.48
23.023481 -98.38
24.322992 -98.14
25.718433 -96.65
27.217833 -89.95
28.83674 -89.53
30.585981 -89.28
32.455627 -85.76
34.454735 -84.32
36.575161 -84.07
38.824162 -80.50
41.195343 -79.84
43.69426 -78.35
46.201054 -77.27
48.700188 -76.74
51.436867 -73.57
54.435665 -72.94
57.673481 -70.25
61.171963 -69.11
64.911255 -67.76
68.90947 -65.99
73.150322 -65.76
77.648323 -65.95
82.390686 -66.85
87.388519 -66.60
92.402107 -59.37
97.400375 -54.62
102.873734 -51.67
108.87133 -46.46
115.117416 -42.61
121.614967 -42.93
128.592163 -44.43
136.089157 -43.77
144.752487 -44.44
154.746918 -42.15
164.781372 -40.97
174.777039 -42.02
184.804214 -46.33
194.800751 -48.35
205.747467 -50.65
217.742661 -50.31
230.234833 -43.68
243.229935 -44.81
257.184326 -49.42
272.178314 -46.58
288.367401 -47.33
305.859802 -45.88
324.556274 -41.78
344.547333 -41.56
365.751617 -44.34
388.241608 -47.58
411.95343 -46.58
436.942596 -47.59
462.010529 -41.35
487.001862 -36.42
514.368652 -42.53
544.356628 -41.60
576.734802 -39.85
611.719604 -40.99
649.112549 -44.87
689.094666 -39.46
731.503235 -41.66
776.483215 -48.56
823.90686 -47.09
873.885193 -46.32
924.021057 -51.27
974.003723 -50.35
1028.737305 -50.43
1088.713257 -50.40
1151.174072 -49.41
1216.149658 -53.54
1285.921631 -51.57
1360.891602 -53.07
1447.52478 -55.84
1547.469116 -54.63
1647.813721 -54.38
1747.770386 -53.16
1848.042114 -54.48
1948.007446 -56.36
2057.474609 -57.00
2177.426514 -58.22
2302.348145 -58.88
2432.299316 -60.06
2571.843262 -60.16
2721.783203 -61.42
2883.674072 -60.98
3058.598145 -61.00
3245.562744 -58.75
3445.473389 -54.98
3657.516357 -56.58
3882.416016 -59.55
4119.53418 -59.44
4369.425781 -58.41
4620.105469 -59.69
4870.018555 -58.31
5143.686523 -55.73
5443.566406 -49.00
5767.348145 -48.41
6117.196289 -51.72
6491.125488 -53.16
6890.946777 -56.89
7315.032715 -57.64
7764.832031 -55.73
8239.068359 -56.28
8738.851563 -59.34
9240.210938 -59.02
9740.037109 -57.42
10287.373047 -59.31
10887.132813 -60.90
11511.741211 -61.69
12161.496094 -64.62
12859.216797 -67.91
13608.916016 -68.45
14475.248047 -67.52
15474.691406 -66.33
16478.136719 -68.60
17477.703125 -71.00
18480.421875 -74.78
19480.074219 -74.56
20574.746094 -75.06
21774.265625 -78.82
23023.482422 -83.67
24322.992188 -90.39
5.767348 -196.47
6.117197 -196.22
6.491126 -195.97
6.890947 -195.72
7.315032 -195.47
7.764832 -195.22
8.239069 -194.97
8.738852 -187.49
9.240211 -181.85
9.740038 -181.60
10.287374 -181.35
10.887133 -181.10
11.511741 -180.85
12.161496 -180.60
12.882118 -180.35
13.681756 -180.10
14.552726 -167.62
15.502251 -163.27
16.455202 -163.02
17.404829 -162.77
18.403366 -162.52
19.452963 -162.27
20.574747 -147.86
21.774265 -144.93
23.023481 -144.68
24.322992 -144.43
25.718433 -137.96
27.217833 -130.76
28.83674 -130.51
30.585981 -130.26
32.455627 -123.29
34.454735 -121.66
36.575161 -121.41
38.824162 -115.22
41.195343 -114.11
43.69426 -111.68
46.201054 -108.48
48.700188 -107.25
51.436867 -102.84
54.435665 -101.38
57.673481 -97.89
61.171963 -95.68
64.911255 -93.81
68.90947 -90.90
73.150322 -89.97
77.648323 -89.25
82.390686 -89.14
87.388519 -88.04
92.402107 -79.95
97.400375 -73.79
102.873734 -70.25
108.87133 -64.12
115.117416 -59.42
121.614967 -59.41
128.592163 -60.09
136.089157 -58.88
144.752487 -59.82
154.746918 -56.70
164.781372 -54.33
174.777039 -54.11
184.804214 -57.37
194.800751 -59.01
205.747467 -61.16
217.742661 -60.33
230.234833 -52.97
243.229935 -53.79
257.184326 -57.75
272.178314 -54.10
288.367401 -55.01
305.859802 -52.42
324.556274 -48.23
344.547333 -47.69
365.751617 -49.98
388.241608 -52.76
411.95343 -51.33
436.942596 -52.16
462.010529 -45.25
487.001862 -39.63
514.368652 -45.88
544.356628 -43.89
576.734802 -42.44
611.719604 -43.25
649.112549 -46.86
689.094666 -41.18
731.503235 -42.77
776.483215 -49.06
823.90686 -48.67
873.885193 -46.22
924.021057 -51.40
974.003723 -50.13
1028.737305 -50.31
1088.713257 -50.08
1151.174072 -48.89
1216.149658 -53.42
1285.921631 -50.80
1360.891602 -51.95
1447.52478 -56.92
1547.469116 -54.46
1647.813721 -53.62
1747.770386 -52.14
1848.042114 -53.20
1948.007446 -54.23
2057.474609 -55.65
2177.426514 -56.92
2302.348145 -57.33
2432.299316 -58.88
2571.843262 -58.79
2721.783203 -60.23
2883.674072 -59.73
3058.598145 -59.88
3245.562744 -57.54
3445.473389 -53.98
3657.516357 -55.51
3882.416016 -58.74
4119.53418 -58.37
4369.425781 -57.79
4620.105469 -58.75
4870.018555 -57.35
5143.686523 -55.28
5443.566406 -48.20
5767.348145 -48.77
6117.196289 -51.77
6491.125488 -53.42
6890.946777 -57.49
7315.032715 -58.48
7764.832031 -56.73
8239.068359 -57.64
8738.851563 -60.41
9240.210938 -61.22
9740.037109 -59.21
10287.373047 -61.98
10887.132813 -63.98
11511.741211 -65.17
12161.496094 -68.86
12859.216797 -72.60
13608.916016 -73.37
14475.248047 -73.99
15474.691406 -73.00
16478.136719 -75.09
17477.703125 -78.55
18480.421875 -81.54
19480.074219 -82.95
20574.746094 -84.26
21774.265625 -88.03
23023.482422 -92.79
24322.992188 -100.22
6.3 -119.67
8 -117.73
10 -111.06
12.5 -110.06
16 -103.36
20 -95.94
25 -87.83
31.5 -80.71
40 -74.52
50 -68.42
63 -62.10
80 -60.36
100 -44.54
125 -37.24
160 -36.47
200 -41.94
250 -39.49
315 -37.51
400 -40.42
500 -33.58
630 -35.02
800 -38.86
1000 -44.41
1250 -45.46
1600 -48.93
2000 -49.92
2500 -53.94
3150 -52.22
4000 -52.38
5000 -47.06
6300 -45.81
8000 -51.05
10000 -52.82
12500 -58.74
16000 -62.36
20000 -68.88
25000 -82.77
6.3 -190.07
8 -185.71
10 -175.44
12.5 -174.44
16 -157.77
20 -143.04
25 -129.71
31.5 -118.75
40 -108.42
50 -98.02
63 -87.80
80 -83.02
100 -62.73
125 -53.41
160 -49.68
200 -53.20
250 -48.30
315 -43.88
400 -45.41
500 -36.87
630 -36.97
800 -39.88
1000 -44.43
1250 -44.92
1600 -47.94
2000 -48.76
2500 -52.67
3150 -51.05
4000 -51.39
5000 -46.72
6300 -45.80
8000 -52.10
10000 -55.24
12500 -62.72
16000 -68.70
20000 -77.59
25000 -92.07
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -5,24 +5,33 @@ Created on Jan 16 2025 21:31
@author: Jan.Reimes
"""
import numpy as np
from pathlib import Path
from typing import Any
from typing import Any, Self, Optional
import shutil
from enum import Enum
import urllib.request
class Downloads(Enum):
P501 = r'https://www.itu.int/rec/dologin_pub.asp?lang=e&id=T-REC-P.501-202005-I!!SOFT-ZST-E&type=items'
P501_B = (P501_ANNEX_B := r'https://www.itu.int/wftp3/public/t/testsignal/GenAudio/P501/v2025_04/Speech_Signals_AnnexB.zip')
P501_C = (P501_ANNEX_C :=r'https://www.itu.int/wftp3/public/t/testsignal/GenAudio/P501/v2025_04/Speech_Signals_AnnexC.zip')
P501_D = (P501_ANNEX_D :=r'https://www.itu.int/wftp3/public/t/testsignal/GenAudio/P501/v2025_04/Speech_Signals_AnnexD.zip')
P501_E = (P501_ANNEX_E :=r'https://www.itu.int/wftp3/public/t/testsignal/GenAudio/P501/v2025_04/Speech_Signals_AnnexE.zip')
P501_7 = (P501_CL_7 :=r'https://www.itu.int/wftp3/public/t/testsignal/GenAudio/P501/v2025_04/Test_Signals_Clause_7.zip')
P501 = [P501_ANNEX_B, P501_ANNEX_C, P501_ANNEX_D, P501_ANNEX_E, P501_CL_7]
G191 = r'https://www.itu.int/rec/dologin_pub.asp?lang=e&id=T-REC-G.191-202405-I!!SOFT-ZST-E&type=items'
evs = 'https://www.3gpp.org/ftp/Specs/archive/26_series/26.442/26442-i00.zip'
amr_wb = 'https://www.3gpp.org/ftp/tsg_sa/WG4_CODEC/EVS_Permanent_Documents/EVS-7a_S4-130155.zip'
amr = 'https://www.3gpp.org/ftp/tsg_sa/WG4_CODEC/EVS_Permanent_Documents/EVS-7a_S4-130155.zip'
EVS = r'https://www.3gpp.org/ftp/Specs/archive/26_series/26.442/26442-i00.zip'
AMR_WB = r'https://www.3gpp.org/ftp/tsg_sa/WG4_CODEC/EVS_Permanent_Documents/EVS-7a_S4-130155.zip'
AMR = r'https://www.3gpp.org/ftp/tsg_sa/WG4_CODEC/EVS_Permanent_Documents/EVS-7a_S4-130155.zip'
@classmethod
def get(cls, x: Any) -> 'Downloads':
def get(cls, x: Any) -> Self:
if isinstance(x, cls):
return x
try:
return cls[str(x).lower()]
return cls[str(x).upper()]
except: # noqa: E722
return cls(x)
......@@ -33,7 +42,7 @@ def download(url: str, dl_path: Path) -> Path:
return Path(x[0])
class FileFetcher:
def __init__(self, doc_download: Downloads, dl_dir: Path, extract_dir: Path = None):
def __init__(self, doc_download: Downloads, dl_dir: Path, extract_dir: Optional[Path] = None):
self.doc_download = Downloads.get(doc_download)
self.dl_dir = Path(dl_dir).absolute()
......@@ -41,12 +50,12 @@ class FileFetcher:
self.extract_dir = Path(dl_dir if extract_dir is None else extract_dir).absolute() / self.doc_download.name
def get_file(self, name: str) -> Path:
def get_file(self, name: str) -> Path|None:
self.dl_dir.mkdir(parents=True, exist_ok=True)
self.extract_dir.mkdir(parents=True, exist_ok=True)
def _search_file(name: str, raise_if_not_found: bool = True) -> Path:
def _search_file(name: str, raise_if_not_found: bool = True) -> Path|None:
candidates = list(self.extract_dir.rglob(name + '*'))
if len(candidates) == 0:
if raise_if_not_found:
......@@ -61,15 +70,23 @@ class FileFetcher:
self.zip_dl_file.unlink(missing_ok=True)
shutil.rmtree(self.extract_dir, ignore_errors=True)
download((url := self.doc_download.value), self.zip_dl_file)
# download value might contain multiple URLs
urls = np.atleast_1d(self.doc_download.value)
for url in urls:
if not isinstance(url, str):
raise ValueError(f"Invalid URL: {url}")
download(url, self.zip_dl_file)
shutil.unpack_archive(self.zip_dl_file, self.extract_dir)
# extract all zip files (inside the downloaded zip) recursively
# Search for zip files in the extract directory and unpack them.
# This is useful if the archive contains nested zip files.
while len(zip_files := list(self.extract_dir.rglob('*.zip'))) > 0:
for zip_file in zip_files:
shutil.unpack_archive(zip_file, zip_file.parent)
zip_file.unlink(missing_ok=True)
# final search for the file
return _search_file(name)
else:
return file
......
This diff is collapsed.
......@@ -12,7 +12,7 @@ from typing import Optional, Union, Iterable
from collections import namedtuple
from ensure import check
from nonlinearity.spectrum import calculate_spectrum_vs_time
from nonlinearity.spectrum import FftSpectrumAvg
THDResult = namedtuple('THDResult',
['thdn', 'thd', 'freqs_harmonics', 'levels_harmonics', 'level_harmonics_total',
......@@ -25,13 +25,16 @@ def thd_plus_n(signal: NDArray, fs: int, f0: float, harmonics: Optional[Union[in
fmin: float = 20.0, fmax: float = 20_000.0, delta_f_factor: Optional[float] = None,
always_2d: bool = False,
) -> THDResult:
n_channels = 1
if len(signal.shape) == 1:
signal = signal[:, np.newaxis]
single_channel = True
elif len(signal.shape) == 2:
single_channel = False
n_channels = signal.shape[1]
elif len(signal.shape) > 2:
raise ValueError(f"Invalid signal shape: {signal.shape}")
else:
single_channel = False
# parse harmonics
all_harmonics = np.arange(2 * f0, fmax, step=f0)
......@@ -53,8 +56,9 @@ def thd_plus_n(signal: NDArray, fs: int, f0: float, harmonics: Optional[Union[in
raise ValueError(f"Parameter harmonics must be either int or List[int], but got {type(harmonics)}")
# average FFT spectrum (full frequency range) in power domain
freq, time, spec, wcf = calculate_spectrum_vs_time(signal, fs, window, nperseg, noverlap, nfft, fmin=0, fmax=fs / 2)
spec_avg = spec.mean(axis=1) * np.power(10, wcf / 10)
spectrum = FftSpectrumAvg.from_signals(signal, fs, always_2d=True, window=window, nperseg=nperseg, noverlap=noverlap, nfft=nfft, fmin=20.0, fmax=fs / 2)
spec_avg = spectrum.get_values('pow', include_window_correction=True)
freq = spectrum.get_freqs()
# find indices for fmin, fmax, f0 +/- margin
idx_fmin = np.argmin(np.abs(freq - fmin))
......@@ -80,16 +84,16 @@ def thd_plus_n(signal: NDArray, fs: int, f0: float, harmonics: Optional[Union[in
# energy of fundamental frequency
s = slice(idx0_lower, idx0_upper + 1)
level_fund = spec_avg[s, :].sum(axis=0)
level_fund = spec_avg[s].sum(axis=0)
### Calculation of THD+N ###
# levels below and above f0
s = slice(idx_fmin, idx0_lower)
level_below_f0 = spec_avg[s, :].sum(axis=0)
level_below_f0 = spec_avg[s].sum(axis=0)
s = slice(idx0_upper + 1, idx_fmax + 1)
level_above_f0 = spec_avg[s, :].sum(axis=0)
level_above_f0 = spec_avg[s].sum(axis=0)
thdn = 10 * np.log10(level_fund) - 10 * np.log10(level_below_f0 + level_above_f0)
......@@ -101,16 +105,16 @@ def thd_plus_n(signal: NDArray, fs: int, f0: float, harmonics: Optional[Union[in
# find harmonics, calculate levels
harmonics_idx = [np.argmin(np.abs(freq - fh)) for fh in harmonics]
levels_harmonics = np.zeros_like(harmonics_idx, dtype=spec_avg.dtype)
levels_harmonics = np.zeros((len(harmonics), n_channels), dtype=spec_avg.dtype)
for j, h_ii in enumerate(harmonics_idx):
s = slice(max(idx_fmin, h_ii - nbr_margin_lower), min(idx_fmax, h_ii + nbr_margin_upper) + 1)
levels_harmonics[j] = spec_avg[s, :].sum(axis=0)
levels_harmonics[j, :] = spec_avg[s].sum(axis=0)
level_harmonics_total = levels_harmonics.sum()
level_harmonics_total = levels_harmonics.sum(axis=0)
thd = 10 * np.log10(level_fund) - 10 * np.log10(level_harmonics_total)
# additional overall level for information
level_overall = spec_avg[idx_fmin:idx_fmax + 1, :].sum(axis=0)
level_overall = spec_avg[idx_fmin:idx_fmax + 1].sum(axis=0)
# result dict (w/o harmonics)
result = dict(thdn=thdn, thd=thd, level_harmonics_total=level_harmonics_total,
......
This diff is collapsed.