I have an interesting (to me anyway) problem. I am working on OpenServo.org for V4 and I am trying to determine the length of an arc of travel and its direction.
I have a magnetic encoder that returns the position of the shaft from 0 to 4095.
The servo has two logical end points, call them MAX and MIN which are set in software and can be changed at any time, and the shaft must rotate (i.e. travel) on one arc between the MAX and MIN positions. For example in the picture the blue arc is valid but the red is not for all travel between and including MIN and MAX.
I am trying to work out a simple algorithm using only integer math that can tell me the distance between any two points A and B that can be anywhere on the circumference, bounded by MIN and MAX and with either A as the current place and B is the target position, or B is the current place and A is the target (which is denoted by a negative distance from B to A). Note the side I allowed to travel is known, it is either "red" or "blue".
The issue is when the 4095/0 exists in the ARC, then the calculations get a bit interesting.
You need to adjust all your coordinates so they're on the same side of your limit points. Since it's a circular system you can add 4096 without affecting the absolute position.
lowest = min(MIN, MAX);
if (A < lowest)
A += 4096;
if (B < lowest)
B += 4096;
distance = B - A; /* or abs(B - A) */
In your example A would not be adjusted but B would be adjusted to 5156. The difference would be a positive 1116.
In your second example with A=3000 and B=2500, they're both above 2000 so neither would need adjustment. The difference is -500.
Here's a simple algorithm:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
int rotate_diff(int a, int b, bool * clockwise);
int main(void) {
int degrees_rotated, a, b;
bool clockwise;
a = 4040;
b = 1060;
degrees_rotated = rotate_diff(a, b, &clockwise);
printf("A = %d, B = %d, rotation = %d degrees, direction = %s\n",
a, b, degrees_rotated,
(clockwise ? "clockwise" : "counter-clockwise"));
return EXIT_SUCCESS;
}
int rotate_diff(int a, int b, bool * clockwise) {
static const int min = 2000;
if ( a <= min ) {
a += 4096;
}
if ( b <= min ) {
b += 4096;
}
int degrees_rotated = b - a;
if ( degrees_rotated > 0 ) {
*clockwise = false;
} else {
degrees_rotated = -degrees_rotated;
*clockwise = true;
}
return degrees_rotated * 360 / 4096;
}
Note that this gives you the degrees traveled, but not the distance traveled, since you don't tell us what dimensions of the shaft are. To get the distance traveled, obviously multiply the circumference by the degrees traveled divided by 360. If your points 0 through 4095 are some kind of known units, then just skip the conversion to degrees in the above algorithm, and change the variable names accordingly.
Unless I missed something, this should give the result you need:
if MIN < A,B < MAX
distance = A - B
else
if A > MAX and B < MIN
distance = A - (B + 4096)
else if B > MAX and A < MIN
distance = (A + 4096) - B
else
distance = A - B
(get the absolute value of the distance if you don't need the direction)
Related
I have to create a program that generates 3 random rectangles and finds the area of each using the coordinates of the upper left point and the bottom right point (coordinates are random and between (-50;50).
The problem is that it must determine the largest rectangle and indicate whether the other two/one are/is located in it, if not - display the corresponding message.
It's not a overlap, other rectangles/rectangle must be fully in the biggest one.
Here is what I've already done:
#include <stdio.h>
#include <locale>
struct Point {
int x;
int y;
};
struct Rectangle {
struct Point topLeft;
struct Point botRight;
};
int Area(struct Rectangle r) {
int length, breadth;
length = r.botRight.x - r.topLeft.x;
breadth = r.topLeft.y - r.botRight.y;
return length * breadth;
}
int main() {
srand(time(NULL));
struct Rectangle r1, r2, r3;
r1.topLeft.x = -50 + rand() % 50;
r1.topLeft.y = -50 + rand() % 50;
r1.botRight.x = -50 + rand() % 50;
r1.botRight.y = -50 + rand() % 50;
while (r1.botRight.x <= r1.topLeft.x) {
r1.botRight.x = -50 + rand() % 50;
}
while (r1.topLeft.y <= r1.botRight.y) {
r1.topLeft.y = -50 + rand() % 50;
}
printf("\t----------RECTANGLE 1----------\n");
printf("\tTop left point is x = %d y = %d\n", r1.topLeft.x, r1.topLeft.y);
printf("\tBottom right point is x = %d y = %d\n", r1.botRight.x, r1.botRight.y);
printf("\tArea is %d\n", Area(r1));
r2.topLeft.x = -50 + rand() % 50;
r2.topLeft.y = -50 + rand() % 50;
r2.botRight.x = -50 + rand() % 50;
r2.botRight.y = -50 + rand() % 50;
while (r2.botRight.x <= r2.topLeft.x) {
r2.botRight.x = -50 + rand() % 50;
}
while (r2.topLeft.y <= r2.botRight.y) {
r2.topLeft.y = -50 + rand() % 50;
}
printf("\t----------RECTANGLE 2----------\n");
printf("\tTop left point is x = %d y = %d\n", r2.topLeft.x, r2.topLeft.y);
printf("\tBottom right point is x = %d y = %d\n", r2.botRight.x, r2.botRight.y);
printf("\tArea is %d\n", Area(r2));
r3.topLeft.x = -50 + rand() % 50;
r3.topLeft.y = -50 + rand() % 50;
r3.botRight.x = -50 + rand() % 50;
r3.botRight.y = -50 + rand() % 50;
while (r3.botRight.x <= r3.topLeft.x) {
r3.botRight.x = -50 + rand() % 50;
}
while (r3.topLeft.y <= r3.botRight.y) {
r3.topLeft.y = -50 + rand() % 50;
}
printf("\t----------RECTANGLE 3----------\n");
printf("\tTop left point is x = %d y = %d\n", r3.topLeft.x, r3.topLeft.y);
printf("\tBottom right point is x = %d y = %d\n", r3.botRight.x, r3.botRight.y);
printf("\tArea is %d\n\n", Area(r3));
if (Area(r1) >= Area(r2) && Area(r1) >= Area(r3))
printf("\tRECTANGLE 1 HAS A BIGGEST AREA --> %d\n", Area(r1));
if (Area(r2) >= Area(r1) && Area(r2) >= Area(r3))
printf("\tRECTANGLE 2 HAS A BIGGEST AREA --> %d\n", Area(r2));
if (Area(r3) >= Area(r1) && Area(r3) >= Area(r2))
printf("\tRECTANGLE 3 HAS A BIGGEST AREA --> %d\n", Area(r3));
}
Item 1:
There really is no need to use a point struct. The problem is simple enough to merely keep track to 2 values for x and 2 values for y. While we're at it, the area of each rectangle could be stored, too.
typedef struct {
int x0, x1, y0, y1, area;
} Rect;
Notice that there is no bias in the names x0 and x1. Attempting to control which coordinate pair is "top left" and which is "bottom right" is difficult. A rectangle has two horizonal edges (importantly they are not equal). Merely store the lower and higher values of y. Similarly, store only the "left & right" values of the vertical edges x... This makes life simple.
Item 2:
It's worthwhile, if possible, to think and to code without immediate concern for negative numbers.
const int wid = 101; // for -50 to +50
const int hgt = 101; // for -50 to +50
Item 3:
Generating 3 sets of values by copy/paste of code indicates that this should be done in a function called 3 times. (Imagine the next assignment is "do the same for 20 rectangles.")
Below includes two bonus "branchless" functions that return the minimum or maximum of two integer values.
int min( int x, int y ) { return y ^ ((x^y) & -(x<y)); }
int max( int x, int y ) { return y ^ ((x^y) & -(x>y)); }
void genRect( Rect *r ) {
int v0 = rand() % wid; // A random horizontal value (a vertical line)
int v1 = ( v0 + 1 + rand()%(wid-3) ) % wid; // A different horizontal value
r->x0 = min( v0, v1 ); // the lower of the two values
r->x1 = max( v0, v1 ); // and the higher
// do the same for horizontal edges (vertical boundaries)
v0 = rand() % hgt;
v1 = ( r->y0 + 1 + rand()%(hgt-3) ) % hgt;
r->y0 = min( v0, v1 );
r->y1 = max( v0, v1 );
// calc and store the area, too
r->area = (r->x1 - r->x0) * (r->y1 - r->y0);
}
Important to note is that the calculation of the second value for x and for y will never be the same as the first value. The OP code had the potential to generate a "left edge" at the right boundary, then enter an endless loop trying to generate a value that was always rejected.
As suggested in the other answer, it is now easy to qsort() the small array (big rectangles may contain smaller ones).
The search for one inside another is much simpler with comparing x0 against x0 and x1 against x1... (Likewise for the y dimension).
Because the code has been dealing with (0,0) to (100,100) inclusive, the output is where to tailor to suit the assignment.
void print( int n, Rect *r ) {
printf( "Rect %d: BotLft(%d,%d) TopRgt(%d, %d) Area %d\n",
n, r->x0 - 50, r->y0 - 50, r->x1 - 50, r->y1 - 50, r->area );
}
I leave it as an exercise for the reader to eliminate the arbitrary constants above.
Finally, it is a trivial exercise to determine if the xy boundaries of one smaller rectangle fall completely within the xy boundaries of a larger one. A single if() statement with 4 conditions would suffice.
PS: I completed the code and ran it a few times. It was only by increasing the number of candidate rectangles that luck would have it that a larger did contain a smaller. The sample size of only 3 rectangles will take a lot of iterations to, by chance, define one inside another...
First, you need an array of Rectangles and sort them by their area:
struct Rectangle rects[N];
//return:
//- negative value, if a < b
//- zero, if a == b
//- positive value, if a > b
int rect_cmp(const void *a, const void *b)
{
return Area(*((struct Rectangle*)a)) - Area(*((struct Rectangle*)b));
}
//use qsort: https://en.cppreference.com/w/c/algorithm/qsort
qsort(rects, N, sizeof(struct Rectangle), rect_cmp);
The array rects will now contain all the rectangles, sorted in ascending order, from lowest to highest area.
From now on, all you have to do is to iterate over the array and test if the largest rectangle encloses the following, subsequent rectangles.
The following code picks the largest rectangle and iterates over all subsequent rectangles to test if they are inside. Then pick the second largest and do the testing again, and so on, e.g.
for (int i=N-1; i >= 0; --i) { //current largest rectangle
for (int j=i-1; j >= 0; --j) { //test if the next rectangles in sequence are inside
if (contains(rects[i], rects[j])) {
//rect[j] inside rect[i]
} else {
//rect[j] not inside rect[i]
}
}
}
A possible outcome could be that the first rect neither contains the second and third rect but the second rect could contain the third one.
I am trying to slowly decelerate based on a percentage.
Basically: if percentage is 0 the speed should be speed_max, if the percentage hits 85 the speed should be speed_min, continuing with speed_min until the percentage hits 100%. At percentages between 0% and 85%, the speed should be calculated with the percentage.
I started writing the code already, though I am not sure how to continue:
// Target
int degrees = 90;
// Making sure we're at 0
resetGyro(0);
int speed_max = 450;
int speed_min = 150;
float currentDeg = 0;
float percentage = 0;
while(percentage < 100)
{
//??
getGyroDeg(¤tDeg);
percentage = (degrees/100)*currentDeg;
}
killMotors(1);
Someone in the comments asked why I am doing this.
Unfortunately, I am working with very limited hardware and a pretty bad gyroscope, all while trying to guarantee +- 1 degree precision.
To do this, I am starting at speed_max, slowly decreasing to speed_min (this is to have better control over the motors) when nearing the target value (90).
Why does it stop decelerating at 85%? This is to really be precise and hit the target value successfully.
Assuming speed is linearly calculated based on percentages from 0 to 85 (and stays at speed_min with percentage is gt 85), then this is your formula for calculating speed:
if (percentage >= 85)
{
speed = speed_min;
}
else
{
speed = speed_max - (((speed_max - speed_min)*percentage)/85);
}
Linear interpolation is fairly straight forward.
At percentage 0, the speed should be speed_max.
At percentage 85, the speed should be speed_min.
At percentage values greater than 85, the speed should still be speed_min.
Between 0 and 85, the speed should be linearly interpolated between speed_max and speed_min, so percentage is a 'amount of drop from maximum speed'.
Assuming percentage is of type float:
float speed_from_percentage(float percent)
{
if (percent <= 0.0)
return speed_max;
if (percent >= 85.0)
return speed_min;
return speed_min + (speed_max - speed_min) * (85.0 - percentage) / 85.0;
}
You can also replace the final return with the equivalent:
return speed_max - (speed_max - speed_min) * percentage / 85.0;
If you're truly pedantic, all the constants should be suffixed with F to indicate float and hence use float arithmetic instead of double arithmetic. And hence you should probably also use float for speed_min and speed_max. If everything is meant to be integer arithmetic, you can change float to int and drop the .0 from the expressions.
Assuming getGyroDeg is input from the controller, what you are describing is a proportional control. A constant response curve, ie, 0 to 85 has an output of 450 to 150, and 150 after that, is an ad-hoc approach, based on experience. However, a properly initialised PID controller generally attains a faster time to set-point and greater stability.
#include <stdio.h>
#include <time.h>
#include <assert.h>
#include <stdlib.h>
static float sim_current = 0.0f;
static float sim_dt = 0.01f;
static float sim_speed = 0.0f /* 150.0f */;
static void getGyroDeg(float *const current) {
assert(current);
sim_current += sim_speed * sim_dt;
/* Simulate measurement error. */
*current = sim_current + 3.0 * ((2.0 * rand() / RAND_MAX) - 1.0);
}
static void setGyroSpeed(const float speed) {
assert(speed >= /*150.0f*/-450.0f && speed <= 450.0f);
sim_speed = speed;
}
int main(void) {
/* https://en.wikipedia.org/wiki/PID_controller
u(t) = K_p e(t) + K_i \int_0^t e(\theta)d\theta + K_d de(t)/dt */
const float setpoint = 90.0f;
const float max = 450.0f;
const float min = -450.0f/* 150.0f */;
/* Random value; actually get this number. */
const float dt = 1.0f;
/* Tune these. */
const float kp = 30.0f, ki = 4.0f, kd = 2.0f;
float current, last = 0.0f, integral = 0.0f;
float t = 0.0f;
float e, p, i, d, pid;
size_t count;
for(count = 0; count < 40; count++) {
getGyroDeg(¤t);
e = setpoint - current;
p = kp * e;
i = ki * integral * dt;
d = kd * (e - last) / dt;
last = e;
pid = p + i + d;
if(pid > max) {
pid = max;
} else if(pid < min) {
pid = min;
} else {
integral += e;
}
setGyroSpeed(pid);
printf("%f\t%f\t%f\n", t, sim_current, pid);
t += dt;
}
return EXIT_SUCCESS;
}
Here, instead of the speed linearly decreasing, it calculates the speed in a control loop. However, if the minimum is 150, then it's not going to achieve greater stability; if you go over 90, then you have no way of getting back.
If the controls are [-450, 450], it goes through zero and it is much nicer; I think this might be what you are looking for. It actively corrects for errors.
Here is some pseudocode. I understand how to do everything except Im unsure of what the condition should be to check if the randomly generated coordinate is within the circle.
For example with circle of radius 1,
(-1, 1) would not fall in the circle, (-1, 0.5) would though.
numDartsInCircle = 0
repeat 1000 times
throw a dart (generate (x,y), where -1 ≤ x ≤ 1, -1 ≤ y ≤ 1)
if dart is in circle
numDartsInCircle++
fractionOfDartsInCircle = numDartsInCircle / 1000
pi ≅ fractionOfDartsInCircle * 4
The formula for the distance from the origin (0,0) to a point (x,y) is sqrt(x*x + y*y). If the distance is less than the radius of the circle, which in this case is 1, then the point lies within the circle. If the distance is equal to or more than the radius then the point does not lie within the circle.
Best of luck.
What exactly was hard about this?
I took your pseudo-code and made C code almost line-for-line.
(you may notice that I don't actually have any if statements in the code)
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int numDartsInCircle = 0;
int throws = 1000;
int trial;
double pi;
for( trial=0; trial<throws; ++trial )
{
double x = 2*((double)rand() / RAND_MAX) - 1;
double y = 2*((double)rand() / RAND_MAX) - 1;
numDartsInCircle += ( x*x + y*y <= 1.0 );
}
pi = 4* (double)numDartsInCircle / throws;
return !printf("Pi is approximately %f\n", pi);
}
I have a problem that, after much head scratching, I think is to do with very small numbers in a long-double.
I am trying to implement Planck's law equation to generate a normalised blackbody curve at 1nm intervals between a given wavelength range and for a given temperature. Ultimately this will be a function accepting inputs, for now it is main() with the variables fixed and outputting by printf().
I see examples in matlab and python, and they are implementing the same equation as me in a similar loop with no trouble at all.
This is the equation:
My code generates an incorrect blackbody curve:
I have tested key parts of the code independently. After trying to test the equation by breaking it into blocks in excel I noticed that it does result in very small numbers and I wonder if my implementation of large numbers could be causing the issue? Does anyone have any insight into using C to implement equations? This a new area to me and I have found the maths much harder to implement and debug than normal code.
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
//global variables
const double H = 6.626070040e-34; //Planck's constant (Joule-seconds)
const double C = 299800000; //Speed of light in vacume (meters per second)
const double K = 1.3806488e-23; //Boltzmann's constant (Joules per Kelvin)
const double nm_to_m = 1e-6; //conversion between nm and m
const int interval = 1; //wavelength interval to caculate at (nm)
//typedef structure to hold results
typedef struct {
int *wavelength;
long double *radiance;
long double *normalised;
} results;
int main() {
int min = 100 , max = 3000; //wavelength bounds to caculate between, later to be swaped to function inputs
double temprature = 200; //temprature in kelvin, later to be swaped to function input
double new_valu, old_valu = 0;
static results SPD_data, *SPD; //setup a static results structure and a pointer to point to it
SPD = &SPD_data;
SPD->wavelength = malloc(sizeof(int) * (max - min)); //allocate memory based on wavelength bounds
SPD->radiance = malloc(sizeof(long double) * (max - min));
SPD->normalised = malloc(sizeof(long double) * (max - min));
for (int i = 0; i <= (max - min); i++) {
//Fill wavelength vector
SPD->wavelength[i] = min + (interval * i);
//Computes radiance for every wavelength of blackbody of given temprature
SPD->radiance[i] = ((2 * H * pow(C, 2)) / (pow((SPD->wavelength[i] / nm_to_m), 5))) * (1 / (exp((H * C) / ((SPD->wavelength[i] / nm_to_m) * K * temprature))-1));
//Copy SPD->radiance to SPD->normalised
SPD->normalised[i] = SPD->radiance[i];
//Find largest value
if (i <= 0) {
old_valu = SPD->normalised[0];
} else if (i > 0){
new_valu = SPD->normalised[i];
if (new_valu > old_valu) {
old_valu = new_valu;
}
}
}
//for debug perposes
printf("wavelength(nm) radiance(Watts per steradian per meter squared) normalised radiance\n");
for (int i = 0; i <= (max - min); i++) {
//Normalise SPD
SPD->normalised[i] = SPD->normalised[i] / old_valu;
//for debug perposes
printf("%d %Le %Lf\n", SPD->wavelength[i], SPD->radiance[i], SPD->normalised[i]);
}
return 0; //later to be swaped to 'return SPD';
}
/*********************UPDATE Friday 24th Mar 2017 23:42*************************/
Thank you for the suggestions so far, lots of useful pointers especially understanding the way numbers are stored in C (IEEE 754) but I don't think that is the issue here as it only applies to significant digits. I implemented most of the suggestions but still no progress on the problem. I suspect Alexander in the comments is probably right, changing the units and order of operations is likely what I need to do to make the equation work like the matlab or python examples, but my knowledge of maths is not good enough to do this. I broke the equation down into chunks to take a closer look at what it was doing.
//global variables
const double H = 6.6260700e-34; //Planck's constant (Joule-seconds) 6.626070040e-34
const double C = 299792458; //Speed of light in vacume (meters per second)
const double K = 1.3806488e-23; //Boltzmann's constant (Joules per Kelvin) 1.3806488e-23
const double nm_to_m = 1e-9; //conversion between nm and m
const int interval = 1; //wavelength interval to caculate at (nm)
const int min = 100, max = 3000; //max and min wavelengths to caculate between (nm)
const double temprature = 200; //temprature (K)
//typedef structure to hold results
typedef struct {
int *wavelength;
long double *radiance;
long double *normalised;
} results;
//main program
int main()
{
//setup a static results structure and a pointer to point to it
static results SPD_data, *SPD;
SPD = &SPD_data;
//allocate memory based on wavelength bounds
SPD->wavelength = malloc(sizeof(int) * (max - min));
SPD->radiance = malloc(sizeof(long double) * (max - min));
SPD->normalised = malloc(sizeof(long double) * (max - min));
//break equasion into visible parts for debuging
long double aa, bb, cc, dd, ee, ff, gg, hh, ii, jj, kk, ll, mm, nn, oo;
for (int i = 0; i < (max - min); i++) {
//Computes radiance at every wavelength interval for blackbody of given temprature
SPD->wavelength[i] = min + (interval * i);
aa = 2 * H;
bb = pow(C, 2);
cc = aa * bb;
dd = pow((SPD->wavelength[i] / nm_to_m), 5);
ee = cc / dd;
ff = 1;
gg = H * C;
hh = SPD->wavelength[i] / nm_to_m;
ii = K * temprature;
jj = hh * ii;
kk = gg / jj;
ll = exp(kk);
mm = ll - 1;
nn = ff / mm;
oo = ee * nn;
SPD->radiance[i] = oo;
}
//for debug perposes
printf("wavelength(nm) | radiance(Watts per steradian per meter squared)\n");
for (int i = 0; i < (max - min); i++) {
printf("%d %Le\n", SPD->wavelength[i], SPD->radiance[i]);
}
return 0;
}
Equation variable values during runtime in xcode:
I notice a couple of things that are wrong and/or suspicious about the current state of your program:
You have defined nm_to_m as 10-9,, yet you divide by it. If your wavelength is measured in nanometers, you should multiply it by 10-9 to get it in meters. To wit, if hh is supposed to be your wavelength in meters, it is on the order of several light-hours.
The same is obviously true for dd as well.
mm, being the exponential expression minus 1, is zero, which gives you infinity in the results deriving from it. This is apparently because you don't have enough digits in a double to represent the significant part of the exponential. Instead of using exp(...) - 1 here, try using the expm1() function instead, which implements a well-defined algorithm for calculating exponentials minus 1 without cancellation errors.
Since interval is 1, it doesn't currently matter, but you can probably see that your results wouldn't match the meaning of the code if you set interval to something else.
Unless you plan to change something about this in the future, there shouldn't be a need for this program to "save" the values of all calculations. You could just print them out as you run them.
On the other hand, you don't seem to be in any danger of underflow or overflow. The largest and smallest numbers you use don't seem to be a far way from 10±60, which is well within what ordinary doubles can deal with, let alone long doubles. The being said, it might not hurt to use more normalized units, but at the magnitudes you currently display, I wouldn't worry about it.
Thanks for all the pointers in the comments. For anyone else running into a similar problem with implementing equations in C, I had a few silly errors in the code:
writing a 6 not a 9
dividing when I should be multiplying
an off by one error with the size of my array vs the iterations of for() loop
200 when I meant 2000 in the temperature variable
As a result of the last one particularly I was not getting the results I expected (my wavelength range was not right for plotting the temperature I was calculating) and this was leading me to the assumption that something was wrong in the implementation of the equation, specifically I was thinking about big/small numbers in C because I did not understand them. This was not the case.
In summary, I should have made sure I knew exactly what my equation should be outputting for given test conditions before implementing it in code. I will work on getting more comfortable with maths, particularly algebra and dimensional analysis.
Below is the working code, implemented as a function, feel free to use it for anything but obviously no warranty of any kind etc.
blackbody.c
//
// Computes radiance for every wavelength of blackbody of given temprature
//
// INPUTS: int min wavelength to begin calculation from (nm), int max wavelength to end calculation at (nm), int temperature (kelvin)
// OUTPUTS: pointer to structure containing:
// - spectral radiance (Watts per steradian per meter squared per wavelength at 1nm intervals)
// - normalised radiance
//
//include & define
#include "blackbody.h"
//global variables
const double H = 6.626070040e-34; //Planck's constant (Joule-seconds) 6.626070040e-34
const double C = 299792458; //Speed of light in vacuum (meters per second)
const double K = 1.3806488e-23; //Boltzmann's constant (Joules per Kelvin) 1.3806488e-23
const double nm_to_m = 1e-9; //conversion between nm and m
const int interval = 1; //wavelength interval to calculate at (nm), to change this line 45 also need to be changed
bbresults* blackbody(int min, int max, double temperature) {
double new_valu, old_valu = 0; //variables for normalising result
bbresults *SPD;
SPD = malloc(sizeof(bbresults));
//allocate memory based on wavelength bounds
SPD->wavelength = malloc(sizeof(int) * (max - min));
SPD->radiance = malloc(sizeof(long double) * (max - min));
SPD->normalised = malloc(sizeof(long double) * (max - min));
for (int i = 0; i < (max - min); i++) {
//Computes radiance for every wavelength of blackbody of given temperature
SPD->wavelength[i] = min + (interval * i);
SPD->radiance[i] = ((2 * H * pow(C, 2)) / (pow((SPD->wavelength[i] * nm_to_m), 5))) * (1 / (expm1((H * C) / ((SPD->wavelength[i] * nm_to_m) * K * temperature))));
//Copy SPD->radiance to SPD->normalised
SPD->normalised[i] = SPD->radiance[i];
//Find largest value
if (i <= 0) {
old_valu = SPD->normalised[0];
} else if (i > 0){
new_valu = SPD->normalised[i];
if (new_valu > old_valu) {
old_valu = new_valu;
}
}
}
for (int i = 0; i < (max - min); i++) {
//Normalise SPD
SPD->normalised[i] = SPD->normalised[i] / old_valu;
}
return SPD;
}
blackbody.h
#ifndef blackbody_h
#define blackbody_h
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
//typedef structure to hold results
typedef struct {
int *wavelength;
long double *radiance;
long double *normalised;
} bbresults;
//function declarations
bbresults* blackbody(int, int, double);
#endif /* blackbody_h */
main.c
#include <stdio.h>
#include "blackbody.h"
int main() {
bbresults *TEST;
int min = 100, max = 3000, temp = 5000;
TEST = blackbody(min, max, temp);
printf("wavelength | normalised radiance | radiance |\n");
printf(" (nm) | - | (W per meter squr per steradian) |\n");
for (int i = 0; i < (max - min); i++) {
printf("%4d %Lf %Le\n", TEST->wavelength[i], TEST->normalised[i], TEST->radiance[i]);
}
free(TEST);
free(TEST->wavelength);
free(TEST->radiance);
free(TEST->normalised);
return 0;
}
Plot of output:
I'm trying to use the Sine Table lookup method to find the tone frequency at different step size, but when I'm converting the floating point to integer and use the oscicopte to view the frequncy, it can't display any things on screen.
Does anyone know what's the solution for this issues. Any help is apperaite.
Below is the code:
// use the formula: StepSize = 360/(Fs/f) Where Fs is the Sample frequency 44.1 kHz and f is the tone frequency.
// example: StepSize = 360/(44100/440) = 3.576, since the STM32 doesn't support the floating point, therefore, we have to use the fixed-point format which multiply it by 1000 to be 3575
int StepSize = 3575;
unsigned int v=0;
signed int sine_table[91] = {
0x800,0x823,0x847,0x86b,
0x88e,0x8b2,0x8d6,0x8f9,
0x91d,0x940,0x963,0x986,
0x9a9,0x9cc,0x9ef,0xa12,
0xa34,0xa56,0xa78,0xa9a,
0xabc,0xadd,0xaff,0xb20,
0xb40,0xb61,0xb81,0xba1,
0xbc1,0xbe0,0xc00,0xc1e,
0xc3d,0xc5b,0xc79,0xc96,
0xcb3,0xcd0,0xcec,0xd08,
0xd24,0xd3f,0xd5a,0xd74,
0xd8e,0xda8,0xdc1,0xdd9,
0xdf1,0xe09,0xe20,0xe37,
0xe4d,0xe63,0xe78,0xe8d,
0xea1,0xeb5,0xec8,0xedb,
0xeed,0xeff,0xf10,0xf20,
0xf30,0xf40,0xf4e,0xf5d,
0xf6a,0xf77,0xf84,0xf90,
0xf9b,0xfa6,0xfb0,0xfba,
0xfc3,0xfcb,0xfd3,0xfda,
0xfe0,0xfe6,0xfec,0xff0,
0xff4,0xff8,0xffb,0xffd,
0xffe,0xfff,0xfff};
unsigned int sin(int x){
x = x % 360;
if(x <= 90)
return sine_table[x];
else if ( x <= 180){
return sine_table[180 - x];
}else if ( x <= 270){
return 4096 - sine_table[x - 180];
}else{
return 4096 - sine_table[360 - x];
}
}
void main(void)
{
while(1){
v+=StepSize; // Don't know why it doesn't work in this way. not display anything on screen.
DAC->DHR12R2 = sin(v/1000); // DAC channel-2 12-bit Right aligned data
if (v >= 360) v = 0;
}
}
But, if I change the StepSize = 3; it shows the frequency:
There are a few issues with your code. But I will start with the one that you asked about.
int StepSize = 3575;
unsigned int v=0;
while(1){
v+=StepSize;
DAC->DHR12R2 = sin(v/1000);
if (v >= 360) v = 0;
}
The reason why this code doesn't work is that v is always set to 0 at the end of the loop because 3575 is greater than 360. So then you always call sin(3) because 3575/1000 is 3 in integer division.
Perhaps, you should rewrite your last line as if ((v/1000) >= 360) v = 0;. Otherwise, I would rewrite your loop like this
while(1){
v+=StepSize;
v/=1000;
DAC->DHR12R2 = sin(v);
if (v >= 360) v = 0;
}
I would also recommend that you declare your lookup table a const. So it would look like
const signed int sine_table[91] = {
Last recommendation is to choose another name for your sin function so as not to confuse with the sin library function. Even though in this case there shouldn't be a problem.