Уменьшите гармоники, генерирующие чистый тон в Java

Я пытаюсь разработать статический метод в Java для генерации чистого тона.

Вначале это казалось простым, но когда я пытаюсь записать двойной массив в динамики, я ценю слишком много гармоник.

Я тестирую его с помощью анализатора спектра (сонометр), а затем также нарисую результирующий массив. Когда я это сделал, я увидел проблему:

Речь идет о форме волны, она обрывается. Я хочу сгладить этот массив, но я не знаю, как это сделать.

Это код:

/**
 * Genera un tono puro.
 * @param bufferSize Tamaño del buffer.
 * @param fs Frecuencia de muestreo.
 * @param f0 Frecuencia central. 
 * @return El tono puro.
 */
public static double[] generateTone(int bufferSize, int fs, int f0) {
    double[] tone = new double[bufferSize]; // Tono
    double angle; // Ángulo del tono

    // Sólo hace falta recorrer la mitad del array, ya que hay simetría:
    for (int i = 0; i < tone.length / 2; i++) {
        angle = 2 * Math.PI * f0 * i / fs; // Calculamos la variación del ángulo

        // Tenemos que conseguir que la señal sea menos abrupta para reducir al máximo los armónicos):
        tone[2 * i + 1] = tone[2 * i] = Math.sin(angle); // Aprovechamos la simetría
    }

    return tone;
} // getSinus()

4 ответа

Решение

Это окончательный код:

/**
 * Genera un tono puro.
 * @param bufferSize Tamaño del buffer.
 * @param fs Frecuencia de muestreo.
 * @param f0 Frecuencia central. 
 * @return El tono puro.
 */
public static double[] generateTone(int bufferSize, int fs, double f0) {
    double[] tone = new double[bufferSize]; // Tono
    double angle; // Ángulo del tono

    for (int i = 0; i < tone.length; i++) {
        angle = 2 * Math.PI * f0 * i / fs; // Calculamos la variación del ángulo
        tone[i] = Math.sin(angle); // Cada muestra se obtiene a partir del seno del ángulo
    }

    return tone;
} // generateTone()

Основное (), чтобы проверить это:

public static void main(String[] args) {
    double[] x; // Señal de entrada (en nuestro caso es un tono puro a 250 Hz)
    int bufferSize = 1024;
    int fs = 44100;
    double f0 = ((float) fs / (float) bufferSize);
    System.out.println("f0 =  " + f0);

    x = GSignals.generateTone(bufferSize, fs, f0); // Generamos la señal de entrada
} // main()

Запись одного и того же значения в два последовательных местоположения представляет собой шаг в осциллограмме. Любое отклонение от гладкой синусоиды добавляет гармоники. Если тебе нужен чистый тон, не делай этого. Если вы хотите сделать это, не ждите чистого тона.

Вам нужно вычислять угол и синус для каждого значения 'bufferLength', а не для каждого второго значения. То, что вы делаете, это по сути недостаточная выборка с интерполяцией. Я не вижу никакой "симметрии" в этом.

Я не совсем уверен, но я думаю, что запутался в том, о чем говорил @EJP: мне нужно было получать каждое значение шаг за шагом. Симметрия это был быстрый, но худший метод качества сигнала.

Это новый код:

/**
 * Genera un tono puro.
 * @param bufferSize Tamaño del buffer.
 * @param fs Frecuencia de muestreo.
 * @param f0 Frecuencia central. 
 * @return El tono puro.
 */
public static double[] generateTone(int bufferSize, int fs, int f0) {
    double[] tone = new double[bufferSize]; // Tono
    double angle; // Ángulo del tono

    for (int i = 0; i < tone.length; i++) {
        angle = 2 * Math.PI * f0 * i / fs; // Calculamos la variación del ángulo
        tone[i] = Math.sin(angle); // Cada muestra se obtiene a partir del seno del ángulo
    }

    return tone;
} // generateTone()
Другие вопросы по тегам