Application Center - Maplesoft

App Preview:

Classroom Tips and Techniques: A Vexing Trig Conversion

You can switch back to the summary page by clicking here.

Learn about Maple
Download Application


 

Image 

Classroom Tips and Techniques: A Vexing Trig Conversion 

 

Robert J. Lopez 

Emeritus Professor of Mathematics and Maple Fellow 

Maplesoft 

 

Introduction 

 

In engineering, it is common to express the sum 

 

`+`(`*`(a, `*`(`^`(e, `*`(c, `*`(t))), `*`(cos(`*`(omega, `*`(t)))))), `*`(b, `*`(`^`(e, `*`(c, `*`(t))), `*`(sin(`*`(omega, `*`(t)))))))  

 

in the form 

 

`*`(A, `*`(`^`(e, `*`(c, `*`(t))), `*`(cos(`+`(`*`(omega, `*`(t)), `-`(phi))))))  

 

where A = sqrt(`+`(`*`(`^`(a, 2)), `*`(`^`(b, 2)))) and phi = arctan(`/`(`*`(b), `*`(a))).  Expressions like this often arise in the solution of initial value problems for damped oscillators, so the transformation is really useful for extracting the magnitude and phase shift of the oscillations.  Unfortunately, Maple does not presently provide a built-in facility for making this transformation. 

 

In [1], I explored use of Maple's solve/identity construct to effect the transformation in Maple V Release 4, the extant version of Maple at that time (1996).  A year later in [2], Dr. Michael Monagan followed up on this question, and provided a procedure for the transformation, and applied it to 

 

y(t) = `+`(`*`(`^`(e, `+`(`*`(`/`(1, 2), `*`(t)))), `*`(cos(`+`(`*`(`/`(1, 2), `*`(sqrt(3), `*`(t))))))), `*`(`/`(1, 3), `*`(sqrt(3), `*`(`^`(e, `+`(`*`(`/`(1, 2), `*`(t)))), `*`(sin(`+`(`*`(`/`(1, 2)...  

 

the solution of the IVP `+`(diff(y(t), t, t), `-`(diff(y(t), t)), y(t)) = 0, `and`(y(0) = (D(y))(0), (D(y))(0) = 1), obtaining 

 

y(t) = `*`(`*`(`+`(`*`(2, `*`(sqrt(3)))), `/`(1, 3)), `*`(`^`(e, `+`(`*`(`/`(1, 2), `*`(t)))), `*`(sin(`+`(`*`(`/`(1, 2), `*`(sqrt(3), `*`(t))), `*`(`/`(1, 3), `*`(Pi)))))))  

 

It's not clear from the article which version of Maple was used, but the conclusion, that Maple converted the cosine to a sine resulted in his writing 

 

"Ugghhh!  Maple has simplified the cosine to a sine on us.  It has made the transformation cos(`+`(x, `-`(`*`(`/`(1, 6), `*`(Pi))))) = sin(`+`(x, `*`(`/`(1, 3), `*`(Pi)))) thinking that we'd prefer the result with a positive angle." 

 

We revisit both approaches, then add another alternative to the mix. 

 

Initializations 

 

restart 

 

The 1996 solve/identity Approach 

 

To convert 

`+`(`*`(5, `*`(exp(`+`(`-`(`*`(3, `*`(t))))), `*`(cos(`+`(`*`(4, `*`(t))))))), `-`(`*`(9, `*`(exp(`+`(`-`(`*`(3, `*`(t))))), `*`(sin(`+`(`*`(4, `*`(t))))))))) (3.1)
 

to the form 

`*`(A, `*`(exp(`+`(`-`(`*`(3, `*`(t))))), `*`(cos(`+`(`*`(4, `*`(t)), `-`(z)))))) (3.2)
 

use the Maple command 

 

solve(identity(`+`(`*`(5, `*`(exp(`+`(`-`(`*`(3, `*`(t))))), `*`(cos(`+`(`*`(4, `*`(t))))))), `-`(`*`(9, `*`(exp(`+`(`-`(`*`(3, `*`(t))))), `*`(sin(`+`(`*`(4, `*`(t))))))))) = `*`(A, `*`(exp(`+`(`-`(`... 

{A = `*`(`^`(106, `/`(1, 2))), z = `+`(`-`(arctan(`/`(9, 5))))}, {A = `+`(`-`(`*`(`^`(106, `/`(1, 2))))), z = `+`(`-`(arctan(`/`(9, 5))), Pi)} (3.3)
 

 

The solution with positive amplitude A is the desired one, and results in the form 

 

eval(`*`(A, `*`(exp(`+`(`-`(`*`(3, `*`(t))))), `*`(cos(`+`(`*`(4, `*`(t)), `-`(z)))))), ({A = `*`(`^`(106, `/`(1, 2))), z = `+`(`-`(arctan(`/`(9, 5))))}, {A = `+`(`-`(`*`(`^`(106, `/`(1, 2))))), z = `... 

`*`(`^`(106, `/`(1, 2)), `*`(exp(`+`(`-`(`*`(3, `*`(t))))), `*`(cos(`+`(`*`(4, `*`(t)), arctan(`/`(9, 5))))))) (3.4)
 

 

This is essentially the same approach as in [1], but no longer is it necessary to expand `*`(A, `*`(exp(`+`(`-`(`*`(3, `*`(t))))), `*`(cos(`+`(`*`(4, `*`(t)), `-`(z)))))) with all the concomitant difficulties of keeping cos(`+`(`*`(4, `*`(t)))) and sin(`+`(`*`(4, `*`(t)))) from themselves expanding in powers of sin(t) and cos(t). 

 

As an update to the calculation, I would like Maple to determine the coefficient of t in the exponential, and w, the value of angular frequency in the cosine and sine terms.  To this end, try to match against a more general template via the command 

 

solve(identity(`+`(`*`(5, `*`(exp(`+`(`-`(`*`(3, `*`(t))))), `*`(cos(`+`(`*`(4, `*`(t))))))), `-`(`*`(9, `*`(exp(`+`(`-`(`*`(3, `*`(t))))), `*`(sin(`+`(`*`(4, `*`(t))))))))) = `*`(A, `*`(exp(`*`(c, `*... 

Warning, solutions may have been lost
 

 

Unfortunately, this does not work, and even setting the environment variable _EnvAllSolutions to true does not change the outcome.  Hence, we revisit Monagan's code to see if it is more robust than the solve/identity device. 

 

Monagan's 1997 Code 

 

In [2], Monagan goes through several iterations of a procedure designed to morph `+`(`*`(5, `*`(exp(`+`(`-`(`*`(3, `*`(t))))), `*`(cos(`+`(`*`(4, `*`(t))))))), `-`(`*`(9, `*`(exp(`+`(`-`(`*`(3, `*`(t))))), `*`(sin(`+`(`*`(4, `*`(t)))))))))to `*`(A, `*`(exp(`+`(`-`(`*`(3, `*`(t))))), `*`(cos(`+`(`*`(4, `*`(t)), `-`(z)))))), thinking out loud as to why he makes the various modifications shown.  The result is the pair of procedures given in Table 1, where the second procedure invokes the first. 

 

`:=`(common, proc (f, g, newf, newg) local C, F, G; if type(f, `*`) then `:=`(F, {op(f)}) else `:=`(F, {f}) end if; if type(g, `*`) then `:=`(G, {op(g)}) else `:=`(G, {g}) end if; `:=`(C, `intersect`(...
`:=`(common, proc (f, g, newf, newg) local C, F, G; if type(f, `*`) then `:=`(F, {op(f)}) else `:=`(F, {f}) end if; if type(g, `*`) then `:=`(G, {op(g)}) else `:=`(G, {g}) end if; `:=`(C, `intersect`(...
`:=`(common, proc (f, g, newf, newg) local C, F, G; if type(f, `*`) then `:=`(F, {op(f)}) else `:=`(F, {f}) end if; if type(g, `*`) then `:=`(G, {op(g)}) else `:=`(G, {g}) end if; `:=`(C, `intersect`(...
`:=`(common, proc (f, g, newf, newg) local C, F, G; if type(f, `*`) then `:=`(F, {op(f)}) else `:=`(F, {f}) end if; if type(g, `*`) then `:=`(G, {op(g)}) else `:=`(G, {g}) end if; `:=`(C, `intersect`(...
`:=`(common, proc (f, g, newf, newg) local C, F, G; if type(f, `*`) then `:=`(F, {op(f)}) else `:=`(F, {f}) end if; if type(g, `*`) then `:=`(G, {op(g)}) else `:=`(G, {g}) end if; `:=`(C, `intersect`(...
`:=`(common, proc (f, g, newf, newg) local C, F, G; if type(f, `*`) then `:=`(F, {op(f)}) else `:=`(F, {f}) end if; if type(g, `*`) then `:=`(G, {op(g)}) else `:=`(G, {g}) end if; `:=`(C, `intersect`(...
`:=`(common, proc (f, g, newf, newg) local C, F, G; if type(f, `*`) then `:=`(F, {op(f)}) else `:=`(F, {f}) end if; if type(g, `*`) then `:=`(G, {op(g)}) else `:=`(G, {g}) end if; `:=`(C, `intersect`(...
`:=`(common, proc (f, g, newf, newg) local C, F, G; if type(f, `*`) then `:=`(F, {op(f)}) else `:=`(F, {f}) end if; if type(g, `*`) then `:=`(G, {op(g)}) else `:=`(G, {g}) end if; `:=`(C, `intersect`(...
`:=`(common, proc (f, g, newf, newg) local C, F, G; if type(f, `*`) then `:=`(F, {op(f)}) else `:=`(F, {f}) end if; if type(g, `*`) then `:=`(G, {op(g)}) else `:=`(G, {g}) end if; `:=`(C, `intersect`(...
`:=`(common, proc (f, g, newf, newg) local C, F, G; if type(f, `*`) then `:=`(F, {op(f)}) else `:=`(F, {f}) end if; if type(g, `*`) then `:=`(G, {op(g)}) else `:=`(G, {g}) end if; `:=`(C, `intersect`(...
`:=`(common, proc (f, g, newf, newg) local C, F, G; if type(f, `*`) then `:=`(F, {op(f)}) else `:=`(F, {f}) end if; if type(g, `*`) then `:=`(G, {op(g)}) else `:=`(G, {g}) end if; `:=`(C, `intersect`(...
 

 

`:=`(trigcombine, proc (f, x) local A, B, s, C, phi; if type(f, {name, numeric, procedure}) then f elif `and`(`and`(`and`(type(f, `+`), degree(f, sin(x)) = 1), degree(f, cos(x)) = 1), degree(f, {cos(x...
`:=`(trigcombine, proc (f, x) local A, B, s, C, phi; if type(f, {name, numeric, procedure}) then f elif `and`(`and`(`and`(type(f, `+`), degree(f, sin(x)) = 1), degree(f, cos(x)) = 1), degree(f, {cos(x...
`:=`(trigcombine, proc (f, x) local A, B, s, C, phi; if type(f, {name, numeric, procedure}) then f elif `and`(`and`(`and`(type(f, `+`), degree(f, sin(x)) = 1), degree(f, cos(x)) = 1), degree(f, {cos(x...
`:=`(trigcombine, proc (f, x) local A, B, s, C, phi; if type(f, {name, numeric, procedure}) then f elif `and`(`and`(`and`(type(f, `+`), degree(f, sin(x)) = 1), degree(f, cos(x)) = 1), degree(f, {cos(x...
`:=`(trigcombine, proc (f, x) local A, B, s, C, phi; if type(f, {name, numeric, procedure}) then f elif `and`(`and`(`and`(type(f, `+`), degree(f, sin(x)) = 1), degree(f, cos(x)) = 1), degree(f, {cos(x...
`:=`(trigcombine, proc (f, x) local A, B, s, C, phi; if type(f, {name, numeric, procedure}) then f elif `and`(`and`(`and`(type(f, `+`), degree(f, sin(x)) = 1), degree(f, cos(x)) = 1), degree(f, {cos(x...
`:=`(trigcombine, proc (f, x) local A, B, s, C, phi; if type(f, {name, numeric, procedure}) then f elif `and`(`and`(`and`(type(f, `+`), degree(f, sin(x)) = 1), degree(f, cos(x)) = 1), degree(f, {cos(x...
`:=`(trigcombine, proc (f, x) local A, B, s, C, phi; if type(f, {name, numeric, procedure}) then f elif `and`(`and`(`and`(type(f, `+`), degree(f, sin(x)) = 1), degree(f, cos(x)) = 1), degree(f, {cos(x...
`:=`(trigcombine, proc (f, x) local A, B, s, C, phi; if type(f, {name, numeric, procedure}) then f elif `and`(`and`(`and`(type(f, `+`), degree(f, sin(x)) = 1), degree(f, cos(x)) = 1), degree(f, {cos(x...
`:=`(trigcombine, proc (f, x) local A, B, s, C, phi; if type(f, {name, numeric, procedure}) then f elif `and`(`and`(`and`(type(f, `+`), degree(f, sin(x)) = 1), degree(f, cos(x)) = 1), degree(f, {cos(x...
`:=`(trigcombine, proc (f, x) local A, B, s, C, phi; if type(f, {name, numeric, procedure}) then f elif `and`(`and`(`and`(type(f, `+`), degree(f, sin(x)) = 1), degree(f, cos(x)) = 1), degree(f, {cos(x...
`:=`(trigcombine, proc (f, x) local A, B, s, C, phi; if type(f, {name, numeric, procedure}) then f elif `and`(`and`(`and`(type(f, `+`), degree(f, sin(x)) = 1), degree(f, cos(x)) = 1), degree(f, {cos(x...
`:=`(trigcombine, proc (f, x) local A, B, s, C, phi; if type(f, {name, numeric, procedure}) then f elif `and`(`and`(`and`(type(f, `+`), degree(f, sin(x)) = 1), degree(f, cos(x)) = 1), degree(f, {cos(x...
`:=`(trigcombine, proc (f, x) local A, B, s, C, phi; if type(f, {name, numeric, procedure}) then f elif `and`(`and`(`and`(type(f, `+`), degree(f, sin(x)) = 1), degree(f, cos(x)) = 1), degree(f, {cos(x...
`:=`(trigcombine, proc (f, x) local A, B, s, C, phi; if type(f, {name, numeric, procedure}) then f elif `and`(`and`(`and`(type(f, `+`), degree(f, sin(x)) = 1), degree(f, cos(x)) = 1), degree(f, {cos(x...
 

Table 1   Monagan's procedures from [2] that morph `+`(`*`(5, `*`(exp(`+`(`-`(`*`(3, `*`(t))))), `*`(cos(`+`(`*`(4, `*`(t))))))), `-`(`*`(9, `*`(exp(`+`(`-`(`*`(3, `*`(t))))), `*`(sin(`+`(`*`(4, `*`(t)))))))))to `*`(A, `*`(exp(`+`(`-`(`*`(3, `*`(t))))), `*`(cos(`+`(`*`(4, `*`(t)), `-`(z)))))) 

 

Applying the trigcombine procedure, we have 

 

trigcombine(`+`(`*`(5, `*`(exp(`+`(`-`(`*`(3, `*`(t))))), `*`(cos(`+`(`*`(4, `*`(t))))))), `-`(`*`(9, `*`(exp(`+`(`-`(`*`(3, `*`(t))))), `*`(sin(`+`(`*`(4, `*`(t))))))))), `+`(`*`(4, `*`(t)))) 

`*`(`^`(106, `/`(1, 2)), `*`(exp(`+`(`-`(`*`(3, `*`(t))))), `*`(cos(`+`(`*`(4, `*`(t)), arctan(`/`(9, 5))))))) (4.1)
 

 

The earlier version of Maple used for [2] returned this as `*`(`*`(`+`(`*`(2, `*`(sqrt(3)))), `/`(1, 3)), `*`(`^`(e, `+`(`*`(`/`(1, 2), `*`(t)))), `*`(sin(`+`(`*`(`/`(1, 2), `*`(sqrt(3), `*`(t))), `*`(`/`(1, 3), `*`(Pi))))))), prompting Monagan's Ugghhh!  However, even though Maple 12 now returns the cosine, as expected, one still has to include the extra argument, `+`(`*`(4, `*`(t))).  In return, we note that this procedure is robust enough to convert the generic 

 

`+`(`*`(alpha, `*`(exp(`*`(gamma, `*`(t))), `*`(cos(`*`(omega, `*`(t)))))), `*`(beta, `*`(exp(`*`(gamma, `*`(t))), `*`(sin(`*`(omega, `*`(t))))))) (4.2)
 

to 

 

trigcombine(`+`(`*`(alpha, `*`(exp(`*`(gamma, `*`(t))), `*`(cos(`*`(omega, `*`(t)))))), `*`(beta, `*`(exp(`*`(gamma, `*`(t))), `*`(sin(`*`(omega, `*`(t))))))), `*`(omega, `*`(t))) 

`*`(exp(`*`(gamma, `*`(t))), `*`(`^`(`+`(`*`(`^`(alpha, 2)), `*`(`^`(beta, 2))), `/`(1, 2)), `*`(cos(`+`(`*`(omega, `*`(t)), arctan(`+`(`-`(beta)), alpha))))))
 

 

 

Maple 12 in 2008 

 

Monagan's code in the right-hand column of Table 1 uses the coeff command to obtain the coefficients of the trig terms.  However, for this to work, the trig terms must have arguments, which is why the trigcombine command requires the second argument, `*`(omega, `*`(t)).  We sought code that would deduce this argument.  Dr. James McCarron, one of the Maple developers, provided that code and a lot more in the procedure TrigCombine, defined in the Code Edit Region below.  

 

To access the procedure TrigCombine, click the button  

 

Button  

 

To view the code in this Code Edit Region, use Context Menu: Expand Code Edit Region.  The code is work worthy of one of the Maple developers.  It finds the appropriate trig terms in larger expressions, and applies the requisite transformation in every instance possible in the given expression. 

 

The TrigCombine procedure evolved from the desire to write 

 

`+`(`-`(`*`(exp(`+`(`-`(`*`(`/`(1, 4), `*`(t))))), `*`(cos(`+`(`*`(`/`(1, 4), `*`(t, `*`(`^`(15, `/`(1, 2)))))))))), `-`(`*`(`/`(1, 15), `*`(exp(`+`(`-`(`*`(`/`(1, 4), `*`(t))))), `*`(sin(`+`(`*`(`/`(... (5.1)
 

 

in the form 

 

`+`(1, `-`(`*`(`/`(4, 15), `*`(sqrt(15), `*`(exp(`+`(`-`(`*`(`/`(1, 4), `*`(t))))), `*`(cos(`+`(`*`(`/`(1, 4), `*`(t, `*`(sqrt(15)))), `-`(arctan(`+`(`*`(`/`(1, 15), `*`(sqrt(15))))))))))))))  

 

without having to retype the argument of the trig functions.  Monagan's trigcombine returns unevaluated because of the "+1" in `+`(`-`(`*`(exp(`+`(`-`(`*`(`/`(1, 4), `*`(t))))), `*`(cos(`+`(`*`(`/`(1, 4), `*`(t, `*`(`^`(15, `/`(1, 2)))))))))), `-`(`*`(`/`(1, 15), `*`(exp(`+`(`-`(`*`(`/`(1, 4), `*`(t))))), `*`(sin(`+`(`*`(`/`(.... Application of the TrigCombine procedure then gives 

 

TrigCombine(`+`(`-`(`*`(exp(`+`(`-`(`*`(`/`(1, 4), `*`(t))))), `*`(cos(`+`(`*`(`/`(1, 4), `*`(t, `*`(`^`(15, `/`(1, 2)))))))))), `-`(`*`(`/`(1, 15), `*`(exp(`+`(`-`(`*`(`/`(1, 4), `*`(t))))), `*`(sin(... 

`+`(1, `-`(`*`(`/`(4, 15), `*`(`^`(15, `/`(1, 2)), `*`(exp(`+`(`-`(`*`(`/`(1, 4), `*`(t))))), `*`(cos(`+`(`*`(`/`(1, 4), `*`(t, `*`(`^`(15, `/`(1, 2))))), `-`(arctan(`+`(`*`(`/`(1, 15), `*`(`^`(15, `/...
 

 

Like Monagan's trigcombine procedure, TrigCombine is robust enough to work with parameters, as we see from  

 

TrigCombine(`+`(`*`(alpha, `*`(exp(`*`(gamma, `*`(t))), `*`(cos(`*`(omega, `*`(t)))))), `*`(beta, `*`(exp(`*`(gamma, `*`(t))), `*`(sin(`*`(omega, `*`(t))))))), t) 

`*`(`^`(`+`(`*`(`^`(alpha, 2)), `*`(`^`(beta, 2))), `/`(1, 2)), `*`(exp(`*`(gamma, `*`(t))), `*`(cos(`+`(`*`(omega, `*`(t)), `-`(arctan(beta, alpha)))))))
 

 

It is even robust enough to find multiple instances of trig terms that need to be combined.  For example, if we apply TrigCombine to an expression such as 

 

`+`(A, `*`(3, `*`(`^`(t, 2), `*`(exp(`+`(`-`(`*`(c[1], `*`(t))))), `*`(cos(`*`(omega[1], `*`(t))))))), `*`(4, `*`(`^`(t, 2), `*`(exp(`+`(`-`(`*`(c[1], `*`(t))))), `*`(sin(`*`(omega[1], `*`(t))))))), `... (5.2)
 

 

we would get 

 

TrigCombine(`+`(A, `*`(3, `*`(`^`(t, 2), `*`(exp(`+`(`-`(`*`(c[1], `*`(t))))), `*`(cos(`*`(omega[1], `*`(t))))))), `*`(4, `*`(`^`(t, 2), `*`(exp(`+`(`-`(`*`(c[1], `*`(t))))), `*`(sin(`*`(omega[1], `*`... 

`+`(A, `*`(`^`(74, `/`(1, 2)), `*`(`^`(t, 3), `*`(exp(`+`(`-`(`*`(c[2], `*`(t))))), `*`(cos(`+`(`*`(omega[2], `*`(t)), arctan(`/`(7, 5)))))))), `*`(5, `*`(`^`(t, 2), `*`(exp(`+`(`-`(`*`(c[1], `*`(t)))...
 

 

in distinction from Monagan's trigcombine which would return unevaluated on `+`(A, `*`(3, `*`(`^`(t, 2), `*`(exp(`+`(`-`(`*`(c[1], `*`(t))))), `*`(cos(`*`(omega[1], `*`(t))))))), `*`(4, `*`(`^`(t, 2), `*`(exp(`+`(`-`(`*`(c[1], `*`(t))))), `*`(sin(`*`(omega[1], `*`(t))))))), `....  It is not an inconvenience to include the independent variable as an argument to the TrigCombine command.  However, it is anticipated that in a future release of Maple, this functionality will be realized as an option to the convert command, with syntax something like 

 

convert(expression, phaseamp, t)  

 

where the option "phaseamp" refers to the phase-amplitude form of the trig expressions we have been examining. 

 

Monagan's "Ugghhh" 

 

In [2], Monagan expressed great disappointment when Maple returned sin(`+`(x, `*`(`/`(1, 3), `*`(Pi)))) where he expected cos(`+`(x, `-`(`*`(`/`(1, 6), `*`(Pi))))).  In fact, entering the latter will always result in the former, as we see from  

 

cos(`+`(x, `-`(`*`(`/`(1, 6), `*`(Pi))))) 

sin(`+`(x, `*`(`/`(1, 3), `*`(Pi))))
 

 

This is not the fault of Monagan's code, and it will not be the fault of the code in TrigCombine, where this conversion will continue to occur.  The conversion of the cosine to the sine has been and still is, an automatic simplification in Maple that cannot be blocked by the user.  Hence, application of TrigCombine to 

 

`+`(`*`(`^`(3, `/`(1, 2)), `*`(cos(x))), sin(x)) (6.1)
 

necessarily results in 

 

TrigCombine(`+`(`*`(`^`(3, `/`(1, 2)), `*`(cos(x))), sin(x)), x) 

`+`(`*`(2, `*`(sin(`+`(x, `*`(`/`(1, 3), `*`(Pi))))))) (6.2)
 

 

and not in `+`(`*`(2, `*`(cos(`+`(x, `-`(`*`(`/`(1, 6), `*`(Pi)))))))). 

 

References 

 

[1] Tips for Maple Instructors, Robert J. Lopez, MapleTech, Vol. 3, No. 3, 1966, p. 41. 

 

[2] Tips for Maple Users and Programmers, Michael B. Monagan, MapleTech, Vol. 4, No. 3, 1997, p. 13. 

 

 

Legal Notice: The copyright for this application is owned by Maplesoft. The application is intended to demonstrate the use of Maple to solve a particular problem. It has been made available for product evaluation purposes only and may not be used in any other context without the express permission of Maplesoft.