簡體   English   中英

無法在C / Matlab中從基礎知識生成正弦波

[英]Trouble Generating a Sine Wave in C/Matlab from Basics

我一直在編寫一個基本的C程序來生成一個正弦波,並將其寫到STDOUT中,以便通過管道傳遞到一個濾波器中,我也將要編寫該濾波器,但是我遇到了問題。

我能夠產生聽起來像是干凈的正弦波的聲音,但是頻率卻關閉了。 當我收聽正在生成的輸出並將其與真實信號生成器的輸出進行比較時,我的頻率略高。

C代碼應生成原始的16位帶符號立體聲波形@ 44100Hz,其頻率作為參數傳遞給程序,默認為500Hz。

Matlab版本的代碼在這里(對Matlab中的1個索引進行了很小的修改,為什么要使用MATHWORKS WHY!??)減去傳遞給STDOUT等的方式,因為我知道效果很好

CHANNELS = 2; SAMPLING_RATE = 44100; NUM_SAMPLES = 512;

frequency = 1000;

%% BEGIN WHILE(1) LOOP HERE

output_buff = zeros(1,CHANNELS*NUM_SAMPLES);

for i = 1:2:CHANNELS*NUM_SAMPLES
    output_buff(i) = 30000 * sin(frequency * pi * (i-1)/NUM_SAMPLES);
    output_buff(i+1) = output_buff(i);
end

%% OUTPUT TO STDOUT AND REPEAT

我應該補充一點,這段代碼在while真正的循環內運行(在C版本中),生成完整的output_buff值,然后將緩沖區推入STDOUT。

我編寫了一些進一步的測試代碼,以查看實際生成的內容,如下所示:

plot(1:CHANNELS*NUM_SAMPLES, output_buff)

output_buff = output_buff .* hanning(length(output_buff))';    
Y = fft(output_buff);    
Mag=abs(Y(1:length(output_buff)/2)).^2;    
[a,b]=max(Mag);    
% Result    
SAMPLING_RATE*b/length(output_buff)

當我運行此腳本時,我可以看到最終生成的信號的頻率實際上是1.0767e + 03Hz ...關閉但沒有雪茄...

我嘗試調整一些參數,但不知道出了什么問題或如何使生成的頻率更准確。

C代碼本身在我的Linux安裝中,如果需要,我可以在明天添加。

您正在處理數字信號處理,這是一個復雜的領域,並且有一個專用的dsp stackexchange網站。 我的建議是:

  • 如果要輸出的內容與您輸入的內容完全一樣 ,請選擇生成一個頻率,該頻率是采樣率除以2的冪,例如44100/44 = 1002.272727 ...在這種情況下,是2的冪,將完全適合您的FFT輸入。

  • 如果想要更好的FFT結果 ,請嘗試將采樣數增加到4096或8192。因為以44,100Hz的采樣率進行512個采樣意味着您有512 / 44,100 =〜11.61 ms的信號..因此,這意味着您的數字不完整正弦波。 一個完整的正弦波在1000 Hz時正好為1 ms。 這種不完整的周期數可能會導致FFT產生近似誤差。

原來我有些錯誤。 我的for循環使用輸出緩沖區中的字節數,而不是緩沖區中的元素數。 我忽略了wav文件采樣率與生成正弦波的相關性,並且使用loop變量的不連續性導致了奇怪的偽像。

最終的工作代碼如下:

#include <sys/types.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>

#include <unistd.h>

#define M_PI 3.1415926535897932384626433832795L
#define NUM_CHANNELS 2
#define NUM_SAMPLES 512
#define SAMPLE_RATE 44100

double frequency = 500.0;

int main(int argc, char *argv[])
{   
    if (argc >= 2){
        frequency = atof(argv[1]);
    }

    int16_t samples[NUM_CHANNELS * NUM_SAMPLES];
    unsigned cbBuffer=sizeof(samples);
    int counter = 0;

    while(1){
        for (int i = 0; i < NUM_CHANNELS * NUM_SAMPLES; i+=NUM_CHANNELS){
            samples[i] = (int16_t) 3000 * sin(frequency * 2 * M_PI * (double)counter /(double)(SAMPLE_RATE));
            samples[i+1] = samples[i];
            counter++;
        }

        int done=write(STDOUT_FILENO, samples, cbBuffer);
        if(done<0){
            fprintf(stderr, "%s : Write to stdout failed, error=%s.", argv[0], strerror(errno));
            exit(1);
        }else if(done!=cbBuffer){
            fprintf(stderr, "%s : Could not read requested number of bytes from stream.\n", argv[0]);
        }
    }

    return 0;
}

我認為我有一個稍微改進的版本-使用在主while循環之外預先定義的四分之一正弦查找表。

#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <stdint.h>
#include <unistd.h>

// PI defined here for use in code
#define PI 3.141592653589793
// SINE_TABLE_SIZE - number of values in the sine lookup table - defined here for use in code
#define SINE_TABLE_SIZE 256
#define NUM_CHANNELS 2
#define NUM_SAMPLES 512

//* Sampling frequency in HZ. Must only be set to 8000, 16000, 24000 32000, 44100 (CD standard), 48000 or 96000 */
int sampling_freq = 44100;
// Array of data used by sinegen to generate sine. These are the initial values.
float y[3] = {0,0,0};
float x[1] = {1}; // impulse to start filter
float a0 = 1.4142; // coefficients for difference equation
float b0 = 0.707;
// Holds the value of the current sample
float sample;
float sine_freq = 500.0;

// An array of floats containing SINE_TABLE_SIZE elements
float table[SINE_TABLE_SIZE];
// Step variable for use in the quarter sinegen function
float step4 = 0;
// Modified step value to within Sine wave table values - for use in quarter sine wave table
float table_value;



/********************************** sine_init() **************************/ 
void sine_init4()
{
    // Fill the lookup table with 256 sine data points across one quarter cycle.
    int j;
    for(j=0; j < SINE_TABLE_SIZE; j++)
    {
        table[j] = sin(((0.5*PI*j)/SINE_TABLE_SIZE));
    }
}



/********************************** sinegen4() **************************/
float sinegen4(void)
{
/* This code produces a variable frequency sine wave, using a
quarter-sine-wave lookup table.
*
* */
    float wave4 = 0; // Initialise a variable to store the sine wave datapoint values in.
// To create a sine wave from the quarter sinewave table data.
//For values in the first sinewave quadrant - no adjustment to the step value needs to be made.
    if (step4 < (SINE_TABLE_SIZE))
    {
        table_value = step4;
        wave4 = table[(int)step4];
    }
//Second quadrant - step value must be adjusted to bring the value back into the range 0-255
    else if (step4 < (2*SINE_TABLE_SIZE) && (step4 >= SINE_TABLE_SIZE))
    {
        table_value = ((SINE_TABLE_SIZE-1)-(step4-SINE_TABLE_SIZE));

        wave4 = table[(int)((SINE_TABLE_SIZE-1)-(step4- SINE_TABLE_SIZE))];
    }
//Third quadrant - step value must be adjusted to bring the value back into the range 0-255 and the wave value negated
    else if (step4 < (3*SINE_TABLE_SIZE) && (step4 >= (2*SINE_TABLE_SIZE)) )
    {   
        table_value = (step4-(2*SINE_TABLE_SIZE));
        wave4 = -table[(int)(step4-(2*SINE_TABLE_SIZE))];
    }
//Fourth quadrant - step value must be adjusted to bring the value back into the range 0-255 and the wave value negated
    else if (step4 < (4*SINE_TABLE_SIZE) && (step4 >=(3*SINE_TABLE_SIZE)) )
    {
        table_value = ((SINE_TABLE_SIZE-1)-(step4-(3*SINE_TABLE_SIZE)));
        wave4 = -table[(int)((SINE_TABLE_SIZE-1)-(step4-(3*SINE_TABLE_SIZE)))];
    }
// assign step a value based on sampling frequency and desired output frequency to calculate next table value required.
    step4 += ((4*SINE_TABLE_SIZE)/(sampling_freq/sine_freq));
//To prevent step containing values greater than 4*SINE_TABLE_SIZE-1 which would cause the operation to overflow.
    if (step4 > ((4*SINE_TABLE_SIZE-1)))
    {
        step4 = step4 - (4*SINE_TABLE_SIZE-1);
    }

    return wave4;
}




int main(int argc, char *argv[])
{   

    if(argc > 1)
    {
        sine_freq = atoi(argv[1]);
//      printf("n = %d \n", n );
    }

    // initialises table of one quarter sinewave data
    sine_init4();
    int16_t samples[NUM_CHANNELS * NUM_SAMPLES];
    unsigned cbBuffer=sizeof(samples);
    // Loop endlessley generating a sine wave
    while(1)
    {

    // Calculate next sample from quarter sinewave data table
        for (int i = 0; i < NUM_CHANNELS * NUM_SAMPLES; i+=NUM_CHANNELS)
        {
            samples[i] = 3000*sinegen4();
            samples[i+1] = samples[i];
            //printf(" samples[i] = %d", samples[i]);
        }
        // Copy one sample to output
        int done=write(STDOUT_FILENO, samples, cbBuffer);
        //int done = cbBuffer;
        if(done<0)
        {
            fprintf(stderr, "%s : Write to stdout failed, error=%s.", argv[0], strerror(errno));
            exit(1);
        }
        else if(done!=cbBuffer)
        {
            fprintf(stderr, "%s : Could not read requested number of bytes from stream.\n", argv[0]);
        }
    }

    return 0;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM