PREP 2014 Question Authoring - Archived

setting test points

setting test points

by Joel Trussell -
Number of replies: 6
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();
In reply to Joel Trussell

Re: setting test points

by Paul Pearson -
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.

Context()->variables->add(n => ['Real', limits=>[1,20], resolution=>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
In reply to Paul Pearson

Re: setting test points

by Joel Trussell -
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? 
In reply to Joel Trussell

Re: setting test points

by Paul Pearson -
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();

In reply to Paul Pearson

Re: setting test points

by Davide Cervone -
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);
In reply to Joel Trussell

Re: setting test points

by Davide Cervone -
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.
In reply to Davide Cervone

Re: setting test points

by Joel Trussell -
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.