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

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

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

`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 for the prompt answer!!

Boy - knowing when to use various commands is an art form I haven't mastered.