Least Squares Method for a sum of functions












1















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:
enter image description here



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.










share|improve this question























  • 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


















1















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:
enter image description here



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.










share|improve this question























  • 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
















1












1








1








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:
enter image description here



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.










share|improve this question














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:
enter image description here



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






share|improve this question













share|improve this question











share|improve this question




share|improve this question










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





















  • 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














1 Answer
1






active

oldest

votes


















1














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')





share|improve this answer
























  • 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





    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













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
});


}
});














draft saved

draft discarded


















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









1














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')





share|improve this answer
























  • 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





    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


















1














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')





share|improve this answer
























  • 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





    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
















1












1








1







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')





share|improve this answer













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')






share|improve this answer












share|improve this answer



share|improve this answer










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 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





    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





















  • 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





    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



















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






















draft saved

draft discarded




















































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.




draft saved


draft discarded














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





















































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







Popular posts from this blog

A CLEAN and SIMPLE way to add appendices to Table of Contents and bookmarks

Calculate evaluation metrics using cross_val_predict sklearn

Insert data from modal to MySQL (multiple modal on website)