{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Reading SOFA Files With Python\n", "\n", "SOFA: http://www.sofaconventions.org/\n", "\n", "Example file from https://depositonce.tu-berlin.de/handle/11303/245.2, also available at http://sofacoustics.org/data/database/tuburo/.\n", "\n", "This is only about *reading* files, *creating* and *writing* to SOFA files is beyond the scope of this page." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## scipy.io.netcdf\n", "\n", "scipy.io.netcdf (v0.18) doesn't support NetCDF4.\n", "\n", "http://docs.scipy.org/doc/scipy/reference/generated/scipy.io.netcdf.netcdf_file.html" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "from scipy.io import netcdf_file" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Error: RIR_AllAbsorbers_ArrayCentre_Emitters1to64.sofa is not a valid NetCDF 3 file\n" ] } ], "source": [ "try:\n", " netcdf_file('RIR_AllAbsorbers_ArrayCentre_Emitters1to64.sofa')\n", "except Exception as e:\n", " print(e)" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'1.10.1'" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import scipy\n", "scipy.__version__" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## netcdf4-python\n", "\n", "based on Scientific.IO.NetCDF API\n", "\n", "Debian package `python3-netcdf4`\n", "\n", "http://unidata.github.io/netcdf4-python/\n", "\n", "https://github.com/Unidata/netcdf4-python\n", "\n", "http://nbviewer.ipython.org/github/Unidata/netcdf4-python/blob/master/examples/reading_netCDF.ipynb\n", "\n", "http://nbviewer.ipython.org/github/Unidata/netcdf4-python/blob/master/examples/writing_netCDF.ipynb" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "import netCDF4" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "\n", "root group (NETCDF4 data model, file format HDF5):\n", " Conventions: SOFA\n", " Version: 1.0\n", " SOFAConventions: GeneralFIRE\n", " SOFAConventionsVersion: 1.0\n", " APIName: ARI SOFA API for Matlab/Octave\n", " APIVersion: 1.1.1\n", " ApplicationName: Matlab\n", " ApplicationVersion: R2013a\n", " AuthorContact: vera.erbes@uni-rostock.de\n", " Comment: RIR measurements of 64-channel loudspeaker array at University of Rostock.\n", " DataType: FIRE\n", " History: Converted from the TU Berlin/University of Rostock format\n", "Upgraded from SOFA 0.6\n", " License: Creative Commons Attribution-NonCommercial-ShareAlike 4.0\n", " Organization: University of Rostock, Institute of Communications Engineering\n", " References: V. Erbes, M. Geier, S. Weinzierl and S. Spors (2015): Database of single-channel and binaural room impulse responses of a 64-channel loudspeaker array. Proc. of the 138th AES Conv., Warsaw, Poland\n", " RoomType: shoebox\n", " Origin: Acoustically measured with omnidirectional microphone\n", " DateCreated: 2014-12-01 13:50:46\n", " DateModified: 2020-04-02 09:36:39\n", " Title: Rostock RIR audio lab, broadband absorbers on walls and ceiling, listener in centre of array\n", " RoomDescription: University of Rostock, INT Audio Lab, Room 8202, broadband absorbers on walls and ceiling, mid-frequency reverberation time = 0.32 s\n", " ListenerDescription: iSEMcon EMX-7150\n", " EmitterDescription: Neumann KH 120 A\n", " DatabaseName: Multichannel RIRs University of Rostock\n", " ListenerShortName: OmniMic\n", " SourceDescription: 64-channel loudspeaker array\n", " dimensions(sizes): I(1), C(3), R(1), E(64), N(44100), M(1), S(0)\n", " variables(dimensions): float64 ListenerPosition(I, C), float64 ReceiverPosition(R, C, I), float64 SourcePosition(I, C), float64 EmitterPosition(E, C, I), float64 SourceUp(I, C), float64 SourceView(I, C), float64 EmitterUp(E, C, I), float64 EmitterView(E, C, I), float64 RoomCornerA(I, C), float64 RoomCornerB(I, C), float64 Data.IR(M, R, E, N), float64 Data.SamplingRate(I), float64 Data.Delay(I, R, E)\n", " groups: " ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f = netCDF4.Dataset('RIR_AllAbsorbers_ArrayCentre_Emitters1to64.sofa')\n", "f" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'ListenerPosition': \n", " float64 ListenerPosition(I, C)\n", " Type: cartesian\n", " Units: metre\n", " unlimited dimensions: \n", " current shape = (1, 3)\n", " filling on, default _FillValue of 9.969209968386869e+36 used,\n", " 'ReceiverPosition': \n", " float64 ReceiverPosition(R, C, I)\n", " Type: cartesian\n", " Units: metre\n", " unlimited dimensions: \n", " current shape = (1, 3, 1)\n", " filling on, default _FillValue of 9.969209968386869e+36 used,\n", " 'SourcePosition': \n", " float64 SourcePosition(I, C)\n", " Type: cartesian\n", " Units: metre\n", " unlimited dimensions: \n", " current shape = (1, 3)\n", " filling on, default _FillValue of 9.969209968386869e+36 used,\n", " 'EmitterPosition': \n", " float64 EmitterPosition(E, C, I)\n", " Type: cartesian\n", " Units: metre\n", " unlimited dimensions: \n", " current shape = (64, 3, 1)\n", " filling on, default _FillValue of 9.969209968386869e+36 used,\n", " 'SourceUp': \n", " float64 SourceUp(I, C)\n", " unlimited dimensions: \n", " current shape = (1, 3)\n", " filling on, default _FillValue of 9.969209968386869e+36 used,\n", " 'SourceView': \n", " float64 SourceView(I, C)\n", " Type: cartesian\n", " Units: metre\n", " unlimited dimensions: \n", " current shape = (1, 3)\n", " filling on, default _FillValue of 9.969209968386869e+36 used,\n", " 'EmitterUp': \n", " float64 EmitterUp(E, C, I)\n", " unlimited dimensions: \n", " current shape = (64, 3, 1)\n", " filling on, default _FillValue of 9.969209968386869e+36 used,\n", " 'EmitterView': \n", " float64 EmitterView(E, C, I)\n", " Type: cartesian\n", " Units: metre\n", " unlimited dimensions: \n", " current shape = (64, 3, 1)\n", " filling on, default _FillValue of 9.969209968386869e+36 used,\n", " 'RoomCornerA': \n", " float64 RoomCornerA(I, C)\n", " Type: cartesian\n", " Units: metre\n", " unlimited dimensions: \n", " current shape = (1, 3)\n", " filling on, default _FillValue of 9.969209968386869e+36 used,\n", " 'RoomCornerB': \n", " float64 RoomCornerB(I, C)\n", " Type: cartesian\n", " Units: metre\n", " unlimited dimensions: \n", " current shape = (1, 3)\n", " filling on, default _FillValue of 9.969209968386869e+36 used,\n", " 'Data.IR': \n", " float64 Data.IR(M, R, E, N)\n", " unlimited dimensions: \n", " current shape = (1, 1, 64, 44100)\n", " filling on, default _FillValue of 9.969209968386869e+36 used,\n", " 'Data.SamplingRate': \n", " float64 Data.SamplingRate(I)\n", " Units: hertz\n", " unlimited dimensions: \n", " current shape = (1,)\n", " filling on, default _FillValue of 9.969209968386869e+36 used,\n", " 'Data.Delay': \n", " float64 Data.Delay(I, R, E)\n", " unlimited dimensions: \n", " current shape = (1, 1, 64)\n", " filling on, default _FillValue of 9.969209968386869e+36 used}" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f.variables" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "\n", "float64 Data.IR(M, R, E, N)\n", "unlimited dimensions: \n", "current shape = (1, 1, 64, 44100)\n", "filling on, default _FillValue of 9.969209968386869e+36 used" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "var = f.variables['Data.IR']\n", "var" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(64, 44100)" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "data = var[0, 0]\n", "data.shape" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [], "source": [ "f.close()" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'1.6.4'" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "netCDF4.__version__" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'4.9.3-development'" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "netCDF4.__netcdf4libversion__" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'1.12.2'" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "netCDF4.__hdf5libversion__" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Scientific.IO.NetCDF\n", "\n", "ScientificPython (not to be confused with SciPy!)\n", "\n", "http://dirac.cnrs-orleans.fr/plone/software/scientificpython\n", "\n", "https://bitbucket.org/khinsen/scientificpython\n", "\n", "http://dirac.cnrs-orleans.fr/ScientificPython/ScientificPythonManual/Scientific.IO.NetCDF.NetCDFFile-class.html\n", "\n", "Only for Python 2, no Python 3 support?\n", "\n", "Example:\n", "\n", "```python\n", "from Scientific.IO.NetCDF import NetCDFFile\n", "\n", "f = NetCDFFile('RIR_AllAbsorbers_ArrayCentre_Emitters1to64.sofa')\n", "\n", "var = f.variables['Data.IR']\n", "\n", "var.typecode() # 'd'\n", "\n", "data = var.getValue()\n", "\n", "data.shape # (1, 1, 64, 44100)\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## PyTables\n", "\n", "Open SOFA file as HDF5 (there are a lot of warnings but it seems to work)\n", "\n", "http://www.pytables.org/" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [], "source": [ "import tables" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [], "source": [ "f = tables.open_file('RIR_AllAbsorbers_ArrayCentre_Emitters1to64.sofa')" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [], "source": [ "#f" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [], "source": [ "#f.root" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "It's impossible to get `Data.IR` by attribute access because sadly it contains a period." ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "/home/mg/git/.venv/lib/python3.11/site-packages/tables/attributeset.py:290: DataTypeWarning: Unsupported type for attribute 'DIMENSION_LIST' in node 'Data.IR'. Offending HDF5 class: 9\n", " value = self._g_getattr(self._v_node, name)\n" ] }, { "data": { "text/plain": [ "/Data.IR (CArray(1, 1, 64, 44100)shuffle, zlib(1)) ''\n", " atom := Float64Atom(shape=(), dflt=9.969209968386869e+36)\n", " maindim := 0\n", " flavor := 'numpy'\n", " byteorder := 'little'\n", " chunkshape := (1, 1, 32, 22050)" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "var = f.get_node('/Data.IR')\n", "var" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`CArray` $\\to$ chunked array" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "dtype('float64')" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "var.dtype" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(1, 1, 64, 44100)" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "var.shape" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "numpy.ndarray" ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "data = var[0, 0]\n", "type(data)" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [], "source": [ "f.close()" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'3.9.0'" ] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ "tables.__version__" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## h5py\n", "\n", "http://www.h5py.org/\n", "\n", "http://docs.h5py.org/" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [], "source": [ "import h5py" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 24, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f = h5py.File('RIR_AllAbsorbers_ArrayCentre_Emitters1to64.sofa')\n", "f" ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "b'SOFA'" ] }, "execution_count": 25, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f.attrs['Conventions']" ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "b'GeneralFIRE'" ] }, "execution_count": 26, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f.attrs['SOFAConventions']" ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "b'shoebox'" ] }, "execution_count": 27, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f.attrs['RoomType']" ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 28, "metadata": {}, "output_type": "execute_result" } ], "source": [ "var = f['Data.IR']\n", "var" ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "numpy.ndarray" ] }, "execution_count": 29, "metadata": {}, "output_type": "execute_result" } ], "source": [ "data = var[0, 0]\n", "type(data)" ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [], "source": [ "f.close()" ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'3.9.0'" ] }, "execution_count": 31, "metadata": {}, "output_type": "execute_result" } ], "source": [ "h5py.__version__" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## h5netcdf\n", "\n", "Uses the `h5py` module (see above). The NetCDF4 C library is *not* needed.\n", "\n", "https://pypi.python.org/pypi/h5netcdf/\n", "\n", "https://github.com/shoyer/h5netcdf" ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [], "source": [ "import h5netcdf" ] }, { "cell_type": "code", "execution_count": 33, "metadata": {}, "outputs": [], "source": [ "f = h5netcdf.File('RIR_AllAbsorbers_ArrayCentre_Emitters1to64.sofa', 'r')" ] }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "\n", "Dimensions:\n", " I: \n", " C: \n", " R: \n", " E: \n", " N: \n", " M: \n", " S: \n", "Groups:\n", "Variables:\n", " ListenerPosition: ('I', 'C') float64\n", " ReceiverPosition: ('R', 'C', 'I') float64\n", " SourcePosition: ('I', 'C') float64\n", " EmitterPosition: ('E', 'C', 'I') float64\n", " SourceUp: ('I', 'C') float64\n", " SourceView: ('I', 'C') float64\n", " EmitterUp: ('E', 'C', 'I') float64\n", " EmitterView: ('E', 'C', 'I') float64\n", " RoomCornerA: ('I', 'C') float64\n", " RoomCornerB: ('I', 'C') float64\n", " Data.IR: ('M', 'R', 'E', 'N') float64\n", " Data.SamplingRate: ('I',) float64\n", " Data.Delay: ('I', 'R', 'E') float64\n", "Attributes:\n", " Conventions: 'SOFA'\n", " Version: '1.0'\n", " SOFAConventions: 'GeneralFIRE'\n", " SOFAConventionsVersion: '1.0'\n", " APIName: 'ARI SOFA API for Matlab/Octave'\n", " APIVersion: '1.1.1'\n", " ApplicationName: 'Matlab'\n", " ApplicationVersion: 'R2013a'\n", " AuthorContact: 'vera.erbes@uni-rostock.de'\n", " Comment: 'RIR measurements of 64-channel loudspeaker array at University of Rostock.'\n", " DataType: 'FIRE'\n", " History: 'Converted from the TU Berlin/University of Rostock format\\nUpgraded from SOFA 0.6'\n", " License: 'Creative Commons Attribution-NonCommercial-ShareAlike 4.0'\n", " Organization: 'University of Rostock, Institute of Communications Engineering'\n", " References: 'V. Erbes, M. Geier, S. Weinzierl and S. Spors (2015): Database of single-channel and binaural room impulse responses of a 64-channel loudspeaker array. Proc. of the 138th AES Conv., Warsaw, Poland'\n", " RoomType: 'shoebox'\n", " Origin: 'Acoustically measured with omnidirectional microphone'\n", " DateCreated: '2014-12-01 13:50:46'\n", " DateModified: '2020-04-02 09:36:39'\n", " Title: 'Rostock RIR audio lab, broadband absorbers on walls and ceiling, listener in centre of array'\n", " RoomDescription: 'University of Rostock, INT Audio Lab, Room 8202, broadband absorbers on walls and ceiling, mid-frequency reverberation time = 0.32 s'\n", " ListenerDescription: 'iSEMcon EMX-7150'\n", " EmitterDescription: 'Neumann KH 120 A'\n", " DatabaseName: 'Multichannel RIRs University of Rostock'\n", " ListenerShortName: 'OmniMic'\n", " SourceDescription: '64-channel loudspeaker array'" ] }, "execution_count": 34, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f" ] }, { "cell_type": "code", "execution_count": 35, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "\n", "Attributes:" ] }, "execution_count": 35, "metadata": {}, "output_type": "execute_result" } ], "source": [ "var = f['Data.IR']\n", "var" ] }, { "cell_type": "code", "execution_count": 36, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "numpy.ndarray" ] }, "execution_count": 36, "metadata": {}, "output_type": "execute_result" } ], "source": [ "data = var[0, 0]\n", "type(data)" ] }, { "cell_type": "code", "execution_count": 37, "metadata": {}, "outputs": [], "source": [ "f.close()" ] }, { "cell_type": "code", "execution_count": 38, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'1.2.0'" ] }, "execution_count": 38, "metadata": {}, "output_type": "execute_result" } ], "source": [ "h5netcdf.__version__" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.11.5" }, "widgets": { "state": {}, "version": "2.0.10" } }, "nbformat": 4, "nbformat_minor": 4 }