0
$\begingroup$

The question was asked before in C: How can I generate a sine wave with time varying frequency that is continuous? How can I resolve the following problem? I want a continuous graph. But how do I do I do it in python??? enter image description here

my code is

import numpy as np 
import matplotlib.pyplot as plt
import seaborn as sns
sns.set()


x=np.arange(1,5,0.001)
y=list()

for i in range(0,len(x)):
    if x[i]<2:
       c = np.cos(2*np.pi*.73*x[i])
    elif x[i]<3:
       c = np.cos(2*np.pi*1.1*x[i])
    else:
       c = np.cos(2*np.pi*1.3081*x[i])
    y.append(c)
plt.plot(x, y)
plt.show()
$\endgroup$
4
  • $\begingroup$ Why should the solution of that problem depend on the programming language? $\endgroup$
    – Matt L.
    Jan 21, 2022 at 11:45
  • $\begingroup$ It doesnt really, but the same question was asked for C and I cant figure out how to apply the solution in python... $\endgroup$
    – Cara
    Jan 21, 2022 at 11:56
  • 4
    $\begingroup$ If it is a pure programming question it should probably be asked elsewhere. $\endgroup$
    – Matt L.
    Jan 21, 2022 at 12:17
  • $\begingroup$ I suggest looking into "direct digital synthesis" methods. $\endgroup$
    – MBaz
    Jan 21, 2022 at 15:21

2 Answers 2

2
$\begingroup$

Simple solution using a phase accumulator. The phase is simply the integral over the frequency so a simple sum will do here. Using a running accumulator guarantees a continuous function. For very long signal, you probably should wrap the phase with something like if phi > 2*np.pi, phi = phi - 2*np.pi but for a few thousand points the code below will work just fine

import numpy as np 
import matplotlib.pyplot as plt

dt = 0.001 # time step
# define the three frequencies in radians per sample
omegaT1 = 2*np.pi*.73*dt
omegaT2 = 2*np.pi*1.1*dt
omegaT3 = 2*np.pi*1.083*dt


x=np.arange(1,5,0.001)
y=list()
phi = 0; # phase accumulator
for i in range(0,len(x)):
    c = np.cos(phi) # cosine of current phase
    y.append(c)
    # increment phase based on current frequency
    if x[i]<2:
       phi = phi + omegaT1
    elif x[i]<3:
       phi = phi + omegaT2
    else:
       phi = phi + omegaT3

plt.plot(x, y)
plt.show()
$\endgroup$
0
$\begingroup$

Do you mind sharing a link to the question in C you are referring to and specify where you are struggling to transfer it to Python?

In general your code looks like it works and your problem seems to be more a mathematical one. Depending on what you really require, two solutions come to mind:

  1. A piecewise defined function, without jumps at the region edges.
  2. An actually continuously, smoothly varying frequency.

Both require to more precisely control the phase of the sine function.

For 1): Instead of writing $cos(a \, x)$, you must add a phase offset $y=cos(a \, x + \varphi)$. $\varphi$ must then be chosen such that the value of $y$ matches left and right of a definition edge. Another way to look at the value $\varphi$ is as an offset in $x$: $y=cos(a \, (x- x_0))$.

For 2): The generalization of the above correction is to apply a varying phase argument $y=cos(\varphi(x))$, where e.g. the sine wave gets linearly faster with $x$. This is what happens in reality if e.g. there is a "chirp" in a audio recording.

Coding example for 1):

import numpy as np 
import matplotlib.pyplot as plt
#import seaborn as sns
#sns.set()

x=np.arange(1,5,0.001)
y=list()

for i in range(0,len(x)):
    x1 = 2
    x2 = 3
    if x[i]< x1:
        c = np.cos(2*np.pi*.73*x[i])
    elif x[i]< x2:
        #a1*x1 + phi1 = a0*x1
        phi1 = 2*np.pi*.73*x1 - 2*np.pi*1.1*x1
        c = np.cos(2*np.pi*1.1*x[i] + phi1)
    else:
        #a2*x2 + phi2 = a1*x2 + phi1
        phi2 = 2*np.pi*1.1*x2 - 2*np.pi*1.3081*x2 + phi1
        c = np.cos(2*np.pi*1.3081*x[i] + phi2)
    y.append(c)

plt.plot(x, y)
plt.show()

plot for coding example 1

Note that while things may look smooth in this plot now, the only boundary condition we imposed was the same function value, but the slope will differ, i.e. there will be a kink in the curve.

Coding example for 2):

import numpy as np 
import matplotlib.pyplot as plt

x=np.arange(1,5,0.001)
y=list()

A = .5
B = .3
C = 0 #set e.g. to 1/4 (which will be a Pi/2 phase shift) to transform from cos to sin

phi = 2*np.pi* (A*x**2 + B*x + C)
y = np.cos(phi)

plt.plot(x, y)
plt.show()

plot for coding example 2

You will of course have to calculate the correct values for $A$, $B$ and $C$ in my example or choose a different representation of your $\varphi(x)$.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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