I'm developing problems for digital signal processing, so functions are defined only at integers. I wrote the problem below to give a two-sided sequenceand asked for the negative and non-negative parts. I tried to specify the integers for which the two sides should be tested
Context("Numeric");
Context()->variables->are(
n=>'Real',
z=>"Real"
);
$ans_causal = Formula("$A*($p1)**n + $B*($p3)**n ")->reduce;
$ans_noncausal = Formula("-$C*($p2)**(-n) ")->reduce; # note minus sign
$ans_causal->{test_points} = [[0,0],[1,0],[2,0],[3,0],[4,0]];
$ans_noncausal->{test_points} = [[-1,0],[-2,0],[-3,0],[-4,0]];
ANS( Formula($ans_causal)->cmp(diagnostics=>1) );
ANS( Formula($ans_noncausal)->cmp() );
But the problem error checker evaluates the functions at continuous test points - not the ones I tried to set, and get incorrect answers since the exponential blows up on the "wrong" side.
Entire code below
# DESCRIPTION
# Problem from 'Digital Signal Processing", Proakis and Manolakis, 4t ed.
# WeBWorK problem written by Joel Trussell, <hjt@ncsu.edu>
# ENDDESCRIPTION
## DBsubject(Electrical Engineering)
## DBchapter(Laplace Transforms)
## DBsection(Problems)
## Institution(North Carolina State University)
## Author(H. J. Trussell)
## TitleText1('Digital Signal Processing')
## AuthorText1('Proakis and Manolakis')
## EditionText1('4')
## Problem1('3.3)
##############################
# Initialization
DOCUMENT();
loadMacros(
"PGstandard.pl",
"MathObjects.pl",
"AnswerFormatHelp.pl",
"PGunion.pl",
"answerHints.pl",
"parserAssignment.pl",
"contextInequalities.pl",
"parserFunction.pl",
"PGcourse.pl"
);
TEXT(beginproblem());
# convolve 2-sided sequence with causal sequence
Context("Numeric");
Context()->variables->are(
n=>'Real',
z=>"Real"
);
Context()->functions->add(
step => {
class => 'Parser::Legacy::Numeric',
perl => 'Parser::Legacy::Numeric::do_step'
},
);
parserFunction("u(t)" => "step(t)");
Context()->flags->set(
tolerance => 0.001,
tolType => "absolute",
);
# causal part
$d1 = random(2,9,1); # denominator
do {$n1 = random(1,6,1);} until ($n1 < $d1); # numerator
# fraction for non-causal part
$d2 = random(2,9,1); # denominator
do {$n2 = random(1,6,1);} until ($n2 < $d2); # numerator
# fraction for causal system function
do {$d3 = random(2,9,1); } until ($d3 != $d1); # denominator
do {$n3 = random(1,6,1);} until ($n3 < $d3); # numerator
# check answer of text
#$d1 = 3; $n1 = 1;$d2 = 2; $n2 = 1; $d3 = 2;$n3 = 1;
# compute partial fraction expansion for two parts - the systems x causal part
# system x non-causal part
# then add and take inverse z-transform
$p1 = $n1/$d1;
$p2 = $n2/$d2;
$p3 = $n3/$d3;
# ROC computation
$R1 = $p1;
$R2 = 1/$p2;
$R3 = $p3;
# causal part
# A/(1-a1*z^(-1)) + B/(1-a3*z^(-1))
$D = $p1 - 1/$p2;
$A = $D*(1/$p1)/((1-$p3/$p1)*(1-1/($p1*$p2)));
$B = $D*(1/$p3)/((1-$p1/$p3)*(1-1/($p3*$p2)));
# non-causal part
# C/(1-a2*z^(-1))
$C = $D*$p2/((1-$p1*$p2)*(1-$p3*$p2));
$ans_causal = Formula("$A*($p1)**n + $B*($p3)**n ")->reduce;
$ans_noncausal = Formula("-$C*($p2)**(-n) ")->reduce; # note minus sign
$ans_causal->{test_points} = [[0,0],[1,0],[2,0],[3,0],[4,0]];
$ans_noncausal->{test_points} = [[-1,0],[-2,0],[-3,0],[-4,0]];
$ROC1 = max($p1,$p3);
$ROC2 = 1/$p2;
$ROC = Compute("($ROC1,$ROC2)");
#############################
# Main text1
Context()->texStrings;
BEGIN_TEXT
This problem is related to Problem 3.7 (page 215) in the text.
$PAR
Consider the signal given by
\[ x(n) = \left\lbrace \begin{array}{ l l } ( \frac{$n1}{$d1})^n & n \geq 0 \\
( \frac{$n2}{$d2})^{-n} & n< 0 \end{array} \right. \]
and the impulse response
\[ h(n) = \left\lbrace \begin{array}{ l l } ( \frac{$n3}{$d3})^n & n \geq 0 \\
0& n< 0 \end{array} \right. \]
$PAR
Compute the convolution of the signal with the impulse response, \( y(n) = x(n)*h(n) \). $BR
For \( n \geq 0, y(n) = \) \{ ans_rule(40) \} \{ AnswerFormatHelp("formulas") \}
$BR
For \( n < 0, y(n) = \) \{ ans_rule(40) \} \{ AnswerFormatHelp("formulas") \}
$PAR Determine its region of convergence (ROC). Write the ROC as an interval.
$BR
ROC = \{ ans_rule(20) \}
\{ AnswerFormatHelp("intervals") \}
END_TEXT
Context()->normalStrings;
# save this for future possible use for format
# \[ y(n) = \left\lbrace \begin{array}{ l l } \{ ans_rule(40) \} & n \geq 0 \\
# \{ ans_rule(40) \} & n< 0 \end{array} \right. \]
##############################
# Answer evaluation1
$showPartialCorrectAnswers = 1;
ANS( Formula($ans_causal)->cmp(diagnostics=>1) );
ANS( Formula($ans_noncausal)->cmp() );
ANS( Interval($ROC)->cmp);
ENDDOCUMENT();
Hi Joel,
In the future, I would suggest posting questions to the WeBWorK Problems forum:
http://webwork.maa.org/moodle/mod/forum/view.php?f=3
I think Davide Cervone posted the following "trick" to the forum a while back. In order to evaluate formulas at integers, set the limits to be integers and the resolution (=step size) to be 1.
You could also increase the number of test points, e.g., see "Tolerances and Limits" on
http://webwork.maa.org/pod/pg_TRUNK/doc/MathObjects/MathObjectsAnswerCheckers.html
You could also look at the wiki for help with your original approach:
http://webwork.maa.org/wiki/FormulaTestPoints
Best regards,
Paul Pearson
Thanks - I tried the
Context()->variables->add(n => ['Real', limits=>[1,20], resolution=>1]);
but since the two parts of the sequence require different limits I didn't see how to use it. I checked on the positive part and it worked but the then the part for negative n failed. The problem cold be cured by setting the test points for the two functions for the two parts but for some reason they aren't getting set - or they are getting reset of negated. The diagnostic shows test points of both postive and negative values and non- integer. Any idea why setting the test points is not working?
Hi Joel,
It looks like z is not necessary for the problem, so you may be able to omit it (which generally improves answer checker reliability and performance). What I had in mind was something like this code
## begin code
Context("Numeric");
Context()->variables->are(
n=>'Real',
z=>"Real"
);
Context()->variables->add(n => ['Real', limits=>[-5,5], resolution=>1]);
Context()->flags->set(num_points => 15);
## end code
which should select a variety of positive and negative values for n.
Here's the code in action:
#########################################
# DESCRIPTION
# Problem from 'Digital Signal Processing", Proakis and Manolakis, 4t ed.
# WeBWorK problem written by Joel Trussell, <hjt@ncsu.edu>
# ENDDESCRIPTION
## DBsubject(Electrical Engineering)
## DBchapter(Laplace Transforms)
## DBsection(Problems)
## Institution(North Carolina State University)
## Author(H. J. Trussell)
## TitleText1('Digital Signal Processing')
## AuthorText1('Proakis and Manolakis')
## EditionText1('4')
## Problem1('3.3)
##############################
# Initialization
DOCUMENT();
loadMacros(
"PGstandard.pl",
"MathObjects.pl",
"AnswerFormatHelp.pl",
"PGunion.pl",
"answerHints.pl",
"parserAssignment.pl",
"contextInequalities.pl",
"parserFunction.pl",
"PGcourse.pl"
);
TEXT(beginproblem());
# convolve 2-sided sequence with causal sequence
Context("Numeric");
Context()->variables->are(
n=>'Real',
z=>"Real"
);
Context()->variables->add(n => ['Real', limits=>[-5,5], resolution=>1]);
Context()->flags->set(num_points => 15);
Context()->functions->add(
step => {
class => 'Parser::Legacy::Numeric',
perl => 'Parser::Legacy::Numeric::do_step'
},
);
parserFunction("u(t)" => "step(t)");
Context()->flags->set(
tolerance => 0.001,
tolType => "absolute",
);
# causal part
$d1 = random(2,9,1); # denominator
do {$n1 = random(1,6,1);} until ($n1 < $d1); # numerator
# fraction for non-causal part
$d2 = random(2,9,1); # denominator
do {$n2 = random(1,6,1);} until ($n2 < $d2); # numerator
# fraction for causal system function
do {$d3 = random(2,9,1); } until ($d3 != $d1); # denominator
do {$n3 = random(1,6,1);} until ($n3 < $d3); # numerator
# check answer of text
#$d1 = 3; $n1 = 1;$d2 = 2; $n2 = 1; $d3 = 2;$n3 = 1;
# compute partial fraction expansion for two parts - the systems x causal part
# system x non-causal part
# then add and take inverse z-transform
$p1 = $n1/$d1;
$p2 = $n2/$d2;
$p3 = $n3/$d3;
# ROC computation
$R1 = $p1;
$R2 = 1/$p2;
$R3 = $p3;
# causal part
# A/(1-a1*z^(-1)) + B/(1-a3*z^(-1))
$D = $p1 - 1/$p2;
$A = $D*(1/$p1)/((1-$p3/$p1)*(1-1/($p1*$p2)));
$B = $D*(1/$p3)/((1-$p1/$p3)*(1-1/($p3*$p2)));
# non-causal part
# C/(1-a2*z^(-1))
$C = $D*$p2/((1-$p1*$p2)*(1-$p3*$p2));
$ans_causal = Formula("$A*($p1)**n + $B*($p3)**n ")->reduce;
$ans_noncausal = Formula("-$C*($p2)**(-n) ")->reduce; # note minus sign
$ans_causal->{test_points} = [[0,0],[1,0],[2,0],[3,0],[4,0]];
$ans_noncausal->{test_points} = [[-1,0],[-2,0],[-3,0],[-4,0]];
$ROC1 = max($p1,$p3);
$ROC2 = 1/$p2;
$ROC = Compute("($ROC1,$ROC2)");
#############################
# Main text1
Context()->texStrings;
BEGIN_TEXT
This problem is related to Problem 3.7 (page 215) in the text.
$PAR
Consider the signal given by
\[ xno = \left\lbrace \begin{array}{ l l } ( \frac{$n1}{$d1})^n & n \geq 0 \\
( \frac{$n2}{$d2})^{-n} & n< 0 \end{array} \right. \]
and the impulse response
\[ hno = \left\lbrace \begin{array}{ l l } ( \frac{$n3}{$d3})^n & n \geq 0 \\
0& n< 0 \end{array} \right. \]
$PAR
Compute the convolution of the signal with the impulse response, \( yno = xno*hno \). $BR
For \( n \geq 0, yno = \) \{ ans_rule(40) \} \{ AnswerFormatHelp("formulas") \}
$BR
For \( n < 0, yno = \) \{ ans_rule(40) \} \{ AnswerFormatHelp("formulas") \}
$PAR Determine its region of convergence (ROC). Write the ROC as an interval.
$BR
ROC = \{ ans_rule(20) \}
\{ AnswerFormatHelp("intervals") \}
END_TEXT
Context()->normalStrings;
# save this for future possible use for format
# \[ yno = \left\lbrace \begin{array}{ l l } \{ ans_rule(40) \} & n \geq 0 \\
# \{ ans_rule(40) \} & n< 0 \end{array} \right. \]
##############################
# Answer evaluation1
$showPartialCorrectAnswers = 1;
ANS( Formula($ans_causal)->cmp(diagnostics=>1) );
ANS( Formula($ans_noncausal)->cmp() );
ANS( Interval($ROC)->cmp);
ENDDOCUMENT();
It is also possible to use two separate contexts (one for each formula) with their limits set differently. For example:
Context("Numeric"); Context()->variables->add(n => ['Real', limits=>[0,10], resolution=>1]); $ans_causal = Formula("$A*($p1)**n + $B*($p3)**n ")->reduce; Context("Numeric"); Context()->variables->add(n => ['Real', limits=>[-10,0], resolution=>1]); $ans_noncausal = Formula("-$C*($p2)**(-n) ")->reduce;Here, the second
Context("Numeric")
gets you a fresh copy of the Numeric context, without the previous changes. Since MathObjects retain the context in which they were created, both have the proper limits.
Alternatively, you can set limits on the formulas rather than explicit test points. For example:
$f = Compute("x+1")->with(limits => [0,10], resolution => 1); $g = Compute("x-1")->with(limits => [-10,0], resolution => 1);
The problem is in your
ANS()
calls, where you call the Formula()
and Interval()
functions unnecessarily. Note that $ans_causal
and $ans_noncausal
are already Formula objects, so there is no need to coerce them to be Formulas. Similarly, $ROC
is already an Interval (from the Compute()
call that created it), so there is no need to coerce it, either.
When you call one of the creator functions (like Formula()
or Interval
), MathObjects creates a new instance of the object from scratch, and in that process, properties like test_points
are lost. So your $ans_causal
variable has the correct test points, but Formula($ans_causal)
does not.
You should just use
ANS($ans_causal->cmp(diagnostics=>1)); ANS($ans_noncausal->cmp); ANS($ROC->cmp);if you want to keep the original formulas and intervals with the properties that you have set for them.
Thanks - I suspected something like that was happening. I found that removing the Formula(.) call worked to give the correct test points, but I didn't know why. The problem worked until somebody submitted a slightly modified answer and then we had to look at it.
Thanks for the prompt answer!!
Boy - knowing when to use various commands is an art form I haven't mastered.