0
$\begingroup$

I am working on a digital synthesis project, in python and c currently. I have made a Sine and Saw wave generator and have now been working on FM between the two wave types. I have successfully made FM work with a Sine wave as both carrier and modulator, but whenever I add a Saw wave into the mix, The carrier frequency increase indefinitely. After a lot of research and trying to understand some more complex DSP concepts (instantaneous phase and frequency), I am feeling a bit lost, and hoping for some pointers to resources where I can learn more at a more basic level of understanding.

Essentially, the goal right now is to modulate the frequency of any wave shape with any other wave shape given only the amplitude of the modulator signal. This would in essence be a VCO emulation or a pitch envelope capable of audio rate modulation.

The code below is currently what I have come up with, which works, but only as intended when the modulator frequency is greater than the carrier frequency (I am assuming because this is phase modulation, not FM).


# self.count == the current sample 
# self.fs == 48000 
# fmcv == the amplitude value for the given sample number, between -1 and 1, of the modulator 

pos = self.count / self.fs
value = math.sin(self.freq * 2 * math.pi * pos + math.pi * 2 * fmcv)
value = value * self.gain + self.offset
self.count = self.count + 1
return value  

I have also tried the following which gives similar results.

pos = self.count / self.fs
value = math.sin((self.freq * (1 + (0.9 * fmcv))) * 2 * math.pi * pos)
value = value * self.gain + self.offset
self.count = self.count + 1
return value

Any help and pointers towards good resources where I can understand the concepts better are greatly appreciated.

$\endgroup$
2
  • $\begingroup$ Instead of using the individual value of fmcv, you need to use the cumulative sum of all fmcv values so far. The phase you need to add in is the integral of the frequency (fmcv) values. A cumulative sum is the equivalent of integration when working with discrete samples. Also you might want to put some gain on that cumulative sum, so you get a noticeable frequency change. $\pm 1$ Hz isn't much. $\endgroup$
    – Andy Walls
    Feb 28 at 23:35
  • $\begingroup$ If I were writing code to do FM synthesis, I would implement the oscillators with a wavetable (a lookup table of one entire cycle of a sine or cosine), linear interpolation between wavetable points, and phase-accumulators to set frequency. $\endgroup$ Jul 29 at 6:49
0
$\begingroup$

If the case with two sines is clear (sine wave modulation of a sine wave carrier) then consider expanding any other shape (such as the ramp) into its Fourier components and then superimposing the result of each.

Any waveform with sharp transitions (such as a ramp) requires an infinite number of frequency components, so better to work with smoothed waveforms where the higher frequency components are essentially filtered out.

Another tip when simulating carrier modulation is to not actually simulate the carrier but use a complex baseband signal instead (what you simulate their will match what would occur at any carrier frequency and doesn't require as high of a sampling rate to simulate). This requires understanding the baseband equivalent analytic signal, but would be the recommended next step regarding understanding DSP concepts.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.