Question

I'm trying to develop an static method in Java to generate a pure tone.

In the begining it seemed easy, but when I've try to write the double array to the loudspeakers I appreciate too much harmonics.

I test it with an spectrum analyzer (sonometer) and then, also I've drawn in a graphic the array resultant. When I've done it I've seen the problem:

It's about the wave form, it's abrupted. I want to smooth this array, but I don't know how to do it.

This is the code:

/**
 * 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()
Was it helpful?

Solution 4

This is the definitive code:

/**
 * 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()

A main() to test it:

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()

OTHER TIPS

Writing the same value to two consecutive locations introduces a step into the waveform. Any deviation from a smooth sine curve adds harmonics. If you want a pure tone, Don't Do That. If you want to do that, Don't Expect A Pure Tone.

You need to compute the angle and sine for every value of 'bufferLength', not from every second value. What you're doing is essentially under-sampling with interpolation. I don't see any 'symmetry' about that.

I'm not really sure, but I think I've confused about @EJP was talking about: I needed obtain each value step by step. Symmetry it was a fast but worse method about the quality of the signal.

This is the new code:

/**
 * 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()
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top