---
# System prepended metadata

title: TES-1350A Sound Level Meter with Python

---

# TES-1350A Sound Level Meter with Python

目的：將分貝計連上電腦，獲取即時數據，數值需要與分貝計上顯示的一致。

## Environment
- [TES-1350A Sound Level Meter](https://www.tes.com.tw/product_detail.asp?seq=64)
- [USB Audio Interface / USB 音效卡 / UGREEN USB to Audio Jack Sound Card Adapter](https://www.amazon.com/UGREEN-External-Headphone-Microphone-Desktops/dp/B01N905VOY?th=1)
- 3.5mm audio plug
- Macbook Air M2

## TES-1350A

- [英文說明書](https://d17bck4wpaw2mg.cloudfront.net/att/a/2/c/4/a2c463/tes1350a-manual.pdf)

### 摘要

> Time weighting: FAST(125mS), SLOW(1 sec.)
> Level ranges: Lo: 35~100dB and Hi: 65~130dB
> Accuracy: ± 2.0dB (under reference conditions)
 
> Calibration control can be adjusted clockwise or counterclockwise to standard 94.0dB.

> AC output: 0.65 Vrms at FS (full scale), output impedance approx. 600 Ω
> DC output: 10mV / dB, output impedance approx. 100 Ω

> Calibration: Electrical calibration with the internal oscillator (1KHz sine wave)


![IMG_6091-3-1](https://hackmd.io/_uploads/ryHUezHPA.jpg)

### 使用參數

- low range: Lo: 35 ~ 100dB
- RESPONSE: F: fast respnse
- FUNCT: A: A-weighting

## 使用 pyaudio

- 輸出結果已經很接近分貝計上顯示的數值，但輸出的數字大概要再減個 2~4 dB 才會更接近。


```python=
import numpy as np
import pyaudio
import datetime
import math

# Constants from the TES-1350A manual
V_fs = 0.65  # Full scale voltage in Vrms
db_fs = 100  # Corresponding dB level at full scale in low range

# Calculate the reference voltage for 94 dB SPL
V_94 = V_fs * 10 ** ((94 - db_fs) / 20)


def voltage_to_db_spl(v_rms, v_ref):
    return 20 * np.log10(v_rms / v_ref) + 94


def callback(indata, frames, time, status):
    indata = np.frombuffer(indata, dtype=np.int16)  # Convert to 16-bit integer
    max_int_value = 2**15  # 32768 for 16-bit PCM

    # Scale the integer data to voltage
    voltage_data = indata / max_int_value * V_fs

    squared_data = np.square(voltage_data)
    mean_squared_data = np.mean(squared_data)
    rms_voltage = np.sqrt(mean_squared_data)

    # Calculate the RMS voltage of the input signal
    print(f"RMS Voltage: {rms_voltage:.6f} V", flush=True)

    # Convert the RMS voltage to decibels (A-weighted)
    db_spl = voltage_to_db_spl(rms_voltage, V_94)
    log_entry = f"{datetime.datetime.now()} - {db_spl:.2f} dB(A)\n"
    print(log_entry, end='')


device_index = 2  # Replace with the actual device index
duration = 1  # Replace with the actual duration in seconds

FORMAT = pyaudio.paInt16
CHANNELS = 1
RATE = 44100
CHUNK = 1024

audio = pyaudio.PyAudio()

stream = audio.open(format=FORMAT, channels=CHANNELS,
                    rate=RATE, input=True,
                    input_device_index=device_index,
                    frames_per_buffer=CHUNK)

print("Recording...")
for _ in range(0, int(RATE / CHUNK * duration)):
    indata = stream.read(CHUNK)
    callback(indata, CHUNK, None, None)

print("Finished recording.")

stream.stop_stream()
stream.close()
audio.terminate()

```

## ChatGPT 對程式碼的解釋

### Information Used:
1. **Full Scale Voltage (V_fs)**: 0.65 Vrms as specified in the manual, which corresponds to the full-scale dB level (100 dB) on the meter.
2. **Full Scale dB Level (db_fs)**: 100 dB is the full-scale level for the low range.
3. **Calibration Reference (94 dB SPL)**: The device can be calibrated to 94 dB SPL, a standard reference point.

### Steps and Calculations:

1. **Convert Raw Audio Data to Integers**:
    - The audio data is captured in 16-bit PCM format, which ranges from -32768 to 32767. This raw data is converted to integers using `np.frombuffer(indata, dtype=np.int16)`.

2. **Scale the Integer Data to Voltage**:
    - The raw integer values are scaled to voltages based on the full-scale voltage (0.65 Vrms). The formula used is:
$$
\text{voltage_data} = \frac{\text{indata}}{\text{max_int_value}} \times V_{fs}
$$
    - Here, `max_int_value` is \(2^{15} = 32768\), the maximum value for 16-bit PCM data.

3. **Calculate RMS Voltage**:
    - The Root Mean Square (RMS) voltage is calculated from the scaled voltage data:
    $$
      \text{squared_data} = \text{voltage_data}^2
    $$
    $$
      \text{mean_squared_data} = \text{mean}(\text{squared_data})
    $$
    $$
      \text{rms_voltage} = \sqrt{\text{mean_squared_data}}
    $$
    - This gives the RMS voltage of the input signal.

4. **Reference Voltage Calculation**:
    - Calculate the reference voltage \(V_{94}\) corresponding to 94 dB SPL:
      $$
      V_{94} = V_{fs} \times 10^{\frac{94 - db_{fs}}{20}}
      $$
    - This uses the relationship between voltage and dB SPL, where \(V_{fs}\) is the full-scale voltage and \(db_{fs}\) is the full-scale dB level.

5. **Convert RMS Voltage to dB SPL**:
    - The formula to convert the RMS voltage to dB SPL (A-weighted) is:
      $$
      \text{dB SPL} = 20 \times \log_{10}\left(\frac{\text{rms_voltage}}{V_{94}}\right) + 94
      $$
    - This formula compares the measured RMS voltage to the reference voltage \(V_{94}\) and adds the calibration level (94 dB SPL).

This ensures that the audio signal is correctly processed, scaled, and converted to dB SPL (A-weighted), matching the expected readings from your sound level meter.

## 使用 sounddevice

:::warning
失敗，轉換出錯誤數值，程式碼有問題。
:::


### 伏特轉換分貝

```python=
import numpy as np
import sounddevice as sd
import datetime

# Constants from the TES-1350A manual
V_fs = 0.65  # Full scale voltage in Vrms
db_fs = 100  # Corresponding dB level at full scale in Hi range


def voltage_to_db(v_rms, v_fs, db_fs):
    return (v_rms / v_fs) * db_fs


def callback(indata, frames, time, status):
    # Flatten the array to a single dimension
    flat_indata = indata.flatten()

    # Calculate the RMS voltage of the input signal
    rms_voltage = np.sqrt(np.mean(flat_indata**2))
    print(f"RMS Voltage: {rms_voltage:.6f} V", flush=True)

    # Convert the RMS voltage to decibels
    db = voltage_to_db(rms_voltage, V_fs, db_fs)
    log_entry = f"{datetime.datetime.now()} - {db:.2f} dB\n"
    print(log_entry, end='')


device_index = 2  # Replace with the actual device index
duration = 1  # Replace with the actual duration in seconds

with sd.InputStream(callback=callback, device=device_index):
    sd.sleep(duration * 1000)

```

Output


```
RMS Voltage: 0.000063 V
2024-07-04 19:58:00.784316 - 0.01 dB
RMS Voltage: 0.000065 V
2024-07-04 19:58:00.868526 - 0.01 dB
RMS Voltage: 0.000062 V
2024-07-04 19:58:00.953830 - 0.01 dB
```

### Raw data

```python=
import sounddevice as sd
import numpy as np
import datetime


def log_decibels(duration, device_index=2, filename='raw_output_signals.txt'):

    with open(filename, 'w') as f:
        def callback(indata, frames, time, status):
            log_entry = f"{datetime.datetime.now()} - {indata}\n"
            print(log_entry, end='')
            f.write(log_entry)

        with sd.InputStream(callback=callback, device=device_index):
            sd.sleep(duration * 1000)


if __name__ == "__main__":
    log_decibels(1)

```

Output

```
2024-07-05 14:08:30.426940 - [[-0.00125122]
 [-0.0010376 ]
 [-0.00128174]
 ...
 [ 0.00146484]
 [ 0.00088501]
 [ 0.00115967]]
2024-07-05 14:08:30.512188 - [[ 0.00149536]
 [ 0.00097656]
 [ 0.00018311]
 ...
 [-0.00112915]
 [-0.00057983]
 [-0.00057983]]
2024-07-05 14:08:30.597561 - [[-2.7465820e-04]
 [ 3.0517578e-05]
 [-1.8310547e-04]
 ...
 [ 6.1340332e-03]
 [ 8.3312988e-03]
 [ 7.7819824e-03]]
```


## Reference
- [錄音筆記－數位音量標準、 dBFS、dBTP、LUFS](https://corychu.medium.com/%E9%8C%84%E9%9F%B3%E7%AD%86%E8%A8%98-%E6%95%B8%E4%BD%8D%E9%9F%B3%E9%87%8F%E6%A8%99%E6%BA%96-dbfs-dbtp-lufs-c47ca4646b7f)
- Github repo
    - https://github.com/johnson86tw/noise-monitoring-pi
    - https://github.com/johnson86tw/noise-monitoring

