3
$\begingroup$

I want to build a function of the form

$f(t)= C + \sum_i A_i*Sin(f_i*t+\phi_i)$

Where $(A_i,f_i,\phi_i)$ are amplitudes, frequencies and phases that I have stored in a text file. Here is my attempt:

BuildOscFunction[indata_,freqvals_]:=Module[{i,j,sin,func,t},
    func=Mean[indata[[All,2]]];
    For[i=1,i<=Length[freqvals],i++,
        func+=freqvals[[i,2]]*Sin[freqvals[[i,1]]*t+freqvals[[i,3]]];   
    ];
    f[t_]:=func//Evaluate;
    Return[f[t]];   
];

Here are example snippets of my data set and list of input parameters:

indata[[;;4]]={{0., 1.00105}, {20.0003, 1.00115}, {40.0007, 0.999966}, {60.001, 
1.00177}};

freqvals[[;;4]]={{233.362, 0.000802, 3.93604}, {22.0164, 0.000641, 0.277801}, 
{113.97, 0.00063, 5.8311}, {243.764, 0.000631, 5.94761}}

The Evaluate command only works if t is not a local variable inside Module. What I want is to get a fully written-out function that I can use at will. Something like,

 func[t_]:=BuildOscFunction[indata,freqvals];
 func[t] = 1.2 + 0.00802Sin[233.362t+3.93] + 0.000641Sin[22.0164t+0.277801]+...etc
 func[2]=1.24

EDIT:

Thank you for the several very helpful responses! I ended up finding success using the selected answer using code like this:

BuildOscFunction[f_,A_,phi_]:=Function[t,Total[A*Sin[f*t+phi]]];

ExampleModule[indata_,freqvals_]:=Module[{funcbuild,func},
    funcbuild=BuildOscFunction[freqvals[[All,1]],freqvals[[All,2]],freqvals[[All,3]]];
    func[t_]:=funcbuild[t];
];

func[t] successfully behaves like a standard function where it can be evaluated, manipulated, plotted, etc. inside of the Module environment.

$\endgroup$
2
  • $\begingroup$ Return does not mean the same thing in Mathematica as it does in other languages. Generally, you won't need to use it. To return something from a Module, just have it be the last entry in the Module, and don't use a semicolon. That is, Module[{i,j,sin,func,t}, ...; f[t_] := func // Evaluate] $\endgroup$
    – march
    Jan 25 at 18:24
  • $\begingroup$ How about: BuildOscFunction[in_List, fv_List] := Mean[in[[All, 2]]] + #[[2]] Sin[#[[1]] t + #[[3]]] & /@ fv // Total and BuildOscFunction[indata, freqvals] /. t -> 2 for a single point evaluation. $\endgroup$
    – Syed
    Jan 25 at 18:39

3 Answers 3

6
$\begingroup$

Welcome to MSE!

To be effective with Wolfram Language, you have to change your thinking from "procedural" to "functional". E.g., try to avoid using explicit Do loops etc.

In your particular example, it certainly helps that many functions (including Plus, Times and Sin) are Listable, e.g., they automatically map over their arguments:

Clear[a, b, c]
Sin[{a, b, c}] (* Sin[a], Sin[b], Sin[c]} *)

Knowing this, here is one possible solution to your problem:

BuildOscFunction[A_, f_, phi_] := Function[t, Total[A Sin[f t + phi]]]


Clear[A, f, phi]
A = {0.1, 0.2, 0.3, 0.4};
f = {5.7, 3.8, 9.1, 6.5};
phi = {-1, 0.27, 1.35, -2};


g = BuildOscFunction[A, f, phi]
Plot[g[t], {t, 0, Pi}]

enter image description here

$\endgroup$
3
$\begingroup$

Following suggestions in other answers is a good idea, i.e., avoid the use of loops in Mathematica. There are are almost always better ways to do things. That said, to minimally change your code so that it works, I would do the following:

buildOscFunction[indata_, freqvals_] := Module[{i, j, sin, func},
  func = Mean[indata[[All, 2]]];
  For[i = 1, i <= Length[freqvals], i++,
    func += freqvals[[i, 2]]*Sin[freqvals[[i, 1]]*t + freqvals[[i, 3]]]];
  f[t_] := func
 ]

Then, setting (note that you don't need to declare these as variables before defining these lists!)

 indata = {{0., 1.00105}, {20.0003, 1.00115}, {40.0007, 0.999966}, {60.001, 1.00177}};
 freqvals = {{233.362, 0.000802, 3.93604}, {22.0164, 0.000641, 0.277801}, {113.97, 0.00063, 5.8311}, {243.764, 0.000631, 5.94761}};

and evaluating

 buildOscFunction[indata, freqvals]

creates a function of f[t] that you can then plot

 Plot[f[t], {t, 0, 1}]

enter image description here

Note a couple of things:

  • I have removed the use of Return. It's not the same in Mathematica as in other languages. Instead, I just leave the expression I want Module to return as the last element in the CompoundExpression inside the Module (and without a semicolon).

  • I have removed t from the set of scoped variables inside the Module. This is because Module creates new variable names behind the scenes of the form t$406471 which will cause problems if you want to evaluate this function later. Leave t as an undefined global variables.

  • I have used a lower-case first letter for the function name. It's a good habit to be in using when Mathematica because all built-in names have capitalized first letters; this way, you won't conflict with built-in functions.

Aesthetically, I might want to define a function name outside the Module, in which case I would instead define

buildOscFunction[indata_, freqvals_] := Module[{i, j, sin, func},
  func = Mean[indata[[All, 2]]];
  For[i = 1, i <= Length[freqvals], i++,
    func += freqvals[[i, 2]]*Sin[freqvals[[i, 1]]*t + freqvals[[i, 3]]]];
  func
 ]

and call the function as

func[t_] = buildOscFunction[indata, freqvals];

Then, plot func[t].

$\endgroup$
3
$\begingroup$
f[t_] := Mean[indata[[All, 2]]] + 
  Plus @@ MapThread[#[[2]] Sin[#[[1]] t + #[[3]]] &, {freqvals}]

Plot[f[t], {t, 0, 1}]

enter image description here

$\endgroup$

Your Answer

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

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