How to generate mixed frequency sinewave using STM32F4 DAC? - signal-processing

I am using STM32F4 Discovery board. I have generated a 10Hz sine wave using DAC Channel1.
As per STM's Application note, the sine wave generation should be done as follows:
And it can be used to produce desired frequency using following formula:
This is my simple function which populates 100 Samples. Since I used fTimerTRGO = 1kHz, fSinewave is correctly coming as 1k/100 = 10Hz
Appl_getSineVal();
HAL_DAC_Start_DMA(&hdac, DAC_CHANNEL_1, (uint32_t*)Appl_u16SineValue, 100, DAC_ALIGN_12B_R);
.
.
.
.
void Appl_getSineVal(void)
{
for (uint8_t i=0; i<100; i+=1){
Appl_u16SineValue[i] = ((sin(i*2*PI/100) + 1)*(4096/2));
}
}
Now I want to super impose another sine wave of frequency 5Hz in addition to this on the same channel to get a mixed frequency signal. I need help how to solve this.
I tried by populating Appl_u16SineValue[] array with different sine values, but those attempts doesnot worth mentioning here.

In order to combine two sine waves, just add them:
sin(...) + sin(...)
Since the sum is in the range [-2...2] (instead of [-1...1]), it needs to be scaled. Otherwise it would exceed the DAC range:
0.5 * sin(...) + 0.5 * sin(...)
Now it can be adapted to the DAC integer range as before:
(0.5 * sin(...) + 0.5 * sin(...) + 1) * (4096 / 2)
Instead of the gain 0.5 and 0.5, it's also possible to choose other gains, e.g. 0.3 and 0.7. They just need to add up to 1.0.
Update
For your specific case with a 10Hz and a 5Hz sine wave, the code would look like so:
for (uint8_t i=0; i < 200; i++) {
mixed[i] = (0.5 * sin(i * 2*PI / 100) + 0.5 * sin(i * 2*PI / 200) + 1) * (4096 / 2);
}

Related

Q: What is the mathematical relationship between the amplitudes of the cos and sine waves of an FFT output

I have decomposed some time series data using a custom FFT implementation. By design my FFT implementation gives me a set of cos and sine waves that I can then sum together to regenerate the original signal. This works well without issue, so I know that the extracted sine and cos waves are correct in terms of amplitude, period and phase.
The data I am using has 1024 samples which gives me the properties of 512 cos waves and 512 sine waves (eg the amplitude, phase and period data for each wave).
To save on data storage I am trying to find/understand the mathematical relationship between the amplitudes of the waves. Instead of having to save every amplitude for every sine and cos wave I would like to simply save some coefficients that I can later use to rebuild the amplitudes in code.
FFT Sine Waves with Amplitudes
From the above image you can see that there is a set of Power curve coefficients that roughly fit the amplitude data, however for my use case this is not accurate enough.
As I have all the source data along with the generated properties of each wave, is there a simple formula that I can use or a transform I can perform to generate the amplitudes in code after I have performed the FFT? I know that the amplitudes are related to the real and imaginary values however I cannot store all the real and imaginary values either due to space requirements.
As an example of how I am saving this issue for the period data, I have found that the period of each wave is simply Math.Power(waveIndex, -1). So for the wave periods I do not have to store the data, I can simply regenerate in code.
I cannot currently find a relationship between the amplitudes within the sine wave or even a relationship between cos and sine amplitudes, however the theory and math behind FFT is beyond me so I am hoping that there is a simply formula or concept I can implement.
Following the replies I have added the below code that I use to get the sine and cos wave values, this code snippet may help those replying.
internal void GetSineAndCosWavesBasic(double[] outReal, double[] outImag, int numWaves, out double[,] sineValues, out double[,] cosValues)
{
// the real and imag values from Cooley-Tukey decimation-in-time radix-2 FFT are passed in
// and we want to generate the cos and sine values for each sample for each wave
var length = outReal.Length;
var lengthDouble = (double)length;
var halfLength = lengthDouble / 2.0;
sineValues = new double[numWaves, length];
cosValues = new double[numWaves, length];
var Pi2 = 2 * Math.PI;
for (var waveIdx = 0; waveIdx < numWaves; waveIdx++)
{
for (var sampleIdx = 0; sampleIdx < length; sampleIdx++)
{
// first value case and middle value case
var reX = outReal[waveIdx] / halfLength;
if (sampleIdx == 0)
{
reX = outReal[waveIdx] / lengthDouble;
}
else if (sampleIdx == halfLength)
{
reX = outReal[waveIdx] / lengthDouble;
}
// precompute the value that gets sine/cos applied
var tmp = (Pi2 * waveIdx * sampleIdx) / lengthDouble;
// get the instant cos and sine values
var valueCos = Math.Cos(tmp) * reX;
var valueSin = Math.Sin(tmp) * (-outImag[waveIdx] / halfLength);
// update the sine and cos values for this wave for this sample
cosValues[waveIdx, sampleIdx] = valueCos;
sineValues[waveIdx, sampleIdx] = valueSin;
}
}
}
And the below is how I get the magnitude and phase values, although I do not currently use those anywhere.
internal void CalculateMagAndPhaseBasic(double[] outReal, double[] outImag, out double[] mag, out double[] phase)
{
// the real and imag values from Cooley-Tukey decimation-in-time radix-2 FFT are passed in
// and we want to generate the magnitude and phase values
var length = outReal.Length;
mag = new double[(length / 2) +1];
phase = new double[(length / 2) + 1];
for (var i = 0; i <= length / 2; i++)
{
mag[i] = Math.Pow((outReal[i] * outReal[i]) + (outImag[i] * outImag[i]), 0.5);
phase[i] = Math.Atan2(outImag[i], outReal[i]);
}
}
Actually the fft just returns you complex coefficients S(w)=a+jb
For an N point fft, abs(S(w)) * 2/N will be (close to) the amplitude of the sinusoidal component at frequency w.
This assumes that the sinusoidal component has a frequency close to the center of the fft bin, otherwise the power will be "split" between two adjacent bins.
And that the frequency you're interested in is present through all the fft window.
The output of an FFT has the same number of degrees of freedom as the input. There is no simple formula (other than the FFT itself) that relates the FFT results to just each other, as all of the FFT outputs can change if any of the FFT inputs changes.
The relationship between the sine and cosine of each FFT complex bin result is related to the phase of the sinusoidal input component at that frequency (of the bin center), circularly relative to the start and end. If the phase changes, so can both the sine and cosine component. See: atan2()

How can I align the frequency bins with the fourier transform magnitude?

I am attempting to implement a Fast Fourier Transform with associated complex magnitude function on the STM32F411RE Nucleo developer board. My goal is to separate a combined signal with multiple sinusoidal elements into their separate frequency components, with correct amplitude.
My issues is that I cannot correctly line up the frequency bins outcomes from the Complex magnitude function with the frequencies. I am also starting to question the validity of these outcomes as such.
I have tried to use a number of different implementations posted by people for the FFT algorithm with the magnitude fix, most notably the examples listed on StackoverFlow by SleuthEye and Blog by LB9MG.
AFAIK I have a similar approach, but somehow their approaches yield the desired results and mine do not. Below is my code that I have altered to work via the implementation that SleuthEye has created.
int main(void)
{
fftLen = 32; // can be 32, 64, 128, 256, 512, 1024, 2048, 4096
half_fftLen = fftLen/2;
volatile float32_t sampleFreq = 50 * fftLen; // Fs = binsize * fft length, desired binsize = 50 hz
arm_rfft_fast_instance_f32 inst;
arm_status status;
status = arm_rfft_fast_init_f32(&inst, fftLen);
float32_t signalCombined[fftLen] = {0};
float32_t fftCombined[fftLen] = {0};
float32_t fftMagnitude[fftLen] = {0};
volatile float32_t fftFreq[fftLen] = {0};
float32_t maxAmp;
uint32_t maxAmpInd;
while (1)
{
for (int i = 0; i< fftLen; i++)
{
signalCombined[i] = 40 * arm_sin_f32(450 * i); // 450 frequency at 40 amplitude
}
arm_rfft_fast_f32(&inst, signalCombined, fftCombined, 0); // perhaps switch to complex transform to allow for negative frequencies?
arm_cmplx_mag_f32(fftCombined, fftMagnitude, half_fftLen);
fftMagnitude[0] = fftCombined[0];
fftMagnitude[half_fftLen] = fftCombined[1];
arm_max_f32(fftMagnitude, half_fftLen, &maxAmp, &maxAmpInd); // We need the 3 max values
for (int k = 0; k < fftLen ; k++)
{
fftFreq[k] = ((k*sampleFreq)/fftLen);
}
}
Shown below are the results that I get out of the code listed above: whilst I do get a magnitude out of the algorithms (at the correct index 12), it does not correspond to the frequency or the amplitude of the input array signalCombined[].
Does anyone have an idea of why this is happening? Like so many of my errors it is probably a really trivial and stupid thing, but I cannot figure out for the life of me why this is happening.
EDIT: thanks to SleuthEye's help finding the frequencies is now possible, as the initial approach for generating the sin() signal was done incorrectly.
Some new issues popped up as the FFT only appears to yield the correct frequencies for the 32 samples, despite the bin size scaling accordingly to accommodate the adjusted sample size.
I am also unable to implement the amplitude fixing algorith: as per SleuthEye's Link with the example code 2*(1/N)*abs(X(k))^2 I have made my own implementation 2 * powf(fabs(fftMagnitude[j]), 2) / fftLen as shown in the code below, but this does not yield results that are even close to correct.
while (1)
{
for (int i = 0; i < fftLen; i++)
{
signalCombined[i] = 400 * arm_sin_f32(2 * PI * 450 * i / sampleFreq); // Sin Alpha, 400 amp at 10 kHz
// 700 * arm_sin_f32(2 * PI * 33000 * i / sampleFreq) + // Sin Bravo, 700 amp at 33 kHz
// 300 * arm_sin_f32(2 * PI * 50000 * i / sampleFreq); // Sin Charlie, 300 amp at 50 kHz
}
arm_rfft_fast_f32(&inst, signalCombined, fftCombined, 0); // calculate the fourier transform of the time domain signal
arm_cmplx_mag_f32(fftCombined, fftMagnitude, half_fftLen); // calculate the magnitude of the fourier transform
fftMagnitude[0] = fftCombined[0];
fftMagnitude[half_fftLen] = fftCombined[1];
for (int j = 0; j < sizeof(fftMagnitude); j++)
{
fftMagnitude[j] = 2 * powf(fabs(fftMagnitude[j]), 2) / fftLen; // Algorithm to fix the amplitude of each unique frequency
}
arm_max_f32(fftMagnitude, half_fftLen, &maxAmp, &maxAmpInd); // We need the 3 max values
for (int k = 0; k < fftLen ; k++)
{
fftFreq[k] = ((k*sampleFreq)/fftLen);
}
}
Your tone generation does not take into account the sampling frequency of 1600Hz, so you are effectively generating a tone at a frequency of 450*1600/(2*PI) ~ 114591Hz which gets aliased to ~608Hz. That 608Hz frequency roughly corresponds to a frequency index around 12 when using an FFT size of 32.
The generation of a 450Hz tone at a 1600Hz sampling frequency should be done as follows:
for (int i = 0; i< fftLen; i++)
{
signalCombined[i] = 40 * arm_sin_f32(2 * PI * 450 * i / sampleFreq);
}
As far as matching the amplitude, keep in kind that there is a scaling factor between the time-domain and frequency-domain of approximately 0.5*fftLen (see this other post of mine).

Impulse response - low frequences accuracy

I have question probably more in audio processing, than programming at all.
Just for fun, for understand little bit more I made my own plugin to measure impulse response of the filters. Something that allows me to see various equalisers curves. Similar like it happens in Waves QClone plugin - but qClone can also implement those curves to other signals, like regular EQ, but my plugin just measure those curves - as I know VST Plugin Analyser can do similar things.
But with my plugin the problem is accuracy of low frequences, somewhere below 150 Hz it starts to show crazy curves, inappropriate to real EQ changes. But above 150 Hz everything is OK (almost OK - it shows almost perfectly the EQ curves, but has problem to show curves for very narrow Q parameters).
And I was wondering almost whole week, what I do wrong, I tried to change resolution o measured frequencies range, also tried to change buffersize for one impulse. Don’t know what to do and it is annoying hardly :slight_smile: please help me.
My code for measure impulse response is mainly like that:
float freqResolution = 1000.0f; // it’s for set range of measured freq: float minFreqIndex = log10(20.0f)*freqResolution / log10(wSampleRate); float maxFreqIndex = log10(20000.0f)*freqResolution / log10(wSampleRate); for(int sample=(int)minFreqIndex; sample < maxFreqIndex; sample++) {
logScaleFreq = pow(10.0f, log10(wSampleRate) * (float)sample / (freqResolution-1.0f));
_Re = processor.filteredImpulse[0];
_Im = 0.0f;
for (int i=1; i<buffersize; ++i) {
_Re += processor.filteredImpulse[i] * cosf(-(float)i * 2 * double_Pi * logScaleFreq / wSampleRate);
_Im += processor.filteredImpulse[i] * sinf(-(float)i * 2 * double_Pi * logScaleFreq / wSampleRate);
}
float _Re_2 = pow(_Re, 2.0f);
float _Im_2 = pow(_Im, 2.0f);
float _Hf = pow(_Re_2 + _Im_2, 0.5f);
logScale_dB = 20*log10(_Hf);
Mainly it’s something like that, and then I print it as a logScale_dB in the function of logScaleFreq.
For any help, great thanks in advance.
Of course
processor.filteredImpulse[i]
It’s an filtered data from array of one impulse, something like [1, 0, 0, 0, 0, 0, 0, 0, 0…]
with length dependent on buffersize. But there is always only one 1, and many of zeros, like I think impulse should be :slight_smile:

Use AVAudioRecorder metering to make triangular wave

I am trying to make triangular waves for audio recorder through metering. I am using AVAudioRecorder this means that Fast Fourier Transformation will not work in this case (Secondly i don't have enough knowledge how to implement it). I found this project on github. In this project author is using the following equation to make smooth sine wave:
CGFloat y = scaling * self.maxAmplitude * normedAmplitude * sinf(2 * M_PI *(x / self.waveWidth) * self.frequency + self.phase) + (self.waveHeight * 0.5);
If you consider this sinf(2 * M_PI *(x / self.waveWidth) * self.frequency + self.phase) part of equation you will find that it is the equation of sine wave (wikipedia). If i replace this part with the equation of triangular equation (wikipedia) it still make sine wave with little difference. I want to transform this equation in such a way that it make triangular wave instead of sine wave.
My triangle wave equation looks like this:
CGFloat t = x / self.waveWidth;
CGFloat numerator = sinf( (2.0 * M_PI * (2.0 * self.amplitude + 1.0) * self.frequency * t) );
CGFloat denominator = (2.0 * self.amplitude + 1.0) * (2.0 * self.amplitude + 1.0);
CGFloat multiplyer = (8.0 / pow(M_PI, 2.0));
CGFloat result = multiplyer * (numerator / denominator);
Then finally y position is calculated by:
y = (result * scaling * self.maxAmplitude * normedAmplitude) + (self.waveHeight * 0.5);
Animation is also look unnatural. Output of this equation is:
Thanks
Well by looking at the equation you're using (which is the fourier transform), you're implementing it a bit wrong (k samples should be increasing but you've left it constant with 2.0 * self.amplitude + 1.0. You're also leaving out (-1)^k which adds in the odd harmonics.
Wikipedia wrote this:
It is possible to approximate a triangle wave with additive synthesis by adding odd harmonics of the fundamental, multiplying every (4n−1)th harmonic by −1 (or changing its phase by π), and rolling off the harmonics by the inverse square of their relative frequency to the fundamental.
I'm guessing (as I'm not a DSP expert) that because you're leaving the k value as a constant it is just giving you a sine wave output.
Look at this algorithm block for the triangle wave (try it, then change it for your code):
phaseIncr = (2.0 * M_PI / sample_rate) * self.frequency;
for (int i = 0; i < numSamples; i++) {
triVal = (phase * 2.0/M_PI);
if (phase < 0) triVal = 1.0 + triVal;
else triVal = 1.0 - triVal;
sample = amplitude * triVal;
if ((phase += phaseIncr) >= M_PI) phase -= (2.0 * M_PI);
}
I also see that the original project wrapped the phase in setLevel method so check that out. Hope this helps out and let me know if this doesn't work, I'll try to help as much as I can.

iOS Generate Square Sound

I want to generate a square wave sound on iPhone, I found a sine wave code on Web (sorry forgotten the link), but i want to generate Square wave format.
Could you help me please?
const double amplitude = 0.25;
ViewController *viewController =
(__bridge ViewController *)inRefCon;
double theta = viewController->theta;
double theta_increment = 2.0 * M_PI * viewController->frequency / viewController->sampleRate;
const int channel = 0;
Float32 *buffer = (Float32 *)ioData->mBuffers[channel].mData;
for (UInt32 frame = 0; frame < inNumberFrames; frame++)
{
buffer[frame] = sin(theta) * amplitude;
theta += theta_increment;
if (theta > 2.0 * M_PI)
{
theta -= 2.0 * M_PI;
}
}
viewController->theta = theta;
Sum of the odd harmonics
A perfect square wave is the sum of all the odd harmonics divided by the harmonic number up to infinity. In the real world you have to stop of course - specifically at the nyquist frequency in digital. Below is a picture of the fundamental plus the first 3 odd harmonics. You can see how the square begins to take shape.
In your code sample, this would mean wrapping the sine generation in another loop. Something like this:
double harmNum = 1.0;
while (true)
{
double freq = viewController->frequency * harmNum;
if (freq > viewController->sampleRate / 2.0)
break;
double theta_increment = 2.0 * M_PI * freq / viewController->sampleRate;
double ampl = amplitude / harmNum;
// and then the rest of your code.
for (UInt32 frame = ....
The main problem you'll have is that you need to track theta for each of the harmonics.
A cheater solution
A cheat would be to draw a square like you would on paper. Divide the sample rate by the frequency by 2 and then produce that number of -1 and that number of +1.
For example, for a 1kHz sine at 48kHz. 48000/1000/2 = 24 so you need to output [-1,-1,-1,....,1,1,1,.....] where there are 24 of each.
A major disadvantage is that you'll have poor frequency resolution. Like if your sample rate were 44100 you can't produce exactly 1kHz. because that would require 22.05 samples at -1 and 22.05 samples at 1 so you have to round down.
Depending on your requirements this might an easier way to go since you can implement it with a counter and the last count between invocations (as you're tracking theta now)

Resources