2024.9.22 計劃

Laurance發表於2024-09-22

專案部分

個人學習部分

總結

如果得到了聲音的訊號,可以經過處理用python繪製出來對應位置的熱力圖,這裡採用隨機生成的聲音訊號,程式碼如下:

import numpy as np
import matplotlib.pyplot as plt

# 常量定義
M_side = 16  # 使用4x4陣列
d = 0.1  # 麥克風之間的距離 (m)
c = 343  # 聲速 (m/s)
N = 1000  # 取樣點數
fs = 8000  # 取樣頻率 (Hz)
t = np.linspace(0, N / fs, N)  # 時間陣列

# 定義更大的二維麥克風陣列的位置 (4x4平面陣列)
mic_positions = np.array([[i * d, j * d] for i in range(M_side) for j in range(M_side)])
M = mic_positions.shape[0]  # 總麥克風數量


# 每次生成隨機位置和訊號
def generate_random_signal():
    # 隨機生成聲源的二維平面位置
    true_x = np.random.uniform(0, 1)
    true_y = np.random.uniform(0, 1)

    # 隨機生成訊號頻率 (200 Hz 到 2000 Hz)
    f = np.random.uniform(200, 2000)

    # 生成模擬的聲源訊號 s(t) (隨機頻率的正弦訊號)
    s = np.sin(2 * np.pi * f * t)  # 正弦訊號

    # 隨機生成聲源距離 (0.5米到2米)
    true_distance = np.random.uniform(1, 5)
    print(f"Generated random sound source at ({true_x:.2f}, {true_y:.2f}, {true_distance:.2f}) with frequency {f:.2f} Hz")

    return s, true_x, true_y, true_distance, f


# 生成麥克風陣列接收到的訊號
def generate_received_signals(s, true_x, true_y, true_distance, f):
    X = np.zeros((M, N), dtype=complex)  # 麥克風陣列接收到的訊號
    for m, pos in enumerate(mic_positions):
        # 計算每個麥克風到聲源的距離
        distance = np.sqrt((true_x - pos[0]) ** 2 + (true_y - pos[1]) ** 2 + true_distance ** 2)

        # 引入距離衰減效應和相位延遲
        attenuation = 1 / (distance ** 2)  # 衰減因子
        delay = distance / c  # 計算相位延遲

        # 生成接收到的訊號,並考慮衰減和延遲
        X[m, :] = attenuation * s * np.exp(-1j * 2 * np.pi * f * delay)
    return X


# 計算導向向量函式,考慮平面上的 (x, y) 座標和距離
def calculate_steering_vector(x, y, z, mic_positions, f, c):
    steering_vector = np.zeros(len(mic_positions), dtype=complex)
    for m, pos in enumerate(mic_positions):
        distance = np.sqrt((x - pos[0]) ** 2 + (y - pos[1]) ** 2 + z ** 2)
        steering_vector[m] = np.exp(-1j * 2 * np.pi * f * distance / c)
    return steering_vector


# 計算功率譜
def calculate_power_spectrum(steering_vector, R):
    return np.real(np.conjugate(steering_vector).T @ R @ steering_vector)


# 主函式:生成隨機訊號並計算熱力圖
def generate_heatmap():
    # 生成隨機訊號和位置、距離
    s, true_x, true_y, true_distance, f = generate_random_signal()

    # 生成麥克風陣列接收到的訊號
    X = generate_received_signals(s, true_x, true_y, true_distance, f)

    # 加入噪聲
    noise = 0.1 * np.random.randn(M, N)
    X += noise

    # 計算協方差矩陣 R
    R = (X @ X.conj().T) / N

    # 建立二維平面網格,定義掃描範圍
    grid_size = 100  # 網格尺寸 (100x100)
    x_range = np.linspace(0, 1, grid_size)  # X 軸範圍
    y_range = np.linspace(0, 1, grid_size)  # Y 軸範圍
    power_map = np.zeros((grid_size, grid_size))

    max_power = -np.inf  # 初始化最大功率
    max_position = (0, 0)  # 初始化最大功率的位置

    # 掃描平面中的每個點 (x, y),假設聲源在此點
    for i, x in enumerate(x_range):
        for j, y in enumerate(y_range):
            steering_vector = calculate_steering_vector(x, y, true_distance, mic_positions, f, c)
            power = calculate_power_spectrum(steering_vector, R)
            power_map[j, i] = power
            # 找到最大功率
            if power > max_power:
                max_power = power
                max_position = (x, y)

    # 歸一化功率譜
    power_map = power_map / np.max(power_map)

    # 列印找到的聲源位置和真實距離
    print(f"Estimated sound source position: {max_position} with true distance {true_distance:.2f} meters")

    # 繪製二維熱力圖
    plt.imshow(power_map, extent=[x_range.min(), x_range.max(), y_range.min(), y_range.max()], cmap='hot',
               origin='lower')
    plt.title(f'2D Sound Source Heatmap (Estimated Source at {max_position})')
    plt.colorbar(label='Power Spectrum')
    plt.show()


# 生成隨機訊號並繪製熱力圖
generate_heatmap()

同時考慮距離對於生成圖片的影響,距離近的時候定位非常準確,產生的圓形範圍較小,遠的時候定位不夠準確,圓形範圍較大。
以下三張圖分別以距離為0.31m, 1.31m, 4.31m作比較(位置為(0.34, 0.44)):
2024.9.22 計劃 距離0.31m
2024.9.22 計劃 距離1.31m
2024.9.22 計劃 距離4.31m