Hi All :)
I'm working on my test sinewave generator application wich can generate, visualize and play variety of sinewave signals and signal patterns. I encountered a pretty strange problem (at least for me) when I tried to generate a sinewave with linearly descending frequency (more specifically: starting at 22Hz and descending down to 8.4Hz).
This is an example of frequency modulation where the modulating signal is just a simple linear descending pattern.
But in order to explain exactly what the problem is I have to first show you what my approach is to generate sinewave signal with constant frequency in the first place:
I use the obvious math equation:
Amplitude * sin(Time * Frequency + Phase)
(The phase is not included in the actual equation because it's always 0)
This is a simplified version of the function that generates sinewave audio signals.
#define RAD(a) ((a) * 0.017453292519943295769236907684886)
void CWAV_ViewerDoc::OnToolsGeneratevoice()
{
m_waveHeader.nChannels = 2; m_waveHeader.nSampPerSec = 44100; m_waveHeader.nBytePerSec = 176400; m_waveHeader.nByteInSamp = 4; m_waveHeader.nBitsPerSamp = 16;
m_nNumSamples = m_waveHeader.nSampPerSec * 60;
m_puiAudioData = new UINT[m_nNumSamples];
double dFactor = 360.0 / double(m_waveHeader.nSampPerSec); double dTime = 0.0; UINT uiSample;
for(UINT pos = 0; pos < m_nNumSamples; pos++)
{
uiSample = (SHORT)(32767.0 * sin(RAD(dTime * 22.0));
dTime += dFactor;
m_puiAudioData[pos] = uiSample << 16 | uiSample & 0x0000ffff;
}
}
This is (for my mind) the simplest, the most straightforward and intuitive way to generate sinewave signal, it's tested and it works perfectly.
Now the problem! I'll now list the same function but with frequency descension added to the algorithm, and it's also simple and straightforward. I simply get the difference between 22 and 8.4 and devide it by the total number of samples and that gives me the descension factor at which the frequency sould descend every cycle - here it is:
#define RAD(a) ((a) * 0.017453292519943295769236907684886)
void CWAV_ViewerDoc::OnToolsGeneratevoice()
{
m_waveHeader.nChannels = 2; m_waveHeader.nSampPerSec = 44100; m_waveHeader.nBytePerSec = 176400; m_waveHeader.nByteInSamp = 4; m_waveHeader.nBitsPerSamp = 16;
m_nNumSamples = m_waveHeader.nSampPerSec * 60;
m_puiAudioData = new UINT[m_nNumSamples];
double dFactor = 360.0 / double(m_waveHeader.nSampPerSec); double dTime = 0.0; UINT uiSample;
double dDescFactor = (22.0 - 8.4) / double(m_nNumSamples);
double dDescension = 0.0;
for(UINT pos = 0; pos < m_nNumSamples; pos++)
{
uiSample = (SHORT)(32767.0 * sin(RAD(dTime * (22.0 - dDescension)));
dTime += dFactor;
dDescension += dDescFactor;
m_puiAudioData[pos] = uiSample << 16 | uiSample & 0x0000ffff;
}
}
I'm sure that this example is way too simple to cause any difficulties understanding it, and I think that everybody would agree that the result must be a sinewave signal pattern with frequency descending from 22Hz down to 8.4Hz - but that's not what happens...
In reality what happens is that in the first half of the generated track the frequency descends very little (and it actually starts from freq. higher than 22Hz). In the second part of the track it starts descending at ever increassing rate (that's definitely not a linear pattern), and then roughly at 7/8-ths of the track it forms what I could call a "turnover" - it rapidly shifts the phase at 180 degrees forming 'W' letter like pattern at this point, and then the frequency actualy starts to ascend?! And it does so from that point to the end (also around the turnover the freq. is much lower than 8.4Hz).
Also in my attempts to solve the problem I found that the "turnover" is only one in this particular case. If the freq. range is wider, multiple such 'W' - 'M' turnover points will appear and the frequency between them moves up and down, while the driving pattern of all this is only a linear dissension from one positive number to another positive number.
One last thing: If you get any particular frequency from within the range and set it to be generated as constant freq. - it'll be generated perfectly as it should!
This whole thing does not make any sense! I don't nearly have any idea on how to solve this mistery...
Any help would be much appreciated!
Thank you for even reading this prolong TC! :)