Maker Pro
Maker Pro

Microprocessor Generation of Summed Sine Waves with Random LF Modulation

I would like to program a micro to do the following:
  1. Generate five audio frequency sine waves at different frequencies and amplitudes
  2. Sum all the above sine waves into one signal
  3. Generate a pseudo-random low frequency waveform at a set amplitude
  4. Multiply the summed signal with the LF so the former randomly changes in amplitude and frequency by about 5%.
What is the best design approach to this project? Can it be done in a single micro? What would the blocks of code look like? I need to know where to start.

Thank you for any suggestions.
 

Harald Kapp

Moderator
Moderator
What is the best design approach to this project?
Define "best".
- least amount of memory?
- shortest execution time?
- ...?

Can it be done in a single micro?
Which micro?
You do realize that there are vast differences between e.g. an 8 bit µC running at 8 MHz and a 32 bit µC running at 100 MHz, do you?

What would the blocks of code look like?
Start by defining the relevant parameters like
- sampling rate
- resolution
- frequency and amplitude of the signals (sines and random)

Set up a loop that runs at the defined sample rate. During each pass of the loop calculate the values for the signals (sines and lf-random signal).
Sum the sines and multiply by the random signal (random signal scaled to 5 %).
The amplitudes of the sines and the lf-noise can be scaled by multiplying the generated signals by the respective scale factors.
Output the result e.g. via a DAC.

To calculate the sines you can use trigonometric functions (slow) or look-up tables and interpolation (fast, memory hogging).
To calculate the lf-random signal you can use a pseudo random generator. Since a (pseudo) random signal has a theoretically infinite bandwidth, you need to limit the bandwidth to the lf-range you need by a (digital) low pass filter.
 
Thank you Harald for your reply.

The five summed frequencies would all be below 100Hz (one hundred). So the sampling rate can be low. In this case, what would you recommend? The planned band pass for the noise is about 10Hz to DC. Can I use one LUT for all five sine waves?

Not being "audio quality", the output could probably be 8-bit and rely upon the DAC error for smoothing. Or go with 16 bit just to be sure. I am not concerned about the cost or pin count of the micro, but prefer that all of the above functions (including DAC) be performed within a single chip. Can you make any suggestions? I already have some PIC gear on hand, but my experience to date is with simpler projects.

To select the part, I also need to have an idea of the minimum required memory and clock rate.

Any further advice, or specific recommendations, would be appreciated. Once I have narrowed down the options, I can then research further.
 

Harald Kapp

Moderator
Moderator
the sampling rate can be low. In this case, what would you recommend?
The absolute minimum is 200 Hz acc. to the Nyquist-Shannon theorem. A higher rate makes it easier to filter artifacts. Use e.g. 1 kHz or higher.
Can I use one LUT for all five sine waves?
A single LUT for the sine function is sufficient. You need to step through the table with a stepwidth that is inversely proportional to the frequency. What you do is you sample the table with a frequency that is proportional to the desired output frequency.
the output could probably be 8-bit and rely upon the DAC error for smoothing
The DAC error is not good for smoothing. an analog RC filter should be used to suppress artifacts from the digitalization., This is where a high sampling frequency comes inti play: The higher the difference between the sampling frequency and the highest signal frequency, the easier the filter.
A 16 bit DAC is going to be expensive and also requires well built analog circuitry to make use of the 16 bit. Typical compromises are 10 bit or 12 bit DACs. Probably fully sufficient for your project.
I already have some PIC gear on hand,
Then use a PIC. Experience is a valuable asset.
I also need to have an idea of the minimum required memory and clock rate.
I have no idea. start a project and see what it takes.
As for memory: the LUT will take up a lot of memory. By creating the LUT (1/4 sine is sufficient, see this link)
 
That certainly helps with narrowing down the options. I would probably try an 8 bit PIC first. The following product family offers lots of memory and 8 bit DAC, plus PWM if better filtering is required. https://ww1.microchip.com/downloads/en/DeviceDoc/30010211A.pdf

The PIC18F27Q43 looks like a good option to me. Perhaps more than what I need ... just to play it safe. The real cost is in the time to write the code.

I should have mentioned that the sine frequencies need to be specified to 0.1Hz, e.g. 42.7Hz. Does this affect the chosen sample rate? I am also not clear on how to generate 5 different sine waves simultaneously from one LUT. Is it done with loops? How would you describe this process?

If I were to use a 1KHz sample rate, how do I determine the optimal clock rate?

I will need to buy a newer programmer for these micros, so want to be sure about the part and its capabilities first.

Thanks for any further suggestions.
 

Harald Kapp

Moderator
Moderator
bit DAC, plus PWM if better filtering is required
PWM will actually leave you with a more noisy signal than a DAC - at the same sample rate.
I should have mentioned that the sine frequencies need to be specified to 0.1Hz, e.g. 42.7Hz. Does this affect the chosen sample rate?
You could sample each frequency at a sample rate which is a fixed factor above the signal frequency, e.g. by 100 times the signal frequency. Thus you'd sample the 0.1 Hz sine at 10 Hz, the 42.7 Hz at 4270 Hz etc. But that will make recombining these signals into one more complex. The easiest way (in my opinion) is to use a fixed sampling frequency. 1 kHz or higher. That will allow you to add the samples within the same cycle as they are generated.
I am also not clear on how to generate 5 different sine waves simultaneously from one LUT. Is it done with loops?
You may use a loop or an interrupt routine. But not a loop over the frequencies but a loop over the samples. I'll give you an example. You'll have to refine that and work it out for your specific frequencies of the signals, sample rate and the way your LUT is constructed.

I'll make some very simplified assumptions to illustrate the method. You need to detail these:
- Assume a LUT with 31416 entries (6283 equal to approx. 1000 × 2 ×Pi) representing a full sine wave (I will not go into the details of optimization by using e.g. a 1/4 sine LUT). The step between 2 adjacent entries is then (2 × Pi)/1000. The LUT value for each sample is then LUT(x) = sin((2 × PI)/1000 × x)
- Assume a sample rate of 1 kHz equal to one sample every 1 µs.
- Assume you have set up an interrupt routine that is called every 1 µs, i.e. at the same rate as the sample rate.

If you now take one sample step by step from the LUT during each interrupt, you'll create a full sine wave after 1000 interrupts because (2 × Pi)/1000 × 1000 = 2 × Pi.
1000 interrupts at 1 kHz interrupt rated is equal to 1 s. Therefore the resulting sine wave has a frequency of 1 Hz (approximately since the Table is not exactly 2 × Pi long).
If you take every second sample from the LUT, you will have gone 2 times through the table during the same 1 s interval, therefore the sine wave has a frequency of 2 Hz.
Generally the frequency of the output signal will be fout = stepwidth.

To create multiple sines of different frequencies at the same time all you have to do is to use different stepwidths:
f1 = stepwidth_1 (e.g. 1 Hz from the above example)
f2 = stepwidth_2 (e.g. 2 Hz from the above example)
...
signal_out = f1 + f2 + ...

To create fractional frequencies (e.g. 1.5 Hz) you need to change sampling rate and stepwidth in step. For example reduce the sampling rate to 500 Hz, then a step of 1 is equal to an output frequency of 0.5 Hz. To create 1 Hz set the stepwidth to 2. For 1.5 Hz set the stepwidth to 3 and so on. For more granularity like eg 0.1 Hz you would have to lower the sampling rate to less than 500 Hz which is not suitable for your 100 Hz (max) requirement. You will have to use a longer LUT in this case.

I'm sorry, I can't elaborate the full code for you. You'll have to do some research using your favorite search tool. Lots of examples on the internet.
 
That gives me a good starting point. With regard to the more complex implementation of fractional frequencies, is there anyway to program a divide-by-ten function for the individual or summed sine waves? For example, 47.2Hz would thereby be derived form 472Hz.

I have just one more question. If I understand correctly, the pseudo-random "noise" can be generated within the same PIC, using code similar to these. http://www.piclist.com/techref/microchip/rand8bit.htm? Could you please explain the code sequence by which the random number sequence can modulate the summed sine waves by a fixed percentage, e.g. 5%?
 

Harald Kapp

Moderator
Moderator
is there anyway to program a divide-by-ten function for the individual or summed sine waves?
None that I know of. It'll be much easier to generate the right frequencies from the start.

Could you please explain the code sequence by which the random number sequence can modulate the summed sine waves by a fixed percentage, e.g. 5%?
I assume you want amplitude modulation, right? That's simply multiplication. The modulation index is 5 %.
Assuming your noise signal is a fractional number between 0 and 1, say m(t).
Assuming the "carrier", your sum of sines is c(t).
Assuming the modulation index is 0.05 (5 %).
Then the modulated signal is y(t) = (1+m(t)) × c(t)

Of course, doing all the math with floating point numbers would stress the µC probably over its limits. You'll have to use fixed-point arithmetic (in essence using integers that represent the fractional part of the numbers, see also here) to circumvent that problem. Microchip offers a library for fixed-point math on PICs.
 
As per item 4 in my OP, I would like both the amplitude and frequency to be modulated simultaneously by the 5% noise.

I looked into scaling factors for handling the fractional numbers, but was not aware the operation was so demanding. For simplicity I will start off using whole integers. Thanks to your advice, I now have a better idea of how to proceed.
 
A possible single chip approach :

upload_2022-4-22_8-51-36.png

Basically this is 4 channels, a fifth could be implemented with DMA and a table.

I used DDS on chip to produce the clocks for the WaveDacs. It has a phase accumulator
than could be used to FM the DDS with either API call or DMA. You could eliminate
DDS and use general DMA triggered by PWM programmable clocks, I just got lazy. This
would save other chip resources, even though as show you can see in right hand window
many resources left to use.

The DACs are configed as current out DACs, to preserve the 4 opamps for other purposes,
and to effect mixing. Each Wavedac can be switched between one of two waveforms,
arbitraty, sine, tri, square.....

I showed the DFDB (Dig Filter block), you could use it and SAR to apply filtering to composite
waveform. Also show is an onchip mixer component for whatever.....

Other components on chip, many multiple, attached



Board to use ~ $ 15, IDE and Compiler free.
55e8c77cd5cd8-6+PSoC+5LP.jpg

Also onboard a PRS component to generate noise.

In PSOC land terminology "component" is an onchip resource.

You can also burst waveforms, an example here using counters and other logic.

- https://www.edaboard.com/threads/test-bed-dds-and-wavedac-burst-tool.393572/


Regards, Dana
 

Attachments

  • PSOC Components 1.jpg
    PSOC Components 1.jpg
    131.7 KB · Views: 2
Last edited:
Dana's impressive PSOC approach is way out of my league. But I will keep it on file for motivational purposes.

If anyone wants a "ready-made" solution, multiple sine waves can be generated in Audacity (or similar audio editor) and mixed into one track. Brown noise is generated in another track, and time stretched to simulate low pass filtering. Both tracks are cut to equal duration and combined into a stereo signal.

Existing Nyquist scripts for random amplitude and random pitch may then be applied in succession. https://wiki.audacityteam.org/wiki/Download_Nyquist_Plug-ins

Simply copy to text editor, replace .txt with .ny. and load via Tools > Nyquist Plugin Installer. Here is an example of the result applied to 50Hz. As per my OP, I was however looking for a PIC type implementation.

50hz_random_am_fm.png
 
epsolutions, not out of your league.

Here I dragged out of the onchip catalog a WaveDac, "wired" it to a pin with a wizard, wrote one line of code,
a start instruction for the WaveDac, and generated a sine. What could be more simpler ?

upload_2022-4-24_9-28-47.png


Its a breadboard full of different parts / components on a single chip.

Each component comes with a lib of f() calls to control the component in real time.
This example next step replace clock with clock + PWM or DDS to control frequency.
Still simple.

Don't underestimate yourself, if you are already programming thats 90% of the battle.

Regards, Dana.
 
Top