There's a Mesh Function add-on:
generates a UI for making parametric surfaces:
Blender 2.79-
Or use Sverchok's scripted node. This may be more complicated at first but allows a lot of customization.
import math
from math import pi as PI
from math import cos, sin
def sv_main(p1=0.3, p2=0.7, vdivs=20, points=200):
verts_out = []
in_sockets = [
['s', 'p1', p1],
['s', 'p2', p2],
['s', 'vdivs', vdivs],
['s', 'points', points]
]
r2=20*p1
r1=10*p2
theta = 1/points
vtheta = 1/vdivs
for v in range(vdivs):
v_points = []
for i in range(points):
t = 2 * PI * (theta * i)
p = PI * ((vtheta*v) - 0.5)
x = r1 * cos(t) * cos(p)
y = r1 * sin(t) * cos(p)
z = r1 * sin(p)
x = x + r2 * cos(t)
y = y + r2 * sin(t)
v_points.append([x,y,z])
verts_out.append(v_points)
out_sockets = [
['v', 'verts', [verts_out]]
]
return in_sockets, out_sockets
Because the script makes a nested list of each V ring of verts, the UV Connection node can make the appropriate "UV edge-surf".
For help with Sverchok in general see the documentation.
For help with Scripted Node specifically first have a look at the dedicated document about it
Blender 2.8+
for Blender 2.8 and Sverchok you will use ScriptedNode Lite, and it requires a small modification to the above script. I think you'll agree it's less verbose.
"""
in p1 s d=0.3 n=2
in p2 s d=0.7 n=2
in vdivs s d=20 n=2
in points s d=200 n=2
out verts_out v
"""
import math
from math import pi as PI
from math import cos, sin
r2 = 20 * p1
r1 = 10 * p2
theta = 1/points
vtheta = 1/vdivs
for v in range(vdivs):
v_points = []
for i in range(points):
t = 2 * PI * (theta * i)
p = PI * ((vtheta*v) - 0.5)
x = r1 * cos(t) * cos(p)
y = r1 * sin(t) * cos(p)
z = r1 * sin(p)
x = x + r2 * cos(t)
y = y + r2 * sin(t)
v_points.append([x,y,z])
verts_out.append(v_points)