0

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(2np.pi.73x[i]) elif x[i]<3: c = np.cos(2np.pi1.1x[i]) else: c = np.cos(2np.pi1.3081*x[i]) y.append(c) plt.plot(x, y) plt.show()

Cara
  • 11
  • 1
  • 1

2 Answers2

2

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 = 2np.pi.73dt omegaT2 = 2np.pi1.1dt omegaT3 = 2np.pi1.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()

Hilmar
  • 44,604
  • 1
  • 32
  • 63
0

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 = 2np.pi (Ax2 + Bx + 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)$.

ldoyle
  • 1