Least Squares Method for a sum of functions
I would like to use the curve_fit
function from the scipy.optimize
module to determine amplitudes, frequencies, phases of sum of sine functions (and one y0
). It's easy to do when I know a number of sines to use. For example when I know two frequencies from the DFT (Discrete Fourier Transform): 1.152
and 0.432
I can define a function:
def func(x, amp1, amp2, freq1 , freq2, phase1, phase2, y0):
return amp1*np.sin(freq1*x + phase1) + amp2*np.sin(freq2*x + phase2) + y0
Then, using the curve_fit
and constraining intervals of frequencies I can find a good fitting:
param, _ = curve_fit(func, t, data, bounds=([-np.inf, -np.inf, 1.14, 0.43, -np.inf, -np.inf, -np.inf], [np.inf, np.inf, 1.16, 0.44, np.inf, np.inf, np.inf]))
It looks great:
But in this case I've prepared the data and I've known a number of frequencies. Do you know how to define the func
only once and handle all cases (for example five sine functions)? I've tried to put the parameters into lists, e.g. amp = [amp1, amp2, ... ]
and I've iterated over their length. But there is a problem to define bounds
for parameter lists. bounds
is very important to ensure reality model.
The solution does not have to based on curve_fit
.
python scipy least-squares
add a comment |
I would like to use the curve_fit
function from the scipy.optimize
module to determine amplitudes, frequencies, phases of sum of sine functions (and one y0
). It's easy to do when I know a number of sines to use. For example when I know two frequencies from the DFT (Discrete Fourier Transform): 1.152
and 0.432
I can define a function:
def func(x, amp1, amp2, freq1 , freq2, phase1, phase2, y0):
return amp1*np.sin(freq1*x + phase1) + amp2*np.sin(freq2*x + phase2) + y0
Then, using the curve_fit
and constraining intervals of frequencies I can find a good fitting:
param, _ = curve_fit(func, t, data, bounds=([-np.inf, -np.inf, 1.14, 0.43, -np.inf, -np.inf, -np.inf], [np.inf, np.inf, 1.16, 0.44, np.inf, np.inf, np.inf]))
It looks great:
But in this case I've prepared the data and I've known a number of frequencies. Do you know how to define the func
only once and handle all cases (for example five sine functions)? I've tried to put the parameters into lists, e.g. amp = [amp1, amp2, ... ]
and I've iterated over their length. But there is a problem to define bounds
for parameter lists. bounds
is very important to ensure reality model.
The solution does not have to based on curve_fit
.
python scipy least-squares
Are you trying to do a Least-squares spectral analysis (Lomb-Scargle periodogram)?
– Jan Christoph Terasa
Nov 26 '18 at 12:38
But I can determine the frequencies. I try to find the rest of sine functions parameters. I've read the docs and I don't see how the Lomb-Scargle periodogram can help me with that.
– Benek
Nov 26 '18 at 13:15
add a comment |
I would like to use the curve_fit
function from the scipy.optimize
module to determine amplitudes, frequencies, phases of sum of sine functions (and one y0
). It's easy to do when I know a number of sines to use. For example when I know two frequencies from the DFT (Discrete Fourier Transform): 1.152
and 0.432
I can define a function:
def func(x, amp1, amp2, freq1 , freq2, phase1, phase2, y0):
return amp1*np.sin(freq1*x + phase1) + amp2*np.sin(freq2*x + phase2) + y0
Then, using the curve_fit
and constraining intervals of frequencies I can find a good fitting:
param, _ = curve_fit(func, t, data, bounds=([-np.inf, -np.inf, 1.14, 0.43, -np.inf, -np.inf, -np.inf], [np.inf, np.inf, 1.16, 0.44, np.inf, np.inf, np.inf]))
It looks great:
But in this case I've prepared the data and I've known a number of frequencies. Do you know how to define the func
only once and handle all cases (for example five sine functions)? I've tried to put the parameters into lists, e.g. amp = [amp1, amp2, ... ]
and I've iterated over their length. But there is a problem to define bounds
for parameter lists. bounds
is very important to ensure reality model.
The solution does not have to based on curve_fit
.
python scipy least-squares
I would like to use the curve_fit
function from the scipy.optimize
module to determine amplitudes, frequencies, phases of sum of sine functions (and one y0
). It's easy to do when I know a number of sines to use. For example when I know two frequencies from the DFT (Discrete Fourier Transform): 1.152
and 0.432
I can define a function:
def func(x, amp1, amp2, freq1 , freq2, phase1, phase2, y0):
return amp1*np.sin(freq1*x + phase1) + amp2*np.sin(freq2*x + phase2) + y0
Then, using the curve_fit
and constraining intervals of frequencies I can find a good fitting:
param, _ = curve_fit(func, t, data, bounds=([-np.inf, -np.inf, 1.14, 0.43, -np.inf, -np.inf, -np.inf], [np.inf, np.inf, 1.16, 0.44, np.inf, np.inf, np.inf]))
It looks great:
But in this case I've prepared the data and I've known a number of frequencies. Do you know how to define the func
only once and handle all cases (for example five sine functions)? I've tried to put the parameters into lists, e.g. amp = [amp1, amp2, ... ]
and I've iterated over their length. But there is a problem to define bounds
for parameter lists. bounds
is very important to ensure reality model.
The solution does not have to based on curve_fit
.
python scipy least-squares
python scipy least-squares
asked Nov 26 '18 at 12:19
BenekBenek
346
346
Are you trying to do a Least-squares spectral analysis (Lomb-Scargle periodogram)?
– Jan Christoph Terasa
Nov 26 '18 at 12:38
But I can determine the frequencies. I try to find the rest of sine functions parameters. I've read the docs and I don't see how the Lomb-Scargle periodogram can help me with that.
– Benek
Nov 26 '18 at 13:15
add a comment |
Are you trying to do a Least-squares spectral analysis (Lomb-Scargle periodogram)?
– Jan Christoph Terasa
Nov 26 '18 at 12:38
But I can determine the frequencies. I try to find the rest of sine functions parameters. I've read the docs and I don't see how the Lomb-Scargle periodogram can help me with that.
– Benek
Nov 26 '18 at 13:15
Are you trying to do a Least-squares spectral analysis (Lomb-Scargle periodogram)?
– Jan Christoph Terasa
Nov 26 '18 at 12:38
Are you trying to do a Least-squares spectral analysis (Lomb-Scargle periodogram)?
– Jan Christoph Terasa
Nov 26 '18 at 12:38
But I can determine the frequencies. I try to find the rest of sine functions parameters. I've read the docs and I don't see how the Lomb-Scargle periodogram can help me with that.
– Benek
Nov 26 '18 at 13:15
But I can determine the frequencies. I try to find the rest of sine functions parameters. I've read the docs and I don't see how the Lomb-Scargle periodogram can help me with that.
– Benek
Nov 26 '18 at 13:15
add a comment |
1 Answer
1
active
oldest
votes
Assuming you know the frequencies beforehand the problem is simple. You can set the lower bound to 0 and set the upper bound to 2 * pi * freq for frequency. For amps, set any number (or np.inf
if you want no boundary).
You can formulate the function in the form lambda x, amp1, phase1, amp2, phase2... : y
, curve_fit
can accept a function of undefined number of arguments as long as you supply a proper initial guess.
A sample code for five frequencies:
import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit
x = np.linspace(0,10,60)
w = [1,2,3,4,5]
a = [1,4,2,3,0.1]
x0 = [0,1,0,1,0.5]
y = np.sum(a_i * np.sin(w_i * x - x0_i) for w_i, a_i, x0_i in zip(w,a, x0)) #base_data
yr = y + np.random.normal(0,0.5, size=x.size) #noisy data
def func(x, *args):
""" function of the form lambda x, amp1, phase1, amp2, phase2...."""
return np.sum(a_i * np.sin(w_i * (x-x0)) for w_i, a_i, x0
in zip(w,args[::2], args[1::2]))
ubounds = np.zeros(len(w) * 2)
ubounds[::2] = 10 #setting amp max value to 10 (arbitrary)
ubounds[1::2] = np.asarray(w) * 2 * np.pi
p0 = [0] * 10 # note p0 size
popt, pcov = curve_fit(func, x, yr, p0, bounds=(0, ubounds))
amps, phases = popt[::2], popt[1::2]
plt.plot(x,func(x, *popt))
plt.plot(x,yr, 'go')
Let's summarize. The most important "things" for me are:*args
argument in thefunc(x, *args)
andp0
argument in thecurve_fit
function indicating a number of used parameters explicitly.
– Benek
Nov 28 '18 at 9:13
1
Yep, your*args
are the pair of amps, phases for each frequency (which can be 1, 2 or 10, your choice). YourP0
represents the "seed values" forcurve_fit
optimization, but also it will tell how many parameters you have to optimize: if you don't passP0
when you have*args
in the function definition you'll get an error, ascurve_fit
won't know how many parameters are there to fit.
– Mstaino
Nov 28 '18 at 12:12
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53481007%2fleast-squares-method-for-a-sum-of-functions%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
Assuming you know the frequencies beforehand the problem is simple. You can set the lower bound to 0 and set the upper bound to 2 * pi * freq for frequency. For amps, set any number (or np.inf
if you want no boundary).
You can formulate the function in the form lambda x, amp1, phase1, amp2, phase2... : y
, curve_fit
can accept a function of undefined number of arguments as long as you supply a proper initial guess.
A sample code for five frequencies:
import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit
x = np.linspace(0,10,60)
w = [1,2,3,4,5]
a = [1,4,2,3,0.1]
x0 = [0,1,0,1,0.5]
y = np.sum(a_i * np.sin(w_i * x - x0_i) for w_i, a_i, x0_i in zip(w,a, x0)) #base_data
yr = y + np.random.normal(0,0.5, size=x.size) #noisy data
def func(x, *args):
""" function of the form lambda x, amp1, phase1, amp2, phase2...."""
return np.sum(a_i * np.sin(w_i * (x-x0)) for w_i, a_i, x0
in zip(w,args[::2], args[1::2]))
ubounds = np.zeros(len(w) * 2)
ubounds[::2] = 10 #setting amp max value to 10 (arbitrary)
ubounds[1::2] = np.asarray(w) * 2 * np.pi
p0 = [0] * 10 # note p0 size
popt, pcov = curve_fit(func, x, yr, p0, bounds=(0, ubounds))
amps, phases = popt[::2], popt[1::2]
plt.plot(x,func(x, *popt))
plt.plot(x,yr, 'go')
Let's summarize. The most important "things" for me are:*args
argument in thefunc(x, *args)
andp0
argument in thecurve_fit
function indicating a number of used parameters explicitly.
– Benek
Nov 28 '18 at 9:13
1
Yep, your*args
are the pair of amps, phases for each frequency (which can be 1, 2 or 10, your choice). YourP0
represents the "seed values" forcurve_fit
optimization, but also it will tell how many parameters you have to optimize: if you don't passP0
when you have*args
in the function definition you'll get an error, ascurve_fit
won't know how many parameters are there to fit.
– Mstaino
Nov 28 '18 at 12:12
add a comment |
Assuming you know the frequencies beforehand the problem is simple. You can set the lower bound to 0 and set the upper bound to 2 * pi * freq for frequency. For amps, set any number (or np.inf
if you want no boundary).
You can formulate the function in the form lambda x, amp1, phase1, amp2, phase2... : y
, curve_fit
can accept a function of undefined number of arguments as long as you supply a proper initial guess.
A sample code for five frequencies:
import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit
x = np.linspace(0,10,60)
w = [1,2,3,4,5]
a = [1,4,2,3,0.1]
x0 = [0,1,0,1,0.5]
y = np.sum(a_i * np.sin(w_i * x - x0_i) for w_i, a_i, x0_i in zip(w,a, x0)) #base_data
yr = y + np.random.normal(0,0.5, size=x.size) #noisy data
def func(x, *args):
""" function of the form lambda x, amp1, phase1, amp2, phase2...."""
return np.sum(a_i * np.sin(w_i * (x-x0)) for w_i, a_i, x0
in zip(w,args[::2], args[1::2]))
ubounds = np.zeros(len(w) * 2)
ubounds[::2] = 10 #setting amp max value to 10 (arbitrary)
ubounds[1::2] = np.asarray(w) * 2 * np.pi
p0 = [0] * 10 # note p0 size
popt, pcov = curve_fit(func, x, yr, p0, bounds=(0, ubounds))
amps, phases = popt[::2], popt[1::2]
plt.plot(x,func(x, *popt))
plt.plot(x,yr, 'go')
Let's summarize. The most important "things" for me are:*args
argument in thefunc(x, *args)
andp0
argument in thecurve_fit
function indicating a number of used parameters explicitly.
– Benek
Nov 28 '18 at 9:13
1
Yep, your*args
are the pair of amps, phases for each frequency (which can be 1, 2 or 10, your choice). YourP0
represents the "seed values" forcurve_fit
optimization, but also it will tell how many parameters you have to optimize: if you don't passP0
when you have*args
in the function definition you'll get an error, ascurve_fit
won't know how many parameters are there to fit.
– Mstaino
Nov 28 '18 at 12:12
add a comment |
Assuming you know the frequencies beforehand the problem is simple. You can set the lower bound to 0 and set the upper bound to 2 * pi * freq for frequency. For amps, set any number (or np.inf
if you want no boundary).
You can formulate the function in the form lambda x, amp1, phase1, amp2, phase2... : y
, curve_fit
can accept a function of undefined number of arguments as long as you supply a proper initial guess.
A sample code for five frequencies:
import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit
x = np.linspace(0,10,60)
w = [1,2,3,4,5]
a = [1,4,2,3,0.1]
x0 = [0,1,0,1,0.5]
y = np.sum(a_i * np.sin(w_i * x - x0_i) for w_i, a_i, x0_i in zip(w,a, x0)) #base_data
yr = y + np.random.normal(0,0.5, size=x.size) #noisy data
def func(x, *args):
""" function of the form lambda x, amp1, phase1, amp2, phase2...."""
return np.sum(a_i * np.sin(w_i * (x-x0)) for w_i, a_i, x0
in zip(w,args[::2], args[1::2]))
ubounds = np.zeros(len(w) * 2)
ubounds[::2] = 10 #setting amp max value to 10 (arbitrary)
ubounds[1::2] = np.asarray(w) * 2 * np.pi
p0 = [0] * 10 # note p0 size
popt, pcov = curve_fit(func, x, yr, p0, bounds=(0, ubounds))
amps, phases = popt[::2], popt[1::2]
plt.plot(x,func(x, *popt))
plt.plot(x,yr, 'go')
Assuming you know the frequencies beforehand the problem is simple. You can set the lower bound to 0 and set the upper bound to 2 * pi * freq for frequency. For amps, set any number (or np.inf
if you want no boundary).
You can formulate the function in the form lambda x, amp1, phase1, amp2, phase2... : y
, curve_fit
can accept a function of undefined number of arguments as long as you supply a proper initial guess.
A sample code for five frequencies:
import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit
x = np.linspace(0,10,60)
w = [1,2,3,4,5]
a = [1,4,2,3,0.1]
x0 = [0,1,0,1,0.5]
y = np.sum(a_i * np.sin(w_i * x - x0_i) for w_i, a_i, x0_i in zip(w,a, x0)) #base_data
yr = y + np.random.normal(0,0.5, size=x.size) #noisy data
def func(x, *args):
""" function of the form lambda x, amp1, phase1, amp2, phase2...."""
return np.sum(a_i * np.sin(w_i * (x-x0)) for w_i, a_i, x0
in zip(w,args[::2], args[1::2]))
ubounds = np.zeros(len(w) * 2)
ubounds[::2] = 10 #setting amp max value to 10 (arbitrary)
ubounds[1::2] = np.asarray(w) * 2 * np.pi
p0 = [0] * 10 # note p0 size
popt, pcov = curve_fit(func, x, yr, p0, bounds=(0, ubounds))
amps, phases = popt[::2], popt[1::2]
plt.plot(x,func(x, *popt))
plt.plot(x,yr, 'go')
answered Nov 27 '18 at 13:08
MstainoMstaino
1,439412
1,439412
Let's summarize. The most important "things" for me are:*args
argument in thefunc(x, *args)
andp0
argument in thecurve_fit
function indicating a number of used parameters explicitly.
– Benek
Nov 28 '18 at 9:13
1
Yep, your*args
are the pair of amps, phases for each frequency (which can be 1, 2 or 10, your choice). YourP0
represents the "seed values" forcurve_fit
optimization, but also it will tell how many parameters you have to optimize: if you don't passP0
when you have*args
in the function definition you'll get an error, ascurve_fit
won't know how many parameters are there to fit.
– Mstaino
Nov 28 '18 at 12:12
add a comment |
Let's summarize. The most important "things" for me are:*args
argument in thefunc(x, *args)
andp0
argument in thecurve_fit
function indicating a number of used parameters explicitly.
– Benek
Nov 28 '18 at 9:13
1
Yep, your*args
are the pair of amps, phases for each frequency (which can be 1, 2 or 10, your choice). YourP0
represents the "seed values" forcurve_fit
optimization, but also it will tell how many parameters you have to optimize: if you don't passP0
when you have*args
in the function definition you'll get an error, ascurve_fit
won't know how many parameters are there to fit.
– Mstaino
Nov 28 '18 at 12:12
Let's summarize. The most important "things" for me are:
*args
argument in the func(x, *args)
and p0
argument in the curve_fit
function indicating a number of used parameters explicitly.– Benek
Nov 28 '18 at 9:13
Let's summarize. The most important "things" for me are:
*args
argument in the func(x, *args)
and p0
argument in the curve_fit
function indicating a number of used parameters explicitly.– Benek
Nov 28 '18 at 9:13
1
1
Yep, your
*args
are the pair of amps, phases for each frequency (which can be 1, 2 or 10, your choice). Your P0
represents the "seed values" for curve_fit
optimization, but also it will tell how many parameters you have to optimize: if you don't pass P0
when you have *args
in the function definition you'll get an error, as curve_fit
won't know how many parameters are there to fit.– Mstaino
Nov 28 '18 at 12:12
Yep, your
*args
are the pair of amps, phases for each frequency (which can be 1, 2 or 10, your choice). Your P0
represents the "seed values" for curve_fit
optimization, but also it will tell how many parameters you have to optimize: if you don't pass P0
when you have *args
in the function definition you'll get an error, as curve_fit
won't know how many parameters are there to fit.– Mstaino
Nov 28 '18 at 12:12
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53481007%2fleast-squares-method-for-a-sum-of-functions%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Are you trying to do a Least-squares spectral analysis (Lomb-Scargle periodogram)?
– Jan Christoph Terasa
Nov 26 '18 at 12:38
But I can determine the frequencies. I try to find the rest of sine functions parameters. I've read the docs and I don't see how the Lomb-Scargle periodogram can help me with that.
– Benek
Nov 26 '18 at 13:15