Category: Exterior Ballistics
Blog Entry © Thursday, January 1, 2026, by James Pate Williams, Jr., Win32 C/C++ Fast Battleship Class Iowa Ballistics Calculator (BB-61 Iowa, BB-62 New Jersey, BB-63 Missouri, BB-64 Wisconsin)
Blog Entry Thursday, July 24, 2025, © James Pate Williams, Jr. Comparison of Data Between Two Sources
Blog Entry © Thursday, June 5, 2025, by James Pate Williams, Jr., Analytic, Numeric, and Siacci’s Method for Solving Ballistic Trajectory Problems (Point-Mass Projectile Motion)
Blog Entry (c) Monday, June 2, 2025, Exercises from “Exterior ballistics, 1935” by James Pate Williams, Jr.
Below are some Exercises from the textbook Exterior ballistics, 1935 by former Lieutenant Commander Ernest Edward Herrman of the United States Navy Naval Academy in Annapolis, Maryland, see Chapter Four:
Density Published Density
1.183473 1.183472
1.306584 1.306582
1.202410 1.202408
0.694163 0.694162
Exercises from Exterior ballistics, 1935
By Lieutenant Commander Ernest Edward Herrmann
Exercise 1 Page 41
Book Mine
0.157100 0.157563
0.492680 0.492810
0.517340 0.517829
0.675240 0.675580
0.844370 0.844597
1.018110 1.018197
1.014010 1.014027
1.094820 1.094910
Percentage Differences Exercise 1 Page 41
Percentage Difference [1] = 0.294283%
Percentage Difference [2] = 0.026383%
Percentage Difference [3] = 0.094477%
Percentage Difference [4] = 0.050340%
Percentage Difference [5] = 0.026880%
Percentage Difference [6] = 0.008545%
Percentage Difference [7] = 0.001676%
Percentage Difference [8] = 0.008220%
Three Altitude Related Density Calculations
Rho1 is from Exterior ballistics, 1935
Rho2 is from NASA
Rho3 is from Wikipedia
h ft Rho1 SI Rho2 SI Rho3
0 1.000000 1.226614 1.208993
1000 0.968902 1.215727 1.174010
2000 0.938772 1.204914 1.139806
3000 0.909578 1.194175 1.106369
4000 0.881292 1.183510 1.073689
5000 0.853886 1.172917 1.041752
6000 0.827332 1.162397 1.010547
7000 0.801604 1.151949 0.980062
8000 0.776676 1.141574 0.950286
Three Altitude Related Ballistic Density Calculations
Rho1 is from Exterior ballistics, 1935
Rho2 is from NASA
Rho3 is from Wikipedia
STP = Temperature = 59 F Pressure = 29.53 Humidity = 78%
Temp Press h ft Rho1 SI Rho2 SI Rho3
65 29.60 1000 0.968902 1.203134 1.161848
85 29.75 18000 0.566291 0.992154 0.656245
57 30.25 8000 0.776676 1.174418 0.977626
69 29.80 13000 0.663193 1.077573 0.801819
32 30.15 15000 0.622587 1.157366 0.822138
Exercise 3 Problems 1 - 4 m below means mine
Ra Ram are the Mayevski Retardations
Rf Rfm are the forces of Air Resistence
V Vm are the Applicable Velocities
Ra Ram Rf Rfm V Vm
567.20 567.22 229.28 229.19 2626 2626
323.85 323.86 503.50 503.29 3114 3114
91.58 91.58 2477.50 2476.50 2862 2862
62.02 62.02 4049.40 4047.83 2584 2584
Exercise 4 - Problems 1 to 5
Ra Ram BC Density
293.82 306.84 3.110358 0.989712
160.92 185.47 4.737834 1.009200
119.06 123.90 6.991926 0.952504
73.58 84.81 10.328256 0.987977
60.52 69.59 12.442559 1.080786
Exercise 5 - Problems 1 to 4
Ra Gv i-book i-mine
511.76 803.10 1.001500 0.959553
334.04 1071.14 0.602720 0.578983
90.62 922.06 0.601870 0.577421
57.30 799.71 0.616870 0.593688
Test Case from Exterior ballistics, 1935
Temperature 84 F Pressure 29.90 In Hg
Density SI = 0.959428 Book Density = 0.960
Altitude 18,000 Feet
Density SI = 0.999439 Book Density = 0.991
The differences above are probably due to the fact that Lieutenant Commander Herrmann used logarithms and logarithm tables and perhaps a slide-rule. I use double precision C/C++ real numbers.
Blog Entry © Saturday, May 31, 2025, Air Density and Ballistic Density Computations by James Pate Williams, Jr.
Online references: https://www.grc.nasa.gov/WWW/K-12/airplane/atmosmet.html and https://www.nist.gov/system/files/documents/calibrations/metv29i1p67-2.pdf
Density Published Density
1.183473 1.183472
1.306584 1.306582
1.202410 1.202408
0.694163 0.694162
Exercises from Exterior ballistics, 1935
By Lieutenant Commander Ernest Edward Herrmann
Percentage Differences Exercise 1 Page 41
Percentage Difference [1] = 0.294283%
Percentage Difference [2] = 0.026383%
Percentage Difference [3] = 0.094477%
Percentage Difference [4] = 0.050340%
Percentage Difference [5] = 0.026880%
Percentage Difference [6] = 0.008545%
Percentage Difference [7] = 0.001676%
Percentage Difference [8] = 0.008220%
Three Altitude Related Density Calculations
Rho1 is from Exterior ballistics, 1935
Rho2 is from NASA
Rho3 is from Wikipedia
h ft Rho1 SI Rho2 SI Rho3
0 1.000000 1.226614 1.208993
1000 0.968902 1.215727 1.174010
2000 0.938772 1.204914 1.139806
3000 0.909578 1.194175 1.106369
4000 0.881292 1.183510 1.073689
5000 0.853886 1.172917 1.041752
6000 0.827332 1.162397 1.010547
7000 0.801604 1.151949 0.980062
8000 0.776676 1.141574 0.950286
Three Altitude Related Ballistic Density Calculations
Rho1 is from Exterior ballistics, 1935
Rho2 is from NASA Rho3 is from Wikipedia
STP = Temperature = 59 F Pressure = 29.53 Humidity = 78%
Temp Press h ft Rho1 SI Rho2 SI Rho3
65 29.60 1000 0.968902 1.203134 1.161848
85 29.75 18000 0.566291 0.992155 0.656245
57 30.25 8000 0.776676 1.174418 0.977626
69 29.80 13000 0.663193 1.077573 0.801819
32 30.15 15000 0.622587 1.157366 0.822138
Test Case from Exterior ballistics, 1935
Temperature 84 F Pressure 29.90 In Hg
Density SI = 0.959428 Book Density = 0.960
Altitude 18,000 Feet
Density SI = 0.999439 Book Density = 0.991
Blog Entry © Friday, May 30, 2025, Ballistic Coefficient Exercises from Exterior ballistics, 1935 Written by Ernest Edward Herrmann, C/C++ Code by James Pate Williams, Jr., BA, BS, Master of Software Engineering, PhD Computer Science
#include <iomanip>
#include <iostream>
double BookAnswers[] = {
0.15710, 0.49268, 0.51734, 0.67524,
0.84437, 1.01811, 1.01401, 1.09482 };
double MyAnswers[] = {
0.157563, 0.492810, 0.517829, 0.675580,
0.844597, 1.018197, 1.014027, 1.094910 };
double PD[8];
int main()
{
std::cout << "Percentage Differences" << std::endl;
std::cout << std::fixed << std::setprecision(6);
for (int i = 0; i < 8; i++)
{
PD[i] = 100.0 * fabs(BookAnswers[i] - MyAnswers[i]) /
(0.5 * (BookAnswers[i] + MyAnswers[i]));
std::cout << "Percentage Difference [" << i + 1 << "] = ";
std::cout << PD[i] << '%' << std::endl;
}
}
Blog Entry © Wednesday, May 28, 2025, More C/C++ Siacci Method Ballistic Screenshots by James Pate Williams, Jr., BA, BS, MSWE, PhD
Blog Entry © Tuesday, May 27, 2025, Translation of a Siacci’s Method C# App to C/C++ by James Pate Williams, Jr., BA, BS, MSWE, PhD
Blog Entry © Friday, May 23, 2025, NASA Geopotential Altitude and the Variation of the Gravitational Acceleration by James Pate Williams, Jr., BA, BS, Master of Software Engineering, PhD Computer Science
More source code is available upon request.
Reference: 19770009539.pdf
Win32 C/C++ application output to a Win32 window:
H Z1 Z2 Z3 g
80000 79005.7 79005.7 79005.7 9.56735
80500 79493.3 79493.3 79493.3 9.56590
81000 79980.9 79980.9 79980.9 9.56446
81500 80468.3 80468.3 80468.3 9.56301
82000 80955.7 80955.7 80955.7 9.56156
82500 81443.0 81443.0 81443.0 9.56011
83000 81930.2 81930.2 81930.2 9.55867
83500 82417.4 82417.4 82417.4 9.55722
84000 82904.5 82904.5 82904.5 9.55577
84500 83391.5 83391.5 83391.5 9.55433
85000 83878.4 83878.4 83878.4 9.55288
85500 84365.3 84365.3 84365.3 9.55144
H Geopotential Altitude
Z1 Geopotential Gauss-Legendre 128 Steps
Z2 Geopotential Simpson's Rule 256 Steps
Z3 Geopotential Trapezoidal Rule 512 Steps
g gravitational acceleration in m/s/s
https://ntrs.nasa.gov/api/citations/19770009539/downloads/19770009539.pdf
See Table 8. Page 9
// NASAGeopotentialAltitude.cpp : Defines the entry point for the application.
// Copyright (c) Friday, May 23, 2025 by James Pate Williams, Jr.
// BA, BS, MSWE, PhD All Applicable Rights Reserved
#include "stdafx.h"
#include "GeopotentialAltitude.h"
#include "Integration1d.h"
#include "NASAGeopotentialAltitude.h"
#include <math.h>
#include <stdio.h>
#include <tchar.h>
#include <string.h>
#include <vector>
using namespace std;
#define MAX_LOADSTRING 100
// Global Variables:
HINSTANCE hInst; // current instance
TCHAR szTitle[MAX_LOADSTRING]; // The title bar text
TCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name
// Forward declarations of functions included in this code module:
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
int APIENTRY _tWinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
// TODO: Place code here.
MSG msg;
HACCEL hAccelTable;
// Initialize global strings
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadString(hInstance, IDC_NASAGEOPOTENTIALALTITUDE, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
// Perform application initialization:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_NASAGEOPOTENTIALALTITUDE));
// Main message loop:
while (GetMessage(&msg, NULL, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int) msg.wParam;
}
//
// FUNCTION: MyRegisterClass()
//
// PURPOSE: Registers the window class.
//
// COMMENTS:
//
// This function and its usage are only necessary if you want this code
// to be compatible with Win32 systems prior to the 'RegisterClassEx'
// function that was added to Windows 95. It is important to call this function
// so that the application will get 'well formed' small icons associated
// with it.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_NASAGEOPOTENTIALALTITUDE));
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = MAKEINTRESOURCE(IDC_NASAGEOPOTENTIALALTITUDE);
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
return RegisterClassEx(&wcex);
}
//
// FUNCTION: InitInstance(HINSTANCE, int)
//
// PURPOSE: Saves instance handle and creates main window
//
// COMMENTS:
//
// In this function, we save the instance handle in a global variable and
// create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
HWND hWnd;
hInst = hInstance; // Store instance handle in our global variable
hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
if (!hWnd)
{
return FALSE;
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
//
// FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
//
// PURPOSE: Processes messages for the main window.
//
// WM_CREATE - creates a multiple line edit control
// WM_COMMAND - process the application menu
// WM_PAINT - Paint the main window
// WM_DESTROY - post a quit message and return
//
//
#define ID_EDITCHILD 100
char asciiData[16384];
char asciiLine[16384];
TCHAR textData[16384];
void ConvertCharToTChar(const char* charArray, TCHAR* tcharArray, size_t tcharSize) {
#ifdef _UNICODE
MultiByteToWideChar(CP_ACP, 0, charArray, -1, tcharArray, (int)tcharSize);
#else
strncpy(tcharArray, charArray, tcharSize - 1);
tcharArray[tcharSize - 1] = '\0'; // Ensure null-termination
#endif
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
static HWND hwndEdit;
static double zArray[] = {
80000, 80500, 81000, 81500, 82000, 82500,
83000, 83500, 84000, 84500, 85000, 85500 };
static vector<double> z(12);
static vector<double> potential1(12);
static vector<double> potential2(12);
static vector<double> potential3(12);
static vector<double> potential4(12);
size_t numberPoints = z.size();
for (size_t i = 0; i < z.size(); i++)
{
z[i] = zArray[i];
}
switch (message)
{
case WM_CREATE:
GeopotentialAltitude::GaussianLegendre(
numberPoints, z, potential1);
GeopotentialAltitude::SimpsonsRule(
numberPoints, z, potential2);
GeopotentialAltitude::TrapezoidalRule(
numberPoints, z, potential3);
strcpy_s(asciiData, 16384, "H\tZ1\tZ2\tZ3\tg\r\n");
for (size_t i = 0; i < z.size(); i++)
{
double zi = z[i];
double p1 = potential1[i];
double p2 = potential2[i];
double p3 = potential3[i];
double g = g0 * pow(r0 / (r0 + p1), 2.0);
sprintf_s(
asciiLine, 16384,
"%5.0lf\t%5.1lf\t%5.1lf\t%5.1lf\t%7.5lf\r\n",
zi, p1, p2, p3, g);
strcat_s(asciiData, 16384, asciiLine);
}
strcat_s(asciiData, "H Geopotential Altitude\r\n");
strcat_s(asciiData, "Z1 Geopotential Gauss-Legendre 128 Steps\r\n");
strcat_s(asciiData, "Z2 Geopotential Simpson's Rule 256 Steps\r\n");
strcat_s(asciiData, "Z3 Geopotential Trapezoidal Rule 512 Steps\r\n");
strcat_s(asciiData, "g gravitational acceleration in m/s/s\r\n");
strcat_s(asciiData, "https://ntrs.nasa.gov/api/citations/19770009539/downloads/19770009539.pdf\r\n");
strcat_s(asciiData, "See Table 8. Page 9\r\n");
ConvertCharToTChar(asciiData, textData, sizeof(textData));
// https://learn.microsoft.com/en-us/windows/win32/controls/use-a-multiline-edit-control
hwndEdit = CreateWindowEx(
0, L"EDIT", // predefined class
NULL, // no window title
WS_CHILD | WS_VISIBLE | WS_VSCROLL |
ES_LEFT | ES_MULTILINE | ES_AUTOVSCROLL,
0, 0, 0, 0, // set size in WM_SIZE message
hWnd, // parent window
(HMENU) ID_EDITCHILD, // edit control ID
hInst,
/*(HINSTANCE) GetWindowLongPtr(hWnd, GWLP_HINSTANCE),*/
NULL); // pointer not needed
// Add text to the window.
SendMessage(hwndEdit, WM_SETTEXT, 0, (LPARAM) textData);
return 0;
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code here...
EndPaint(hWnd, &ps);
break;
case WM_SIZE:
// Make the edit control the size of the window's client area.
MoveWindow(hwndEdit,
0, 0, // starting x- and y-coordinates
LOWORD(lParam), // width of client area
HIWORD(lParam), // height of client area
TRUE); // repaint window
return 0;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
// Message handler for about box.
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(lParam);
switch (message)
{
case WM_INITDIALOG:
return (INT_PTR)TRUE;
case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
{
EndDialog(hDlg, LOWORD(wParam));
return (INT_PTR)TRUE;
}
break;
}
return (INT_PTR)FALSE;
}