472,983 Members | 2,432 Online

# FM synthesis using Numpy

Hello fellow Python coders,

I'm trying to build a simple FM synthesizer in Python. As a beginner,
I take 'FM synthesizer' to
mean: "using a sine wave to control the frequency of another sine wave."

I tried to generate a tone of 1000 Hz that deviates 15 Hz six times a
second. The start of the
resulting wave file sounds right, i.e., a vibrato effect can be heard.
After a second or so, the
vibrato becomes more and more extreme, as if the modulating
oscillator's amplitude is rising
over time. I suspect that I am misunderstanding the math. I tried a
couple of things:

- removing the factor 2 * num.pi from either of the oscillators does
not fix it, besides, doing so is
even more wrong because numpy.sin works with radians

- using a higher sampling frequency makes no difference

- making t run from 0 to 1 each second (t %= 1) causes a clipping of
the sound, so this seems
wrong too

- the problem is not related to Numpy, because the effect also happens
in pure-Python
implementations of my bug

As you can see, I'm at a loss and am even trying incorrect bugfixes.
Any help would be
very welcome.

Joost Molenaar
[I left out a writewavheader function to aid brevity]
-------------------------------------------------------------------

import numpy as num

def oscillator(x, freq=1, amp=1, base=0, phase=0):
return base + amp * num.sin(2 * num.pi * freq * x + phase)

def writewav(filename, data):
wave = open(filename, 'wb')

# .wav header: 30 s at 44100 Hz, 1 channel of 16 bit signed samples
wave.write('RIFF\x14`(\x00WAVEfmt \x10\x00\x00\x00\x01\x00\x01\x00D'
'\xac\x00\x00\x88X\x01\x00\x02\x00\x10\x00data\xf0 _(\x00')

# write float64 data as signed int16
(32767 * data).astype(num.int16).tofile(wave)

wave.close()

t = num.arange(0, 30, 1./44100)

freq = oscillator(t, freq=6, amp=15, base=1000)
tone = oscillator(t, freq=freq, amp=0.1)

writewav('spam.wav', tone)
-------------------------------------------------------------------
Aug 14 '07 #1
2 5922 You got your math wrong. What you are calculating is:
sin(2*pi*(1000+15*sin(2*pi*6*t))*t) = sin(2*pi*1000*t +
2*pi*15*sin(2*pi*6*t)*t)
The 'instantaneous frequency' can be calculated by differentiating the
argument of the sine and dividing by 2pi:
x = sin(phi(t)) -f_inst = d (phi(t)) / dt / (2*pi)
f_inst = 1000 + 15*sin(2*pi*6*t) + 2*pi*t*6*15*cos(2*pi*6*t)
the last term explains the effect you hear.

What you want is:
f_inst = f0 + df*cos(2*pi*fm*t)
Integrating this and multiplying by 2pi gives the phase:
phi(t) = 2*pi*f0*t + sin(2*pi*fm*t)*df/fm

So you can achieve the frequency modulation by using phase modulation
(these two are related). You can do this with your own code by

phi = oscillator(t, freq=6, amp=15/6)
tone = oscillator(t, freq=1000, amp=0.1, phase=phi)

cheers,
Bas

Aug 15 '07 #2
Thanks/bedankt Bas for the educative reply. I think I got misleaded by
Max/MSP's tutorial, because MSP seems to automatically adjust the
phase when you combine two oscillators in the way that I did.

Joost

 13 by: Gary Wessle | last post by: Hi I am trying to install NumPy in my debian/testing linux 2.6.15-1-686. with no numpy for debian/testing, I am left alone, since the experimental version available by debian will result in a... 0 by: robert | last post by: just a note - some speed comparisons : 0.60627370238398726 0.42836673376223189 0.36965815487747022 0.016557970357098384 0.15692469294117473 0.01951756438393204 2 by: robert | last post by: in Gnuplot (Gnuplot.utils) the input array will be converted to a Numeric float array as shown below. When I insert a numpy array into Gnuplot like that below, numbers 7.44 are cast to 7.0 Why is... 5 by: robert | last post by: Turning algs for old NumPy modules into numpy code I suffer from this: Upon further processing of returns of numpy calculations, lots of data in an apps object tree will become elementary numpy... 0 by: Mangabasi | last post by: Howdy, I would like to use the Synthesis Toolkit for a demo. I downloaded the STK from http://ccrma.stanford.edu/software/stk/index.html. It seems very powerful and user friendly. There are... 5 by: Marc Oldenhof | last post by: Hello all, I'm pretty new to Python, but use it a lot lately. I'm getting a crazy error trying to do operations on a string list after importing numpy. Minimal example: Python 2.5.1... 3 by: Sean Davis | last post by: I have a set of numpy arrays which I would like to save to a gzip file. Here is an example without gzip: b=numpy.ones(1000000,dtype=numpy.uint8) a=numpy.zeros(1000000,dtype=numpy.uint8) fd =... 2 by: Travis Oliphant | last post by: I wanted to point anybody interested to a blog post that describes a useful pattern for having a NumPy array that points to the memory created by a different memory manager than the standard one... 3 by: Slaunger | last post by: I know there must be a simple method to do this. I have implemented this function for calculating a checksum based on a ones complement addition: def complement_ones_checksum(ints): """... 2 by: DJRhino | last post by: Was curious if anyone else was having this same issue or not.... I was just Up/Down graded to windows 11 and now my access combo boxes are not acting right. With win 10 I could start typing... 2 by: isladogs | last post by: The next Access Europe meeting will be on Wednesday 4 Oct 2023 starting at 18:00 UK time (6PM UTC+1) and finishing at about 19:15 (7.15PM) The start time is equivalent to 19:00 (7PM) in Central... 0 by: tracyyun | last post by: Hello everyone, I have a question and would like some advice on network connectivity. I have one computer connected to my router via WiFi, but I have two other computers that I want to be able to... 2 by: giovanniandrean | last post by: The energy model is structured as follows and uses excel sheets to give input data: 1-Utility.py contains all the functions needed to calculate the variables and other minor things (mentions... 4 by: NeoPa | last post by: Hello everyone. I find myself stuck trying to find the VBA way to get Access to create a PDF of the currently-selected (and open) object (Form or Report). I know it can be done by selecting :... 3 by: NeoPa | last post by: Introduction For this article I'll be using a very simple database which has Form (clsForm) & Report (clsReport) classes that simply handle making the calling Form invisible until the Form, or all... 3 by: nia12 | last post by: Hi there, I am very new to Access so apologies if any of this is obvious/not clear. I am creating a data collection tool for health care employees to complete. It consists of a number of... 0 by: NeoPa | last post by: Introduction For this article I'll be focusing on the Report (clsReport) class. This simply handles making the calling Form invisible until all of the Reports opened by it have been closed, when it... 4 by: GKJR | last post by: Does anyone have a recommendation to build a standalone application to replace an Access database? I have my bookkeeping software I developed in Access that I would like to make available to other...